summaryrefslogtreecommitdiff
path: root/usr/src/cmd/priocntl
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/priocntl')
-rw-r--r--usr/src/cmd/priocntl/Makefile136
-rw-r--r--usr/src/cmd/priocntl/fsspriocntl.c461
-rw-r--r--usr/src/cmd/priocntl/fxpriocntl.c550
-rw-r--r--usr/src/cmd/priocntl/iapriocntl.c509
-rw-r--r--usr/src/cmd/priocntl/priocntl.c1108
-rw-r--r--usr/src/cmd/priocntl/priocntl.h100
-rw-r--r--usr/src/cmd/priocntl/rtpriocntl.c524
-rw-r--r--usr/src/cmd/priocntl/subr.c729
-rw-r--r--usr/src/cmd/priocntl/tspriocntl.c477
9 files changed, 4594 insertions, 0 deletions
diff --git a/usr/src/cmd/priocntl/Makefile b/usr/src/cmd/priocntl/Makefile
new file mode 100644
index 0000000000..a947c89073
--- /dev/null
+++ b/usr/src/cmd/priocntl/Makefile
@@ -0,0 +1,136 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+PROG= priocntl
+
+PRIOCNTLOBJ= $(PROG).o subr.o
+
+PRIOCNTLSRC= $(PRIOCNTLOBJ:%.o=%.c)
+OBJS= $(PRIOCNTLOBJ) rt$(PROG).o ts$(PROG).o ia$(PROG).o fss$(PROG).o \
+ fx$(PROG).o
+SRCS= $(OBJ:%.o=%.c)
+
+include ../Makefile.cmd
+
+LDLIBS += -lcontract
+
+CLASSD = $(ROOTLIB)/class
+RTD = $(CLASSD)/RT
+TSD = $(CLASSD)/TS
+IAD = $(CLASSD)/IA
+FSSD = $(CLASSD)/FSS
+FXD = $(CLASSD)/FX
+DIRS = $(CLASSD) $(RTD) $(TSD) $(IAD) $(FSSD) $(FXD)
+
+RTPROG = RT$(PROG)
+TSPROG = TS$(PROG)
+IAPROG = IA$(PROG)
+FSSPROG = FSS$(PROG)
+FXPROG = FX$(PROG)
+
+ROOTRTPROG = $(RTD)/$(RTPROG)
+ROOTTSPROG = $(TSD)/$(TSPROG)
+ROOTIAPROG = $(IAD)/$(IAPROG)
+ROOTFSSPROG = $(FSSD)/$(FSSPROG)
+ROOTFXPROG = $(FXD)/$(FXPROG)
+
+$(ROOTUSRSBINPROG) := FILEMODE = 04555
+$(ROOTUSRSBINPROG) := OWNER= root
+$(ROOTUSRSBINPROG) := GROUP= root
+$(DIRS) := FILEMODE = 0775
+$(DIRS) := OWNER = root
+$(DIRS) := GROUP = bin
+CLOBBERFILES += $(RTPROG) $(TSPROG) $(IAPROG) $(FSSPROG) $(FXPROG)
+
+# installation rules
+$(RTD)/% : %
+ $(INS.file)
+
+$(TSD)/% : %
+ $(INS.file)
+
+$(IAD)/% : %
+ $(INS.file)
+
+$(FSSD)/% : %
+ $(INS.file)
+
+$(FXD)/% : %
+ $(INS.file)
+
+.KEEP_STATE:
+
+all: $(PROG) $(RTPROG) $(TSPROG) $(IAPROG) $(FSSPROG) $(FXPROG)
+
+$(PROG): $(PRIOCNTLOBJ)
+ $(LINK.c) $(PRIOCNTLOBJ) -o $@ $(LDLIBS)
+ $(POST_PROCESS)
+
+$(RTPROG): rt$(PRIOCNTLOBJ)
+ $(LINK.c) rt$(PRIOCNTLOBJ) -o $@ $(LDLIBS)
+ $(POST_PROCESS)
+
+$(TSPROG): ts$(PRIOCNTLOBJ)
+ $(LINK.c) ts$(PRIOCNTLOBJ) -o $@ $(LDLIBS)
+ $(POST_PROCESS)
+
+$(IAPROG): ia$(PRIOCNTLOBJ)
+ $(LINK.c) ia$(PRIOCNTLOBJ) -o $@ $(LDLIBS)
+ $(POST_PROCESS)
+
+$(FSSPROG): fss$(PRIOCNTLOBJ)
+ $(LINK.c) fss$(PRIOCNTLOBJ) -o $@ $(LDLIBS)
+ $(POST_PROCESS)
+
+$(FXPROG): fx$(PRIOCNTLOBJ)
+ $(LINK.c) fx$(PRIOCNTLOBJ) -o $@ $(LDLIBS)
+ $(POST_PROCESS)
+
+install: all $(DIRS) \
+ $(ROOTPROG) \
+ $(ROOTRTPROG) \
+ $(ROOTTSPROG) \
+ $(ROOTIAPROG) \
+ $(ROOTFSSPROG) \
+ $(ROOTFXPROG)
+
+$(DIRS):
+ $(INS.dir)
+
+clean:
+ $(RM) $(OBJS)
+
+lint:
+ $(LINT.c) $(PRIOCNTLSRC) $(LDLIBS)
+ $(LINT.c) rt$(PRIOCNTLSRC) $(LDLIBS)
+ $(LINT.c) ts$(PRIOCNTLSRC) $(LDLIBS)
+ $(LINT.c) ia$(PRIOCNTLSRC) $(LDLIBS)
+ $(LINT.c) fss$(PRIOCNTLSRC) $(LDLIBS)
+ $(LINT.c) fx$(PRIOCNTLSRC) $(LDLIBS)
+
+include ../Makefile.targ
diff --git a/usr/src/cmd/priocntl/fsspriocntl.c b/usr/src/cmd/priocntl/fsspriocntl.c
new file mode 100644
index 0000000000..d37c165592
--- /dev/null
+++ b/usr/src/cmd/priocntl/fsspriocntl.c
@@ -0,0 +1,461 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/procset.h>
+#include <sys/priocntl.h>
+#include <sys/fsspriocntl.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <libgen.h>
+#include <limits.h>
+#include <errno.h>
+#include "priocntl.h"
+
+/*
+ * This file contains the class specific code implementing the fair-share
+ * scheduler priocntl sub-command.
+ */
+#define ADDKEYVAL(p, k, v) { (p[0]) = (k); (p[1]) = (v); p += 2; }
+#define FSS_KEYCNT 2 /* max number of (key, value) pairs */
+
+/*
+ * Control flags
+ */
+#define FSS_DOUPRILIM 0x01 /* user priority limit */
+#define FSS_DOUPRI 0x02 /* user priority */
+
+static void print_fssinfo(void);
+static int print_fssprocs(void);
+static int fss_priocntl(idtype_t, id_t, int, char *, uintptr_t *);
+static int set_fssprocs(idtype_t, int, char **, uint_t, pri_t, pri_t);
+static void exec_fsscmd(char **, uint_t, pri_t, pri_t);
+
+static char usage[] =
+"usage: priocntl -l\n"
+" priocntl -d [-d idtype] [idlist]\n"
+" priocntl -s [-c FSS] [-m fssuprilim] [-p fssupri] [-i idtype] "
+"[idlist]\n"
+" priocntl -e [-c FSS] [-m fssuprilim] [-p fssupri] command [argument(s)]"
+"\n";
+
+static char cmdpath[MAXPATHLEN];
+static char basenm[BASENMSZ];
+
+
+int
+main(int argc, char *argv[])
+{
+ int c;
+ int lflag, dflag, sflag, mflag, pflag, eflag, iflag;
+ pri_t fssuprilim;
+ pri_t fssupri;
+ char *idtypnm;
+ idtype_t idtype;
+ int idargc;
+ uint_t cflags;
+
+ (void) strlcpy(cmdpath, argv[0], MAXPATHLEN);
+ (void) strlcpy(basenm, basename(argv[0]), BASENMSZ);
+ lflag = dflag = sflag = mflag = pflag = eflag = iflag = 0;
+ while ((c = getopt(argc, argv, "ldsm:p:ec:i:")) != -1) {
+ switch (c) {
+ case 'l':
+ lflag++;
+ break;
+ case 'd':
+ dflag++;
+ break;
+ case 's':
+ sflag++;
+ break;
+ case 'm':
+ mflag++;
+ fssuprilim = (pri_t)str2num(optarg, SHRT_MIN, SHRT_MAX);
+ if (errno)
+ fatalerr("%s: Specified user priority limit %s "
+ "out of configured range\n",
+ basenm, optarg);
+ break;
+ case 'p':
+ pflag++;
+ fssupri = (pri_t)str2num(optarg, SHRT_MIN, SHRT_MAX);
+ if (errno)
+ fatalerr("%s: Specified user priority %s "
+ "out of configured range\n",
+ basenm, optarg);
+ break;
+ case 'e':
+ eflag++;
+ break;
+ case 'c':
+ if (strcmp(optarg, "FSS") != 0)
+ fatalerr("error: %s executed for %s class, %s "
+ "is actually sub-command for FSS class\n",
+ cmdpath, optarg, cmdpath);
+ break;
+ case 'i':
+ iflag++;
+ idtypnm = optarg;
+ break;
+ case '?':
+ fatalerr(usage);
+ default:
+ break;
+ }
+ }
+
+ if (lflag) {
+ if (dflag || sflag || mflag || pflag || eflag || iflag)
+ fatalerr(usage);
+
+ print_fssinfo();
+
+ } else if (dflag) {
+ if (lflag || sflag || mflag || pflag || eflag)
+ fatalerr(usage);
+
+ return (print_fssprocs());
+
+ } else if (sflag) {
+ if (lflag || dflag || eflag)
+ fatalerr(usage);
+
+ if (iflag) {
+ if (str2idtyp(idtypnm, &idtype) == -1)
+ fatalerr("%s: Bad idtype %s\n", basenm,
+ idtypnm);
+ } else {
+ idtype = P_PID;
+ }
+
+ cflags = (pflag ? FSS_DOUPRI : 0);
+
+ if (mflag)
+ cflags |= FSS_DOUPRILIM;
+
+ if (optind < argc)
+ idargc = argc - optind;
+ else
+ idargc = 0;
+
+ return (set_fssprocs(idtype, idargc, &argv[optind], cflags,
+ fssuprilim, fssupri));
+
+ } else if (eflag) {
+ if (lflag || dflag || sflag || iflag)
+ fatalerr(usage);
+
+ cflags = (pflag ? FSS_DOUPRI : 0);
+
+ if (mflag)
+ cflags |= FSS_DOUPRILIM;
+
+ exec_fsscmd(&argv[optind], cflags, fssuprilim, fssupri);
+
+ } else {
+ fatalerr(usage);
+ }
+
+ return (0);
+}
+
+/*
+ * Print our class name and the configured user priority range.
+ */
+static void
+print_fssinfo(void)
+{
+ pcinfo_t pcinfo;
+
+ (void) strcpy(pcinfo.pc_clname, "FSS");
+
+ (void) printf("FSS (Fair Share)\n");
+
+ if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1)
+ fatalerr("\tCan't get configured FSS user priority range\n");
+
+ (void) printf("\tConfigured FSS User Priority Range: -%d through %d\n",
+ ((fssinfo_t *)pcinfo.pc_clinfo)->fss_maxupri,
+ ((fssinfo_t *)pcinfo.pc_clinfo)->fss_maxupri);
+}
+
+/*
+ * Read a list of pids from stdin and print the user priority and user
+ * priority limit for each of the corresponding processes.
+ */
+static int
+print_fssprocs(void)
+{
+ pid_t *pidlist;
+ size_t numread;
+ int i;
+ char clname[PC_CLNMSZ];
+ pri_t fssuprilim;
+ pri_t fssupri;
+ int error = 0;
+
+ /*
+ * Read a list of pids from stdin.
+ */
+ if ((pidlist = read_pidlist(&numread, stdin)) == NULL)
+ fatalerr("%s: Can't read pidlist.\n", basenm);
+
+ (void) printf("FAIR SHARING PROCESSES:\n"
+ " PID FSSUPRILIM FSSUPRI\n");
+
+ if (numread == 0)
+ fatalerr("%s: No pids on input\n", basenm);
+
+ for (i = 0; i < numread; i++) {
+ (void) printf("%7ld", pidlist[i]);
+ if (priocntl(P_PID, pidlist[i], PC_GETXPARMS, "FSS",
+ FSS_KY_UPRI, &fssupri,
+ FSS_KY_UPRILIM, &fssuprilim, 0) != -1) {
+ (void) printf(" %5d %5d\n",
+ fssuprilim, fssupri);
+ } else {
+ error = 1;
+
+ if (priocntl(P_PID, pidlist[i], PC_GETXPARMS, NULL,
+ PC_KY_CLNAME, clname, 0) == -1 &&
+ strcmp(clname, "FSS"))
+ /*
+ * Process from some class other than fair
+ * sharing. It has probably changed class while
+ * priocntl command was executing (otherwise
+ * we wouldn't have been passed its pid).
+ * Print the little we know about it.
+ */
+ (void) printf("\tChanged to class %s while"
+ " priocntl command executing\n", clname);
+ else
+ (void) printf("\tCan't get FSS user priority"
+ "\n");
+ }
+ }
+
+ free_pidlist(pidlist);
+ return (error);
+}
+
+/*
+ * Call priocntl() with command codes PC_SETXPARMS or PC_GETXPARMS. The
+ * first parameter behind the command code is always the class name.
+ * Each parameter is headed by a key, which detemines the meanin of the
+ * following value. There is maximum FSS_KEYCNT == 2 of (key, value) pairs.
+ */
+static int
+fss_priocntl(idtype_t idtype, id_t id, int cmd, char *clname, uintptr_t *argsp)
+{
+ return (priocntl(idtype, id, cmd, clname, argsp[0], argsp[1],
+ argsp[2], argsp[3], 0));
+}
+
+/*
+ * Set all processes in the set specified by idtype/idargv to fair-sharing
+ * (if they aren't already fair-sharing) and set their user priority limit
+ * and user priority to those specified by fssuprilim and fssupri.
+ */
+static int
+set_fssprocs(idtype_t idtype, int idargc, char **idargv, uint_t cflags,
+ short fssuprilim, short fssupri)
+{
+ pcinfo_t pcinfo;
+ uintptr_t args[2 * FSS_KEYCNT + 1];
+ uintptr_t *argsp = &args[0];
+ pri_t maxupri;
+ char idtypnm[PC_IDTYPNMSZ];
+ int i;
+ int error = 0;
+ id_t id;
+
+ /*
+ * Get the fair sharing class ID and max configured user priority.
+ */
+ (void) strcpy(pcinfo.pc_clname, "FSS");
+ if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1)
+ fatalerr("%s: Can't get FSS class ID, priocntl system call "
+ "failed (%s)\n", basenm, strerror(errno));
+ maxupri = ((fssinfo_t *)pcinfo.pc_clinfo)->fss_maxupri;
+
+ /*
+ * Validate the fssuprilim and fssupri arguments.
+ */
+ if ((cflags & FSS_DOUPRILIM) != 0) {
+ if (fssuprilim > maxupri || fssuprilim < -maxupri)
+ fatalerr("%s: Specified user priority limit %d out of "
+ "configured range\n", basenm, fssuprilim);
+ ADDKEYVAL(argsp, FSS_KY_UPRILIM, fssuprilim);
+ }
+
+ if ((cflags & FSS_DOUPRI) != 0) {
+ if (fssupri > maxupri || fssupri < -maxupri)
+ fatalerr("%s: Specified user priority %d out of "
+ "configured range\n", basenm, fssupri);
+ ADDKEYVAL(argsp, FSS_KY_UPRI, fssupri);
+ }
+ *argsp = 0;
+
+ if (idtype == P_ALL) {
+ if (fss_priocntl(P_ALL, 0, PC_SETXPARMS, "FSS", args) == -1) {
+ if (errno == EPERM) {
+ (void) fprintf(stderr, "Permissions error "
+ "encountered on one or more processes.\n");
+ error = 1;
+ } else {
+ fatalerr("%s: Can't reset fair sharing "
+ "parameters\npriocntl system call failed "
+ "(%s)\n", basenm, strerror(errno));
+ }
+ } else if ((cflags & (FSS_DOUPRILIM|FSS_DOUPRI)) ==
+ FSS_DOUPRI) {
+ (void) verifyupri(idtype, 0, "FSS", FSS_KY_UPRILIM,
+ fssupri, basenm);
+ }
+ } else if (idargc == 0) {
+ if (fss_priocntl(idtype, P_MYID, PC_SETXPARMS, "FSS",
+ args) == -1) {
+ if (errno == EPERM) {
+ (void) idtyp2str(idtype, idtypnm);
+ (void) fprintf(stderr, "Permissions error "
+ "encountered on current %s.\n", idtypnm);
+ error = 1;
+ } else {
+ fatalerr("%s: Can't reset fair sharing "
+ "parameters\npriocntl system call failed "
+ "(%s)\n", basenm, strerror(errno));
+ }
+ } else if ((cflags & (FSS_DOUPRILIM|FSS_DOUPRI)) ==
+ FSS_DOUPRI && getmyid(idtype, &id) != -1) {
+ (void) verifyupri(idtype, id, "FSS", FSS_KY_UPRILIM,
+ fssupri, basenm);
+ }
+ } else {
+ (void) idtyp2str(idtype, idtypnm);
+ for (i = 0; i < idargc; i++) {
+ if (idtype == P_CID) {
+ (void) strcpy(pcinfo.pc_clname, idargv[i]);
+ if (priocntl(0, 0, PC_GETCID,
+ (caddr_t)&pcinfo) == -1)
+ fatalerr("%s: Invalid or unconfigured "
+ "class %s, priocntl system call "
+ "failed (%s)\n",
+ basenm, pcinfo.pc_clname,
+ strerror(errno));
+ id = pcinfo.pc_cid;
+ } else {
+ id = (id_t)str2num(idargv[i], INT_MIN, INT_MAX);
+ if (errno)
+ fatalerr("%s: Invalid id \"%s\"\n",
+ basenm, idargv[i]);
+ }
+
+ if (fss_priocntl(idtype, id, PC_SETXPARMS, "FSS",
+ args) == -1) {
+ if (errno == EPERM) {
+ (void) fprintf(stderr, "Permissions "
+ "error encountered on %s %s.\n",
+ idtypnm, idargv[i]);
+ error = 1;
+ } else {
+ fatalerr("%s: Can't reset fair sharing"
+ " parameters\npriocntl system call"
+ " failed (%s)\n",
+ basenm, strerror(errno));
+ }
+ } else if ((cflags & (FSS_DOUPRILIM|FSS_DOUPRI)) ==
+ FSS_DOUPRI) {
+ (void) verifyupri(idtype, id, "FSS",
+ FSS_KY_UPRILIM, fssupri, basenm);
+ }
+ }
+ }
+
+ return (error);
+}
+
+/*
+ * Execute the command pointed to by cmdargv as a fair-sharing process
+ * with the user priority limit given by fssuprilim and user priority fssupri.
+ */
+static void
+exec_fsscmd(char **cmdargv, uint_t cflags, pri_t fssuprilim, pri_t fssupri)
+{
+ pcinfo_t pcinfo;
+ uintptr_t args[2 * FSS_KEYCNT + 1];
+ uintptr_t *argsp = &args[0];
+ pri_t maxupri;
+ pri_t uprilim;
+
+ /*
+ * Get the fair sharing class ID and max configured user priority.
+ */
+ (void) strcpy(pcinfo.pc_clname, "FSS");
+ if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1)
+ fatalerr("%s: Can't get FSS class ID, priocntl system call "
+ "failed (%s)\n", basenm, strerror(errno));
+ maxupri = ((fssinfo_t *)pcinfo.pc_clinfo)->fss_maxupri;
+
+ if ((cflags & FSS_DOUPRILIM) != 0) {
+ if (fssuprilim > maxupri || fssuprilim < -maxupri)
+ fatalerr("%s: Specified user priority limit %d out of "
+ "configured range\n", basenm, fssuprilim);
+ ADDKEYVAL(argsp, FSS_KY_UPRILIM, fssuprilim);
+ }
+
+ if ((cflags & FSS_DOUPRI) != 0) {
+ if (fssupri > maxupri || fssupri < -maxupri)
+ fatalerr("%s: Specified user priority %d out of "
+ "configured range\n", basenm, fssupri);
+ ADDKEYVAL(argsp, FSS_KY_UPRI, fssupri);
+ }
+ *argsp = 0;
+
+ if (fss_priocntl(P_PID, P_MYID, PC_SETXPARMS, "FSS", args) == -1)
+ fatalerr("%s: Can't reset fair sharing parameters\n"
+ "priocntl system call failed (%s)\n",
+ basenm, strerror(errno));
+
+ if ((cflags & (FSS_DOUPRILIM|FSS_DOUPRI)) == FSS_DOUPRI) {
+ if (priocntl(P_PID, P_MYID, PC_GETXPARMS, "FSS",
+ FSS_KY_UPRILIM, &uprilim, 0) != -1 && fssupri > uprilim)
+ (void) fprintf(stderr,
+ "%s: Specified user priority %d exceeds"
+ " limit %d; set to %d (pid %d)\n",
+ basenm, fssupri, uprilim, uprilim, (int)getpid());
+ }
+
+ (void) execvp(cmdargv[0], cmdargv);
+ fatalerr("%s: Can't execute %s, exec failed (%s)\n",
+ basenm, cmdargv[0], strerror(errno));
+}
diff --git a/usr/src/cmd/priocntl/fxpriocntl.c b/usr/src/cmd/priocntl/fxpriocntl.c
new file mode 100644
index 0000000000..118762b3f7
--- /dev/null
+++ b/usr/src/cmd/priocntl/fxpriocntl.c
@@ -0,0 +1,550 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2001-2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <string.h>
+#include <libgen.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/procset.h>
+#include <sys/priocntl.h>
+#include <sys/fxpriocntl.h>
+#include <limits.h>
+#include <errno.h>
+
+#include "priocntl.h"
+
+/*
+ * This file contains the class specific code implementing
+ * the fixed-priority priocntl sub-command.
+ */
+
+#define ADDKEYVAL(p, k, v) { (p[0]) = (k); (p[1]) = (v); p += 2; }
+
+#define FX_KEYCNT 4 /* maximal number of (key, value) pairs */
+
+/*
+ * control flags
+ */
+#define FX_DOUPRILIM 0x01 /* user priority limit */
+#define FX_DOUPRI 0x02 /* user priority */
+#define FX_DOTQ 0x04 /* time quantum */
+
+
+
+static void print_fxinfo();
+static int print_fxprocs();
+static int set_fxprocs(idtype_t, int, char **, uint_t, pri_t, pri_t, long,
+ long);
+static void exec_fxcmd(char **, uint_t, pri_t, pri_t, long, long);
+static int fx_priocntl(idtype_t, id_t, int, char *, uintptr_t *);
+
+static char usage[] =
+"usage: priocntl -l\n\
+ priocntl -d [-d idtype] [idlist]\n\
+ priocntl -s [-c FX] [-m fxuprilim] [-p fxupri] [-t tqntm [-r res]] \
+[-i idtype] [idlist]\n\
+ priocntl -e [-c FX] [-m fxuprilim] [-p fxupri] [-t tqntm [-r res]] \
+command [argument(s)]\n";
+
+static char cmdpath[MAXPATHLEN];
+static char basenm[BASENMSZ];
+
+int
+main(int argc, char *argv[])
+{
+ extern char *optarg;
+ extern int optind;
+
+ int c;
+ int lflag, dflag, sflag, mflag, pflag, eflag, iflag, tflag;
+ int rflag;
+ pri_t fxuprilim;
+ pri_t fxupri;
+ char *idtypnm;
+ idtype_t idtype;
+ int idargc;
+ long res;
+ long tqntm;
+ uint_t cflags;
+
+ (void) strlcpy(cmdpath, argv[0], MAXPATHLEN);
+ (void) strlcpy(basenm, basename(argv[0]), BASENMSZ);
+ lflag = dflag = sflag = mflag = pflag = eflag = iflag = tflag = 0;
+ rflag = 0;
+ while ((c = getopt(argc, argv, "ldsm:p:ec:i:t:r:")) != -1) {
+ switch (c) {
+
+ case 'l':
+ lflag++;
+ break;
+
+ case 'd':
+ dflag++;
+ break;
+
+ case 's':
+ sflag++;
+ break;
+
+ case 'm':
+ mflag++;
+ fxuprilim = (pri_t)str2num(optarg, SHRT_MIN, SHRT_MAX);
+ if (errno)
+ fatalerr("%s: Specified user priority limit %s"
+ " out of configured range\n",
+ basenm, optarg);
+ break;
+
+ case 'p':
+ pflag++;
+ fxupri = (pri_t)str2num(optarg, SHRT_MIN, SHRT_MAX);
+ if (errno)
+ fatalerr("%s: Specified user priority %s out of"
+ " configured range\n", basenm, optarg);
+ break;
+
+ case 'e':
+ eflag++;
+ break;
+
+ case 'c':
+ if (strcmp(optarg, "FX") != 0)
+ fatalerr("error: %s executed for %s class, %s"
+ " is actually sub-command for FX class\n",
+ cmdpath, optarg, cmdpath);
+ break;
+
+ case 'i':
+ iflag++;
+ idtypnm = optarg;
+ break;
+ case 't':
+ tflag++;
+ tqntm = str2num(optarg, 1, INT_MAX);
+ if (errno)
+ fatalerr("%s: Invalid time quantum specified;"
+ " time quantum must be positive\n", basenm);
+ break;
+
+ case 'r':
+ rflag++;
+ res = str2num(optarg, 1, 1000000000);
+ if (errno)
+ fatalerr("%s: Invalid resolution specified;"
+ " resolution must be between"
+ " 1 and 1,000,000,000\n", basenm);
+
+ break;
+
+ case '?':
+ fatalerr(usage);
+
+ default:
+ break;
+ }
+ }
+
+ if (lflag) {
+ if (dflag || sflag || mflag || pflag || eflag || iflag ||
+ tflag || rflag)
+ fatalerr(usage);
+
+ print_fxinfo();
+
+ } else if (dflag) {
+ if (sflag || mflag || pflag || eflag)
+ fatalerr(usage);
+
+ return (print_fxprocs());
+
+ } else if (sflag) {
+ if (eflag)
+ fatalerr(usage);
+
+ if (iflag) {
+ if (str2idtyp(idtypnm, &idtype) == -1)
+ fatalerr("%s: Bad idtype %s\n", basenm,
+ idtypnm);
+ } else
+ idtype = P_PID;
+
+ cflags = (pflag ? FX_DOUPRI : 0);
+
+ if (mflag)
+ cflags |= FX_DOUPRILIM;
+
+ if (tflag)
+ cflags |= FX_DOTQ;
+
+ if (rflag == 0)
+ res = 1000;
+
+ if (optind < argc)
+ idargc = argc - optind;
+ else
+ idargc = 0;
+
+ return (set_fxprocs(idtype, idargc, &argv[optind], cflags,
+ fxuprilim, fxupri, tqntm, res));
+
+ } else if (eflag) {
+ if (iflag)
+ fatalerr(usage);
+
+ cflags = (pflag ? FX_DOUPRI : 0);
+
+ if (mflag)
+ cflags |= FX_DOUPRILIM;
+
+ if (tflag)
+ cflags |= FX_DOTQ;
+
+ if (rflag == 0)
+ res = 1000;
+
+ exec_fxcmd(&argv[optind], cflags, fxuprilim, fxupri, tqntm,
+ res);
+
+ } else {
+ fatalerr(usage);
+ }
+ return (0);
+}
+
+
+/*
+ * Print our class name and the configured user priority range.
+ */
+static void
+print_fxinfo()
+{
+ pcinfo_t pcinfo;
+
+ (void) strcpy(pcinfo.pc_clname, "FX");
+
+ (void) printf("FX (Fixed priority)\n");
+
+ if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1)
+ fatalerr("\tCan't get configured FX user priority range\n");
+
+ (void) printf("\tConfigured FX User Priority Range: 0 through %d\n",
+ ((fxinfo_t *)pcinfo.pc_clinfo)->fx_maxupri);
+}
+
+
+/*
+ * Read a list of pids from stdin and print the user priority and user
+ * priority limit for each of the corresponding processes.
+ */
+static int
+print_fxprocs()
+{
+ pid_t *pidlist;
+ size_t numread;
+ int i;
+ char clname[PC_CLNMSZ];
+ uint_t fx_tqsecs;
+ int fx_tqnsecs;
+ pri_t fx_uprilim;
+ pri_t fx_upri;
+ int error = 0;
+
+
+ /*
+ * Read a list of pids from stdin.
+ */
+ if ((pidlist = read_pidlist(&numread, stdin)) == NULL)
+ fatalerr("%s: Can't read pidlist.\n", basenm);
+
+ (void) printf("FIXED PRIORITY PROCESSES:\n PID FXUPRILIM "
+ "FXUPRI FXTQNTM\n");
+
+ if (numread == 0)
+ fatalerr("%s: No pids on input\n", basenm);
+
+
+ for (i = 0; i < numread; i++) {
+ (void) printf("%7ld", pidlist[i]);
+ if (priocntl(P_PID, pidlist[i], PC_GETXPARMS, "FX",
+ FX_KY_UPRI, &fx_upri, FX_KY_UPRILIM, &fx_uprilim,
+ FX_KY_TQSECS, &fx_tqsecs, FX_KY_TQNSECS,
+ &fx_tqnsecs, 0) != -1) {
+ (void) printf(" %5d %5d", fx_uprilim, fx_upri);
+
+ if (fx_tqnsecs == FX_TQINF)
+ (void) printf(" FX_TQINF\n");
+ else
+ (void) printf(" %11lld\n",
+ (longlong_t)fx_tqsecs * 1000 +
+ fx_tqnsecs / 1000000);
+
+ } else {
+ error = 1;
+
+ if (priocntl(P_PID, pidlist[i], PC_GETXPARMS, NULL,
+ PC_KY_CLNAME, clname, 0) != -1 &&
+ strcmp(clname, "FX")) {
+ /*
+ * Process from some class other than fixed priority.
+ * It has probably changed class while priocntl
+ * command was executing (otherwise we wouldn't
+ * have been passed its pid). Print the little
+ * we know about it.
+ */
+ (void) printf("\tChanged to class %s while priocntl"
+ " command executing\n", clname);
+ } else {
+ (void) printf("\tCan't get FX user priority\n");
+ }
+ }
+ }
+
+ free_pidlist(pidlist);
+ return (error);
+}
+
+/*
+ * Call priocntl() with command codes PC_SETXPARMS or PC_GETXPARMS.
+ * The first parameter behind the command code is always the class name.
+ * Each parameter is headed by a key, which determines the meaning of the
+ * following value. There are maximal FX_KEYCNT = 4 (key, value) pairs.
+ */
+static int
+fx_priocntl(idtype_t idtype, id_t id, int cmd, char *clname, uintptr_t *argsp)
+{
+ return (priocntl(idtype, id, cmd, clname, argsp[0], argsp[1],
+ argsp[2], argsp[3], argsp[4], argsp[5], argsp[6], argsp[7], 0));
+}
+
+/*
+ * Set all processes in the set specified by idtype/idargv to fixed-priority
+ * (if they aren't already fixed-priority) and set their user priority limit
+ * and user priority to those specified by fxuprilim and fxupri.
+ */
+static int
+set_fxprocs(idtype_t idtype, int idargc, char **idargv, uint_t cflags,
+ pri_t fxuprilim, pri_t fxupri, long tqntm, long res)
+{
+ pcinfo_t pcinfo;
+ uintptr_t args[2*FX_KEYCNT+1];
+ uintptr_t *argsp = &args[0];
+ pri_t maxupri;
+ char idtypnm[PC_IDTYPNMSZ];
+ int i;
+ id_t id;
+ hrtimer_t hrtime;
+ int error = 0;
+
+ /*
+ * Get the fixed priority class ID and max configured user priority.
+ */
+ (void) strcpy(pcinfo.pc_clname, "FX");
+ if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1)
+ fatalerr("%s: Can't get FX class ID, priocntl system call"
+ " failed with errno %d\n", basenm, errno);
+ maxupri = ((fxinfo_t *)pcinfo.pc_clinfo)->fx_maxupri;
+
+ /*
+ * Validate the fxuprilim and fxupri arguments.
+ */
+ if ((cflags & FX_DOUPRILIM) != 0) {
+ if (fxuprilim > maxupri || fxuprilim < 0) {
+ fatalerr("%s: Specified user priority limit %d out of"
+ " configured range\n", basenm, fxuprilim);
+ }
+ ADDKEYVAL(argsp, FX_KY_UPRILIM, fxuprilim);
+ }
+
+ if ((cflags & FX_DOUPRI) != 0) {
+ if (fxupri > maxupri || fxupri < 0)
+ fatalerr("%s: Specified user priority %d out of "
+ "configured range\n", basenm, fxupri);
+ ADDKEYVAL(argsp, FX_KY_UPRI, fxupri);
+
+ }
+
+ if (cflags & FX_DOTQ) {
+ hrtime.hrt_secs = 0;
+ hrtime.hrt_rem = tqntm;
+ hrtime.hrt_res = res;
+ if (_hrtnewres(&hrtime, NANOSEC, HRT_RNDUP) == -1)
+ fatalerr("%s: Can't convert resolution.\n", basenm);
+ ADDKEYVAL(argsp, FX_KY_TQSECS, hrtime.hrt_secs);
+ ADDKEYVAL(argsp, FX_KY_TQNSECS, hrtime.hrt_rem);
+ }
+
+ *argsp = 0;
+
+ if (idtype == P_ALL) {
+ if (fx_priocntl(P_ALL, 0, PC_SETXPARMS, "FX", args) == -1) {
+ if (errno == EPERM) {
+ (void) fprintf(stderr,
+ "Permissions error encountered "
+ "on one or more processes.\n");
+ error = 1;
+ } else {
+ fatalerr("%s: Can't reset fixed priority"
+ " parameters\npriocntl system call failed "
+ " with errno %d\n", basenm, errno);
+ }
+ } else if ((cflags & (FX_DOUPRILIM|FX_DOUPRI)) == FX_DOUPRI) {
+ (void) verifyupri(idtype, 0, "FX", FX_KY_UPRILIM,
+ fxupri, basenm);
+ }
+ } else if (idargc == 0) {
+ if (fx_priocntl(idtype, P_MYID, PC_SETXPARMS, "FX",
+ args) == -1) {
+ if (errno == EPERM) {
+ (void) idtyp2str(idtype, idtypnm);
+ (void) fprintf(stderr, "Permissions error"
+ " encountered on current %s.\n", idtypnm);
+ error = 1;
+ } else {
+ fatalerr("%s: Can't reset fixed priority"
+ " parameters\npriocntl system call failed"
+ " with errno %d\n", basenm, errno);
+ }
+ } else if ((cflags & (FX_DOUPRILIM|FX_DOUPRI)) == FX_DOUPRI &&
+ getmyid(idtype, &id) != -1) {
+ (void) verifyupri(idtype, id, "FX", FX_KY_UPRILIM,
+ fxupri, basenm);
+ }
+ } else {
+ (void) idtyp2str(idtype, idtypnm);
+ for (i = 0; i < idargc; i++) {
+ if (idtype == P_CID) {
+ (void) strcpy(pcinfo.pc_clname, idargv[i]);
+ if (priocntl(0, 0, PC_GETCID,
+ (caddr_t)&pcinfo) == -1)
+ fatalerr("%s: Invalid or unconfigured"
+ " class %s, priocntl system call"
+ " failed with errno %d\n",
+ basenm, pcinfo.pc_clname, errno);
+ id = pcinfo.pc_cid;
+ } else {
+ id = (id_t)str2num(idargv[i], INT_MIN, INT_MAX);
+ }
+
+ if (fx_priocntl(idtype, id, PC_SETXPARMS, "FX", args)
+ == -1) {
+ if (errno == EPERM) {
+ (void) fprintf(stderr,
+ "Permissions error encountered on"
+ " %s %s.\n", idtypnm, idargv[i]);
+ error = 1;
+ } else {
+ fatalerr("%s: Can't reset fixed "
+ "priority"
+ " parameters\npriocntl system call"
+ " failed with errno %d\n",
+ basenm, errno);
+ }
+ } else if ((cflags & (FX_DOUPRILIM|FX_DOUPRI)) ==
+ FX_DOUPRI) {
+ (void) verifyupri(idtype, id, "FX",
+ FX_KY_UPRILIM, fxupri, basenm);
+ }
+ }
+ }
+ return (error);
+
+}
+
+
+/*
+ * Execute the command pointed to by cmdargv as a fixed-priority process
+ * with the user priority limit given by fxuprilim and user priority fxupri.
+ */
+static void
+exec_fxcmd(char **cmdargv, uint_t cflags, pri_t fxuprilim, pri_t fxupri,
+ long tqntm, long res)
+{
+ pcinfo_t pcinfo;
+ uintptr_t args[2*FX_KEYCNT+1];
+ uintptr_t *argsp = &args[0];
+
+ pri_t maxupri;
+ pri_t uprilim;
+ hrtimer_t hrtime;
+
+ /*
+ * Get the fixed priority class ID and max configured user priority.
+ */
+ (void) strcpy(pcinfo.pc_clname, "FX");
+ if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1)
+ fatalerr("%s: Can't get FX class ID, priocntl system call"
+ " failed with errno %d\n", basenm, errno);
+ maxupri = ((fxinfo_t *)pcinfo.pc_clinfo)->fx_maxupri;
+
+ if ((cflags & FX_DOUPRILIM) != 0) {
+ if (fxuprilim > maxupri || fxuprilim < 0)
+ fatalerr("%s: Specified user priority limit %d out of"
+ " configured range\n", basenm, fxuprilim);
+ ADDKEYVAL(argsp, FX_KY_UPRILIM, fxuprilim);
+ }
+
+ if ((cflags & FX_DOUPRI) != 0) {
+ if (fxupri > maxupri || fxupri < 0)
+ fatalerr("%s: Specified user priority %d out of"
+ " configured range\n", basenm, fxupri);
+ ADDKEYVAL(argsp, FX_KY_UPRI, fxupri);
+ }
+
+ if ((cflags & FX_DOTQ) != 0) {
+ hrtime.hrt_secs = 0;
+ hrtime.hrt_rem = tqntm;
+ hrtime.hrt_res = res;
+ if (_hrtnewres(&hrtime, NANOSEC, HRT_RNDUP) == -1)
+ fatalerr("%s: Can't convert resolution.\n", basenm);
+ ADDKEYVAL(argsp, FX_KY_TQSECS, hrtime.hrt_secs);
+ ADDKEYVAL(argsp, FX_KY_TQNSECS, hrtime.hrt_rem);
+
+ }
+ *argsp = 0;
+ if (fx_priocntl(P_PID, P_MYID, PC_SETXPARMS, "FX", args) == -1)
+ fatalerr("%s: Can't reset fixed priority parameters\n"
+ " priocntl system call failed with errno %d\n",
+ basenm, errno);
+
+ if ((cflags & (FX_DOUPRILIM|FX_DOUPRI)) == FX_DOUPRI) {
+ if (priocntl(P_PID, P_MYID, PC_GETXPARMS, "FX",
+ FX_KY_UPRILIM, &uprilim, 0) != -1 && fxupri > uprilim)
+ (void) fprintf(stderr,
+ "%s: Specified user priority %d exceeds"
+ " limit %d; set to %d (pid %d)\n",
+ basenm, fxupri, uprilim, uprilim, (int)getpid());
+ }
+
+ (void) execvp(cmdargv[0], cmdargv);
+ fatalerr("%s: Can't execute %s, exec failed with errno %d\n",
+ basenm, cmdargv[0], errno);
+}
diff --git a/usr/src/cmd/priocntl/iapriocntl.c b/usr/src/cmd/priocntl/iapriocntl.c
new file mode 100644
index 0000000000..d353415982
--- /dev/null
+++ b/usr/src/cmd/priocntl/iapriocntl.c
@@ -0,0 +1,509 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/procset.h>
+#include <sys/priocntl.h>
+#include <sys/iapriocntl.h>
+#include <libgen.h>
+#include <limits.h>
+#include <errno.h>
+
+#include "priocntl.h"
+
+/*
+ * This file contains the class specific code implementing
+ * the interactive class priocntl sub-command.
+ */
+
+#define ADDKEYVAL(p, k, v) { (p[0]) = (k); (p[1]) = (v); p += 2; }
+
+#define IA_KEYCNT 3 /* maximal number of (key, value) pairs */
+
+/*
+ * control flags
+ */
+#define IA_DOUPRILIM 0x01 /* user priority limit */
+#define IA_DOUPRI 0x02 /* user priority */
+#define IA_DOMODE 0x04 /* interactive on/off */
+
+static void print_iainfo(void);
+static int print_iaprocs(void);
+static int ia_priocntl(idtype_t, id_t, int, char *, uintptr_t *);
+static int set_iaprocs(idtype_t, int, char **, uint_t, pri_t, pri_t, int);
+static void exec_iacmd(char **, uint_t, pri_t, pri_t, int);
+
+static char usage[] =
+"usage: priocntl -l\n\
+ priocntl -d [-i idtype] [idlist]\n\
+ priocntl -s [-c IA] [-m iauprilim] [-p iaupri] [-t iamode]\n\
+ [-i idtype] [idlist]\n\
+ priocntl -e [-c IA] [-m iauprilim] [-p iaupri] [-t iamode]\n\
+ command [argument(s)]\n";
+
+static char cmdpath[MAXPATHLEN];
+static char basenm[BASENMSZ];
+
+
+int
+main(int argc, char *argv[])
+{
+ int c;
+ int lflag, dflag, sflag, mflag, pflag, eflag, iflag, tflag;
+ int iamode;
+ pri_t iauprilim;
+ pri_t iaupri;
+ char *idtypnm;
+ idtype_t idtype;
+ int idargc;
+ uint_t cflags;
+
+ (void) strlcpy(cmdpath, argv[0], MAXPATHLEN);
+ (void) strlcpy(basenm, basename(argv[0]), BASENMSZ);
+ lflag = dflag = sflag = mflag = pflag = eflag = iflag = tflag = 0;
+ while ((c = getopt(argc, argv, "ldsm:p:t:ec:i:")) != -1) {
+ switch (c) {
+
+ case 'l':
+ lflag++;
+ break;
+
+ case 'd':
+ dflag++;
+ break;
+
+ case 's':
+ sflag++;
+ break;
+
+ case 'm':
+ mflag++;
+ iauprilim = (pri_t)str2num(optarg, SHRT_MIN, SHRT_MAX);
+ if (errno)
+ fatalerr("%s: Specified user priority limit %s"
+ " out of configured range\n",
+ basenm, optarg);
+ break;
+
+ case 'p':
+ pflag++;
+ iaupri = (pri_t)str2num(optarg, SHRT_MIN, SHRT_MAX);
+ if (errno)
+ fatalerr("%s: Specified user priority %s out of"
+ " configured range\n", basenm, optarg);
+ break;
+
+ case 't':
+ tflag++;
+ iamode = (int)str2num(optarg, INT_MIN, INT_MAX);
+ if (errno || (iamode != IA_INTERACTIVE_OFF &&
+ iamode != IA_SET_INTERACTIVE))
+ fatalerr("%s: Specified illegal mode %s\n",
+ basenm, optarg);
+ break;
+
+ case 'e':
+ eflag++;
+ break;
+
+ case 'c':
+ if (strcmp(optarg, "IA") != 0)
+ fatalerr("error: %s executed for %s class, %s"
+ " is actually sub-command for IA class\n",
+ cmdpath, optarg, cmdpath);
+ break;
+
+ case 'i':
+ iflag++;
+ idtypnm = optarg;
+ break;
+
+ case '?':
+ fatalerr(usage);
+
+ default:
+ break;
+ }
+ }
+
+ if (lflag) {
+ if (dflag || sflag || mflag || pflag || tflag || eflag || iflag)
+ fatalerr(usage);
+
+ print_iainfo();
+
+ } else if (dflag) {
+ if (lflag || sflag || mflag || pflag || tflag || eflag)
+ fatalerr(usage);
+
+ return (print_iaprocs());
+
+ } else if (sflag) {
+ if (lflag || dflag || eflag)
+ fatalerr(usage);
+
+ if (iflag) {
+ if (str2idtyp(idtypnm, &idtype) == -1)
+ fatalerr("%s: Bad idtype %s\n", basenm,
+ idtypnm);
+ } else {
+ idtype = P_PID;
+ }
+
+ cflags = (pflag ? IA_DOUPRI : 0);
+
+ if (mflag)
+ cflags |= IA_DOUPRILIM;
+
+ if (tflag)
+ cflags |= IA_DOMODE;
+
+ if (optind < argc)
+ idargc = argc - optind;
+ else
+ idargc = 0;
+
+ return (set_iaprocs(idtype, idargc, &argv[optind], cflags,
+ iauprilim, iaupri, iamode));
+
+ } else if (eflag) {
+ if (lflag || dflag || sflag || iflag)
+ fatalerr(usage);
+
+ cflags = (pflag ? IA_DOUPRI : 0);
+
+ if (mflag)
+ cflags |= IA_DOUPRILIM;
+
+ if (tflag)
+ cflags |= IA_DOMODE;
+
+ exec_iacmd(&argv[optind], cflags, iauprilim, iaupri, iamode);
+
+ } else {
+ fatalerr(usage);
+ }
+
+ return (0);
+}
+
+
+/*
+ * Print our class name and the configured user priority range.
+ */
+static void
+print_iainfo(void)
+{
+ pcinfo_t pcinfo;
+
+ (void) strcpy(pcinfo.pc_clname, "IA");
+
+ (void) printf("IA (Interactive)\n");
+
+ if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1)
+ fatalerr("\tCan't get configured IA user priority range\n");
+
+ (void) printf("\tConfigured IA User Priority Range: -%d through %d\n",
+ ((iainfo_t *)pcinfo.pc_clinfo)->ia_maxupri,
+ ((iainfo_t *)pcinfo.pc_clinfo)->ia_maxupri);
+}
+
+
+/*
+ * Read a list of pids from stdin and print the user priority and user
+ * priority limit for each of the corresponding processes.
+ * print their interactive mode and nice values
+ */
+static int
+print_iaprocs(void)
+{
+ pid_t *pidlist;
+ size_t numread;
+ int i;
+ char clname[PC_CLNMSZ];
+ pri_t ia_uprilim;
+ pri_t ia_upri;
+ int ia_mode;
+ int error = 0;
+
+ /*
+ * Read a list of pids from stdin.
+ */
+ if ((pidlist = read_pidlist(&numread, stdin)) == NULL)
+ fatalerr("%s: Can't read pidlist.\n", basenm);
+
+ (void) printf("INTERACTIVE CLASS PROCESSES:");
+ (void) printf("\n PID IAUPRILIM IAUPRI IAMODE\n");
+
+ if (numread == 0)
+ fatalerr("%s: No pids on input\n", basenm);
+
+ for (i = 0; i < numread; i++) {
+ (void) printf("%7ld", pidlist[i]);
+ if (priocntl(P_PID, pidlist[i], PC_GETXPARMS, "IA",
+ IA_KY_UPRI, &ia_upri, IA_KY_UPRILIM, &ia_uprilim,
+ IA_KY_MODE, &ia_mode, 0) != -1) {
+ (void) printf(" %5d %5d %5d\n",
+ ia_uprilim, ia_upri, ia_mode);
+ } else {
+ error = 1;
+
+ if (priocntl(P_PID, pidlist[i], PC_GETXPARMS, NULL,
+ PC_KY_CLNAME, clname, 0) != -1 &&
+ strcmp(clname, "IA"))
+ /*
+ * Process from some class other than
+ * interactive. It has probably changed class
+ * while priocntl command was executing
+ * (otherwise we wouldn't have been passed its
+ * pid). Print the little we know about it.
+ */
+ (void) printf("\tChanged to class %s while"
+ " priocntl command executing\n", clname);
+ else
+ (void) printf("\tCan't get IA user priority\n");
+ }
+ }
+
+ free_pidlist(pidlist);
+ return (error);
+}
+
+
+/*
+ * Call priocntl() with command codes PC_SETXPARMS or PC_GETXPARMS.
+ * The first parameter behind the command code is always the class name.
+ * Each parameter is headed by a key, which determines the meaning of the
+ * following value. There are maximal IA_KEYCNT = 3 (key, value) pairs.
+ */
+static int
+ia_priocntl(idtype_t idtype, id_t id, int cmd, char *clname, uintptr_t *argsp)
+{
+ return (priocntl(idtype, id, cmd, clname, argsp[0], argsp[1],
+ argsp[2], argsp[3], argsp[4], argsp[5], 0));
+}
+
+
+/*
+ * Set all processes in the set specified by idtype/idargv to interactive
+ * (if they aren't already interactive ) and set their user priority limit
+ * and user priority to those specified by iauprilim and iaupri.
+ */
+static int
+set_iaprocs(idtype_t idtype, int idargc, char **idargv, uint_t cflags,
+ pri_t iauprilim, pri_t iaupri, int iamode)
+{
+ pcinfo_t pcinfo;
+ uintptr_t args[2*IA_KEYCNT+1];
+ uintptr_t *argsp = &args[0];
+ int maxupri;
+ char idtypnm[PC_IDTYPNMSZ];
+ int i;
+ int error = 0;
+ id_t id;
+
+ /*
+ * Get the interactive class ID and max configured user priority.
+ */
+ (void) strcpy(pcinfo.pc_clname, "IA");
+ if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1)
+ fatalerr("%s: Can't get IA class ID, priocntl system call"
+ " failed with errno %d\n", basenm, errno);
+ maxupri = ((iainfo_t *)pcinfo.pc_clinfo)->ia_maxupri;
+
+ /*
+ * Validate the iauprilim and iaupri arguments.
+ */
+ if ((cflags & IA_DOUPRILIM) != 0) {
+ if (iauprilim > maxupri || iauprilim < -maxupri)
+ fatalerr("%s: Specified user priority limit %d out of"
+ " configured range\n", basenm, iauprilim);
+ ADDKEYVAL(argsp, IA_KY_UPRILIM, iauprilim);
+ }
+
+ if ((cflags & IA_DOUPRI) != 0) {
+ if (iaupri > maxupri || iaupri < -maxupri)
+ fatalerr("%s: Specified user priority %d out of"
+ " configured range\n", basenm, iaupri);
+ ADDKEYVAL(argsp, IA_KY_UPRI, iaupri);
+ }
+
+ if ((cflags & IA_DOMODE) != 0)
+ ADDKEYVAL(argsp, IA_KY_MODE, iamode);
+ *argsp = 0;
+
+ if (idtype == P_ALL) {
+ if (ia_priocntl(P_ALL, 0, PC_SETXPARMS, "IA", args) == -1) {
+ if (errno == EPERM) {
+ (void) fprintf(stderr,
+ "Permissions error encountered"
+ " on one or more processes.\n");
+ error = 1;
+ } else {
+ fatalerr("%s: Can't reset interactive"
+ " parameters\npriocntl system call failed"
+ " with errno %d\n", basenm, errno);
+ }
+ } else if ((cflags & (IA_DOUPRILIM|IA_DOUPRI)) == IA_DOUPRI) {
+ (void) verifyupri(idtype, 0, "IA", IA_KY_UPRILIM,
+ iaupri, basenm);
+ }
+ } else if (idargc == 0) {
+ if (ia_priocntl(idtype, P_MYID, PC_SETXPARMS, "IA",
+ args) == -1) {
+ if (errno == EPERM) {
+ (void) idtyp2str(idtype, idtypnm);
+ (void) fprintf(stderr,
+ "Permissions error encountered"
+ " on current %s.\n", idtypnm);
+ error = 1;
+ } else {
+ fatalerr("%s: Can't reset interactive"
+ " parameters\npriocntl system call failed"
+ " with errno %d\n", basenm, errno);
+ }
+ } else if ((cflags & (IA_DOUPRILIM|IA_DOUPRI)) == IA_DOUPRI &&
+ getmyid(idtype, &id) != -1) {
+ (void) verifyupri(idtype, id, "IA", IA_KY_UPRILIM,
+ iaupri, basenm);
+ }
+ } else {
+ (void) idtyp2str(idtype, idtypnm);
+ for (i = 0; i < idargc; i++) {
+ if (idtype == P_CID) {
+ (void) strcpy(pcinfo.pc_clname, idargv[i]);
+ if (priocntl(0, 0, PC_GETCID,
+ (caddr_t)&pcinfo) == -1)
+ fatalerr("%s: Invalid or unconfigured"
+ " class %s, priocntl system call"
+ " failed with errno %d\n",
+ basenm, pcinfo.pc_clname, errno);
+ id = pcinfo.pc_cid;
+ } else {
+ id = (id_t)str2num(idargv[i], INT_MIN, INT_MAX);
+ if (errno)
+ fatalerr("%s: Invalid id \"%s\"\n",
+ basenm, idargv[i]);
+ }
+
+ if (ia_priocntl(idtype, id, PC_SETXPARMS, "IA",
+ args) == -1) {
+ if (errno == EPERM) {
+ (void) fprintf(stderr,
+ "Permissions error"
+ " encountered on %s %s.\n",
+ idtypnm, idargv[i]);
+ error = 1;
+ } else {
+ fatalerr("%s: Can't reset interactive"
+ " parameters\npriocntl system call"
+ " failed with errno %d\n",
+ basenm, errno);
+ }
+ } else if ((cflags & (IA_DOUPRILIM|IA_DOUPRI)) ==
+ IA_DOUPRI) {
+ (void) verifyupri(idtype, id, "IA",
+ IA_KY_UPRILIM, iaupri, basenm);
+ }
+ }
+ }
+
+ return (error);
+}
+
+
+/*
+ * Execute the command pointed to by cmdargv as a interactive process
+ * with the user priority limit given by iauprilim and user priority iaupri.
+ */
+static void
+exec_iacmd(char **cmdargv, uint_t cflags, pri_t iauprilim, pri_t iaupri,
+ int iamode)
+{
+ pcinfo_t pcinfo;
+ uintptr_t args[2*IA_KEYCNT+1];
+ uintptr_t *argsp = &args[0];
+ pri_t maxupri;
+ pri_t uprilim;
+
+ /*
+ * Get the time sharing class ID and max configured user priority.
+ */
+ (void) strcpy(pcinfo.pc_clname, "IA");
+ if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1)
+ fatalerr("%s: Can't get IA class ID, priocntl system call"
+ " failed with errno %d\n", basenm, errno);
+ maxupri = ((iainfo_t *)pcinfo.pc_clinfo)->ia_maxupri;
+
+ /*
+ * Validate the iauprilim and iaupri arguments.
+ */
+ if ((cflags & IA_DOUPRILIM) != 0) {
+ if (iauprilim > maxupri || iauprilim < -maxupri)
+ fatalerr("%s: Specified user priority limit %d out of"
+ " configured range\n", basenm, iauprilim);
+ ADDKEYVAL(argsp, IA_KY_UPRILIM, iauprilim);
+ }
+
+ if ((cflags & IA_DOUPRI) != 0) {
+ if (iaupri > maxupri || iaupri < -maxupri)
+ fatalerr("%s: Specified user priority %d out of"
+ " configured range\n", basenm, iaupri);
+ ADDKEYVAL(argsp, IA_KY_UPRI, iaupri);
+ }
+
+ if ((cflags & IA_DOMODE) != 0)
+ ADDKEYVAL(argsp, IA_KY_MODE, iamode);
+ *argsp = 0;
+
+ if (ia_priocntl(P_PID, P_MYID, PC_SETXPARMS, "IA", args) == -1)
+ fatalerr("%s: Can't reset interactive parameters\n"
+ "priocntl system call failed with errno %d\n",
+ basenm, errno);
+
+ if ((cflags & (IA_DOUPRILIM|IA_DOUPRI)) == IA_DOUPRI) {
+ if (priocntl(P_PID, P_MYID, PC_GETXPARMS, "IA",
+ IA_KY_UPRILIM, &uprilim, 0) != -1 && iaupri > uprilim)
+ (void) fprintf(stderr,
+ "%s: Specified user priority %d exceeds"
+ " limit %d; set to %d (pid %d)\n",
+ basenm, iaupri, uprilim, uprilim, (int)getpid());
+ }
+
+ (void) execvp(cmdargv[0], cmdargv);
+ fatalerr("%s: Can't execute %s, exec failed with errno %d\n",
+ basenm, cmdargv[0], errno);
+}
diff --git a/usr/src/cmd/priocntl/priocntl.c b/usr/src/cmd/priocntl/priocntl.c
new file mode 100644
index 0000000000..f599c18dad
--- /dev/null
+++ b/usr/src/cmd/priocntl/priocntl.c
@@ -0,0 +1,1108 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wait.h>
+#include <search.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/param.h>
+#include <sys/procset.h>
+#include <sys/priocntl.h>
+#include <procfs.h>
+#include <macros.h>
+#include <libgen.h>
+#include <limits.h>
+#include <errno.h>
+
+#include "priocntl.h"
+
+/*
+ * This file contains the code implementing the class independent part
+ * of the priocntl command. Most of the useful work for the priocntl
+ * command is done by the class specific sub-commands, the code for
+ * which is elsewhere. The class independent part of the command is
+ * responsible for executing the appropriate class specific sub-commands
+ * and providing any necessary input to the sub-commands.
+ * Code in this file should never assume any knowledge of any specific
+ * scheduler class (other than the SYS class).
+ */
+
+#define CLASSPATH "/usr/lib/class"
+
+typedef struct classpids {
+ char clp_clname[PC_CLNMSZ];
+ pid_t *clp_pidlist;
+ int clp_pidlistsz;
+ int clp_npids;
+} classpids_t;
+
+static char usage[] =
+"usage: priocntl -l\n\
+ priocntl -d [-i idtype] [idlist]\n\
+ priocntl -s [-c class] [c.s.o.] [-i idtype] [idlist]\n\
+ priocntl -e [-c class] [c.s.o.] command [argument(s)]\n";
+
+static char basenm[BASENMSZ];
+static char cmdpath[MAXPATHLEN];
+
+static char *procdir = "/proc";
+
+static int print_classlist(void);
+static void set_procs(char *, idtype_t, int, char **, char **);
+static void exec_cmd(char *, char **);
+static int print_procs(idtype_t, int, char *[]);
+static void ids2pids(idtype_t, id_t *, int, classpids_t *, int);
+static void add_pid_tolist(classpids_t *, int, char *, pid_t);
+static void increase_pidlist(classpids_t *);
+static boolean_t idmatch(char *, char *, int, char **);
+
+/*
+ * These variables are defined to be used in prio_getopt() below.
+ */
+static int prio_getopt();
+/* LINTED static unused */
+static int prio_optopt = 0;
+static char *prio_optarg = 0;
+static int prio_optind = 1;
+static int prio_sp = 1;
+
+int
+main(int argc, char *argv[])
+{
+ int c;
+ int lflag, dflag, sflag, eflag, cflag, iflag, csoptsflag;
+ char *clname;
+ char *idtypnm;
+ idtype_t idtype;
+ int idargc;
+ char **idargv;
+
+ (void) strlcpy(cmdpath, argv[0], MAXPATHLEN);
+ (void) strlcpy(basenm, basename(argv[0]), BASENMSZ);
+ lflag = dflag = sflag = eflag = cflag = iflag = csoptsflag = 0;
+ while ((c = prio_getopt(argc, argv, "ldsec:i:")) != -1) {
+
+ switch (c) {
+
+ case 'l':
+ lflag++;
+ break;
+
+ case 'd':
+ dflag++;
+ break;
+
+ case 's':
+ sflag++;
+ break;
+
+ case 'e':
+ eflag++;
+ break;
+
+ case 'c':
+ cflag++;
+ clname = prio_optarg;
+ break;
+
+ case 'i':
+ iflag++;
+ idtypnm = prio_optarg;
+ break;
+
+ case '?':
+ if (strcmp(argv[prio_optind - 1], "-c") == 0 ||
+ strcmp(argv[prio_optind - 1], "-i") == 0) {
+
+ /*
+ * getopt() will return ? if either
+ * of these appear without an argument.
+ */
+ fatalerr(usage);
+ }
+
+ /*
+ * We assume for now that any option that
+ * getopt() doesn't recognize (with the
+ * exception of c and i) is intended for a
+ * class specific subcommand. For now we also
+ * require that all class specific options
+ * take an argument (until we can get smarter
+ * about parsing our options).
+ */
+ csoptsflag++;
+ prio_optind++;
+ prio_sp = 1;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (lflag) {
+ if (dflag || sflag || eflag || cflag || iflag || csoptsflag)
+ fatalerr(usage);
+
+ return (print_classlist());
+
+ } else if (dflag) {
+ if (lflag || sflag || eflag || cflag || csoptsflag)
+ fatalerr(usage);
+ if (iflag) {
+ if (str2idtyp(idtypnm, &idtype) == -1)
+ fatalerr("%s: bad idtype %s\n", cmdpath,
+ idtypnm);
+ } else {
+ idtype = P_PID;
+ }
+
+ if (prio_optind < argc) {
+ idargc = argc - prio_optind;
+ idargv = &argv[prio_optind];
+ } else {
+ idargc = 0;
+ }
+
+ return (print_procs(idtype, idargc, idargv));
+
+ } else if (sflag) {
+ if (lflag || dflag || eflag)
+ fatalerr(usage);
+ if (iflag) {
+ if (str2idtyp(idtypnm, &idtype) == -1)
+ fatalerr("%s: bad idtype %s\n", cmdpath,
+ idtypnm);
+ } else {
+ idtype = P_PID;
+ }
+
+ if (cflag == 0)
+ clname = NULL;
+
+ if (prio_optind < argc) {
+ idargc = argc - prio_optind;
+ idargv = &argv[prio_optind];
+ } else {
+ idargc = 0;
+ }
+
+ set_procs(clname, idtype, idargc, idargv, argv);
+
+ } else if (eflag) {
+ if (lflag || dflag || sflag || iflag)
+ fatalerr(usage);
+
+ if (cflag == 0)
+ clname = NULL;
+
+ if (prio_optind >= argc)
+ fatalerr(usage);
+
+ exec_cmd(clname, argv);
+
+ } else {
+ fatalerr(usage);
+ }
+
+ return (0);
+}
+
+
+/*
+ * Print the heading for the class list and execute the class
+ * specific sub-command with the -l option for each configured class.
+ */
+static int
+print_classlist(void)
+{
+ id_t cid;
+ int nclass;
+ pcinfo_t pcinfo;
+ static char subcmdpath[128];
+ int status;
+ pid_t pid;
+ int error = 0;
+
+ /*
+ * No special privileges required for this operation.
+ * Set the effective UID back to the real UID.
+ */
+ if (setuid(getuid()) == -1)
+ fatalerr("%s: Can't set effective UID back to real UID\n",
+ cmdpath);
+
+ if ((nclass = priocntl(0, 0, PC_GETCLINFO, NULL)) == -1)
+ fatalerr("%s: Can't get number of configured classes, priocntl"
+ " system call failed with errno %d\n", cmdpath, errno);
+
+ (void) printf("CONFIGURED CLASSES\n==================\n\n");
+ (void) printf("SYS (System Class)\n");
+ for (cid = 1; cid < nclass; cid++) {
+ (void) printf("\n");
+ (void) fflush(stdout);
+ pcinfo.pc_cid = cid;
+ if (priocntl(0, 0, PC_GETCLINFO, (caddr_t)&pcinfo) == -1)
+ fatalerr("%s: can't get class name (class ID = %ld)\n",
+ cmdpath, cid);
+ if (snprintf(subcmdpath, sizeof (subcmdpath), "%s/%s/%s%s",
+ CLASSPATH, pcinfo.pc_clname, pcinfo.pc_clname, basenm) >=
+ sizeof (subcmdpath))
+ fatalerr("%s: can't generate %s specific subcommand\n",
+ cmdpath, pcinfo.pc_clname);
+ if ((pid = fork()) == 0) {
+ (void) execl(subcmdpath, subcmdpath, "-l", (char *)0);
+ (void) printf("%s\n", pcinfo.pc_clname);
+ fatalerr("\tCan't execute %s specific subcommand\n",
+ pcinfo.pc_clname);
+ } else if (pid == (pid_t)-1) {
+ (void) printf("%s\n", pcinfo.pc_clname);
+ (void) fprintf(stderr,
+ "Can't execute %s specific subcommand)\n",
+ pcinfo.pc_clname);
+ error = 1;
+ } else {
+ (void) wait(&status);
+ if (status)
+ error = 1;
+ }
+ }
+
+ return (error);
+}
+
+
+/*
+ * For each class represented within the set of processes specified by
+ * idtype/idargv, print_procs() executes the class specific sub-command
+ * with the -d option. We pipe to each sub-command a list of pids in
+ * the set belonging to that class.
+ */
+static int
+print_procs(idtype_t idtype, int idargc, char *idargv[])
+{
+ int i;
+ id_t id;
+ id_t idlist[NIDS];
+ int nids;
+ classpids_t *clpids;
+ int nclass;
+ id_t cid;
+ pcinfo_t pcinfo;
+ int pidexists;
+ FILE *pipe_to_subcmd;
+ char subcmd[128];
+ int error = 0;
+
+
+ /*
+ * Build a list of ids eliminating any duplicates in idargv.
+ */
+ if (idtype == P_ALL) {
+ /*
+ * No idlist should be specified. If one is specified,
+ * it is ignored.
+ */
+ nids = 0;
+ } else if (idargc == 0) {
+
+ /*
+ * No ids supplied by user; use current id.
+ */
+ if (getmyid(idtype, &idlist[0]) == -1)
+ fatalerr("%s: Can't get ID for current process,"
+ " idtype = %d\n", cmdpath, idtype);
+ nids = 1;
+ } else {
+ nids = 0;
+ for (i = 0; i < idargc && nids < NIDS; i++) {
+ if (idtype == P_CID) {
+ if ((id = clname2cid(idargv[i])) == -1) {
+ (void) fprintf(stderr, "%s: Invalid or"
+ " unconfigured class %s in idlist"
+ " - ignored\n", cmdpath, idargv[i]);
+ error = 1;
+ }
+ } else {
+ id = (id_t)str2num(idargv[i], INT_MIN, INT_MAX);
+ if (errno) {
+ (void) fprintf(stderr,
+ "%s: Invalid id \"%s\"\n",
+ cmdpath, idargv[i]);
+ error = 1;
+ id = BADPID;
+ }
+ }
+
+ /*
+ * lsearch(3C) adds ids to the idlist,
+ * eliminating duplicates.
+ */
+ (void) lsearch((void *)&id, (void *)idlist,
+ (size_t *)&nids, sizeof (id), (int (*)())idcompar);
+ }
+ }
+
+ if ((nclass = priocntl(0, 0, PC_GETCLINFO, NULL)) == -1)
+ fatalerr("%s: Can't get number of configured classes, priocntl"
+ " system call failed with errno %d\n", cmdpath, errno);
+
+ if ((clpids = (classpids_t *)malloc(sizeof (classpids_t) * nclass)) ==
+ NULL)
+ fatalerr("%s: Can't allocate memory for clpids.\n", cmdpath);
+
+ for (cid = 1; cid < nclass; cid++) {
+ pcinfo.pc_cid = cid;
+ if (priocntl(0, 0, PC_GETCLINFO, (caddr_t)&pcinfo) == -1)
+ fatalerr("%s: Can't get class name, cid = %ld\n",
+ cmdpath, cid);
+
+ (void) strncpy(clpids[cid].clp_clname, pcinfo.pc_clname,
+ PC_CLNMSZ);
+
+ /*
+ * The memory allocation for the pidlist uses realloc().
+ * A realloc() call is required, when "clp_npids" is
+ * equal to "clp_pidlistsz".
+ */
+ clpids[cid].clp_pidlist = (pid_t *)NULL;
+ clpids[cid].clp_pidlistsz = 0;
+ clpids[cid].clp_npids = 0;
+ }
+
+ /*
+ * Build the pidlist.
+ */
+ ids2pids(idtype, idlist, nids, clpids, nclass);
+
+ /*
+ * No need for special privileges any more.
+ * Set the effective UID back to the real UID.
+ */
+ if (setuid(getuid()) == -1)
+ fatalerr("%s: Can't set effective UID back to real UID\n",
+ cmdpath);
+
+ pidexists = 0;
+ for (cid = 1; cid < nclass; cid++) {
+ if (clpids[cid].clp_npids == 0)
+ continue;
+
+ pidexists = 1;
+ if (snprintf(subcmd, sizeof (subcmd), "%s/%s/%s%s -d",
+ CLASSPATH, clpids[cid].clp_clname, clpids[cid].clp_clname,
+ basenm) >= sizeof (subcmd)) {
+ (void) fprintf(stderr,
+ "Can't generate %s specific subcommand\n",
+ clpids[cid].clp_clname);
+ error = 1;
+ free(clpids[cid].clp_pidlist);
+ continue;
+ }
+ if ((pipe_to_subcmd = popen(subcmd, "w")) == NULL) {
+ (void) printf("%s\n", clpids[cid].clp_clname);
+ (void) fprintf(stderr,
+ "Can't execute %s specific subcommand\n",
+ clpids[cid].clp_clname);
+ error = 1;
+ free(clpids[cid].clp_pidlist);
+ continue;
+ }
+ (void) fwrite(clpids[cid].clp_pidlist, sizeof (pid_t),
+ clpids[cid].clp_npids, pipe_to_subcmd);
+ if (pclose(pipe_to_subcmd))
+ error = 1;
+
+ free(clpids[cid].clp_pidlist);
+ }
+
+ free(clpids);
+
+ if (pidexists == 0)
+ fatalerr("%s: Process(es) not found.\n", cmdpath);
+
+ return (error);
+}
+
+
+/*
+ * Execute the appropriate class specific sub-command with the arguments
+ * pointed to by subcmdargv. If the user specified a class we simply
+ * exec the sub-command for that class. If no class was specified we
+ * verify that the processes in the set specified by idtype/idargv are
+ * all in the same class and then execute the sub-command for that class.
+ */
+static void
+set_procs(clname, idtype, idargc, idargv, subcmdargv)
+char *clname;
+idtype_t idtype;
+int idargc;
+char **idargv;
+char **subcmdargv;
+{
+ char idstr[PC_IDTYPNMSZ];
+ char myidstr[PC_IDTYPNMSZ];
+ char clnmbuf[PC_CLNMSZ];
+ pcinfo_t pcinfo;
+ static psinfo_t prinfo;
+ static prcred_t prcred;
+ DIR *dirp;
+ struct dirent *dentp;
+ static char pname[100];
+ char *fname;
+ int procfd;
+ int saverr;
+ static char subcmdpath[128];
+ boolean_t procinset;
+ id_t id;
+ size_t len;
+
+ if (clname == NULL && idtype == P_PID && idargc <= 1) {
+
+ /*
+ * No class specified by user but only one process
+ * in specified set. Get the class the easy way.
+ */
+ if (idargc == 0) {
+ if (priocntl(P_PID, P_MYID, PC_GETXPARMS, NULL,
+ PC_KY_CLNAME, clnmbuf, 0) == -1)
+ if (errno == ESRCH)
+ fatalerr("%s: Process not found.\n",
+ cmdpath);
+ else
+ fatalerr("%s: Can't get class of"
+ " current process\npriocntl"
+ " system call failed with"
+ " errno %d\n", cmdpath, errno);
+ } else {
+ /* idargc == 1 */
+ id = (id_t)str2num(idargv[0], INT_MIN, INT_MAX);
+ if (errno)
+ fatalerr("%s: Invalid id \"%s\"\n", cmdpath,
+ idargv[0]);
+
+ if (priocntl(P_PID, id, PC_GETXPARMS,
+ NULL, PC_KY_CLNAME, clnmbuf, 0) == -1)
+ if (errno == ESRCH)
+ fatalerr("%s: Process not found.\n",
+ cmdpath);
+ else
+ fatalerr("%s: Can't get class of "
+ " specified process\npriocntl"
+ " system call failed with"
+ " errno %d\n", cmdpath, errno);
+ }
+
+ clname = clnmbuf;
+ } else if (clname == NULL) {
+
+ /*
+ * No class specified by user and potentially more
+ * than one process in specified set. Verify that
+ * all procs in set are in the same class.
+ */
+ if (idargc == 0 && idtype != P_ALL) {
+
+ /*
+ * No ids supplied by user; use current id.
+ */
+ if (getmyidstr(idtype, myidstr) == -1)
+ fatalerr("%s: Can't get ID string for current"
+ " process, idtype = %d\n", cmdpath, idtype);
+ }
+ if ((dirp = opendir(procdir)) == NULL)
+ fatalerr("%s: Can't open PROC directory %s\n",
+ cmdpath, procdir);
+
+ while ((dentp = readdir(dirp)) != NULL) {
+ if (dentp->d_name[0] == '.') /* skip . and .. */
+ continue;
+
+ len = snprintf(pname, sizeof (pname), "%s/%s/",
+ procdir, dentp->d_name);
+ /* Really max(sizeof ("psinfo"), sizeof ("cred")) */
+ if (len + sizeof ("psinfo") > sizeof (pname)) {
+ (void) fprintf(stderr,
+ "%s: skipping %s, name too long.\n",
+ cmdpath, dentp->d_name);
+ continue;
+ }
+ fname = pname + len;
+retry:
+ (void) strcpy(fname, "psinfo");
+ if ((procfd = open(pname, O_RDONLY)) < 0)
+ continue;
+
+ if (read(procfd, &prinfo, sizeof (prinfo)) !=
+ sizeof (prinfo)) {
+ saverr = errno;
+ (void) close(procfd);
+ if (saverr == EAGAIN)
+ goto retry;
+ if (saverr != ENOENT) {
+ (void) fprintf(stderr,
+ "%s: Can't get process info for"
+ " %s\n", cmdpath, pname);
+ }
+ continue;
+ }
+ (void) close(procfd);
+
+ if (idtype == P_UID || idtype == P_GID) {
+ (void) strcpy(fname, "cred");
+ if ((procfd = open(pname, O_RDONLY)) < 0 ||
+ read(procfd, &prcred, sizeof (prcred)) !=
+ sizeof (prcred)) {
+ saverr = errno;
+ if (procfd >= 0)
+ (void) close(procfd);
+ if (saverr == EAGAIN)
+ goto retry;
+ if (saverr != ENOENT) {
+ (void) fprintf(stderr,
+ "%s: Can't get process"
+ " credentials for %s\n",
+ cmdpath, pname);
+ }
+ continue;
+ }
+ (void) close(procfd);
+ }
+
+ if (prinfo.pr_lwp.pr_state == 0 || prinfo.pr_nlwp == 0)
+ continue;
+
+
+ switch (idtype) {
+
+ case P_PID:
+ itoa((long)prinfo.pr_pid, idstr);
+ procinset = idmatch(idstr, myidstr,
+ idargc, idargv);
+ break;
+
+ case P_PPID:
+ itoa((long)prinfo.pr_ppid, idstr);
+ procinset = idmatch(idstr, myidstr,
+ idargc, idargv);
+ break;
+
+ case P_PGID:
+ itoa((long)prinfo.pr_pgid, idstr);
+ procinset = idmatch(idstr, myidstr,
+ idargc, idargv);
+ break;
+
+ case P_SID:
+ itoa((long)prinfo.pr_sid, idstr);
+ procinset = idmatch(idstr, myidstr,
+ idargc, idargv);
+ break;
+
+ case P_CID:
+ procinset = idmatch(prinfo.pr_lwp.pr_clname,
+ myidstr, idargc, idargv);
+ break;
+
+ case P_UID:
+ itoa((long)prcred.pr_euid, idstr);
+ procinset = idmatch(idstr, myidstr,
+ idargc, idargv);
+ break;
+
+ case P_GID:
+ itoa((long)prcred.pr_egid, idstr);
+ procinset = idmatch(idstr, myidstr,
+ idargc, idargv);
+ break;
+
+ case P_PROJID:
+ itoa((long)prinfo.pr_projid, idstr);
+ procinset = idmatch(idstr, myidstr,
+ idargc, idargv);
+ break;
+
+ case P_TASKID:
+ itoa((long)prinfo.pr_taskid, idstr);
+ procinset = idmatch(idstr, myidstr,
+ idargc, idargv);
+ break;
+
+ case P_ZONEID:
+ itoa((long)prinfo.pr_zoneid, idstr);
+ procinset = idmatch(idstr, myidstr,
+ idargc, idargv);
+ break;
+
+ case P_CTID:
+ itoa((long)prinfo.pr_contract, idstr);
+ procinset = idmatch(idstr, myidstr,
+ idargc, idargv);
+ break;
+
+ case P_ALL:
+ procinset = B_TRUE;
+ break;
+
+ default:
+ fatalerr("%s: Bad idtype %d in set_procs()\n",
+ cmdpath, idtype);
+ }
+ if (procinset == B_TRUE) {
+ if (clname == NULL) {
+
+ /*
+ * First proc found in set.
+ */
+ (void) strcpy(clnmbuf,
+ prinfo.pr_lwp.pr_clname);
+ clname = clnmbuf;
+ } else if (strcmp(clname,
+ prinfo.pr_lwp.pr_clname) != 0) {
+ fatalerr("%s: Specified processes"
+ " from different classes.\n",
+ cmdpath);
+ }
+ }
+ }
+ (void) closedir(dirp);
+ if (clname == NULL)
+ fatalerr("%s: Process(es) not found.\n", cmdpath);
+ } else {
+
+ /*
+ * User specified class. Check it for validity.
+ */
+ (void) strcpy(pcinfo.pc_clname, clname);
+ if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1)
+ fatalerr("%s: Invalid or unconfigured class %s\n",
+ cmdpath, clname);
+ }
+
+ /*
+ * No need for special privileges any more.
+ * Set the effective UID back to the real UID.
+ */
+ if (setuid(getuid()) == -1)
+ fatalerr("%s: Can't set effective UID back to real UID\n",
+ cmdpath);
+
+ if (snprintf(subcmdpath, sizeof (subcmdpath), "%s/%s/%s%s",
+ CLASSPATH, clname, clname, basenm) >= sizeof (subcmdpath))
+ fatalerr("%s: can't generate %s specific subcommand\n",
+ cmdpath, clname);
+
+ subcmdargv[0] = subcmdpath;
+ (void) execv(subcmdpath, subcmdargv);
+ fatalerr("%s: Can't execute %s sub-command\n", cmdpath, clname);
+}
+
+
+/*
+ * Execute the appropriate class specific sub-command with the arguments
+ * pointed to by subcmdargv. If the user specified a class we simply
+ * exec the sub-command for that class. If no class was specified we
+ * execute the sub-command for our own current class.
+ */
+static void
+exec_cmd(clname, subcmdargv)
+char *clname;
+char **subcmdargv;
+{
+ pcinfo_t pcinfo;
+ char clnmbuf[PC_CLNMSZ];
+ char subcmdpath[128];
+
+ /*
+ * No special privileges required for this operation.
+ * Set the effective UID back to the real UID.
+ */
+ if (setuid(getuid()) == -1)
+ fatalerr("%s: Can't set effective UID back to real UID\n",
+ cmdpath);
+
+ if (clname == NULL) {
+ if (priocntl(P_PID, P_MYID, PC_GETXPARMS, NULL,
+ PC_KY_CLNAME, clnmbuf, 0) == -1)
+ fatalerr("%s: Can't get class name of current process\n"
+ "priocntl system call failed with errno %d\n",
+ cmdpath, errno);
+
+ clname = clnmbuf;
+ } else {
+
+ /*
+ * User specified class. Check it for validity.
+ */
+ (void) strcpy(pcinfo.pc_clname, clname);
+ if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1)
+ fatalerr("%s: Invalid or unconfigured class %s\n",
+ cmdpath, clname);
+ }
+
+ if (snprintf(subcmdpath, sizeof (subcmdpath), "%s/%s/%s%s",
+ CLASSPATH, clname, clname, basenm) >= sizeof (subcmdpath))
+ fatalerr("%s: can't generate %s specific subcommand\n",
+ cmdpath, clname);
+ subcmdargv[0] = subcmdpath;
+ (void) execv(subcmdpath, subcmdargv);
+ fatalerr("%s: Can't execute %s sub-command\n", cmdpath, clname);
+}
+
+
+/*
+ * Fill in the classpids structures in the array pointed to by clpids
+ * with pids for the processes in the set specified by idtype/idlist.
+ * We read the /proc/<pid>/psinfo file to get the necessary process
+ * information.
+ */
+static void
+ids2pids(idtype, idlist, nids, clpids, nclass)
+idtype_t idtype;
+id_t *idlist;
+int nids;
+classpids_t *clpids;
+int nclass;
+{
+ static psinfo_t prinfo;
+ static prcred_t prcred;
+ DIR *dirp;
+ struct dirent *dentp;
+ char pname[100];
+ char *fname;
+ int procfd;
+ int saverr;
+ int i;
+ char *clname;
+ size_t len;
+
+ if ((dirp = opendir(procdir)) == NULL)
+ fatalerr("%s: Can't open PROC directory %s\n",
+ cmdpath, procdir);
+
+ while ((dentp = readdir(dirp)) != NULL) {
+ if (dentp->d_name[0] == '.') /* skip . and .. */
+ continue;
+
+ len = snprintf(pname, sizeof (pname), "%s/%s/",
+ procdir, dentp->d_name);
+ /* Really max(sizeof ("psinfo"), sizeof ("cred")) */
+ if (len + sizeof ("psinfo") > sizeof (pname)) {
+ (void) fprintf(stderr,
+ "%s: skipping %s, name too long.\n",
+ cmdpath, dentp->d_name);
+ continue;
+ }
+ fname = pname + len;
+retry:
+ (void) strcpy(fname, "psinfo");
+ if ((procfd = open(pname, O_RDONLY)) < 0)
+ continue;
+ if (read(procfd, &prinfo, sizeof (prinfo)) != sizeof (prinfo)) {
+ saverr = errno;
+ (void) close(procfd);
+ if (saverr == EAGAIN)
+ goto retry;
+ if (saverr != ENOENT) {
+ (void) fprintf(stderr,
+ "%s: Can't get process info for %s\n",
+ cmdpath, pname);
+ }
+ continue;
+ }
+ (void) close(procfd);
+
+ if (idtype == P_UID || idtype == P_GID) {
+ (void) strcpy(fname, "cred");
+ if ((procfd = open(pname, O_RDONLY)) < 0 ||
+ read(procfd, &prcred, sizeof (prcred)) !=
+ sizeof (prcred)) {
+ saverr = errno;
+ (void) close(procfd);
+ if (saverr == EAGAIN)
+ goto retry;
+ if (saverr != ENOENT) {
+ (void) fprintf(stderr,
+ "%s: Can't get process credentials"
+ " for %s\n",
+ cmdpath, pname);
+ }
+ continue;
+ }
+ (void) close(procfd);
+ }
+
+ if (prinfo.pr_lwp.pr_state == 0 || prinfo.pr_nlwp == 0)
+ continue;
+
+ switch (idtype) {
+
+ case P_PID:
+ for (i = 0; i < nids; i++) {
+ if (idlist[i] == (id_t)prinfo.pr_pid)
+ add_pid_tolist(clpids, nclass,
+ prinfo.pr_lwp.pr_clname,
+ prinfo.pr_pid);
+ }
+ break;
+
+ case P_PPID:
+ for (i = 0; i < nids; i++) {
+ if (idlist[i] == (id_t)prinfo.pr_ppid)
+ add_pid_tolist(clpids, nclass,
+ prinfo.pr_lwp.pr_clname,
+ prinfo.pr_pid);
+ }
+ break;
+
+ case P_PGID:
+ for (i = 0; i < nids; i++) {
+ if (idlist[i] == (id_t)prinfo.pr_pgid)
+ add_pid_tolist(clpids, nclass,
+ prinfo.pr_lwp.pr_clname,
+ prinfo.pr_pid);
+ }
+ break;
+
+ case P_SID:
+ for (i = 0; i < nids; i++) {
+ if (idlist[i] == (id_t)prinfo.pr_sid)
+ add_pid_tolist(clpids, nclass,
+ prinfo.pr_lwp.pr_clname,
+ prinfo.pr_pid);
+ }
+ break;
+
+ case P_CID:
+ for (i = 0; i < nids; i++) {
+ clname = clpids[idlist[i]].clp_clname;
+ if (strcmp(clname,
+ prinfo.pr_lwp.pr_clname) == 0)
+ add_pid_tolist(clpids, nclass,
+ prinfo.pr_lwp.pr_clname,
+ prinfo.pr_pid);
+ }
+ break;
+
+ case P_UID:
+ for (i = 0; i < nids; i++) {
+ if (idlist[i] == (id_t)prcred.pr_euid)
+ add_pid_tolist(clpids, nclass,
+ prinfo.pr_lwp.pr_clname,
+ prinfo.pr_pid);
+ }
+ break;
+
+ case P_GID:
+ for (i = 0; i < nids; i++) {
+ if (idlist[i] == (id_t)prcred.pr_egid)
+ add_pid_tolist(clpids, nclass,
+ prinfo.pr_lwp.pr_clname,
+ prinfo.pr_pid);
+ }
+ break;
+
+ case P_PROJID:
+ for (i = 0; i < nids; i++) {
+ if (idlist[i] == (id_t)prinfo.pr_projid)
+ add_pid_tolist(clpids, nclass,
+ prinfo.pr_lwp.pr_clname,
+ prinfo.pr_pid);
+ }
+ break;
+
+ case P_TASKID:
+ for (i = 0; i < nids; i++) {
+ if (idlist[i] == (id_t)prinfo.pr_taskid)
+ add_pid_tolist(clpids, nclass,
+ prinfo.pr_lwp.pr_clname,
+ prinfo.pr_pid);
+ }
+ break;
+
+ case P_ZONEID:
+ for (i = 0; i < nids; i++) {
+ if (idlist[i] == (id_t)prinfo.pr_zoneid)
+ add_pid_tolist(clpids, nclass,
+ prinfo.pr_lwp.pr_clname,
+ prinfo.pr_pid);
+ }
+ break;
+
+ case P_CTID:
+ for (i = 0; i < nids; i++) {
+ if (idlist[i] == (id_t)prinfo.pr_contract)
+ add_pid_tolist(clpids, nclass,
+ prinfo.pr_lwp.pr_clname,
+ prinfo.pr_pid);
+ }
+ break;
+
+ case P_ALL:
+ add_pid_tolist(clpids, nclass, prinfo.pr_lwp.pr_clname,
+ prinfo.pr_pid);
+ break;
+
+ default:
+ fatalerr("%s: Bad idtype %d in ids2pids()\n",
+ cmdpath, idtype);
+ }
+ }
+ (void) closedir(dirp);
+}
+
+
+/*
+ * Search the array pointed to by clpids for the classpids
+ * structure corresponding to clname and add pid to its
+ * pidlist.
+ */
+static void
+add_pid_tolist(clpids, nclass, clname, pid)
+classpids_t *clpids;
+int nclass;
+char *clname;
+pid_t pid;
+{
+ classpids_t *clp;
+
+ for (clp = clpids; clp != &clpids[nclass]; clp++) {
+ if (strcmp(clp->clp_clname, clname) == 0) {
+ if (clp->clp_npids == clp->clp_pidlistsz)
+ increase_pidlist(clp);
+
+ (clp->clp_pidlist)[clp->clp_npids] = pid;
+ clp->clp_npids++;
+ return;
+ }
+ }
+}
+
+
+static void
+increase_pidlist(classpids_t *clp)
+{
+ if ((clp->clp_pidlist = realloc(clp->clp_pidlist,
+ (clp->clp_pidlistsz + NPIDS) * sizeof (pid_t))) == NULL)
+ /*
+ * The pidlist is filled up and we cannot increase the size.
+ */
+ fatalerr("%s: Can't allocate memory for pidlist.\n", cmdpath);
+
+ clp->clp_pidlistsz += NPIDS;
+}
+
+
+/*
+ * Compare id strings for equality. If idargv contains ids
+ * (idargc > 0) compare idstr to each id in idargv, otherwise
+ * just compare to curidstr.
+ */
+static boolean_t
+idmatch(idstr, curidstr, idargc, idargv)
+char *idstr;
+char *curidstr;
+int idargc;
+char **idargv;
+{
+ int i;
+
+ if (idargc == 0) {
+ if (strcmp(curidstr, idstr) == 0)
+ return (B_TRUE);
+ } else {
+ for (i = 0; i < idargc; i++) {
+ if (strcmp(idargv[i], idstr) == 0)
+ return (B_TRUE);
+ }
+ }
+ return (B_FALSE);
+}
+
+/*
+ * This is a copy of the getopt() function found in libc:getopt.c. A separate
+ * copy is required to fix the bug id #1114636. To fix the problem we need to
+ * reset the _sp to 1. Since _sp in libc:getopt() is not exposed, a copy of
+ * the getopt() is kept so that prio_sp can be reset to 1.
+ */
+
+static int
+prio_getopt(argc, argv, opts)
+int argc;
+#ifdef __STDC__
+char *const *argv, *opts;
+#else
+char **argv, *opts;
+#endif
+{
+ register char c;
+ register char *cp;
+
+ if (prio_sp == 1)
+ if (prio_optind >= argc ||
+ argv[prio_optind][0] != '-' || argv[prio_optind][1] == '\0')
+ return (EOF);
+ else if (strcmp(argv[prio_optind], "--") == NULL) {
+ prio_optind++;
+ return (EOF);
+ }
+ prio_optopt = c = (unsigned char)argv[prio_optind][prio_sp];
+ if (c == ':' || (cp = strchr(opts, c)) == NULL) {
+ if (argv[prio_optind][++prio_sp] == '\0') {
+ prio_optind++;
+ prio_sp = 1;
+ }
+ return ('?');
+ }
+ if (*++cp == ':') {
+ if (argv[prio_optind][prio_sp+1] != '\0')
+ prio_optarg = &argv[prio_optind++][prio_sp+1];
+ else if (++prio_optind >= argc) {
+ prio_sp = 1;
+ return ('?');
+ } else
+ prio_optarg = argv[prio_optind++];
+ prio_sp = 1;
+ } else {
+ if (argv[prio_optind][++prio_sp] == '\0') {
+ prio_sp = 1;
+ prio_optind++;
+ }
+ prio_optarg = NULL;
+ }
+ return (c);
+}
diff --git a/usr/src/cmd/priocntl/priocntl.h b/usr/src/cmd/priocntl/priocntl.h
new file mode 100644
index 0000000000..cd0f3e0ac4
--- /dev/null
+++ b/usr/src/cmd/priocntl/priocntl.h
@@ -0,0 +1,100 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright 2001-2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#ifndef _PRIOCNTL_H
+#define _PRIOCNTL_H
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.3 */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define NPIDS 1024 /* number of additional pids allocated by realloc(). */
+#define NIDS 1024 /* max number of id arguments we handle */
+
+#define BASENMSZ 16
+#define CSOPTSLN 128 /* max length of class specific opts string */
+#define PC_IDTYPNMSZ 12 /* max length of an idtype name */
+
+/*
+ * The command string for the sub-command must be big enough for the
+ * path, the class specific options, and plenty of space for arguments.
+ */
+#define SUBCMDSZ 512
+
+#define BADPID (-2)
+
+extern void fatalerr();
+extern int str2idtyp(char *, idtype_t *);
+extern int idtyp2str(idtype_t, char *);
+extern int idcompar(id_t *, id_t *);
+extern id_t clname2cid(char *);
+extern int getmyid(idtype_t, id_t *);
+extern int getmyidstr(idtype_t, char *);
+extern int verifyupri(idtype_t, id_t, char *, int, pri_t, char *);
+extern pid_t *read_pidlist(size_t *, FILE *);
+extern void free_pidlist(pid_t *);
+extern long str2num(char *, long, long);
+extern void itoa(long, char *);
+
+/*
+ * The following is an excerpt from <sys/hrtcntl.h>. HRT timers are not
+ * supported by SunOS (which will support the POSIX definition). Priocntl
+ * uses the hrt routine _hrtnewres because it coincidentally does the
+ * right thing. These defines allow this routine to be locally included
+ * in priocntl (rather than exported in libc). This should be improved in
+ * the long term.
+ */
+
+#define HRT_TRUNC 0 /* Round results down. */
+#define HRT_RND 1 /* Round results (rnd up if fractional */
+ /* part >= .5 otherwise round down). */
+#define HRT_RNDUP 2 /* Always round results up. */
+
+/*
+ * Structure used to represent a high-resolution time-of-day
+ * or interval.
+ */
+
+typedef struct hrtimer {
+ ulong_t hrt_secs; /* Seconds. */
+ long hrt_rem; /* A value less than a second. */
+ ulong_t hrt_res; /* The resolution of hrt_rem. */
+} hrtimer_t;
+
+extern int _hrtnewres(hrtimer_t *, ulong_t, long);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PRIOCNTL_H */
diff --git a/usr/src/cmd/priocntl/rtpriocntl.c b/usr/src/cmd/priocntl/rtpriocntl.c
new file mode 100644
index 0000000000..8a7340589f
--- /dev/null
+++ b/usr/src/cmd/priocntl/rtpriocntl.c
@@ -0,0 +1,524 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/procset.h>
+#include <sys/priocntl.h>
+#include <sys/rtpriocntl.h>
+#include <sys/param.h>
+#include <signal.h>
+#include <libgen.h>
+#include <limits.h>
+#include <errno.h>
+
+#include "priocntl.h"
+
+/*
+ * This file contains the class specific code implementing
+ * the real-time priocntl sub-command.
+ */
+
+#define ADDKEYVAL(p, k, v) { (p[0]) = (k); (p[1]) = (v); p += 2; }
+
+#define RT_KEYCNT 4 /* maximal number of (key, value) pairs */
+
+/*
+ * control flags
+ */
+#define RT_DOPRI 0x01 /* change priority */
+#define RT_DOTQ 0x02 /* change RT time quantum */
+#define RT_DOSIG 0x10 /* change RT time quantum signal */
+
+
+static void print_rtinfo(void);
+static int print_rtprocs(void);
+static int rt_priocntl(idtype_t, id_t, int, char *, uintptr_t *);
+static int set_rtprocs(idtype_t, int, char **, uint_t, pri_t, long,
+ long, int);
+static void exec_rtcmd(char **, uint_t, pri_t, long, long, int);
+
+
+static char usage[] =
+"usage: priocntl -l\n"
+" priocntl -d [-i idtype] [idlist]\n"
+" priocntl -s [-c RT] [-p rtpri] [-t tqntm [-r res]] [-q tqsig]\n"
+" [-i idtype] [idlist]\n"
+" priocntl -e [-c RT] [-p rtpri] [-t tqntm [-r res]] [-q tqsig]\n"
+" command [argument(s)]\n";
+
+static char cmdpath[MAXPATHLEN];
+static char basenm[BASENMSZ];
+
+
+int
+main(int argc, char *argv[])
+{
+ int c;
+ int lflag, dflag, sflag, pflag, tflag, rflag, eflag, iflag;
+ int qflag;
+ pri_t rtpri;
+ long tqntm;
+ long res;
+ int tqsig;
+ char *idtypnm;
+ idtype_t idtype;
+ int idargc;
+ uint_t cflags;
+
+ (void) strlcpy(cmdpath, argv[0], MAXPATHLEN);
+ (void) strlcpy(basenm, basename(argv[0]), BASENMSZ);
+ qflag =
+ lflag = dflag = sflag = pflag = tflag = rflag = eflag = iflag = 0;
+ while ((c = getopt(argc, argv, "ldsp:t:r:q:ec:i:")) != -1) {
+ switch (c) {
+
+ case 'l':
+ lflag++;
+ break;
+
+ case 'd':
+ dflag++;
+ break;
+
+ case 's':
+ sflag++;
+ break;
+
+ case 'p':
+ pflag++;
+ rtpri = (pri_t)str2num(optarg, SHRT_MIN, SHRT_MAX);
+ if (errno)
+ fatalerr("%s: Specified real time priority %s"
+ " out of configured range\n",
+ basenm, optarg);
+ break;
+
+ case 't':
+ tflag++;
+ tqntm = str2num(optarg, 1, INT_MAX);
+ if (errno)
+ fatalerr("%s: Invalid time quantum specified;"
+ " time quantum must be positive\n", basenm);
+ break;
+
+ case 'r':
+ rflag++;
+ res = str2num(optarg, 1, 1000000000);
+ if (errno)
+ fatalerr("%s: Invalid resolution specified;"
+ " resolution must be between"
+ " 1 and 1,000,000,000\n", basenm);
+
+ break;
+
+ case 'q':
+ qflag++;
+ if (str2sig(optarg, &tqsig) != 0)
+ fatalerr("%s: Invalid real time quantum signal"
+ " specified\n", basenm);
+ break;
+
+ case 'e':
+ eflag++;
+ break;
+
+ case 'c':
+ if (strcmp(optarg, "RT") != 0)
+ fatalerr("error: %s executed for %s class, %s"
+ " is actually sub-command for RT class\n",
+ cmdpath, optarg, cmdpath);
+ break;
+
+ case 'i':
+ iflag++;
+ idtypnm = optarg;
+ break;
+
+ case '?':
+ fatalerr(usage);
+
+ default:
+ break;
+ }
+ }
+
+ if (lflag) {
+ if (dflag || sflag || pflag || tflag || rflag || eflag ||
+ iflag || qflag)
+ fatalerr(usage);
+
+ print_rtinfo();
+
+ } else if (dflag) {
+ if (lflag || sflag || pflag || tflag || rflag || eflag || qflag)
+ fatalerr(usage);
+
+ return (print_rtprocs());
+
+ } else if (sflag) {
+ if (lflag || dflag || eflag)
+ fatalerr(usage);
+
+ if (iflag) {
+ if (str2idtyp(idtypnm, &idtype) == -1)
+ fatalerr("%s: Bad idtype %s\n", basenm,
+ idtypnm);
+ } else {
+ idtype = P_PID;
+ }
+
+ cflags = (pflag ? RT_DOPRI : 0);
+
+ if (tflag)
+ cflags |= RT_DOTQ;
+
+ if (rflag == 0)
+ res = 1000;
+
+ if (optind < argc)
+ idargc = argc - optind;
+ else
+ idargc = 0;
+
+ if (qflag)
+ cflags |= RT_DOSIG;
+
+ return (set_rtprocs(idtype, idargc, &argv[optind], cflags,
+ rtpri, tqntm, res, tqsig));
+
+ } else if (eflag) {
+ if (lflag || dflag || sflag || iflag)
+ fatalerr(usage);
+
+ cflags = (pflag ? RT_DOPRI : 0);
+
+ if (tflag)
+ cflags |= RT_DOTQ;
+
+ if (rflag == 0)
+ res = 1000;
+
+ if (qflag)
+ cflags |= RT_DOSIG;
+
+ exec_rtcmd(&argv[optind], cflags, rtpri, tqntm, res, tqsig);
+
+ } else {
+ fatalerr(usage);
+ }
+
+ return (0);
+}
+
+
+/*
+ * Print our class name and the maximum configured real-time priority.
+ */
+static void
+print_rtinfo(void)
+{
+ pcinfo_t pcinfo;
+
+ (void) strcpy(pcinfo.pc_clname, "RT");
+
+ (void) printf("RT (Real Time)\n");
+
+ if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1)
+ fatalerr("\tCan't get maximum configured RT priority\n");
+
+ (void) printf("\tMaximum Configured RT Priority: %d\n",
+ ((rtinfo_t *)pcinfo.pc_clinfo)->rt_maxpri);
+}
+
+
+/*
+ * Read a list of pids from stdin and print the real-time priority and time
+ * quantum (in millisecond resolution) for each of the corresponding processes.
+ */
+static int
+print_rtprocs(void)
+{
+ pid_t *pidlist;
+ size_t numread;
+ int i;
+ char clname[PC_CLNMSZ];
+ pri_t rt_pri;
+ uint_t rt_tqsecs;
+ int rt_tqnsecs;
+ int rt_tqsig;
+ int error = 0;
+
+ /*
+ * Read a list of pids from stdin.
+ */
+ if ((pidlist = read_pidlist(&numread, stdin)) == NULL)
+ fatalerr("%s: Can't read pidlist.\n", basenm);
+
+ (void) printf("REAL TIME PROCESSES:\n"
+ " PID RTPRI TQNTM TQSIG\n");
+
+ if (numread == 0)
+ fatalerr("%s: No pids on input\n", basenm);
+
+ for (i = 0; i < numread; i++) {
+ (void) printf("%7ld", pidlist[i]);
+ if (priocntl(P_PID, pidlist[i], PC_GETXPARMS, "RT",
+ RT_KY_TQSECS, &rt_tqsecs, RT_KY_TQNSECS, &rt_tqnsecs,
+ RT_KY_PRI, &rt_pri, RT_KY_TQSIG, &rt_tqsig, 0) != -1) {
+ (void) printf(" %5d", rt_pri);
+ if (rt_tqnsecs == RT_TQINF)
+ (void) printf(" RT_TQINF");
+ else
+ (void) printf(" %11lld",
+ (longlong_t)rt_tqsecs * 1000 +
+ rt_tqnsecs / 1000000);
+
+ (void) printf(" %3d\n", rt_tqsig);
+ } else {
+ error = 1;
+
+ if (priocntl(P_PID, pidlist[i], PC_GETXPARMS, NULL,
+ PC_KY_CLNAME, clname, 0) != -1 &&
+ strcmp(clname, "RT"))
+ /*
+ * Process from some class other than real time.
+ * It has probably changed class while priocntl
+ * command was executing (otherwise we wouldn't
+ * have been passed its pid). Print the little
+ * we know about it.
+ */
+ (void) printf("\tChanged to class %s while"
+ " priocntl command executing\n", clname);
+ else
+ (void) printf("\tCan't get real time"
+ " parameters\n");
+ }
+ }
+
+ free_pidlist(pidlist);
+ return (error);
+}
+
+
+/*
+ * Call priocntl() with command codes PC_SETXPARMS or PC_GETXPARMS.
+ * The first parameter behind the command code is always the class name.
+ * Each parameter is headed by a key, which determines the meaning of the
+ * following value. There are maximal RT_KEYCNT = 4 (key, value) pairs.
+ */
+static int
+rt_priocntl(idtype_t idtype, id_t id, int cmd, char *clname, uintptr_t *argsp)
+{
+ return (priocntl(idtype, id, cmd, clname, argsp[0], argsp[1],
+ argsp[2], argsp[3], argsp[4], argsp[5], argsp[6], argsp[7], 0));
+}
+
+
+/*
+ * Set all processes in the set specified by idtype/idargv to real time
+ * (if they aren't already real time) and set their real-time priority,
+ * real-time quantum and real-time quantum signal to those specified by
+ * rtpri, tqntm/res and rtqsig.
+ */
+static int
+set_rtprocs(idtype_t idtype, int idargc, char **idargv, uint_t cflags,
+ pri_t rtpri, long tqntm, long res, int rtqsig)
+{
+ pcinfo_t pcinfo;
+ uintptr_t args[2*RT_KEYCNT+1];
+ uintptr_t *argsp = &args[0];
+ pri_t maxrtpri;
+ hrtimer_t hrtime;
+ char idtypnm[PC_IDTYPNMSZ];
+ int i;
+ id_t id;
+ int error = 0;
+
+
+ /*
+ * Get the real time class ID and max configured RT priority.
+ */
+ (void) strcpy(pcinfo.pc_clname, "RT");
+ if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1)
+ fatalerr("%s: Can't get RT class ID, priocntl system call"
+ " failed with errno %d\n", basenm, errno);
+ maxrtpri = ((rtinfo_t *)pcinfo.pc_clinfo)->rt_maxpri;
+
+ /*
+ * Validate the rtpri and res arguments.
+ */
+ if ((cflags & RT_DOPRI) != 0) {
+ if (rtpri > maxrtpri || rtpri < 0)
+ fatalerr("%s: Specified real time priority %d out of"
+ " configured range\n", basenm, rtpri);
+ ADDKEYVAL(argsp, RT_KY_PRI, rtpri);
+ }
+
+ if ((cflags & RT_DOTQ) != 0) {
+ hrtime.hrt_secs = 0;
+ hrtime.hrt_rem = tqntm;
+ hrtime.hrt_res = res;
+ if (_hrtnewres(&hrtime, NANOSEC, HRT_RNDUP) == -1)
+ fatalerr("%s: Can't convert resolution.\n", basenm);
+ ADDKEYVAL(argsp, RT_KY_TQSECS, hrtime.hrt_secs);
+ ADDKEYVAL(argsp, RT_KY_TQNSECS, hrtime.hrt_rem);
+ }
+
+ if ((cflags & RT_DOSIG) != 0)
+ ADDKEYVAL(argsp, RT_KY_TQSIG, rtqsig);
+ *argsp = 0;
+
+ if (idtype == P_ALL) {
+ if (rt_priocntl(P_ALL, 0, PC_SETXPARMS, "RT", args) == -1) {
+ if (errno == EPERM) {
+ (void) fprintf(stderr,
+ "Permissions error encountered"
+ " on one or more processes.\n");
+ error = 1;
+ } else {
+ fatalerr("%s: Can't reset real time parameters"
+ "\npriocntl system call failed with"
+ " errno %d\n", basenm, errno);
+ }
+ }
+ } else if (idargc == 0) {
+ if (rt_priocntl(idtype, P_MYID, PC_SETXPARMS, "RT",
+ args) == -1) {
+ if (errno == EPERM) {
+ (void) idtyp2str(idtype, idtypnm);
+ (void) fprintf(stderr, "Permissions error"
+ " encountered on current %s.\n", idtypnm);
+ error = 1;
+ } else {
+ fatalerr("%s: Can't reset real time parameters"
+ "\npriocntl system call failed with"
+ " errno %d\n", basenm, errno);
+ }
+ }
+ } else {
+ (void) idtyp2str(idtype, idtypnm);
+ for (i = 0; i < idargc; i++) {
+ if (idtype == P_CID) {
+ (void) strcpy(pcinfo.pc_clname, idargv[i]);
+ if (priocntl(0, 0, PC_GETCID,
+ (caddr_t)&pcinfo) == -1)
+ fatalerr("%s: Invalid or unconfigured"
+ " class %s, priocntl system call"
+ " failed with errno %d\n",
+ basenm, pcinfo.pc_clname, errno);
+ id = pcinfo.pc_cid;
+ } else {
+ id = (id_t)str2num(idargv[i], INT_MIN, INT_MAX);
+ if (errno)
+ fatalerr("%s: Invalid id \"%s\"\n",
+ basenm, idargv[i]);
+ }
+
+ if (rt_priocntl(idtype, id, PC_SETXPARMS, "RT",
+ args) == -1) {
+ if (errno == EPERM) {
+ (void) fprintf(stderr,
+ "Permissions error encountered on"
+ " %s %s.\n", idtypnm, idargv[i]);
+ error = 1;
+ } else {
+ fatalerr("%s: Can't reset real time"
+ " parameters\npriocntl system call"
+ " failed with errno %d\n",
+ basenm, errno);
+ }
+ }
+ }
+ }
+
+ return (error);
+}
+
+
+/*
+ * Execute the command pointed to by cmdargv as a real-time process
+ * with real time priority rtpri, quantum tqntm/res and quantum signal rtqsig.
+ */
+static void
+exec_rtcmd(char **cmdargv, uint_t cflags, pri_t rtpri, long tqntm, long res,
+ int rtqsig)
+{
+ pcinfo_t pcinfo;
+ uintptr_t args[2*RT_KEYCNT+1];
+ uintptr_t *argsp = &args[0];
+ pri_t maxrtpri;
+ hrtimer_t hrtime;
+
+ /*
+ * Get the real time class ID and max configured RT priority.
+ */
+ (void) strcpy(pcinfo.pc_clname, "RT");
+ if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1)
+ fatalerr("%s: Can't get RT class ID, priocntl system call"
+ " failed with errno %d\n", basenm, errno);
+ maxrtpri = ((rtinfo_t *)pcinfo.pc_clinfo)->rt_maxpri;
+
+ if ((cflags & RT_DOPRI) != 0) {
+ if (rtpri > maxrtpri || rtpri < 0)
+ fatalerr("%s: Specified real time priority %d out of"
+ " configured range\n", basenm, rtpri);
+ ADDKEYVAL(argsp, RT_KY_PRI, rtpri);
+ }
+
+ if ((cflags & RT_DOTQ) != 0) {
+ hrtime.hrt_secs = 0;
+ hrtime.hrt_rem = tqntm;
+ hrtime.hrt_res = res;
+ if (_hrtnewres(&hrtime, NANOSEC, HRT_RNDUP) == -1)
+ fatalerr("%s: Can't convert resolution.\n", basenm);
+ ADDKEYVAL(argsp, RT_KY_TQSECS, hrtime.hrt_secs);
+ ADDKEYVAL(argsp, RT_KY_TQNSECS, hrtime.hrt_rem);
+ }
+
+ if ((cflags & RT_DOSIG) != 0)
+ ADDKEYVAL(argsp, RT_KY_TQSIG, rtqsig);
+ *argsp = 0;
+
+ if (rt_priocntl(P_PID, P_MYID, PC_SETXPARMS, "RT", args) == -1)
+ fatalerr("%s: Can't reset real time parameters\n"
+ "priocntl system call failed with errno %d\n",
+ basenm, errno);
+
+ (void) execvp(cmdargv[0], cmdargv);
+ fatalerr("%s: Can't execute %s, exec failed with errno %d\n",
+ basenm, cmdargv[0], errno);
+}
diff --git a/usr/src/cmd/priocntl/subr.c b/usr/src/cmd/priocntl/subr.c
new file mode 100644
index 0000000000..a9caf5fff5
--- /dev/null
+++ b/usr/src/cmd/priocntl/subr.c
@@ -0,0 +1,729 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <limits.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <sys/procset.h>
+#include <sys/priocntl.h>
+#include <sys/task.h>
+#include <procfs.h>
+#include <project.h>
+#include <errno.h>
+#include <zone.h>
+#include <libcontract_priv.h>
+
+#include "priocntl.h"
+
+/*LINTLIBRARY*/
+
+/*
+ * Utility functions for priocntl command.
+ */
+
+static char *procdir = "/proc";
+
+/*PRINTFLIKE1*/
+void
+fatalerr(format, a1, a2, a3, a4, a5)
+char *format;
+int a1, a2, a3, a4, a5;
+{
+ (void) fprintf(stderr, format, a1, a2, a3, a4, a5);
+ exit(1);
+}
+
+
+/*
+ * Structure defining idtypes known to the priocntl command
+ * along with the corresponding names and a liberal guess
+ * of the max number of procs sharing any given ID of that type.
+ * The idtype values themselves are defined in <sys/procset.h>.
+ */
+static struct idtypes {
+ idtype_t idtype;
+ char *idtypnm;
+} idtypes [] = {
+ { P_PID, "pid" },
+ { P_PPID, "ppid" },
+ { P_PGID, "pgid" },
+ { P_SID, "sid" },
+ { P_CID, "class" },
+ { P_UID, "uid" },
+ { P_GID, "gid" },
+ { P_PROJID, "projid" },
+ { P_TASKID, "taskid" },
+ { P_ZONEID, "zoneid" },
+ { P_CTID, "ctid" },
+ { P_ALL, "all" }
+};
+
+#define IDCNT (sizeof (idtypes) / sizeof (struct idtypes))
+
+
+int
+str2idtyp(idtypnm, idtypep)
+char *idtypnm;
+idtype_t *idtypep;
+{
+ register struct idtypes *curp;
+ register struct idtypes *endp;
+
+ for (curp = idtypes, endp = &idtypes[IDCNT]; curp < endp; curp++) {
+ if (strcmp(curp->idtypnm, idtypnm) == 0) {
+ *idtypep = curp->idtype;
+ return (0);
+ }
+ }
+ return (-1);
+}
+
+
+int
+idtyp2str(idtype, idtypnm)
+idtype_t idtype;
+char *idtypnm;
+{
+ register struct idtypes *curp;
+ register struct idtypes *endp;
+
+ for (curp = idtypes, endp = &idtypes[IDCNT]; curp < endp; curp++) {
+ if (idtype == curp->idtype) {
+ (void) strncpy(idtypnm, curp->idtypnm, PC_IDTYPNMSZ);
+ return (0);
+ }
+ }
+ return (-1);
+}
+
+
+/*
+ * Compare two IDs for equality.
+ */
+int
+idcompar(id1p, id2p)
+id_t *id1p;
+id_t *id2p;
+{
+ if (*id1p == *id2p)
+ return (0);
+ else
+ return (-1);
+}
+
+
+id_t
+clname2cid(clname)
+char *clname;
+{
+ pcinfo_t pcinfo;
+
+ (void) strncpy(pcinfo.pc_clname, clname, PC_CLNMSZ);
+ if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1)
+ return ((id_t)-1);
+ return (pcinfo.pc_cid);
+}
+
+
+int
+getmyid(idtype, idptr)
+idtype_t idtype;
+id_t *idptr;
+{
+ pcinfo_t pcinfo;
+
+ switch (idtype) {
+
+ case P_PID:
+ *idptr = (id_t)getpid();
+ break;
+
+ case P_PPID:
+ *idptr = (id_t)getppid();
+ break;
+
+ case P_PGID:
+ *idptr = (id_t)getpgrp();
+ break;
+
+ case P_SID:
+ *idptr = (id_t)getsid(getpid());
+ break;
+
+ case P_CID:
+ if (priocntl(P_PID, P_MYID, PC_GETXPARMS, NULL,
+ PC_KY_CLNAME, pcinfo.pc_clname, 0) == -1 ||
+ priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1)
+ return (-1);
+
+ *idptr = pcinfo.pc_cid;
+ break;
+
+ case P_UID:
+ *idptr = (id_t)getuid();
+ break;
+
+ case P_GID:
+ *idptr = (id_t)getgid();
+ break;
+
+ case P_PROJID:
+ *idptr = (id_t)getprojid();
+ break;
+
+ case P_TASKID:
+ *idptr = (id_t)gettaskid();
+ break;
+
+ case P_ZONEID:
+ *idptr = (id_t)getzoneid();
+ break;
+
+ case P_CTID: {
+ ctid_t id = getctid();
+ if (id == -1)
+ return (-1);
+ *idptr = id;
+ break;
+ }
+
+ default:
+ return (-1);
+ }
+ return (0);
+}
+
+
+int
+getmyidstr(idtype, idstr)
+idtype_t idtype;
+char *idstr;
+{
+ char clname[PC_CLNMSZ];
+
+ switch (idtype) {
+
+ case P_PID:
+ itoa((long)getpid(), idstr);
+ break;
+
+ case P_PPID:
+ itoa((long)getppid(), idstr);
+ break;
+
+ case P_PGID:
+ itoa((long)getpgrp(), idstr);
+ break;
+ case P_SID:
+ itoa((long)getsid(getpid()), idstr);
+ break;
+
+ case P_CID:
+ if (priocntl(P_PID, P_MYID, PC_GETXPARMS, NULL,
+ PC_KY_CLNAME, clname, 0) == -1)
+ return (-1);
+ (void) strncpy(idstr, clname, PC_CLNMSZ);
+ break;
+
+ case P_UID:
+ itoa((long)getuid(), idstr);
+ break;
+
+ case P_GID:
+ itoa((long)getgid(), idstr);
+ break;
+
+ case P_PROJID:
+ itoa((long)getprojid(), idstr);
+ break;
+
+ case P_TASKID:
+ itoa((long)gettaskid(), idstr);
+ break;
+
+ case P_ZONEID:
+ itoa((long)getzoneid(), idstr);
+ break;
+
+ case P_CTID: {
+ id_t id;
+ if ((id = getctid()) == -1)
+ return (-1);
+ itoa((long)id, idstr);
+ break;
+ }
+
+ default:
+ return (-1);
+ }
+ return (0);
+}
+
+/*
+ * Look for pids with "upri > uprilim" in the set specified by idtype/id.
+ * If upri exceeds uprilim then print a warning.
+ */
+int
+verifyupri(idtype_t idtype, id_t id, char *clname, int key,
+ pri_t upri, char *basenm)
+{
+ psinfo_t prinfo;
+ prcred_t prcred;
+ DIR *dirp;
+ struct dirent *dentp;
+ char pname[MAXNAMLEN];
+ char *fname;
+ int procfd;
+ int saverr;
+ pri_t uprilim;
+ int verify;
+ int error = 0;
+
+ if (idtype == P_PID) {
+ if (priocntl(P_PID, id, PC_GETXPARMS, clname, key,
+ &uprilim, 0) == -1)
+ error = -1;
+ else if (upri > uprilim)
+ (void) fprintf(stderr,
+ "%s: Specified user priority %d exceeds"
+ " limit %d; set to %d (pid %d)\n",
+ basenm, upri, uprilim, uprilim, (int)id);
+
+ return (error);
+ }
+
+ /*
+ * Look for the processes in the set specified by idtype/id.
+ * We read the /proc/<pid>/psinfo file to get the necessary
+ * process information.
+ */
+
+ if ((dirp = opendir(procdir)) == NULL)
+ fatalerr("%s: Can't open PROC directory %s\n",
+ basenm, procdir);
+
+ while ((dentp = readdir(dirp)) != NULL) {
+ if (dentp->d_name[0] == '.') /* skip . and .. */
+ continue;
+
+ (void) snprintf(pname, MAXNAMLEN, "%s/%s/",
+ procdir, dentp->d_name);
+ fname = pname + strlen(pname);
+retry:
+ (void) strncpy(fname, "psinfo", strlen("psinfo") + 1);
+ if ((procfd = open(pname, O_RDONLY)) < 0)
+ continue;
+ if (read(procfd, &prinfo, sizeof (prinfo)) != sizeof (prinfo)) {
+ saverr = errno;
+ (void) close(procfd);
+ if (saverr == EAGAIN)
+ goto retry;
+ continue;
+ }
+ (void) close(procfd);
+
+ if (idtype == P_UID || idtype == P_GID) {
+ (void) strncpy(fname, "cred", strlen("cred") + 1);
+ if ((procfd = open(pname, O_RDONLY)) < 0 ||
+ read(procfd, &prcred, sizeof (prcred)) !=
+ sizeof (prcred)) {
+ saverr = errno;
+ (void) close(procfd);
+ if (saverr == EAGAIN)
+ goto retry;
+ continue;
+ }
+ (void) close(procfd);
+ }
+
+ if (prinfo.pr_lwp.pr_state == 0 || prinfo.pr_nlwp == 0)
+ continue;
+
+ /*
+ * The lwp must be in the correct class.
+ */
+ if (strncmp(clname, prinfo.pr_lwp.pr_clname, PC_CLNMSZ) != 0)
+ continue;
+
+ verify = 0;
+ switch (idtype) {
+
+ case P_PPID:
+ if (id == (id_t)prinfo.pr_ppid)
+ verify++;
+ break;
+
+ case P_PGID:
+ if (id == (id_t)prinfo.pr_pgid)
+ verify++;
+ break;
+
+ case P_SID:
+ if (id == (id_t)prinfo.pr_sid)
+ verify++;
+ break;
+
+ case P_UID:
+ if (id == (id_t)prcred.pr_euid)
+ verify++;
+ break;
+
+ case P_GID:
+ if (id == (id_t)prcred.pr_egid)
+ verify++;
+ break;
+
+ case P_PROJID:
+ if (id == (id_t)prinfo.pr_projid)
+ verify++;
+ break;
+
+ case P_TASKID:
+ if (id == (id_t)prinfo.pr_taskid)
+ verify++;
+ break;
+
+ case P_ZONEID:
+ if (id == (id_t)prinfo.pr_zoneid)
+ verify++;
+ break;
+
+ case P_CTID:
+ if (id == (id_t)prinfo.pr_contract)
+ verify++;
+ break;
+
+ case P_CID:
+ case P_ALL:
+ verify++;
+ break;
+
+ default:
+ fatalerr("%s: Bad idtype %d in verifyupri()\n",
+ basenm, idtype);
+ }
+
+ if (verify) {
+ if (priocntl(P_PID, prinfo.pr_pid, PC_GETXPARMS,
+ clname, key, &uprilim, 0) == -1)
+ error = -1;
+ else if (upri > uprilim)
+ (void) fprintf(stderr,
+ "%s: Specified user priority %d exceeds"
+ " limit %d; set to %d (pid %d)\n",
+ basenm, upri, uprilim, uprilim,
+ (int)prinfo.pr_pid);
+ }
+ }
+ (void) closedir(dirp);
+
+ return (error);
+}
+
+
+/*
+ * Read a list of pids from a stream.
+ */
+pid_t *
+read_pidlist(size_t *npidsp, FILE *filep)
+{
+ size_t nitems;
+ pid_t *pidlist = NULL;
+
+ *npidsp = 0;
+
+ do {
+ if ((pidlist = (pid_t *)realloc(pidlist,
+ (*npidsp + NPIDS) * sizeof (pid_t))) == NULL)
+ return (NULL);
+
+ nitems = fread(pidlist + *npidsp, sizeof (pid_t), NPIDS, filep);
+ if (ferror(filep))
+ return (NULL);
+
+ *npidsp += nitems;
+ } while (nitems == NPIDS);
+
+ return (pidlist);
+}
+
+
+void
+free_pidlist(pid_t *pidlist)
+{
+ free(pidlist);
+}
+
+
+long
+str2num(char *p, long min, long max)
+{
+ long val;
+ char *q;
+ errno = 0;
+
+ val = strtol(p, &q, 10);
+ if (errno != 0 || q == p || *q != '\0' || val < min || val > max)
+ errno = EINVAL;
+
+ return (val);
+}
+
+
+/*
+ * itoa() and reverse() taken almost verbatim from K & R Chapter 3.
+ */
+static void reverse();
+
+/*
+ * itoa(): Convert n to characters in s.
+ */
+void
+itoa(n, s)
+long n;
+char *s;
+{
+ long i, sign;
+
+ if ((sign = n) < 0) /* record sign */
+ n = -n; /* make sign positive */
+ i = 0;
+ do { /* generate digits in reverse order */
+ s[i++] = n % 10 + '0'; /* get next digit */
+ } while ((n /= 10) > 0); /* delete it */
+ if (sign < 0)
+ s[i++] = '-';
+ s[i] = '\0';
+ reverse(s);
+}
+
+
+/*
+ * reverse(): Reverse string s in place.
+ */
+static void
+reverse(s)
+char *s;
+{
+ int c, i, j;
+
+ for (i = 0, j = strlen(s) - 1; i < j; i++, j--) {
+ c = s[i];
+ s[i] = s[j];
+ s[j] = (char)c;
+ }
+}
+
+
+/*
+ * The following routine was removed from libc (libc/port/gen/hrtnewres.c).
+ * It has also been added to disadmin, so if you fix it here, you should
+ * also probably fix it there. In the long term, this should be recoded to
+ * not be hrt'ish.
+ */
+
+/*
+ * Convert interval expressed in htp->hrt_res to new_res.
+ *
+ * Calculate: (interval * new_res) / htp->hrt_res rounding off as
+ * specified by round.
+ *
+ * Note: All args are assumed to be positive. If
+ * the last divide results in something bigger than
+ * a long, then -1 is returned instead.
+ */
+
+int
+_hrtnewres(htp, new_res, round)
+register hrtimer_t *htp;
+register ulong_t new_res;
+long round;
+{
+ register long interval;
+ longlong_t dint;
+ longlong_t dto_res;
+ longlong_t drem;
+ longlong_t dfrom_res;
+ longlong_t prod;
+ longlong_t quot;
+ register long numerator;
+ register long result;
+ ulong_t modulus;
+ ulong_t twomodulus;
+ long temp;
+
+ if (new_res > NANOSEC || htp->hrt_rem < 0)
+ return (-1);
+
+ if (htp->hrt_rem >= htp->hrt_res) {
+ htp->hrt_secs += htp->hrt_rem / htp->hrt_res;
+ htp->hrt_rem = htp->hrt_rem % htp->hrt_res;
+ }
+
+ interval = htp->hrt_rem;
+ if (interval == 0) {
+ htp->hrt_res = new_res;
+ return (0);
+ }
+
+ /*
+ * Try to do the calculations in single precision first
+ * (for speed). If they overflow, use double precision.
+ * What we want to compute is:
+ *
+ * (interval * new_res) / hrt->hrt_res
+ */
+
+ numerator = interval * new_res;
+
+ if (numerator / new_res == interval) {
+
+ /*
+ * The above multiply didn't give overflow since
+ * the division got back the original number. Go
+ * ahead and compute the result.
+ */
+
+ result = numerator / htp->hrt_res;
+
+ /*
+ * For HRT_RND, compute the value of:
+ *
+ * (interval * new_res) % htp->hrt_res
+ *
+ * If it is greater than half of the htp->hrt_res,
+ * then rounding increases the result by 1.
+ *
+ * For HRT_RNDUP, we increase the result by 1 if:
+ *
+ * result * htp->hrt_res != numerator
+ *
+ * because this tells us we truncated when calculating
+ * result above.
+ *
+ * We also check for overflow when incrementing result
+ * although this is extremely rare.
+ */
+
+ if (round == HRT_RND) {
+ modulus = numerator - result * htp->hrt_res;
+ if ((twomodulus = 2 * modulus) / 2 == modulus) {
+
+ /*
+ * No overflow (if we overflow in calculation
+ * of twomodulus we fall through and use
+ * double precision).
+ */
+ if (twomodulus >= htp->hrt_res) {
+ temp = result + 1;
+ if (temp - 1 == result)
+ result++;
+ else
+ return (-1);
+ }
+ htp->hrt_res = new_res;
+ htp->hrt_rem = result;
+ return (0);
+ }
+ } else if (round == HRT_RNDUP) {
+ if (result * htp->hrt_res != numerator) {
+ temp = result + 1;
+ if (temp - 1 == result)
+ result++;
+ else
+ return (-1);
+ }
+ htp->hrt_res = new_res;
+ htp->hrt_rem = result;
+ return (0);
+ } else { /* round == HRT_TRUNC */
+ htp->hrt_res = new_res;
+ htp->hrt_rem = result;
+ return (0);
+ }
+ }
+
+ /*
+ * We would get overflow doing the calculation is
+ * single precision so do it the slow but careful way.
+ *
+ * Compute the interval times the resolution we are
+ * going to.
+ */
+
+ dint = interval;
+ dto_res = new_res;
+ prod = dint * dto_res;
+
+ /*
+ * For HRT_RND the result will be equal to:
+ *
+ * ((interval * new_res) + htp->hrt_res / 2) / htp->hrt_res
+ *
+ * and for HRT_RNDUP we use:
+ *
+ * ((interval * new_res) + htp->hrt_res - 1) / htp->hrt_res
+ *
+ * This is a different but equivalent way of rounding.
+ */
+
+ if (round == HRT_RND) {
+ drem = htp->hrt_res / 2;
+ prod = prod + drem;
+ } else if (round == HRT_RNDUP) {
+ drem = htp->hrt_res - 1;
+ prod = prod + drem;
+ }
+
+ dfrom_res = htp->hrt_res;
+ quot = prod / dfrom_res;
+
+ /*
+ * If the quotient won't fit in a long, then we have
+ * overflow. Otherwise, return the result.
+ */
+
+ if (quot > UINT_MAX) {
+ return (-1);
+ } else {
+ htp->hrt_res = new_res;
+ htp->hrt_rem = (int)quot;
+ return (0);
+ }
+}
diff --git a/usr/src/cmd/priocntl/tspriocntl.c b/usr/src/cmd/priocntl/tspriocntl.c
new file mode 100644
index 0000000000..21b4882c69
--- /dev/null
+++ b/usr/src/cmd/priocntl/tspriocntl.c
@@ -0,0 +1,477 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/procset.h>
+#include <sys/priocntl.h>
+#include <sys/tspriocntl.h>
+#include <libgen.h>
+#include <limits.h>
+#include <errno.h>
+
+#include "priocntl.h"
+
+/*
+ * This file contains the class specific code implementing
+ * the time-sharing priocntl sub-command.
+ */
+
+#define ADDKEYVAL(p, k, v) { (p[0]) = (k); (p[1]) = (v); p += 2; }
+
+#define TS_KEYCNT 2 /* maximal number of (key, value) pairs */
+
+/*
+ * control flags
+ */
+#define TS_DOUPRILIM 0x01 /* user priority limit */
+#define TS_DOUPRI 0x02 /* user priority */
+
+
+static void print_tsinfo(void);
+static int print_tsprocs(void);
+static int ts_priocntl(idtype_t, id_t, int, char *, uintptr_t *);
+static int set_tsprocs(idtype_t, int, char **, uint_t, pri_t, pri_t);
+static void exec_tscmd(char **, uint_t, pri_t, pri_t);
+
+
+static char usage[] =
+"usage: priocntl -l\n\
+ priocntl -d [-d idtype] [idlist]\n\
+ priocntl -s [-c TS] [-m tsuprilim] [-p tsupri] [-i idtype] [idlist]\n\
+ priocntl -e [-c TS] [-m tsuprilim] [-p tsupri] command [argument(s)]\n";
+
+static char cmdpath[MAXPATHLEN];
+static char basenm[BASENMSZ];
+
+
+int
+main(int argc, char *argv[])
+{
+ int c;
+ int lflag, dflag, sflag, mflag, pflag, eflag, iflag;
+ pri_t tsuprilim;
+ pri_t tsupri;
+ char *idtypnm;
+ idtype_t idtype;
+ int idargc;
+ uint_t cflags;
+
+ (void) strlcpy(cmdpath, argv[0], MAXPATHLEN);
+ (void) strlcpy(basenm, basename(argv[0]), BASENMSZ);
+ lflag = dflag = sflag = mflag = pflag = eflag = iflag = 0;
+ while ((c = getopt(argc, argv, "ldsm:p:ec:i:")) != -1) {
+ switch (c) {
+
+ case 'l':
+ lflag++;
+ break;
+
+ case 'd':
+ dflag++;
+ break;
+
+ case 's':
+ sflag++;
+ break;
+
+ case 'm':
+ mflag++;
+ tsuprilim = (pri_t)str2num(optarg, SHRT_MIN, SHRT_MAX);
+ if (errno)
+ fatalerr("%s: Specified user priority limit %s"
+ " out of configured range\n",
+ basenm, optarg);
+ break;
+
+ case 'p':
+ pflag++;
+ tsupri = (pri_t)str2num(optarg, SHRT_MIN, SHRT_MAX);
+ if (errno)
+ fatalerr("%s: Specified user priority %s out of"
+ " configured range\n", basenm, optarg);
+ break;
+
+ case 'e':
+ eflag++;
+ break;
+
+ case 'c':
+ if (strcmp(optarg, "TS") != 0)
+ fatalerr("error: %s executed for %s class, %s"
+ " is actually sub-command for TS class\n",
+ cmdpath, optarg, cmdpath);
+ break;
+
+ case 'i':
+ iflag++;
+ idtypnm = optarg;
+ break;
+
+ case '?':
+ fatalerr(usage);
+
+ default:
+ break;
+ }
+ }
+
+ if (lflag) {
+ if (dflag || sflag || mflag || pflag || eflag || iflag)
+ fatalerr(usage);
+
+ print_tsinfo();
+
+ } else if (dflag) {
+ if (lflag || sflag || mflag || pflag || eflag)
+ fatalerr(usage);
+
+ return (print_tsprocs());
+
+ } else if (sflag) {
+ if (lflag || dflag || eflag)
+ fatalerr(usage);
+
+ if (iflag) {
+ if (str2idtyp(idtypnm, &idtype) == -1)
+ fatalerr("%s: Bad idtype %s\n", basenm,
+ idtypnm);
+ } else {
+ idtype = P_PID;
+ }
+
+ cflags = (pflag ? TS_DOUPRI : 0);
+
+ if (mflag)
+ cflags |= TS_DOUPRILIM;
+
+ if (optind < argc)
+ idargc = argc - optind;
+ else
+ idargc = 0;
+
+ return (set_tsprocs(idtype, idargc, &argv[optind], cflags,
+ tsuprilim, tsupri));
+
+ } else if (eflag) {
+ if (lflag || dflag || sflag || iflag)
+ fatalerr(usage);
+
+ cflags = (pflag ? TS_DOUPRI : 0);
+
+ if (mflag)
+ cflags |= TS_DOUPRILIM;
+
+ exec_tscmd(&argv[optind], cflags, tsuprilim, tsupri);
+
+ } else {
+ fatalerr(usage);
+ }
+
+ return (0);
+}
+
+
+/*
+ * Print our class name and the configured user priority range.
+ */
+static void
+print_tsinfo(void)
+{
+ pcinfo_t pcinfo;
+
+ (void) strcpy(pcinfo.pc_clname, "TS");
+
+ (void) printf("TS (Time Sharing)\n");
+
+ if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1)
+ fatalerr("\tCan't get configured TS user priority range\n");
+
+ (void) printf("\tConfigured TS User Priority Range: -%d through %d\n",
+ ((tsinfo_t *)pcinfo.pc_clinfo)->ts_maxupri,
+ ((tsinfo_t *)pcinfo.pc_clinfo)->ts_maxupri);
+}
+
+
+/*
+ * Read a list of pids from stdin and print the user priority and user
+ * priority limit for each of the corresponding processes.
+ */
+static int
+print_tsprocs(void)
+{
+ pid_t *pidlist;
+ size_t numread;
+ int i;
+ char clname[PC_CLNMSZ];
+ pri_t ts_uprilim;
+ pri_t ts_upri;
+ int error = 0;
+
+ /*
+ * Read a list of pids from stdin.
+ */
+ if ((pidlist = read_pidlist(&numread, stdin)) == NULL)
+ fatalerr("%s: Can't read pidlist.\n", basenm);
+
+ (void) printf(
+ "TIME SHARING PROCESSES:\n PID TSUPRILIM TSUPRI\n");
+
+ if (numread == 0)
+ fatalerr("%s: No pids on input\n", basenm);
+
+ for (i = 0; i < numread; i++) {
+ (void) printf("%7ld", pidlist[i]);
+ if (priocntl(P_PID, pidlist[i], PC_GETXPARMS, "TS", TS_KY_UPRI,
+ &ts_upri, TS_KY_UPRILIM, &ts_uprilim, 0) != -1) {
+ (void) printf(" %5d %5d\n",
+ ts_uprilim, ts_upri);
+ } else {
+ error = 1;
+
+ if (priocntl(P_PID, pidlist[i], PC_GETXPARMS, NULL,
+ PC_KY_CLNAME, clname, 0) != -1 &&
+ strcmp(clname, "TS"))
+ /*
+ * Process from some class other than time
+ * sharing. It has probably changed class while
+ * priocntl command was executing (otherwise
+ * we wouldn't have been passed its pid).
+ * Print the little we know about it.
+ */
+ (void) printf("\tChanged to class %s while"
+ " priocntl command executing\n", clname);
+ else
+ (void) printf("\tCan't get TS user priority\n");
+ }
+ }
+
+ free_pidlist(pidlist);
+ return (error);
+}
+
+
+/*
+ * Call priocntl() with command codes PC_SETXPARMS or PC_GETXPARMS.
+ * The first parameter behind the command code is always the class name.
+ * Each parameter is headed by a key, which determines the meaning of the
+ * following value. There are maximal TS_KEYCNT = 2 (key, value) pairs.
+ */
+static int
+ts_priocntl(idtype_t idtype, id_t id, int cmd, char *clname, uintptr_t *argsp)
+{
+ return (priocntl(idtype, id, cmd, clname, argsp[0], argsp[1],
+ argsp[2], argsp[3], 0));
+}
+
+
+/*
+ * Set all processes in the set specified by idtype/idargv to time-sharing
+ * (if they aren't already time-sharing) and set their user priority limit
+ * and user priority to those specified by tsuprilim and tsupri.
+ */
+static int
+set_tsprocs(idtype_t idtype, int idargc, char **idargv, uint_t cflags,
+ pri_t tsuprilim, pri_t tsupri)
+{
+ pcinfo_t pcinfo;
+ uintptr_t args[2*TS_KEYCNT+1];
+ uintptr_t *argsp = &args[0];
+ pri_t maxupri;
+ char idtypnm[PC_IDTYPNMSZ];
+ int i;
+ int error = 0;
+ id_t id;
+
+ /*
+ * Get the time sharing class ID and max configured user priority.
+ */
+ (void) strcpy(pcinfo.pc_clname, "TS");
+ if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1)
+ fatalerr("%s: Can't get TS class ID, priocntl system call"
+ " failed with errno %d\n", basenm, errno);
+ maxupri = ((tsinfo_t *)pcinfo.pc_clinfo)->ts_maxupri;
+
+ /*
+ * Validate the tsuprilim and tsupri arguments.
+ */
+ if ((cflags & TS_DOUPRILIM) != 0) {
+ if (tsuprilim > maxupri || tsuprilim < -maxupri)
+ fatalerr("%s: Specified user priority limit %d out of"
+ " configured range\n", basenm, tsuprilim);
+ ADDKEYVAL(argsp, TS_KY_UPRILIM, tsuprilim);
+ }
+
+ if ((cflags & TS_DOUPRI) != 0) {
+ if (tsupri > maxupri || tsupri < -maxupri)
+ fatalerr("%s: Specified user priority %d out of"
+ " configured range\n", basenm, tsupri);
+ ADDKEYVAL(argsp, TS_KY_UPRI, tsupri);
+ }
+ *argsp = 0;
+
+ if (idtype == P_ALL) {
+ if (ts_priocntl(P_ALL, 0, PC_SETXPARMS, "TS", args) == -1) {
+ if (errno == EPERM) {
+ (void) fprintf(stderr,
+ "Permissions error encountered"
+ " on one or more processes.\n");
+ error = 1;
+ } else {
+ fatalerr("%s: Can't reset time sharing"
+ " parameters\npriocntl system call failed"
+ " with errno %d\n", basenm, errno);
+ }
+ } else if ((cflags & (TS_DOUPRILIM|TS_DOUPRI)) == TS_DOUPRI) {
+ (void) verifyupri(idtype, 0, "TS", TS_KY_UPRILIM,
+ tsupri, basenm);
+ }
+ } else if (idargc == 0) {
+ if (ts_priocntl(idtype, P_MYID, PC_SETXPARMS, "TS",
+ args) == -1) {
+ if (errno == EPERM) {
+ (void) idtyp2str(idtype, idtypnm);
+ (void) fprintf(stderr, "Permissions error"
+ " encountered on current %s.\n", idtypnm);
+ error = 1;
+ } else {
+ fatalerr("%s: Can't reset time sharing"
+ " parameters\npriocntl system call failed"
+ " with errno %d\n", basenm, errno);
+ }
+ } else if ((cflags & (TS_DOUPRILIM|TS_DOUPRI)) == TS_DOUPRI &&
+ getmyid(idtype, &id) != -1) {
+ (void) verifyupri(idtype, id, "TS", TS_KY_UPRILIM,
+ tsupri, basenm);
+ }
+ } else {
+ (void) idtyp2str(idtype, idtypnm);
+ for (i = 0; i < idargc; i++) {
+ if (idtype == P_CID) {
+ (void) strcpy(pcinfo.pc_clname, idargv[i]);
+ if (priocntl(0, 0, PC_GETCID,
+ (caddr_t)&pcinfo) == -1)
+ fatalerr("%s: Invalid or unconfigured"
+ " class %s, priocntl system call"
+ " failed with errno %d\n",
+ basenm, pcinfo.pc_clname, errno);
+ id = pcinfo.pc_cid;
+ } else {
+ id = (id_t)str2num(idargv[i], INT_MIN, INT_MAX);
+ if (errno)
+ fatalerr("%s: Invalid id \"%s\"\n",
+ basenm, idargv[i]);
+ }
+
+ if (ts_priocntl(idtype, id, PC_SETXPARMS, "TS",
+ args) == -1) {
+ if (errno == EPERM) {
+ (void) fprintf(stderr,
+ "Permissions error encountered on"
+ " %s %s.\n", idtypnm, idargv[i]);
+ error = 1;
+ } else {
+ fatalerr("%s: Can't reset time sharing"
+ " parameters\npriocntl system call"
+ " failed with errno %d\n",
+ basenm, errno);
+ }
+ } else if ((cflags & (TS_DOUPRILIM|TS_DOUPRI)) ==
+ TS_DOUPRI) {
+ (void) verifyupri(idtype, id, "TS",
+ TS_KY_UPRILIM, tsupri, basenm);
+ }
+ }
+ }
+
+ return (error);
+}
+
+
+/*
+ * Execute the command pointed to by cmdargv as a time-sharing process
+ * with the user priority limit given by tsuprilim and user priority tsupri.
+ */
+static void
+exec_tscmd(char **cmdargv, uint_t cflags, pri_t tsuprilim, pri_t tsupri)
+{
+ pcinfo_t pcinfo;
+ uintptr_t args[2*TS_KEYCNT+1];
+ uintptr_t *argsp = &args[0];
+ pri_t maxupri;
+ pri_t uprilim;
+
+ /*
+ * Get the time sharing class ID and max configured user priority.
+ */
+ (void) strcpy(pcinfo.pc_clname, "TS");
+ if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1)
+ fatalerr("%s: Can't get TS class ID, priocntl system call"
+ " failed with errno %d\n", basenm, errno);
+ maxupri = ((tsinfo_t *)pcinfo.pc_clinfo)->ts_maxupri;
+
+ if ((cflags & TS_DOUPRILIM) != 0) {
+ if (tsuprilim > maxupri || tsuprilim < -maxupri)
+ fatalerr("%s: Specified user priority limit %d out of"
+ " configured range\n", basenm, tsuprilim);
+ ADDKEYVAL(argsp, TS_KY_UPRILIM, tsuprilim);
+ }
+
+ if ((cflags & TS_DOUPRI) != 0) {
+ if (tsupri > maxupri || tsupri < -maxupri)
+ fatalerr("%s: Specified user priority %d out of"
+ " configured range\n", basenm, tsupri);
+ ADDKEYVAL(argsp, TS_KY_UPRI, tsupri);
+ }
+ *argsp = 0;
+
+ if (ts_priocntl(P_PID, P_MYID, PC_SETXPARMS, "TS", args) == -1)
+ fatalerr("%s: Can't reset time sharing parameters\n"
+ "priocntl system call failed with errno %d\n",
+ basenm, errno);
+
+ if ((cflags & (TS_DOUPRILIM|TS_DOUPRI)) == TS_DOUPRI) {
+ if (priocntl(P_PID, P_MYID, PC_GETXPARMS, "TS",
+ TS_KY_UPRILIM, &uprilim, 0) != -1 && tsupri > uprilim)
+ (void) fprintf(stderr,
+ "%s: Specified user priority %d exceeds"
+ " limit %d; set to %d (pid %d)\n",
+ basenm, tsupri, uprilim, uprilim, (int)getpid());
+ }
+
+ (void) execvp(cmdargv[0], cmdargv);
+ fatalerr("%s: Can't execute %s, exec failed with errno %d\n",
+ basenm, cmdargv[0], errno);
+}