summaryrefslogtreecommitdiff
path: root/usr/src/cmd/dispadmin
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/cmd/dispadmin
downloadillumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/cmd/dispadmin')
-rw-r--r--usr/src/cmd/dispadmin/Makefile110
-rw-r--r--usr/src/cmd/dispadmin/dispadmin.c400
-rw-r--r--usr/src/cmd/dispadmin/dispadmin.h73
-rw-r--r--usr/src/cmd/dispadmin/fssdispadmin.c279
-rw-r--r--usr/src/cmd/dispadmin/fxdispadmin.c356
-rw-r--r--usr/src/cmd/dispadmin/iadispadmin.c430
-rw-r--r--usr/src/cmd/dispadmin/rtdispadmin.c384
-rw-r--r--usr/src/cmd/dispadmin/subr.c255
-rw-r--r--usr/src/cmd/dispadmin/tsdispadmin.c426
9 files changed, 2713 insertions, 0 deletions
diff --git a/usr/src/cmd/dispadmin/Makefile b/usr/src/cmd/dispadmin/Makefile
new file mode 100644
index 0000000000..14c2d88cff
--- /dev/null
+++ b/usr/src/cmd/dispadmin/Makefile
@@ -0,0 +1,110 @@
+#
+# 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"
+#
+# cmd/dispadmin/Makefile
+#
+
+PROG= dispadmin
+RT= RT$(PROG)
+TS= TS$(PROG)
+IA= IA$(PROG)
+FSS= FSS$(PROG)
+FX= FX$(PROG)
+PROGS= $(PROG) $(RT) $(TS) $(IA) $(FSS) $(FX)
+
+include ../Makefile.cmd
+
+CFLAGS += $(CCVERBOSE)
+
+ROOTDIR= $(ROOT)/usr/lib/class
+ROOTDIRS= $(ROOTDIR) \
+ $(ROOTDIR)/RT \
+ $(ROOTDIR)/TS \
+ $(ROOTDIR)/IA \
+ $(ROOTDIR)/FSS \
+ $(ROOTDIR)/FX
+ROOTPROG= $(PROG:%=$(ROOTUSRSBIN)/%)
+ROOTRT= $(RT:%=$(ROOTDIR)/RT/%)
+ROOTTS= $(TS:%=$(ROOTDIR)/TS/%)
+ROOTIA= $(IA:%=$(ROOTDIR)/IA/%)
+ROOTFSS= $(FSS:%=$(ROOTDIR)/FSS/%)
+ROOTFX= $(FX:%=$(ROOTDIR)/FX/%)
+
+GROUP = bin
+
+# this would be simpler if we renamed rtdispadmin.c and tsdispadmin.c
+OBJECTS= $(PROG).o rt$(PROG).o ts$(PROG).o ia$(PROG).o \
+ fss$(PROG).o fx$(PROG).o subr.o
+
+# conditional assignments, because of above names
+$(PROG):= OBJ= $(PROG).o
+$(RT):= OBJ= rt$(PROG).o
+$(TS):= OBJ= ts$(PROG).o
+$(IA):= OBJ= ia$(PROG).o
+$(FSS):= OBJ= fss$(PROG).o
+$(FX):= OBJ= fx$(PROG).o
+
+# install rules
+$(ROOTDIR)/% \
+$(ROOTDIR)/RT/% \
+$(ROOTDIR)/IA/% \
+$(ROOTDIR)/TS/% \
+$(ROOTDIR)/FSS/% \
+$(ROOTDIR)/FX/% : %
+ $(INS.file)
+
+.KEEP_STATE:
+
+all: $(PROGS)
+
+$(PROGS): $$(OBJ) subr.o
+ $(LINK.c) -o $@ $(OBJ) subr.o $(LDLIBS)
+ $(POST_PROCESS)
+
+llib-lsubr.ln: subr.c
+ $(LINT.c) -y -o subr subr.c
+
+lint := LDLIBS += -L. -lsubr
+
+install: all $(ROOTPROG) $(ROOTRT) $(ROOTTS) $(ROOTIA) $(ROOTFSS) $(ROOTFX)
+
+# Don't re-install directories already installed by Targetdirs
+#$(ROOTDIRS):
+# $(INS.dir)
+
+clean:
+ $(RM) $(OBJECTS) $(PROGS) llib-lsubr.ln
+
+lint: llib-lsubr.ln
+ $(LINT.c) dispadmin.c $(LDLIBS)
+ $(LINT.c) rtdispadmin.c $(LDLIBS)
+ $(LINT.c) tsdispadmin.c $(LDLIBS)
+ $(LINT.c) iadispadmin.c $(LDLIBS)
+ $(LINT.c) fssdispadmin.c $(LDLIBS)
+ $(LINT.c) fxdispadmin.c $(LDLIBS)
+
+include ../Makefile.targ
diff --git a/usr/src/cmd/dispadmin/dispadmin.c b/usr/src/cmd/dispadmin/dispadmin.c
new file mode 100644
index 0000000000..1a8d3503b2
--- /dev/null
+++ b/usr/src/cmd/dispadmin/dispadmin.c
@@ -0,0 +1,400 @@
+/*
+ * 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 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <limits.h>
+#include <wait.h>
+#include <zone.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/priocntl.h>
+
+#include "dispadmin.h"
+
+/*
+ * This file contains the code implementing the class independent part
+ * of the dispadmin command. Most of the functionality of the dispadmin
+ * command is provided by the class specific sub-commands, the code for
+ * which is elsewhere. The class independent part of the command is
+ * responsible for switching out to the appropriate class specific
+ * sub-command based on the user supplied class argument.
+ * Code in this file should never assume any knowledge of any specific
+ * scheduler class (other than the SYS class).
+ */
+
+#define BASENMSZ 16
+#define BUFSZ (PATH_MAX + 80)
+#define CLASSPATH "/usr/lib/class"
+#define CONFIGPATH "/etc/dispadmin.conf"
+#define CONFIGOWNER 0 /* uid 0 (root) */
+#define CONFIGGROUP 1 /* gid 1 (other) */
+#define CONFIGPERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) /* 0644 */
+#define TOKENNAME "DEFAULT_SCHEDULER"
+
+extern char *basename();
+
+static char usage[] =
+"usage: dispadmin -l\n\
+ dispadmin -c class [class-specific options]\n\
+ dispadmin -d [class]\n\
+ dispadmin -u\n";
+
+static char basenm[BASENMSZ];
+static char cmdpath[PATH_MAX];
+
+static void print_classlist();
+static void exec_cscmd(char *, char **);
+static void set_scheduler(char *);
+static void class_info(pcinfo_t *);
+static void set_default_class();
+
+int
+main(int argc, char **argv)
+{
+ extern char *optarg;
+ extern int optind, opterr;
+
+ int c;
+ int uflag, cflag, dflag, lflag, csoptsflag;
+ char *clname;
+
+ (void) strncpy(cmdpath, argv[0], PATH_MAX);
+ (void) strncpy(basenm, basename(argv[0]), BASENMSZ);
+ cflag = dflag = lflag = uflag = csoptsflag = 0;
+ opterr = 0;
+ while ((c = getopt(argc, argv, "c:dlu")) != -1) {
+ switch (c) {
+
+ case 'c':
+ cflag++;
+ clname = optarg;
+ break;
+
+ case 'd':
+ dflag++;
+ clname = argv[optind];
+ break;
+
+ case 'l':
+ lflag++;
+ break;
+
+ case 'u':
+ uflag++;
+ break;
+
+
+ case '?':
+ /*
+ * We assume for now that any option that
+ * getopt() doesn't recognize is intended for a
+ * class specific subcommand.
+ */
+ csoptsflag++;
+ if (argv[optind] && argv[optind][0] != '-') {
+
+
+ /*
+ * Class specific option takes an
+ * argument which we skip over for now.
+ */
+ optind++;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (lflag) {
+ if (uflag || cflag || dflag || csoptsflag)
+ fatalerr(usage);
+
+ print_classlist();
+ exit(0);
+
+ } else if (uflag) {
+ if (lflag || dflag || csoptsflag)
+ fatalerr(usage);
+
+ set_default_class();
+ } else if (cflag) {
+ if (lflag || dflag)
+ fatalerr(usage);
+
+ exec_cscmd(clname, argv);
+
+ } else if (dflag) {
+ if (cflag || lflag || csoptsflag)
+ fatalerr(usage);
+ set_scheduler(clname);
+ exit(0);
+
+ } else {
+ fatalerr(usage);
+ }
+ return (1);
+}
+
+
+/*
+ * Print the heading for the class list and execute the
+ * class specific sub-command with the -l option for each
+ * configured class.
+ */
+static void
+print_classlist()
+{
+ id_t cid;
+ int nclass;
+ pcinfo_t pcinfo;
+
+ if ((nclass = priocntl(0, 0, PC_GETCLINFO, NULL)) == -1)
+ fatalerr("%s: Can't get number of configured classes\n",
+ cmdpath);
+
+ (void) printf("CONFIGURED CLASSES\n==================\n\n");
+ (void) printf("SYS\t(System Class)\n");
+ (void) fflush(stdout);
+ 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 (class ID = %d)\n",
+ cmdpath, cid);
+ class_info(&pcinfo);
+ }
+}
+
+
+/*
+ * Execute the appropriate class specific sub-command for the class
+ * specified by clname, passing it the arguments in subcmdargv.
+ */
+static void
+exec_cscmd(char *clname, char **subcmdargv)
+{
+ pcinfo_t pcinfo;
+ char subcmdpath[PATH_MAX];
+
+ /*
+ * Do a quick check to make sure clname is valid.
+ * We could just wait and see if the exec below
+ * succeeds but we wouldn't know much about the reason.
+ * This way we can give the user a more meaningful error
+ * message.
+ */
+ (void) strncpy(pcinfo.pc_clname, clname, PC_CLNMSZ);
+ if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1)
+ fatalerr("%s: Invalid or unconfigured class %s\n", cmdpath,
+ clname);
+
+ (void) snprintf(subcmdpath, PATH_MAX, "%s/%s/%s%s", CLASSPATH,
+ clname, clname, basenm);
+ subcmdargv[0] = subcmdpath;
+
+ (void) execv(subcmdpath, subcmdargv);
+ fatalerr("%s: Can't execute %s sub-command\n", cmdpath, clname);
+}
+
+static void
+class_info(pcinfo_t *pcinfo)
+{
+ int pid;
+ char subcmdpath[PATH_MAX];
+
+ (void) snprintf(subcmdpath, PATH_MAX, "%s/%s/%s%s", CLASSPATH,
+ pcinfo->pc_clname, pcinfo->pc_clname, basenm);
+ if ((pid = fork()) == 0) {
+ (void) execl(subcmdpath, subcmdpath, "-l", (char *)0);
+ fatalerr("%s\n\tCan't execute %s specific subcommand\n",
+ pcinfo->pc_clname, pcinfo->pc_clname);
+ } else if (pid == (pid_t)-1) {
+ (void) fprintf(stderr,
+ "%s\nCan't execute %s specific subcommand)\n",
+ pcinfo->pc_clname, pcinfo->pc_clname);
+ } else {
+ (void) wait(NULL);
+ }
+}
+
+/*
+ * Return the current default scheduling class as specified in
+ * /etc/dispadmin.conf.
+ */
+static char *
+read_default_file(FILE *fp)
+{
+ char buf[BUFSZ];
+ int line;
+
+ for (line = 1; fgets(buf, BUFSZ, fp) != NULL; line++) {
+ char name[BUFSZ], value[BUFSZ];
+ int len;
+
+ if (buf[0] == '#' || buf[0] == '\n')
+ continue;
+ /* LINTED - unbounded string specifier */
+ if (sscanf(buf, " %[^=]=%s \n%n", name, value, &len) == 2 &&
+ name[0] != '\0' && value[0] != '\0' && len == strlen(buf)) {
+
+ if (strcmp(name, TOKENNAME) != 0)
+ fatalerr("\"%s\", line %d: invalid "
+ "token: %s\n", CONFIGPATH, line, name);
+
+ (void) fclose(fp);
+ return (strdup(value));
+ } else {
+ fatalerr("\"%s\", line %d: syntax error\n", CONFIGPATH,
+ line);
+ (void) fclose(fp);
+ }
+ }
+ if (line == 1)
+ fatalerr("%s: %s is empty\n", cmdpath, CONFIGPATH);
+ return (NULL);
+}
+
+/*
+ * Set the default scheduling class for the system.
+ * Update /etc/dispadmin.conf if necessary.
+ */
+static void
+set_scheduler(char *clname)
+{
+ pcinfo_t pcinfo;
+ FILE *fp;
+ int fd;
+
+ if (getzoneid() != GLOBAL_ZONEID)
+ fatalerr("%s: Operation not supported in non-global zones\n",
+ cmdpath);
+
+ if (clname == NULL) {
+ if ((fd = open(CONFIGPATH, O_RDONLY, CONFIGPERM)) == -1) {
+ if (errno == ENOENT)
+ fatalerr("%s: Default scheduling class "
+ "is not set\n", cmdpath);
+ else
+ fatalerr("%s: Failed to open %s (%s)\n",
+ cmdpath, CONFIGPATH, strerror(errno));
+ }
+
+ if ((fp = fdopen(fd, "r")) == NULL)
+ fatalerr("%s: Failed to open stream for %s (%s)\n",
+ cmdpath, CONFIGPATH, strerror(errno));
+ clname = read_default_file(fp);
+ (void) strncpy(pcinfo.pc_clname, clname, PC_CLNMSZ);
+
+ if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1)
+ fatalerr("\"%s\", scheduling class %s is not "
+ "available\n", CONFIGPATH, clname);
+ else
+ class_info(&pcinfo);
+ return;
+ }
+
+ /*
+ * Do a quick check to make sure clname is valid class name.
+ */
+ (void) strncpy(pcinfo.pc_clname, clname, PC_CLNMSZ);
+ if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1)
+ fatalerr("%s: Invalid or unconfigured class %s\n", cmdpath,
+ clname);
+ if ((fd = open(CONFIGPATH, O_RDWR | O_CREAT, CONFIGPERM)) == -1)
+ fatalerr("%s: Failed to open %s (%s)\n", cmdpath, CONFIGPATH,
+ strerror(errno));
+ if ((fp = fdopen(fd, "w")) == NULL)
+ fatalerr("%s: Failed to open stream for %s\n", CONFIGPATH);
+ if (ftruncate(fd, (off_t)0) == -1)
+ fatalerr("%s: Failed to truncate %s\n", cmdpath, CONFIGPATH);
+ (void) fputs("#\n# /etc/dispadmin.conf\n#\n"
+ "# Do NOT edit this file by hand -- use dispadmin(1m) instead.\n"
+ "#\n", fp);
+ if ((fprintf(fp, "%s=%s\n", TOKENNAME, clname)) == -1)
+ fatalerr("%s: Failed to write to %s\n", cmdpath, CONFIGPATH);
+ if (fflush(fp) != 0)
+ (void) fprintf(stderr,
+ "%s: warning: failed to flush config file\n",
+ cmdpath);
+ if (fsync(fd) == -1)
+ (void) fprintf(stderr,
+ "%s: warning: failed to sync config file to disk\n",
+ cmdpath);
+ if (fchmod(fd, CONFIGPERM) == -1)
+ (void) fprintf(stderr,
+ "%s: warning: failed to reset config file mode\n",
+ cmdpath);
+ if (fchown(fd, CONFIGOWNER, CONFIGGROUP) == -1)
+ (void) fprintf(stderr,
+ "%s: warning: failed to reset config file owner\n",
+ cmdpath);
+ (void) fclose(fp);
+
+ if (priocntl(0, 0, PC_SETDFLCL, clname) == -1)
+ fatalerr("%s: failed to set default class %s in kernel: %s\n",
+ cmdpath, clname, strerror(errno));
+}
+
+static void
+set_default_class()
+{
+ char *clname;
+ FILE *fp;
+ int fd;
+
+ if ((fd = open(CONFIGPATH, O_RDONLY, CONFIGPERM)) == -1) {
+ /* silently succeed, there is nothing to do */
+ if (errno == ENOENT)
+ return;
+ else
+ fatalerr("%s: Failed to open %s (%s)\n",
+ cmdpath, CONFIGPATH, strerror(errno));
+ }
+
+ if ((fp = fdopen(fd, "r")) == NULL)
+ fatalerr("%s: Failed to open stream for %s (%s)\n",
+ cmdpath, CONFIGPATH, strerror(errno));
+
+ if ((clname = read_default_file(fp)) != NULL) {
+ if (priocntl(0, 0, PC_SETDFLCL, clname) == -1)
+ fatalerr("%s: failed to set default class %s in "
+ "kernel: %s\n", cmdpath, clname, strerror(errno));
+ }
+}
diff --git a/usr/src/cmd/dispadmin/dispadmin.h b/usr/src/cmd/dispadmin/dispadmin.h
new file mode 100644
index 0000000000..6c54aebaf8
--- /dev/null
+++ b/usr/src/cmd/dispadmin/dispadmin.h
@@ -0,0 +1,73 @@
+/*
+ * 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 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Note that this file does not exist in the SVr4 base, but
+ * is largely derived from sys/hrtcntl.h, hence the AT&T
+ * copyright is propagated. SVr4.0 1.9
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The following is an excerpt from <sys/hrtcntl.h>. HRT timers are not
+ * supported by SunOS (which will support the POSIX definition). Dispadmin
+ * uses the hrt routine _hrtnewres because it coincidentally does the
+ * right thing. These defines allow this routine to be locally included
+ * in dispadmin (rather than exported in libc). This should be improved in
+ * the long term.
+ */
+
+/*
+ * Definitions for specifying rounding mode.
+ */
+
+#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;
+
+/*
+ * Functions in subr.c
+ */
+extern void fatalerr(const char *, ...);
+extern long hrtconvert(hrtimer_t *);
+extern int _hrtnewres(hrtimer_t *, ulong_t, long);
diff --git a/usr/src/cmd/dispadmin/fssdispadmin.c b/usr/src/cmd/dispadmin/fssdispadmin.c
new file mode 100644
index 0000000000..0a404bec62
--- /dev/null
+++ b/usr/src/cmd/dispadmin/fssdispadmin.c
@@ -0,0 +1,279 @@
+/*
+ * 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/param.h>
+#include <sys/fss.h>
+#include <sys/priocntl.h>
+#include <sys/fsspriocntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include "dispadmin.h"
+
+/*
+ * This file contains the class specific code implementing the fair-share
+ * scheduler dispadmin sub-command.
+ */
+
+#define BASENMSZ 16
+
+extern char *basename();
+static void getadmin(), setadmin();
+
+static char usage[] = "usage: dispadmin -l\n"
+ "dispadmin -c FSS -g [-r res]\n"
+ "dispadmin -c FSS -s infile\n";
+
+static char basenm[BASENMSZ];
+static char cmdpath[256];
+
+int
+main(int argc, char **argv)
+{
+ int c;
+ int lflag, gflag, rflag, sflag;
+ ulong_t res;
+ char *infile;
+ char *endp;
+
+ (void) strcpy(cmdpath, argv[0]);
+ (void) strcpy(basenm, basename(argv[0]));
+ lflag = gflag = rflag = sflag = 0;
+ while ((c = getopt(argc, argv, "lc:gr:s:")) != -1) {
+ switch (c) {
+
+ case 'l':
+ lflag++;
+ 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 'g':
+ gflag++;
+ break;
+
+ case 'r':
+ rflag++;
+ errno = 0;
+ res = strtoul(optarg, &endp, 10);
+ if (res == 0 || errno != 0 || *endp != '\0')
+ fatalerr("%s: Can't convert to requested "
+ "resolution\n", basenm);
+ break;
+
+ case 's':
+ sflag++;
+ infile = optarg;
+ break;
+
+ case '?':
+ fatalerr(usage);
+
+ default:
+ break;
+ }
+ }
+
+ if (lflag) {
+ if (gflag || rflag || sflag)
+ fatalerr(usage);
+
+ (void) printf("FSS\t(Fair Share)\n");
+ return (0);
+
+ } else if (gflag) {
+ if (lflag || sflag)
+ fatalerr(usage);
+
+ if (rflag == 0)
+ res = 1000;
+
+ getadmin(res);
+ return (0);
+
+ } else if (sflag) {
+ if (lflag || gflag || rflag)
+ fatalerr(usage);
+
+ setadmin(infile);
+ return (0);
+
+ } else {
+ fatalerr(usage);
+ }
+ return (1);
+}
+
+/*
+ * Retrieve the current settings from kernel, convert the time quantum
+ * value to the resolution specified by res and print out the results.
+ */
+static void
+getadmin(ulong_t res)
+{
+ pcinfo_t pcinfo;
+ pcadmin_t pcadmin;
+ fssadmin_t fssadmin;
+ hrtimer_t hrtime;
+ long fss_quantum;
+
+ (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));
+
+ pcadmin.pc_cid = pcinfo.pc_cid;
+ pcadmin.pc_cladmin = (char *)&fssadmin;
+ fssadmin.fss_cmd = FSS_GETADMIN;
+
+ if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1)
+ fatalerr("%s: Can't get scheduler configuration, priocntl "
+ "system call failed (%s)\n", basenm, strerror(errno));
+
+ hrtime.hrt_secs = 0;
+ hrtime.hrt_rem = fssadmin.fss_quantum;
+ hrtime.hrt_res = HZ;
+ if (_hrtnewres(&hrtime, res, HRT_RNDUP) == -1)
+ fatalerr("%s: Can't convert to requested resolution\n", basenm);
+ if ((fss_quantum = hrtconvert(&hrtime)) == -1)
+ fatalerr("%s: Can't express time quantum in "
+ "requested resolution,\n"
+ "try coarser resolution\n", basenm);
+
+ (void) printf("#\n# Fair Share Scheduler Configuration\n#\n");
+ (void) printf("RES=%ld\n", res);
+ (void) printf("#\n# Time Quantum\n#\n");
+ (void) printf("QUANTUM=%ld\n", fss_quantum);
+}
+
+/*
+ * Read the scheduler settings from infile, convert the time quantum values
+ * to HZ resolution, do a little sanity checking and overwrite kernel settings
+ * with the values from the file.
+ */
+static void
+setadmin(char *infile)
+{
+ int i;
+ pcinfo_t pcinfo;
+ pcadmin_t pcadmin;
+ fssadmin_t fssadmin;
+ int line;
+ ulong_t res;
+ long fss_quantum;
+ hrtimer_t hrtime;
+ FILE *fp;
+ char buf[512];
+ char *endp;
+ int nparams = 0;
+
+ (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));
+
+ if ((fp = fopen(infile, "r")) == NULL)
+ fatalerr("%s: Can't open %s for input\n", basenm, infile);
+
+ for (line = 1; fgets(buf, sizeof (buf), fp) != NULL; line++) {
+ char name[512], value[512];
+ int len;
+
+ if (buf[0] == '#' || buf[0] == '\n')
+ continue;
+ /*
+ * Look for "name=value", with optional whitespaces on either
+ * side, terminated by a newline, and consuming the whole line.
+ */
+ /* LINTED - unbounded string specifier */
+ if (sscanf(buf, " %[^=]=%s \n%n", name, value, &len) == 2 &&
+ name[0] != '\0' && value[0] != '\0' && len == strlen(buf)) {
+
+ if (strcmp(name, "RES") == 0) {
+ errno = 0;
+ i = (int)strtol(value, &endp, 10);
+ if (errno != 0 || endp == value ||
+ i < 0 || *endp != '\0')
+ fatalerr("%s, line %d: illegal "
+ "resolution value\n", infile, line);
+ else
+ res = i;
+ nparams++;
+ } else if (strcmp(name, "QUANTUM") == 0) {
+ errno = 0;
+ i = (int)strtol(value, &endp, 10);
+ if (errno != 0 || endp == value ||
+ i < 0 || *endp != '\0')
+ fatalerr("%s, line %d: illegal time "
+ "quantum value\n", infile, line);
+ else
+ fss_quantum = i;
+ nparams++;
+ } else {
+ fatalerr("%s, line %d: invalid token\n",
+ infile, line);
+ }
+ } else {
+ fatalerr("%s, line %d: syntax error\n", infile, line);
+ }
+ }
+ if (line == 1 || nparams < 2)
+ fatalerr("cannot read settings from %s\n", infile);
+ if (res != HZ) {
+ hrtime.hrt_secs = 0;
+ hrtime.hrt_rem = fss_quantum;
+ hrtime.hrt_res = res;
+ if (_hrtnewres(&hrtime, HZ, HRT_RNDUP) == -1)
+ fatalerr("%s: Can't convert specified "
+ "resolution to ticks\n", basenm);
+ if ((fssadmin.fss_quantum = hrtconvert(&hrtime)) == -1)
+ fatalerr("%s, line %d: time quantum value out of "
+ "valid range\n", infile, line);
+ } else {
+ fssadmin.fss_quantum = (short)fss_quantum;
+ }
+
+ pcadmin.pc_cid = pcinfo.pc_cid;
+ pcadmin.pc_cladmin = (char *)&fssadmin;
+ fssadmin.fss_cmd = FSS_SETADMIN;
+
+ if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1)
+ fatalerr("%s: Can't set scheduler parameters, priocntl "
+ "system call failed (%s)\n", basenm, strerror(errno));
+}
diff --git a/usr/src/cmd/dispadmin/fxdispadmin.c b/usr/src/cmd/dispadmin/fxdispadmin.c
new file mode 100644
index 0000000000..62d85e829d
--- /dev/null
+++ b/usr/src/cmd/dispadmin/fxdispadmin.c
@@ -0,0 +1,356 @@
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/priocntl.h>
+#include <sys/fxpriocntl.h>
+#include <sys/param.h>
+#include <errno.h>
+#include <sys/fx.h>
+
+#include "dispadmin.h"
+
+/*
+ * This file contains the class specific code implementing
+ * the fixed-priority dispadmin sub-command.
+ */
+
+#define BASENMSZ 16
+
+extern char *basename();
+
+static void get_fxdptbl(), set_fxdptbl();
+
+static char usage[] = "usage: dispadmin -l\n"
+ "dispadmin -c FX -g [-r res]\n"
+ "dispadmin -c FX -s infile\n";
+
+static char basenm[BASENMSZ];
+static char cmdpath[256];
+
+
+int
+main(int argc, char **argv)
+{
+ int c;
+ int lflag, gflag, rflag, sflag;
+ ulong_t res;
+ char *infile;
+ char *endp;
+
+ (void) strcpy(cmdpath, argv[0]);
+ (void) strcpy(basenm, basename(argv[0]));
+ lflag = gflag = rflag = sflag = 0;
+ while ((c = getopt(argc, argv, "lc:gr:s:")) != -1) {
+ switch (c) {
+
+ case 'l':
+ lflag++;
+ 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 'g':
+ gflag++;
+ break;
+
+ case 'r':
+ rflag++;
+ errno = 0;
+ res = strtoul(optarg, &endp, 10);
+ if (res == 0 || errno != 0 || *endp != '\0')
+ fatalerr("%s: Can't convert to requested "
+ "resolution\n", basenm);
+ break;
+
+ case 's':
+ sflag++;
+ infile = optarg;
+ break;
+
+ case '?':
+ fatalerr(usage);
+
+ default:
+ break;
+ }
+ }
+
+
+ if (lflag) {
+ if (gflag || rflag || sflag)
+ fatalerr(usage);
+
+ (void) printf("FX\t(Fixed Priority)\n");
+ return (0);
+
+ } else if (gflag) {
+ if (sflag)
+ fatalerr(usage);
+
+ if (rflag == 0)
+ res = 1000;
+
+ get_fxdptbl(res);
+ return (0);
+
+ } else if (sflag) {
+ if (rflag)
+ fatalerr(usage);
+
+ set_fxdptbl(infile);
+ return (0);
+
+ } else {
+ fatalerr(usage);
+ }
+ return (1);
+}
+
+
+/*
+ * Retrieve the current fx_dptbl from memory, convert the time quantum
+ * values to the resolution specified by res and write the table to stdout.
+ */
+static void
+get_fxdptbl(ulong_t res)
+{
+ int i;
+ int fxdpsz;
+ pcinfo_t pcinfo;
+ pcadmin_t pcadmin;
+ fxadmin_t fxadmin;
+ fxdpent_t *fx_dptbl;
+ hrtimer_t hrtime;
+
+ (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);
+
+ pcadmin.pc_cid = pcinfo.pc_cid;
+ pcadmin.pc_cladmin = (char *)&fxadmin;
+ fxadmin.fx_cmd = FX_GETDPSIZE;
+
+ if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1)
+ fatalerr("%s: Can't get fx_dptbl size, priocntl system call "
+ "failed with errno %d\n", basenm, errno);
+
+ fxdpsz = fxadmin.fx_ndpents * sizeof (fxdpent_t);
+ if ((fx_dptbl = (fxdpent_t *)malloc(fxdpsz)) == NULL)
+ fatalerr("%s: Can't allocate memory for fx_dptbl\n", basenm);
+
+ fxadmin.fx_dpents = fx_dptbl;
+
+ fxadmin.fx_cmd = FX_GETDPTBL;
+ if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1)
+ fatalerr("%s: Can't get fx_dptbl, priocntl system call "
+ "failed with errno %d\n", basenm, errno);
+
+ (void) printf("# Fixed Priority Dispatcher Configuration\n");
+ (void) printf("RES=%ld\n\n", res);
+ (void) printf("# TIME QUANTUM PRIORITY\n");
+ (void) printf("# (fx_quantum) LEVEL\n");
+
+ for (i = 0; i < fxadmin.fx_ndpents; i++) {
+ if (res != HZ && fx_dptbl[i].fx_quantum != FX_TQINF) {
+ hrtime.hrt_secs = 0;
+ hrtime.hrt_rem = fx_dptbl[i].fx_quantum;
+ hrtime.hrt_res = HZ;
+ if (_hrtnewres(&hrtime, res, HRT_RNDUP) == -1)
+ fatalerr("%s: Can't convert to requested "
+ "resolution\n", basenm);
+ if ((fx_dptbl[i].fx_quantum = hrtconvert(&hrtime))
+ == -1)
+ fatalerr("%s: Can't express time quantum in "
+ "requested resolution,\n"
+ "try coarser resolution\n", basenm);
+ }
+ (void) printf("%10d # %3d\n",
+ fx_dptbl[i].fx_quantum, i);
+ }
+}
+
+
+/*
+ * Read the fx_dptbl values from infile, convert the time quantum values
+ * to HZ resolution, do a little sanity checking and overwrite the table
+ * in memory with the values from the file.
+ */
+static void
+set_fxdptbl(char *infile)
+{
+ int i;
+ int nfxdpents;
+ char *tokp;
+ pcinfo_t pcinfo;
+ pcadmin_t pcadmin;
+ fxadmin_t fxadmin;
+ fxdpent_t *fx_dptbl;
+ int linenum;
+ ulong_t res;
+ hrtimer_t hrtime;
+ FILE *fp;
+ char buf[512];
+ int wslength;
+ char *endp;
+ char name[512], value[512];
+ int len;
+
+ (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);
+
+ pcadmin.pc_cid = pcinfo.pc_cid;
+ pcadmin.pc_cladmin = (char *)&fxadmin;
+ fxadmin.fx_cmd = FX_GETDPSIZE;
+
+ if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1)
+ fatalerr("%s: Can't get fx_dptbl size, priocntl system call "
+ "failed with errno %d\n", basenm, errno);
+
+ nfxdpents = fxadmin.fx_ndpents;
+ if ((fx_dptbl =
+ (fxdpent_t *)malloc(nfxdpents * sizeof (fxdpent_t))) == NULL)
+ fatalerr("%s: Can't allocate memory for fx_dptbl\n", basenm);
+
+ if ((fp = fopen(infile, "r")) == NULL)
+ fatalerr("%s: Can't open %s for input\n", basenm, infile);
+
+ linenum = 0;
+
+ /*
+ * Find the first non-blank, non-comment line. A comment line
+ * is any line with '#' as the first non-white-space character.
+ */
+ do {
+ if (fgets(buf, sizeof (buf), fp) == NULL)
+ fatalerr("%s: Too few lines in input table\n", basenm);
+ linenum++;
+ } while (buf[0] == '#' || buf[0] == '\0' ||
+ (wslength = strspn(buf, " \t\n")) == strlen(buf) ||
+ strchr(buf, '#') == buf + wslength);
+
+ /* LINTED - unbounded string specifier */
+ if (sscanf(buf, " %[^=]=%s \n%n", name, value, &len) == 2 &&
+ name[0] != '\0' && value[0] != '\0' && len == strlen(buf)) {
+
+ if (strcmp(name, "RES") == 0) {
+ errno = 0;
+ i = (int)strtol(value, &endp, 10);
+ if (errno != 0 || endp == value ||
+ i < 0 || *endp != '\0')
+ fatalerr("%s: Bad RES specification, "
+ "line %d of input file\n", basenm, linenum);
+ else
+ res = i;
+ } else {
+ fatalerr("%s: Bad RES specification, "
+ "line %d of input file\n", basenm, linenum);
+ }
+ }
+
+ /*
+ * The remainder of the input file should contain exactly enough
+ * non-blank, non-comment lines to fill the table (fx_ndpents lines).
+ * We assume that any non-blank, non-comment line is data for the
+ * table and fail if we find more or less than we need.
+ */
+ for (i = 0; i < fxadmin.fx_ndpents; i++) {
+
+ /*
+ * Get the next non-blank, non-comment line.
+ */
+ do {
+ if (fgets(buf, sizeof (buf), fp) == NULL)
+ fatalerr("%s: Too few lines in input table\n",
+ basenm);
+ linenum++;
+ } while (buf[0] == '#' || buf[0] == '\0' ||
+ (wslength = strspn(buf, " \t\n")) == strlen(buf) ||
+ strchr(buf, '#') == buf + wslength);
+
+ if ((tokp = strtok(buf, " \t")) == NULL)
+ fatalerr("%s: Too few values, line %d of input file\n",
+ basenm, linenum);
+
+ fx_dptbl[i].fx_quantum = atol(tokp);
+ if (fx_dptbl[i].fx_quantum <= 0) {
+ fatalerr("%s: fx_quantum value out of "
+ "valid range; line %d of input,\n"
+ "table not overwritten\n", basenm, linenum);
+ } else if (res != HZ) {
+ hrtime.hrt_secs = 0;
+ hrtime.hrt_rem = fx_dptbl[i].fx_quantum;
+ hrtime.hrt_res = res;
+ if (_hrtnewres(&hrtime, HZ, HRT_RNDUP) == -1)
+ fatalerr("%s: Can't convert specified "
+ "resolution to ticks\n", basenm);
+ if ((fx_dptbl[i].fx_quantum =
+ hrtconvert(&hrtime)) == -1)
+ fatalerr("%s: fx_quantum value out of "
+ "valid range; line %d of input,\n"
+ "table not overwritten\n", basenm, linenum);
+ }
+
+ if ((tokp = strtok(NULL, " \t")) != NULL && tokp[0] != '#')
+ fatalerr("%s: Too many values, line %d of input file\n",
+ basenm, linenum);
+ }
+
+ /*
+ * We've read enough lines to fill the table. We fail
+ * if the input file contains any more.
+ */
+ while (fgets(buf, sizeof (buf), fp) != NULL) {
+ if (buf[0] != '#' && buf[0] != '\0' &&
+ (wslength = strspn(buf, " \t\n")) != strlen(buf) &&
+ strchr(buf, '#') != buf + wslength)
+ fatalerr("%s: Too many lines in input table\n",
+ basenm);
+ }
+
+ fxadmin.fx_dpents = fx_dptbl;
+ fxadmin.fx_cmd = FX_SETDPTBL;
+ if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1)
+ fatalerr("%s: Can't set fx_dptbl, priocntl system call failed "
+ "with errno %d\n", basenm, errno);
+}
diff --git a/usr/src/cmd/dispadmin/iadispadmin.c b/usr/src/cmd/dispadmin/iadispadmin.c
new file mode 100644
index 0000000000..aa0b39d05f
--- /dev/null
+++ b/usr/src/cmd/dispadmin/iadispadmin.c
@@ -0,0 +1,430 @@
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/priocntl.h>
+#include <sys/iapriocntl.h>
+#include <sys/param.h>
+#include <sys/ia.h>
+
+#include "dispadmin.h"
+
+/*
+ * This file contains the class specific code implementing
+ * the interactive dispadmin sub-command.
+ */
+
+#define BASENMSZ 16
+
+extern char *basename();
+
+static void get_iadptbl(), set_iadptbl();
+
+static char usage[] =
+"usage: dispadmin -l\n\
+ dispadmin -c IA -g [-r res]\n\
+ dispadmin -c IA -s infile\n";
+
+static char basenm[BASENMSZ];
+static char cmdpath[256];
+
+
+int
+main(int argc, char **argv)
+{
+ extern char *optarg;
+
+ int c;
+ int lflag, gflag, rflag, sflag;
+ ulong_t res;
+ char *infile;
+
+ (void) strcpy(cmdpath, argv[0]);
+ (void) strcpy(basenm, basename(argv[0]));
+ lflag = gflag = rflag = sflag = 0;
+ while ((c = getopt(argc, argv, "lc:gr:s:")) != -1) {
+ switch (c) {
+
+ case 'l':
+ lflag++;
+ 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 'g':
+ gflag++;
+ break;
+
+ case 'r':
+ rflag++;
+ res = strtoul(optarg, (char **)NULL, 10);
+ break;
+
+ case 's':
+ sflag++;
+ infile = optarg;
+ break;
+
+ case '?':
+ fatalerr(usage);
+
+ default:
+ break;
+ }
+ }
+
+ if (lflag) {
+ if (gflag || rflag || sflag)
+ fatalerr(usage);
+
+ (void) printf("IA\t(Interactive)\n");
+ return (0);
+
+ } else if (gflag) {
+ if (lflag || sflag)
+ fatalerr(usage);
+
+ if (rflag == 0)
+ res = 1000;
+
+ get_iadptbl(res);
+ return (0);
+
+ } else if (sflag) {
+ if (lflag || gflag || rflag)
+ fatalerr(usage);
+
+ set_iadptbl(infile);
+ return (0);
+
+ } else {
+ fatalerr(usage);
+ }
+ return (1);
+}
+
+
+/*
+ * Retrieve the current ia_dptbl from memory, convert the time quantum
+ * values to the resolution specified by res and write the table to stdout.
+ */
+static void
+get_iadptbl(ulong_t res)
+{
+ int i;
+ int iadpsz;
+ pcinfo_t pcinfo;
+ pcadmin_t pcadmin;
+ iaadmin_t iaadmin;
+ iadpent_t *ia_dptbl;
+ hrtimer_t hrtime;
+
+ (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);
+
+ pcadmin.pc_cid = pcinfo.pc_cid;
+ pcadmin.pc_cladmin = (char *)&iaadmin;
+ iaadmin.ia_cmd = IA_GETDPSIZE;
+
+ if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1)
+ fatalerr("%s: Can't get ia_dptbl size, priocntl system "
+ "call failed with errno %d\n",
+ basenm, errno);
+
+ iadpsz = iaadmin.ia_ndpents * sizeof (iadpent_t);
+ if ((ia_dptbl = (iadpent_t *)malloc(iadpsz)) == NULL)
+ fatalerr("%s: Can't allocate memory for ia_dptbl\n", basenm);
+
+ iaadmin.ia_dpents = ia_dptbl;
+
+ iaadmin.ia_cmd = IA_GETDPTBL;
+ if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1)
+ fatalerr("%s: Can't get ia_dptbl, priocntl system call "
+ "call failed with errno %d\n",
+ basenm, errno);
+
+ (void) printf("# Interactive Dispatcher Configuration\n");
+ (void) printf("RES=%ld\n\n", res);
+ (void) printf("# ia_quantum ia_tqexp ia_slpret ia_maxwait ia_lwait \
+PRIORITY LEVEL\n");
+
+ for (i = 0; i < iaadmin.ia_ndpents; i++) {
+ if (res != HZ) {
+ hrtime.hrt_secs = 0;
+ hrtime.hrt_rem = ia_dptbl[i].ia_quantum;
+ hrtime.hrt_res = HZ;
+ if (_hrtnewres(&hrtime, res, HRT_RNDUP) == -1)
+ fatalerr("%s: Can't convert to requested "
+ "resolution\n", basenm);
+ if ((ia_dptbl[i].ia_quantum = hrtconvert(&hrtime))
+ == -1)
+ fatalerr("%s: Can't express time quantum in "
+ "requested resolution,\n"
+ "try coarser resolution\n",
+ basenm);
+ }
+ (void) printf("%10ld%10d%10d%12d%10d # %3d\n",
+ ia_dptbl[i].ia_quantum, ia_dptbl[i].ia_tqexp,
+ ia_dptbl[i].ia_slpret, ia_dptbl[i].ia_maxwait,
+ ia_dptbl[i].ia_lwait, i);
+ }
+}
+
+
+/*
+ * Read the ia_dptbl values from infile, convert the time quantum values
+ * to HZ resolution, do a little sanity checking and overwrite the table
+ * in memory with the values from the file.
+ */
+static void
+set_iadptbl(infile)
+char *infile;
+{
+ int i;
+ int niadpents;
+ char *tokp;
+ pcinfo_t pcinfo;
+ pcadmin_t pcadmin;
+ iaadmin_t iaadmin;
+ iadpent_t *ia_dptbl;
+ int linenum;
+ ulong_t res;
+ hrtimer_t hrtime;
+ FILE *fp;
+ char buf[512];
+ int wslength;
+
+ (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);
+
+ pcadmin.pc_cid = pcinfo.pc_cid;
+ pcadmin.pc_cladmin = (char *)&iaadmin;
+ iaadmin.ia_cmd = IA_GETDPSIZE;
+
+ if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1)
+ fatalerr("%s: Can't get ia_dptbl size, priocntl system "
+ "call failed with errno %d\n", basenm, errno);
+
+ niadpents = iaadmin.ia_ndpents;
+ if ((ia_dptbl =
+ (iadpent_t *)malloc(niadpents * sizeof (iadpent_t))) == NULL)
+ fatalerr("%s: Can't allocate memory for ia_dptbl\n", basenm);
+
+ if ((fp = fopen(infile, "r")) == NULL)
+ fatalerr("%s: Can't open %s for input\n", basenm, infile);
+
+ linenum = 0;
+
+ /*
+ * Find the first non-blank, non-comment line. A comment line
+ * is any line with '#' as the first non-white-space character.
+ */
+ do {
+ if (fgets(buf, sizeof (buf), fp) == NULL)
+ fatalerr("%s: Too few lines in input table\n", basenm);
+ linenum++;
+ } while (buf[0] == '#' || buf[0] == '\0' ||
+ (wslength = strspn(buf, " \t\n")) == strlen(buf) ||
+ strchr(buf, '#') == buf + wslength);
+
+ if ((tokp = strtok(buf, " \t")) == NULL)
+ fatalerr("%s: Bad RES specification, line %d of input file\n",
+ basenm, linenum);
+ if ((int)strlen(tokp) > 4) {
+ if (strncmp(tokp, "RES=", 4) != 0)
+ fatalerr("%s: Bad RES specification, \
+line %d of input file\n", basenm, linenum);
+ if (tokp[4] == '-')
+ fatalerr("%s: Bad RES specification, \
+line %d of input file\n", basenm, linenum);
+ res = strtoul(&tokp[4], (char **)NULL, 10);
+ } else if (strlen(tokp) == 4) {
+ if (strcmp(tokp, "RES=") != 0)
+ fatalerr("%s: Bad RES specification, \
+line %d of input file\n", basenm, linenum);
+ if ((tokp = strtok(NULL, " \t")) == NULL)
+ fatalerr("%s: Bad RES specification, \
+line %d of input file\n", basenm, linenum);
+ if (tokp[0] == '-')
+ fatalerr("%s: Bad RES specification, \
+line %d of input file\n", basenm, linenum);
+ res = strtoul(tokp, (char **)NULL, 10);
+ } else if (strlen(tokp) == 3) {
+ if (strcmp(tokp, "RES") != 0)
+ fatalerr("%s: Bad RES specification, \
+line %d of input file\n", basenm, linenum);
+ if ((tokp = strtok(NULL, " \t")) == NULL)
+ fatalerr("%s: Bad RES specification, \
+line %d of input file\n", basenm, linenum);
+ if ((int)strlen(tokp) > 1) {
+ if (strncmp(tokp, "=", 1) != 0)
+ fatalerr("%s: Bad RES specification, \
+line %d of input file\n", basenm, linenum);
+ if (tokp[1] == '-')
+ fatalerr("%s: Bad RES specification, \
+line %d of input file\n", basenm, linenum);
+ res = strtoul(&tokp[1], (char **)NULL, 10);
+ } else if (strlen(tokp) == 1) {
+ if ((tokp = strtok(NULL, " \t")) == NULL)
+ fatalerr("%s: Bad RES specification, \
+line %d of input file\n", basenm, linenum);
+ if (tokp[0] == '-')
+ fatalerr("%s: Bad RES specification, \
+line %d of input file\n", basenm, linenum);
+ res = strtoul(tokp, (char **)NULL, 10);
+ }
+ } else {
+ fatalerr("%s: Bad RES specification, line %d of input file\n",
+ basenm, linenum);
+ }
+
+ /*
+ * The remainder of the input file should contain exactly enough
+ * non-blank, non-comment lines to fill the table (ia_ndpents lines).
+ * We assume that any non-blank, non-comment line is data for the
+ * table and fail if we find more or less than we need.
+ */
+ for (i = 0; i < iaadmin.ia_ndpents; i++) {
+
+ /*
+ * Get the next non-blank, non-comment line.
+ */
+ do {
+ if (fgets(buf, sizeof (buf), fp) == NULL)
+ fatalerr("%s: Too few lines in input table\n",
+ basenm);
+ linenum++;
+ } while (buf[0] == '#' || buf[0] == '\0' ||
+ (wslength = strspn(buf, " \t\n")) == strlen(buf) ||
+ strchr(buf, '#') == buf + wslength);
+
+ if ((tokp = strtok(buf, " \t")) == NULL)
+ fatalerr("%s: Too few values, line %d of input file\n",
+ basenm, linenum);
+
+ if (res != HZ) {
+ hrtime.hrt_secs = 0;
+ hrtime.hrt_rem = atol(tokp);
+ hrtime.hrt_res = res;
+ if (_hrtnewres(&hrtime, HZ, HRT_RNDUP) == -1)
+ fatalerr("%s: Can't convert specified \
+resolution to ticks\n", basenm);
+ if ((ia_dptbl[i].ia_quantum = hrtconvert(&hrtime))
+ == -1)
+ fatalerr("%s: ia_quantum value out of "
+ "valid range; line %d of input,\n"
+ "table not overwritten\n",
+ basenm, linenum);
+ } else {
+ ia_dptbl[i].ia_quantum = atol(tokp);
+ }
+ if (ia_dptbl[i].ia_quantum <= 0)
+ fatalerr("%s: ia_quantum value out of valid range; "
+ "line %d of input,\ntable not overwritten\n",
+ basenm, linenum);
+
+ if ((tokp = strtok(NULL, " \t")) == NULL || tokp[0] == '#')
+ fatalerr("%s: Too few values, line %d of input file\n",
+ basenm, linenum);
+ ia_dptbl[i].ia_tqexp = (short)atoi(tokp);
+ if (ia_dptbl[i].ia_tqexp < 0 ||
+ ia_dptbl[i].ia_tqexp > iaadmin.ia_ndpents)
+ fatalerr("%s: ia_tqexp value out of valid range; "
+ "line %d of input,\ntable not overwritten\n",
+ basenm, linenum);
+
+ if ((tokp = strtok(NULL, " \t")) == NULL || tokp[0] == '#')
+ fatalerr("%s: Too few values, line %d of input file\n",
+ basenm, linenum);
+ ia_dptbl[i].ia_slpret = (short)atoi(tokp);
+ if (ia_dptbl[i].ia_slpret < 0 ||
+ ia_dptbl[i].ia_slpret > iaadmin.ia_ndpents)
+ fatalerr("%s: ia_slpret value out of valid range; "
+ "line %d of input,\ntable not overwritten\n",
+ basenm, linenum);
+
+ if ((tokp = strtok(NULL, " \t")) == NULL || tokp[0] == '#')
+ fatalerr("%s: Too few values, line %d of input file\n",
+ basenm, linenum);
+ ia_dptbl[i].ia_maxwait = (short)atoi(tokp);
+ if (ia_dptbl[i].ia_maxwait < 0)
+ fatalerr("%s: ia_maxwait value out of valid range; "
+ "line %d of input,\ntable not overwritten\n",
+ basenm, linenum);
+
+ if ((tokp = strtok(NULL, " \t")) == NULL || tokp[0] == '#')
+ fatalerr("%s: Too few values, line %d of input file\n",
+ basenm, linenum);
+ ia_dptbl[i].ia_lwait = (short)atoi(tokp);
+ if (ia_dptbl[i].ia_lwait < 0 ||
+ ia_dptbl[i].ia_lwait > iaadmin.ia_ndpents)
+ fatalerr("%s: ia_lwait value out of valid range; "
+ "line %d of input,\ntable not overwritten\n",
+ basenm, linenum);
+
+ if ((tokp = strtok(NULL, " \t")) != NULL && tokp[0] != '#')
+ fatalerr("%s: Too many values, line %d of input file\n",
+ basenm, linenum);
+ }
+
+ /*
+ * We've read enough lines to fill the table. We fail
+ * if the input file contains any more.
+ */
+ while (fgets(buf, sizeof (buf), fp) != NULL) {
+ if (buf[0] != '#' && buf[0] != '\0' &&
+ (wslength = strspn(buf, " \t\n")) != strlen(buf) &&
+ strchr(buf, '#') != buf + wslength)
+ fatalerr("%s: Too many lines in input table\n",
+ basenm);
+ }
+
+ iaadmin.ia_dpents = ia_dptbl;
+ iaadmin.ia_cmd = IA_SETDPTBL;
+ if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1)
+ fatalerr("%s: Can't set ia_dptbl, priocntl system call \
+failed with errno %d\n", basenm, errno);
+}
diff --git a/usr/src/cmd/dispadmin/rtdispadmin.c b/usr/src/cmd/dispadmin/rtdispadmin.c
new file mode 100644
index 0000000000..6f18bf1f39
--- /dev/null
+++ b/usr/src/cmd/dispadmin/rtdispadmin.c
@@ -0,0 +1,384 @@
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/priocntl.h>
+#include <sys/rtpriocntl.h>
+#include <sys/param.h>
+#include <sys/rt.h>
+
+#include "dispadmin.h"
+
+/*
+ * This file contains the class specific code implementing
+ * the real-time dispadmin sub-command.
+ */
+
+#define BASENMSZ 16
+
+extern char *basename();
+
+static void get_rtdptbl(), set_rtdptbl();
+
+static char usage[] = "usage: dispadmin -l\n"
+ "dispadmin -c RT -g [-r res]\n"
+ "dispadmin -c RT -s infile\n";
+
+static char basenm[BASENMSZ];
+static char cmdpath[256];
+
+
+int
+main(int argc, char **argv)
+{
+ extern char *optarg;
+
+ int c;
+ int lflag, gflag, rflag, sflag;
+ ulong_t res;
+ char *infile;
+
+ (void) strcpy(cmdpath, argv[0]);
+ (void) strcpy(basenm, basename(argv[0]));
+ lflag = gflag = rflag = sflag = 0;
+ while ((c = getopt(argc, argv, "lc:gr:s:")) != -1) {
+ switch (c) {
+
+ case 'l':
+ lflag++;
+ 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 'g':
+ gflag++;
+ break;
+
+ case 'r':
+ rflag++;
+ res = strtoul(optarg, (char **)NULL, 10);
+ break;
+
+ case 's':
+ sflag++;
+ infile = optarg;
+ break;
+
+ case '?':
+ fatalerr(usage);
+
+ default:
+ break;
+ }
+ }
+
+ if (lflag) {
+ if (gflag || rflag || sflag)
+ fatalerr(usage);
+
+ (void) printf("RT\t(Real Time)\n");
+ return (0);
+
+ } else if (gflag) {
+ if (lflag || sflag)
+ fatalerr(usage);
+
+ if (rflag == 0)
+ res = 1000;
+
+ get_rtdptbl(res);
+ return (0);
+
+ } else if (sflag) {
+ if (lflag || gflag || rflag)
+ fatalerr(usage);
+
+ set_rtdptbl(infile);
+ return (0);
+
+ } else {
+ fatalerr(usage);
+ }
+ return (1);
+}
+
+
+/*
+ * Retrieve the current rt_dptbl from memory, convert the time quantum
+ * values to the resolution specified by res and write the table to stdout.
+ */
+static void
+get_rtdptbl(ulong_t res)
+{
+ int i;
+ int rtdpsz;
+ pcinfo_t pcinfo;
+ pcadmin_t pcadmin;
+ rtadmin_t rtadmin;
+ rtdpent_t *rt_dptbl;
+ hrtimer_t hrtime;
+
+ (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);
+
+ pcadmin.pc_cid = pcinfo.pc_cid;
+ pcadmin.pc_cladmin = (char *)&rtadmin;
+ rtadmin.rt_cmd = RT_GETDPSIZE;
+
+ if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1)
+ fatalerr("%s: Can't get rt_dptbl size, priocntl system call "
+ "failed with errno %d\n", basenm, errno);
+
+ rtdpsz = rtadmin.rt_ndpents * sizeof (rtdpent_t);
+ if ((rt_dptbl = (rtdpent_t *)malloc(rtdpsz)) == NULL)
+ fatalerr("%s: Can't allocate memory for rt_dptbl\n", basenm);
+
+ rtadmin.rt_dpents = rt_dptbl;
+
+ rtadmin.rt_cmd = RT_GETDPTBL;
+ if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1)
+ fatalerr("%s: Can't get rt_dptbl, priocntl system call "
+ "failed with errno %d\n", basenm, errno);
+
+ (void) printf("# Real Time Dispatcher Configuration\n");
+ (void) printf("RES=%ld\n\n", res);
+ (void) printf("# TIME QUANTUM PRIORITY\n");
+ (void) printf("# (rt_quantum) LEVEL\n");
+
+ for (i = 0; i < rtadmin.rt_ndpents; i++) {
+ if (res != HZ && rt_dptbl[i].rt_quantum != RT_TQINF) {
+ hrtime.hrt_secs = 0;
+ hrtime.hrt_rem = rt_dptbl[i].rt_quantum;
+ hrtime.hrt_res = HZ;
+ if (_hrtnewres(&hrtime, res, HRT_RNDUP) == -1)
+ fatalerr("%s: Can't convert to requested "
+ "resolution\n", basenm);
+ if ((rt_dptbl[i].rt_quantum =
+ hrtconvert(&hrtime)) == -1)
+ fatalerr("%s: Can't express time quantum in "
+ "requested resolution,\n"
+ "try coarser resolution\n", basenm);
+ }
+ (void) printf("%10d # %3d\n",
+ rt_dptbl[i].rt_quantum, i);
+ }
+}
+
+
+/*
+ * Read the rt_dptbl values from infile, convert the time quantum values
+ * to HZ resolution, do a little sanity checking and overwrite the table
+ * in memory with the values from the file.
+ */
+static void
+set_rtdptbl(infile)
+char *infile;
+{
+ int i;
+ int nrtdpents;
+ char *tokp;
+ pcinfo_t pcinfo;
+ pcadmin_t pcadmin;
+ rtadmin_t rtadmin;
+ rtdpent_t *rt_dptbl;
+ int linenum;
+ ulong_t res;
+ hrtimer_t hrtime;
+ FILE *fp;
+ char buf[512];
+ int wslength;
+
+ (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);
+
+ pcadmin.pc_cid = pcinfo.pc_cid;
+ pcadmin.pc_cladmin = (char *)&rtadmin;
+ rtadmin.rt_cmd = RT_GETDPSIZE;
+
+ if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1)
+ fatalerr("%s: Can't get rt_dptbl size, priocntl system call "
+ "failed with errno %d\n", basenm, errno);
+
+ nrtdpents = rtadmin.rt_ndpents;
+ if ((rt_dptbl =
+ (rtdpent_t *)malloc(nrtdpents * sizeof (rtdpent_t))) == NULL)
+ fatalerr("%s: Can't allocate memory for rt_dptbl\n", basenm);
+
+ if ((fp = fopen(infile, "r")) == NULL)
+ fatalerr("%s: Can't open %s for input\n", basenm, infile);
+
+ linenum = 0;
+
+ /*
+ * Find the first non-blank, non-comment line. A comment line
+ * is any line with '#' as the first non-white-space character.
+ */
+ do {
+ if (fgets(buf, sizeof (buf), fp) == NULL)
+ fatalerr("%s: Too few lines in input table\n", basenm);
+ linenum++;
+ } while (buf[0] == '#' || buf[0] == '\0' ||
+ (wslength = strspn(buf, " \t\n")) == strlen(buf) ||
+ strchr(buf, '#') == buf + wslength);
+
+ if ((tokp = strtok(buf, " \t")) == NULL)
+ fatalerr("%s: Bad RES specification, line %d of input file\n",
+ basenm, linenum);
+ if ((int)strlen(tokp) > 4) {
+ if (strncmp(tokp, "RES=", 4) != 0)
+ fatalerr("%s: Bad RES specification, "
+ "line %d of input file\n", basenm, linenum);
+ if (tokp[4] == '-')
+ fatalerr("%s: Bad RES specification, "
+ "line %d of input file\n", basenm, linenum);
+ res = strtoul(&tokp[4], (char **)NULL, 10);
+ } else if (strlen(tokp) == 4) {
+ if (strcmp(tokp, "RES=") != 0)
+ fatalerr("%s: Bad RES specification, "
+ "line %d of input file\n", basenm, linenum);
+ if ((tokp = strtok(NULL, " \t")) == NULL)
+ fatalerr("%s: Bad RES specification, "
+ "line %d of input file\n", basenm, linenum);
+ if (tokp[0] == '-')
+ fatalerr("%s: Bad RES specification, "
+ "line %d of input file\n", basenm, linenum);
+ res = strtoul(tokp, (char **)NULL, 10);
+ } else if (strlen(tokp) == 3) {
+ if (strcmp(tokp, "RES") != 0)
+ fatalerr("%s: Bad RES specification, "
+ "line %d of input file\n", basenm, linenum);
+ if ((tokp = strtok(NULL, " \t")) == NULL)
+ fatalerr("%s: Bad RES specification, "
+ "line %d of input file\n", basenm, linenum);
+ if ((int)strlen(tokp) > 1) {
+ if (strncmp(tokp, "=", 1) != 0)
+ fatalerr("%s: Bad RES specification, "
+ "line %d of input file\n", basenm, linenum);
+ if (tokp[1] == '-')
+ fatalerr("%s: Bad RES specification, "
+ "line %d of input file\n", basenm, linenum);
+ res = strtoul(&tokp[1], (char **)NULL, 10);
+ } else if (strlen(tokp) == 1) {
+ if ((tokp = strtok(NULL, " \t")) == NULL)
+ fatalerr("%s: Bad RES specification, "
+ "line %d of input file\n", basenm, linenum);
+ if (tokp[0] == '-')
+ fatalerr("%s: Bad RES specification, "
+ "line %d of input file\n", basenm, linenum);
+ res = strtoul(tokp, (char **)NULL, 10);
+ }
+ } else {
+ fatalerr("%s: Bad RES specification, line %d of input file\n",
+ basenm, linenum);
+ }
+
+ /*
+ * The remainder of the input file should contain exactly enough
+ * non-blank, non-comment lines to fill the table (rt_ndpents lines).
+ * We assume that any non-blank, non-comment line is data for the
+ * table and fail if we find more or less than we need.
+ */
+ for (i = 0; i < rtadmin.rt_ndpents; i++) {
+
+ /*
+ * Get the next non-blank, non-comment line.
+ */
+ do {
+ if (fgets(buf, sizeof (buf), fp) == NULL)
+ fatalerr("%s: Too few lines in input table\n",
+ basenm);
+ linenum++;
+ } while (buf[0] == '#' || buf[0] == '\0' ||
+ (wslength = strspn(buf, " \t\n")) == strlen(buf) ||
+ strchr(buf, '#') == buf + wslength);
+
+ if ((tokp = strtok(buf, " \t")) == NULL)
+ fatalerr("%s: Too few values, line %d of input file\n",
+ basenm, linenum);
+
+ rt_dptbl[i].rt_quantum = atol(tokp);
+ if (rt_dptbl[i].rt_quantum <= 0) {
+ if (rt_dptbl[i].rt_quantum != RT_TQINF)
+ fatalerr("%s: rt_quantum value out of "
+ "valid range; line %d of input,\n"
+ "table not overwritten\n", basenm, linenum);
+ } else if (res != HZ) {
+ hrtime.hrt_secs = 0;
+ hrtime.hrt_rem = rt_dptbl[i].rt_quantum;
+ hrtime.hrt_res = res;
+ if (_hrtnewres(&hrtime, HZ, HRT_RNDUP) == -1)
+ fatalerr("%s: Can't convert specified "
+ "resolution to ticks\n", basenm);
+ if ((rt_dptbl[i].rt_quantum =
+ hrtconvert(&hrtime)) == -1)
+ fatalerr("%s: rt_quantum value out of "
+ "valid range; line %d of input,\n"
+ "table not overwritten\n", basenm, linenum);
+ }
+
+ if ((tokp = strtok(NULL, " \t")) != NULL && tokp[0] != '#')
+ fatalerr("%s: Too many values, line %d of input file\n",
+ basenm, linenum);
+ }
+
+ /*
+ * We've read enough lines to fill the table. We fail
+ * if the input file contains any more.
+ */
+ while (fgets(buf, sizeof (buf), fp) != NULL) {
+ if (buf[0] != '#' && buf[0] != '\0' &&
+ (wslength = strspn(buf, " \t\n")) != strlen(buf) &&
+ strchr(buf, '#') != buf + wslength)
+ fatalerr("%s: Too many lines in input table\n",
+ basenm);
+ }
+
+ rtadmin.rt_dpents = rt_dptbl;
+ rtadmin.rt_cmd = RT_SETDPTBL;
+ if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1)
+ fatalerr("%s: Can't set rt_dptbl, priocntl system call failed "
+ "with errno %d\n", basenm, errno);
+}
diff --git a/usr/src/cmd/dispadmin/subr.c b/usr/src/cmd/dispadmin/subr.c
new file mode 100644
index 0000000000..b2c5c10b4a
--- /dev/null
+++ b/usr/src/cmd/dispadmin/subr.c
@@ -0,0 +1,255 @@
+/*
+ * 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 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <limits.h>
+
+#include "dispadmin.h"
+
+
+/*
+ * Utility functions for dispadmin command.
+ */
+
+
+void
+fatalerr(const char *format, ...)
+{
+ va_list ap;
+
+ (void) va_start(ap, format);
+ (void) vfprintf(stderr, format, ap);
+ va_end(ap);
+ exit(1);
+}
+
+
+/*
+ * hrtconvert() returns the interval specified by htp as a single
+ * value in resolution htp->hrt_res. Returns -1 on overflow.
+ */
+long
+hrtconvert(hrtimer_t *htp)
+{
+ long sum;
+ long product;
+
+ product = htp->hrt_secs * htp->hrt_res;
+
+ if (product / htp->hrt_res == htp->hrt_secs) {
+ sum = product + htp->hrt_rem;
+ if (sum - htp->hrt_rem == product) {
+ return (sum);
+ }
+ }
+ return (-1);
+}
+
+/*
+ * The following routine was removed from libc (libc/port/gen/hrtnewres.c).
+ * It has also been added to priocntl, 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(hrtimer_t *htp, ulong_t new_res, long round)
+{
+ long interval;
+ longlong_t dint;
+ longlong_t dto_res;
+ longlong_t drem;
+ longlong_t dfrom_res;
+ longlong_t prod;
+ longlong_t quot;
+ long numerator;
+ long result;
+ ulong_t modulus;
+ ulong_t twomodulus;
+ long temp;
+
+ if (htp->hrt_res == 0 || new_res == 0 ||
+ 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/dispadmin/tsdispadmin.c b/usr/src/cmd/dispadmin/tsdispadmin.c
new file mode 100644
index 0000000000..83bb6dd2c3
--- /dev/null
+++ b/usr/src/cmd/dispadmin/tsdispadmin.c
@@ -0,0 +1,426 @@
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/priocntl.h>
+#include <sys/tspriocntl.h>
+#include <sys/param.h>
+#include <sys/ts.h>
+
+#include "dispadmin.h"
+
+/*
+ * This file contains the class specific code implementing
+ * the time-sharing dispadmin sub-command.
+ */
+
+#define BASENMSZ 16
+
+extern char *basename();
+
+static void get_tsdptbl(), set_tsdptbl();
+
+static char usage[] =
+"usage: dispadmin -l\n\
+ dispadmin -c TS -g [-r res]\n\
+ dispadmin -c TS -s infile\n";
+
+static char basenm[BASENMSZ];
+static char cmdpath[256];
+
+
+int
+main(int argc, char **argv)
+{
+ extern char *optarg;
+
+ int c;
+ int lflag, gflag, rflag, sflag;
+ ulong_t res;
+ char *infile;
+
+ (void) strcpy(cmdpath, argv[0]);
+ (void) strcpy(basenm, basename(argv[0]));
+ lflag = gflag = rflag = sflag = 0;
+ while ((c = getopt(argc, argv, "lc:gr:s:")) != -1) {
+ switch (c) {
+
+ case 'l':
+ lflag++;
+ 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 'g':
+ gflag++;
+ break;
+
+ case 'r':
+ rflag++;
+ res = strtoul(optarg, (char **)NULL, 10);
+ break;
+
+ case 's':
+ sflag++;
+ infile = optarg;
+ break;
+
+ case '?':
+ fatalerr(usage);
+
+ default:
+ break;
+ }
+ }
+
+ if (lflag) {
+ if (gflag || rflag || sflag)
+ fatalerr(usage);
+
+ (void) printf("TS\t(Time Sharing)\n");
+ return (0);
+
+ } else if (gflag) {
+ if (lflag || sflag)
+ fatalerr(usage);
+
+ if (rflag == 0)
+ res = 1000;
+
+ get_tsdptbl(res);
+ return (0);
+
+ } else if (sflag) {
+ if (lflag || gflag || rflag)
+ fatalerr(usage);
+
+ set_tsdptbl(infile);
+ return (0);
+
+ } else {
+ fatalerr(usage);
+ }
+ return (1);
+}
+
+
+/*
+ * Retrieve the current ts_dptbl from memory, convert the time quantum
+ * values to the resolution specified by res and write the table to stdout.
+ */
+static void
+get_tsdptbl(ulong_t res)
+{
+ int i;
+ int tsdpsz;
+ pcinfo_t pcinfo;
+ pcadmin_t pcadmin;
+ tsadmin_t tsadmin;
+ tsdpent_t *ts_dptbl;
+ hrtimer_t hrtime;
+
+ (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);
+
+ pcadmin.pc_cid = pcinfo.pc_cid;
+ pcadmin.pc_cladmin = (char *)&tsadmin;
+ tsadmin.ts_cmd = TS_GETDPSIZE;
+
+ if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1)
+ fatalerr("%s: Can't get ts_dptbl size, priocntl system \
+call failed with errno %d\n", basenm, errno);
+
+ tsdpsz = tsadmin.ts_ndpents * sizeof (tsdpent_t);
+ if ((ts_dptbl = (tsdpent_t *)malloc(tsdpsz)) == NULL)
+ fatalerr("%s: Can't allocate memory for ts_dptbl\n", basenm);
+
+ tsadmin.ts_dpents = ts_dptbl;
+
+ tsadmin.ts_cmd = TS_GETDPTBL;
+ if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1)
+ fatalerr("%s: Can't get ts_dptbl, priocntl system call \
+call failed with errno %d\n", basenm, errno);
+
+ (void) printf("# Time Sharing Dispatcher Configuration\n");
+ (void) printf("RES=%ld\n\n", res);
+ (void) printf("# ts_quantum ts_tqexp ts_slpret ts_maxwait ts_lwait \
+PRIORITY LEVEL\n");
+
+ for (i = 0; i < tsadmin.ts_ndpents; i++) {
+ if (res != HZ) {
+ hrtime.hrt_secs = 0;
+ hrtime.hrt_rem = ts_dptbl[i].ts_quantum;
+ hrtime.hrt_res = HZ;
+ if (_hrtnewres(&hrtime, res, HRT_RNDUP) == -1)
+ fatalerr("%s: Can't convert to requested \
+resolution\n", basenm);
+ if ((ts_dptbl[i].ts_quantum = hrtconvert(&hrtime))
+ == -1)
+ fatalerr("%s: Can't express time quantum in "
+ "requested resolution,\n"
+ "try coarser resolution\n", basenm);
+ }
+ (void) printf("%10d%10d%10d%12d%10d # %3d\n",
+ ts_dptbl[i].ts_quantum, ts_dptbl[i].ts_tqexp,
+ ts_dptbl[i].ts_slpret, ts_dptbl[i].ts_maxwait,
+ ts_dptbl[i].ts_lwait, i);
+ }
+}
+
+
+/*
+ * Read the ts_dptbl values from infile, convert the time quantum values
+ * to HZ resolution, do a little sanity checking and overwrite the table
+ * in memory with the values from the file.
+ */
+static void
+set_tsdptbl(infile)
+char *infile;
+{
+ int i;
+ int ntsdpents;
+ char *tokp;
+ pcinfo_t pcinfo;
+ pcadmin_t pcadmin;
+ tsadmin_t tsadmin;
+ tsdpent_t *ts_dptbl;
+ int linenum;
+ ulong_t res;
+ hrtimer_t hrtime;
+ FILE *fp;
+ char buf[512];
+ int wslength;
+
+ (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);
+
+ pcadmin.pc_cid = pcinfo.pc_cid;
+ pcadmin.pc_cladmin = (char *)&tsadmin;
+ tsadmin.ts_cmd = TS_GETDPSIZE;
+
+ if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1)
+ fatalerr("%s: Can't get ts_dptbl size, priocntl system \
+call failed with errno %d\n", basenm, errno);
+
+ ntsdpents = tsadmin.ts_ndpents;
+ if ((ts_dptbl =
+ (tsdpent_t *)malloc(ntsdpents * sizeof (tsdpent_t))) == NULL)
+ fatalerr("%s: Can't allocate memory for ts_dptbl\n", basenm);
+
+ if ((fp = fopen(infile, "r")) == NULL)
+ fatalerr("%s: Can't open %s for input\n", basenm, infile);
+
+ linenum = 0;
+
+ /*
+ * Find the first non-blank, non-comment line. A comment line
+ * is any line with '#' as the first non-white-space character.
+ */
+ do {
+ if (fgets(buf, sizeof (buf), fp) == NULL)
+ fatalerr("%s: Too few lines in input table\n", basenm);
+ linenum++;
+ } while (buf[0] == '#' || buf[0] == '\0' ||
+ (wslength = strspn(buf, " \t\n")) == strlen(buf) ||
+ strchr(buf, '#') == buf + wslength);
+
+ if ((tokp = strtok(buf, " \t")) == NULL)
+ fatalerr("%s: Bad RES specification, line %d of input file\n",
+ basenm, linenum);
+ if ((int)strlen(tokp) > 4) {
+ if (strncmp(tokp, "RES=", 4) != 0)
+ fatalerr("%s: Bad RES specification, \
+line %d of input file\n", basenm, linenum);
+ if (tokp[4] == '-')
+ fatalerr("%s: Bad RES specification, \
+line %d of input file\n", basenm, linenum);
+ res = strtoul(&tokp[4], (char **)NULL, 10);
+ } else if (strlen(tokp) == 4) {
+ if (strcmp(tokp, "RES=") != 0)
+ fatalerr("%s: Bad RES specification, \
+line %d of input file\n", basenm, linenum);
+ if ((tokp = strtok(NULL, " \t")) == NULL)
+ fatalerr("%s: Bad RES specification, \
+line %d of input file\n", basenm, linenum);
+ if (tokp[0] == '-')
+ fatalerr("%s: Bad RES specification, \
+line %d of input file\n", basenm, linenum);
+ res = strtoul(tokp, (char **)NULL, 10);
+ } else if (strlen(tokp) == 3) {
+ if (strcmp(tokp, "RES") != 0)
+ fatalerr("%s: Bad RES specification, \
+line %d of input file\n", basenm, linenum);
+ if ((tokp = strtok(NULL, " \t")) == NULL)
+ fatalerr("%s: Bad RES specification, \
+line %d of input file\n", basenm, linenum);
+ if ((int)strlen(tokp) > 1) {
+ if (strncmp(tokp, "=", 1) != 0)
+ fatalerr("%s: Bad RES specification, \
+line %d of input file\n", basenm, linenum);
+ if (tokp[1] == '-')
+ fatalerr("%s: Bad RES specification, \
+line %d of input file\n", basenm, linenum);
+ res = strtoul(&tokp[1], (char **)NULL, 10);
+ } else if (strlen(tokp) == 1) {
+ if ((tokp = strtok(NULL, " \t")) == NULL)
+ fatalerr("%s: Bad RES specification, \
+line %d of input file\n", basenm, linenum);
+ if (tokp[0] == '-')
+ fatalerr("%s: Bad RES specification, \
+line %d of input file\n", basenm, linenum);
+ res = strtoul(tokp, (char **)NULL, 10);
+ }
+ } else {
+ fatalerr("%s: Bad RES specification, line %d of input file\n",
+ basenm, linenum);
+ }
+
+ /*
+ * The remainder of the input file should contain exactly enough
+ * non-blank, non-comment lines to fill the table (ts_ndpents lines).
+ * We assume that any non-blank, non-comment line is data for the
+ * table and fail if we find more or less than we need.
+ */
+ for (i = 0; i < tsadmin.ts_ndpents; i++) {
+
+ /*
+ * Get the next non-blank, non-comment line.
+ */
+ do {
+ if (fgets(buf, sizeof (buf), fp) == NULL)
+ fatalerr("%s: Too few lines in input table\n",
+ basenm);
+ linenum++;
+ } while (buf[0] == '#' || buf[0] == '\0' ||
+ (wslength = strspn(buf, " \t\n")) == strlen(buf) ||
+ strchr(buf, '#') == buf + wslength);
+
+ if ((tokp = strtok(buf, " \t")) == NULL)
+ fatalerr("%s: Too few values, line %d of input file\n",
+ basenm, linenum);
+
+ if (res != HZ) {
+ hrtime.hrt_secs = 0;
+ hrtime.hrt_rem = atol(tokp);
+ hrtime.hrt_res = res;
+ if (_hrtnewres(&hrtime, HZ, HRT_RNDUP) == -1)
+ fatalerr("%s: Can't convert specified "
+ "resolution to ticks\n", basenm);
+ if ((ts_dptbl[i].ts_quantum = hrtconvert(&hrtime))
+ == -1)
+ fatalerr("%s: ts_quantum value out of "
+ "valid range; line %d of input,\n"
+ "table not overwritten\n",
+ basenm, linenum);
+ } else {
+ ts_dptbl[i].ts_quantum = atol(tokp);
+ }
+ if (ts_dptbl[i].ts_quantum <= 0)
+ fatalerr("%s: ts_quantum value out of valid range; "
+ "line %d of input,\ntable not overwritten\n",
+ basenm, linenum);
+
+ if ((tokp = strtok(NULL, " \t")) == NULL || tokp[0] == '#')
+ fatalerr("%s: Too few values, line %d of input file\n",
+ basenm, linenum);
+ ts_dptbl[i].ts_tqexp = (short)atoi(tokp);
+ if (ts_dptbl[i].ts_tqexp < 0 ||
+ ts_dptbl[i].ts_tqexp > tsadmin.ts_ndpents)
+ fatalerr("%s: ts_tqexp value out of valid range; "
+ "line %d of input,\ntable not overwritten\n",
+ basenm, linenum);
+
+ if ((tokp = strtok(NULL, " \t")) == NULL || tokp[0] == '#')
+ fatalerr("%s: Too few values, line %d of input file\n",
+ basenm, linenum);
+ ts_dptbl[i].ts_slpret = (short)atoi(tokp);
+ if (ts_dptbl[i].ts_slpret < 0 ||
+ ts_dptbl[i].ts_slpret > tsadmin.ts_ndpents)
+ fatalerr("%s: ts_slpret value out of valid range; "
+ "line %d of input,\ntable not overwritten\n",
+ basenm, linenum);
+
+ if ((tokp = strtok(NULL, " \t")) == NULL || tokp[0] == '#')
+ fatalerr("%s: Too few values, line %d of input file\n",
+ basenm, linenum);
+ ts_dptbl[i].ts_maxwait = (short)atoi(tokp);
+ if (ts_dptbl[i].ts_maxwait < 0)
+ fatalerr("%s: ts_maxwait value out of valid range; "
+ "line %d of input,\ntable not overwritten\n",
+ basenm, linenum);
+
+ if ((tokp = strtok(NULL, " \t")) == NULL || tokp[0] == '#')
+ fatalerr("%s: Too few values, line %d of input file\n",
+ basenm, linenum);
+ ts_dptbl[i].ts_lwait = (short)atoi(tokp);
+ if (ts_dptbl[i].ts_lwait < 0 ||
+ ts_dptbl[i].ts_lwait > tsadmin.ts_ndpents)
+ fatalerr("%s: ts_lwait value out of valid range; "
+ "line %d of input,\ntable not overwritten\n",
+ basenm, linenum);
+
+ if ((tokp = strtok(NULL, " \t")) != NULL && tokp[0] != '#')
+ fatalerr("%s: Too many values, line %d of input file\n",
+ basenm, linenum);
+ }
+
+ /*
+ * We've read enough lines to fill the table. We fail
+ * if the input file contains any more.
+ */
+ while (fgets(buf, sizeof (buf), fp) != NULL) {
+ if (buf[0] != '#' && buf[0] != '\0' &&
+ (wslength = strspn(buf, " \t\n")) != strlen(buf) &&
+ strchr(buf, '#') != buf + wslength)
+ fatalerr("%s: Too many lines in input table\n",
+ basenm);
+ }
+
+ tsadmin.ts_dpents = ts_dptbl;
+ tsadmin.ts_cmd = TS_SETDPTBL;
+ if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1)
+ fatalerr("%s: Can't set ts_dptbl, priocntl system call \
+failed with errno %d\n", basenm, errno);
+}