# # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # cmd/dispadmin/Makefile # PROG= dispadmin MANIFEST= scheduler.xml SVCMETHOD= svc-scheduler SDC= SDC$(PROG) RT= RT$(PROG) TS= TS$(PROG) IA= IA$(PROG) FSS= FSS$(PROG) FX= FX$(PROG) PROGS= $(PROG) $(RT) $(TS) $(IA) $(FSS) $(FX) $(SDC) include ../Makefile.cmd CFLAGS += $(CCVERBOSE) CERRWARN += $(CNOWARN_UNINIT) ROOTDIR= $(ROOT)/usr/lib/class ROOTDIRS= $(ROOTDIR) \ $(ROOTDIR)/FSS \ $(ROOTDIR)/FX \ $(ROOTDIR)/IA \ $(ROOTDIR)/RT \ $(ROOTDIR)/SDC \ $(ROOTDIR)/TS ROOTPROG= $(PROG:%=$(ROOTUSRSBIN)/%) ROOTFSS= $(FSS:%=$(ROOTDIR)/FSS/%) ROOTFX= $(FX:%=$(ROOTDIR)/FX/%) ROOTIA= $(IA:%=$(ROOTDIR)/IA/%) ROOTRT= $(RT:%=$(ROOTDIR)/RT/%) ROOTSDC= $(SDC:%=$(ROOTDIR)/SDC/%) ROOTTS= $(TS:%=$(ROOTDIR)/TS/%) ROOTMANIFESTDIR= $(ROOTSVCSYSTEM) # 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 sdc$(PROG).o subr.o # conditional assignments, because of above names $(PROG): OBJ= $(PROG).o $(FSS): OBJ= fss$(PROG).o $(FX): OBJ= fx$(PROG).o $(IA): OBJ= ia$(PROG).o $(RT): OBJ= rt$(PROG).o $(SDC): OBJ= sdc$(PROG).o $(TS): OBJ= ts$(PROG).o # install rules $(ROOTDIR)/% \ $(ROOTDIR)/FSS/% \ $(ROOTDIR)/FX/% \ $(ROOTDIR)/IA/% \ $(ROOTDIR)/RT/% \ $(ROOTDIR)/SDC/% \ $(ROOTDIR)/TS/% : % $(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) \ $(ROOTSDC) $(ROOTMANIFEST) $(ROOTSVCMETHOD) # Don't re-install directories already installed by Targetdirs #$(ROOTDIRS): # $(INS.dir) check: $(CHKMANIFEST) clean: $(RM) $(OBJECTS) $(PROGS) llib-lsubr.ln lint: llib-lsubr.ln $(LINT.c) dispadmin.c $(LDLIBS) $(LINT.c) fssdispadmin.c $(LDLIBS) $(LINT.c) fxdispadmin.c $(LDLIBS) $(LINT.c) iadispadmin.c $(LDLIBS) $(LINT.c) rtdispadmin.c $(LDLIBS) $(LINT.c) sdcdispadmin.c $(LDLIBS) $(LINT.c) tsdispadmin.c $(LDLIBS) include ../Makefile.targ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #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"; 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(8) 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)); } } /* * 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 */ /* * The following is an excerpt from . 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); /* * 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 */ #include #include #include #include #include #include #include #include #include #include #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)); } /* * 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 */ #include #include #include #include #include #include #include #include #include #include #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); } /* * 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 */ #include #include #include #include #include #include #include #include #include #include #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); } /* * 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 */ #include #include #include #include #include #include #include #include #include #include #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); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include "dispadmin.h" static char usage[] = "usage: dispadmin -l\n"; int main(int argc, char *argv[]) { int lflag = 0; int c; while ((c = getopt(argc, argv, "lc:")) != -1) { switch (c) { case 'l': lflag++; break; case 'c': if (strcmp(optarg, "SDC") != 0) fatalerr("error: %s executed for %s class, " "%s is actually sub-command for %s class\n", argv[0], optarg, argv[0], "SDC"); fatalerr("error: no scheduling-class specific options" " for SDC\n"); break; case '?': fatalerr(usage); default: break; } } if (!lflag) fatalerr(usage); (void) printf("SDC\t(System Duty-Cycle Class)\n"); return (0); } /* * 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. */ #include #include #include #include #include #include #include #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); } } #!/sbin/sh # # 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 2005 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" # # Set default scheduling class # . /lib/svc/share/smf_include.sh [ -f /etc/dispadmin.conf ] || exit $SMF_EXIT_OK if [ -x /usr/sbin/dispadmin ] && [ -x /usr/bin/priocntl ]; then ERROR="$0: cannot set default scheduling class to " DISPADMIN_D=`/usr/sbin/dispadmin -d` if [ $? -eq 0 ]; then # # Inform the kernel about the default scheduling class. # /usr/sbin/dispadmin -u DEFAULT_SCHEDULER=`echo $DISPADMIN_D | /usr/bin/cut -f1 -d' '` /usr/bin/priocntl -s -c $DEFAULT_SCHEDULER -i all if [ $? -ne 0 ]; then echo $ERROR $DEFAULT_SCHEDULER exit $SMF_EXIT_ERR_FATAL else # # Also need to move init process explicitly # because it was ignored by "-i all". # /usr/bin/priocntl -s -c $DEFAULT_SCHEDULER -i pid 1 if [ $? -ne 0 ]; then echo $ERROR $DEFAULT_SCHEDULER exit $SMF_EXIT_ERR_FATAL fi fi else # # Default scheduling class from dispadmin.conf is # invalid or not available. # exit $SMF_EXIT_ERR_CONFIG fi else # dispadmin or priocntl commands can't be executed echo "$0: cannot execute command" exit $SMF_EXIT_ERR_FATAL fi exit $SMF_EXIT_OK /* * 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 */ #include #include #include #include #include #include #include #include #include #include #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); }