dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / dispadmin / dispadmin.c
blob7de9e04c2063792d330852c9162989bf66cf9763
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
23 /* All Rights Reserved */
26 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
27 * Use is subject to license terms.
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <fcntl.h>
35 #include <errno.h>
36 #include <string.h>
37 #include <limits.h>
38 #include <wait.h>
39 #include <zone.h>
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <sys/priocntl.h>
44 #include "dispadmin.h"
47 * This file contains the code implementing the class independent part
48 * of the dispadmin command. Most of the functionality of the dispadmin
49 * command is provided by the class specific sub-commands, the code for
50 * which is elsewhere. The class independent part of the command is
51 * responsible for switching out to the appropriate class specific
52 * sub-command based on the user supplied class argument.
53 * Code in this file should never assume any knowledge of any specific
54 * scheduler class (other than the SYS class).
57 #define BASENMSZ 16
58 #define BUFSZ (PATH_MAX + 80)
59 #define CLASSPATH "/usr/lib/class"
60 #define CONFIGPATH "/etc/dispadmin.conf"
61 #define CONFIGOWNER 0 /* uid 0 (root) */
62 #define CONFIGGROUP 1 /* gid 1 (other) */
63 #define CONFIGPERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) /* 0644 */
64 #define TOKENNAME "DEFAULT_SCHEDULER"
66 extern char *basename();
68 static char usage[] =
69 "usage: dispadmin -l\n\
70 dispadmin -c class [class-specific options]\n\
71 dispadmin -d [class]\n";
73 static char basenm[BASENMSZ];
74 static char cmdpath[PATH_MAX];
76 static void print_classlist();
77 static void exec_cscmd(char *, char **);
78 static void set_scheduler(char *);
79 static void class_info(pcinfo_t *);
80 static void set_default_class();
82 int
83 main(int argc, char **argv)
85 extern char *optarg;
86 extern int optind, opterr;
88 int c;
89 int uflag, cflag, dflag, lflag, csoptsflag;
90 char *clname;
92 (void) strncpy(cmdpath, argv[0], PATH_MAX);
93 (void) strncpy(basenm, basename(argv[0]), BASENMSZ);
94 cflag = dflag = lflag = uflag = csoptsflag = 0;
95 opterr = 0;
96 while ((c = getopt(argc, argv, "c:dlu")) != -1) {
97 switch (c) {
99 case 'c':
100 cflag++;
101 clname = optarg;
102 break;
104 case 'd':
105 dflag++;
106 clname = argv[optind];
107 break;
109 case 'l':
110 lflag++;
111 break;
113 case 'u':
114 uflag++;
115 break;
118 case '?':
120 * We assume for now that any option that
121 * getopt() doesn't recognize is intended for a
122 * class specific subcommand.
124 csoptsflag++;
125 if (argv[optind] && argv[optind][0] != '-') {
129 * Class specific option takes an
130 * argument which we skip over for now.
132 optind++;
134 break;
136 default:
137 break;
141 if (lflag) {
142 if (uflag || cflag || dflag || csoptsflag)
143 fatalerr(usage);
145 print_classlist();
146 exit(0);
148 } else if (uflag) {
149 if (lflag || dflag || csoptsflag)
150 fatalerr(usage);
152 set_default_class();
153 } else if (cflag) {
154 if (lflag || dflag)
155 fatalerr(usage);
157 exec_cscmd(clname, argv);
159 } else if (dflag) {
160 if (cflag || lflag || csoptsflag)
161 fatalerr(usage);
162 set_scheduler(clname);
163 exit(0);
165 } else {
166 fatalerr(usage);
168 return (1);
173 * Print the heading for the class list and execute the
174 * class specific sub-command with the -l option for each
175 * configured class.
177 static void
178 print_classlist()
180 id_t cid;
181 int nclass;
182 pcinfo_t pcinfo;
184 if ((nclass = priocntl(0, 0, PC_GETCLINFO, NULL)) == -1)
185 fatalerr("%s: Can't get number of configured classes\n",
186 cmdpath);
188 (void) printf("CONFIGURED CLASSES\n==================\n\n");
189 (void) printf("SYS\t(System Class)\n");
190 (void) fflush(stdout);
191 for (cid = 1; cid < nclass; cid++) {
192 pcinfo.pc_cid = cid;
193 if (priocntl(0, 0, PC_GETCLINFO, (caddr_t)&pcinfo) == -1)
194 fatalerr("%s: Can't get class name (class ID = %d)\n",
195 cmdpath, cid);
196 class_info(&pcinfo);
202 * Execute the appropriate class specific sub-command for the class
203 * specified by clname, passing it the arguments in subcmdargv.
205 static void
206 exec_cscmd(char *clname, char **subcmdargv)
208 pcinfo_t pcinfo;
209 char subcmdpath[PATH_MAX];
212 * Do a quick check to make sure clname is valid.
213 * We could just wait and see if the exec below
214 * succeeds but we wouldn't know much about the reason.
215 * This way we can give the user a more meaningful error
216 * message.
218 (void) strncpy(pcinfo.pc_clname, clname, PC_CLNMSZ);
219 if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1)
220 fatalerr("%s: Invalid or unconfigured class %s\n", cmdpath,
221 clname);
223 (void) snprintf(subcmdpath, PATH_MAX, "%s/%s/%s%s", CLASSPATH,
224 clname, clname, basenm);
225 subcmdargv[0] = subcmdpath;
227 (void) execv(subcmdpath, subcmdargv);
228 fatalerr("%s: Can't execute %s sub-command\n", cmdpath, clname);
231 static void
232 class_info(pcinfo_t *pcinfo)
234 int pid;
235 char subcmdpath[PATH_MAX];
237 (void) snprintf(subcmdpath, PATH_MAX, "%s/%s/%s%s", CLASSPATH,
238 pcinfo->pc_clname, pcinfo->pc_clname, basenm);
239 if ((pid = fork()) == 0) {
240 (void) execl(subcmdpath, subcmdpath, "-l", (char *)0);
241 fatalerr("%s\n\tCan't execute %s specific subcommand\n",
242 pcinfo->pc_clname, pcinfo->pc_clname);
243 } else if (pid == (pid_t)-1) {
244 (void) fprintf(stderr,
245 "%s\nCan't execute %s specific subcommand)\n",
246 pcinfo->pc_clname, pcinfo->pc_clname);
247 } else {
248 (void) wait(NULL);
253 * Return the current default scheduling class as specified in
254 * /etc/dispadmin.conf.
256 static char *
257 read_default_file(FILE *fp)
259 char buf[BUFSZ];
260 int line;
262 for (line = 1; fgets(buf, BUFSZ, fp) != NULL; line++) {
263 char name[BUFSZ], value[BUFSZ];
264 int len;
266 if (buf[0] == '#' || buf[0] == '\n')
267 continue;
268 /* LINTED - unbounded string specifier */
269 if (sscanf(buf, " %[^=]=%s \n%n", name, value, &len) == 2 &&
270 name[0] != '\0' && value[0] != '\0' && len == strlen(buf)) {
272 if (strcmp(name, TOKENNAME) != 0)
273 fatalerr("\"%s\", line %d: invalid "
274 "token: %s\n", CONFIGPATH, line, name);
276 (void) fclose(fp);
277 return (strdup(value));
278 } else {
279 fatalerr("\"%s\", line %d: syntax error\n", CONFIGPATH,
280 line);
281 (void) fclose(fp);
284 if (line == 1)
285 fatalerr("%s: %s is empty\n", cmdpath, CONFIGPATH);
286 return (NULL);
290 * Set the default scheduling class for the system.
291 * Update /etc/dispadmin.conf if necessary.
293 static void
294 set_scheduler(char *clname)
296 pcinfo_t pcinfo;
297 FILE *fp;
298 int fd;
300 if (getzoneid() != GLOBAL_ZONEID)
301 fatalerr("%s: Operation not supported in non-global zones\n",
302 cmdpath);
304 if (clname == NULL) {
305 if ((fd = open(CONFIGPATH, O_RDONLY, CONFIGPERM)) == -1) {
306 if (errno == ENOENT)
307 fatalerr("%s: Default scheduling class "
308 "is not set\n", cmdpath);
309 else
310 fatalerr("%s: Failed to open %s (%s)\n",
311 cmdpath, CONFIGPATH, strerror(errno));
314 if ((fp = fdopen(fd, "r")) == NULL)
315 fatalerr("%s: Failed to open stream for %s (%s)\n",
316 cmdpath, CONFIGPATH, strerror(errno));
317 clname = read_default_file(fp);
318 (void) strncpy(pcinfo.pc_clname, clname, PC_CLNMSZ);
320 if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1)
321 fatalerr("\"%s\", scheduling class %s is not "
322 "available\n", CONFIGPATH, clname);
323 else
324 class_info(&pcinfo);
325 return;
329 * Do a quick check to make sure clname is valid class name.
331 (void) strncpy(pcinfo.pc_clname, clname, PC_CLNMSZ);
332 if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1)
333 fatalerr("%s: Invalid or unconfigured class %s\n", cmdpath,
334 clname);
335 if ((fd = open(CONFIGPATH, O_RDWR | O_CREAT, CONFIGPERM)) == -1)
336 fatalerr("%s: Failed to open %s (%s)\n", cmdpath, CONFIGPATH,
337 strerror(errno));
338 if ((fp = fdopen(fd, "w")) == NULL)
339 fatalerr("%s: Failed to open stream for %s\n", CONFIGPATH);
340 if (ftruncate(fd, (off_t)0) == -1)
341 fatalerr("%s: Failed to truncate %s\n", cmdpath, CONFIGPATH);
342 (void) fputs("#\n# /etc/dispadmin.conf\n#\n"
343 "# Do NOT edit this file by hand -- use dispadmin(1m) instead.\n"
344 "#\n", fp);
345 if ((fprintf(fp, "%s=%s\n", TOKENNAME, clname)) == -1)
346 fatalerr("%s: Failed to write to %s\n", cmdpath, CONFIGPATH);
347 if (fflush(fp) != 0)
348 (void) fprintf(stderr,
349 "%s: warning: failed to flush config file\n",
350 cmdpath);
351 if (fsync(fd) == -1)
352 (void) fprintf(stderr,
353 "%s: warning: failed to sync config file to disk\n",
354 cmdpath);
355 if (fchmod(fd, CONFIGPERM) == -1)
356 (void) fprintf(stderr,
357 "%s: warning: failed to reset config file mode\n",
358 cmdpath);
359 if (fchown(fd, CONFIGOWNER, CONFIGGROUP) == -1)
360 (void) fprintf(stderr,
361 "%s: warning: failed to reset config file owner\n",
362 cmdpath);
363 (void) fclose(fp);
365 if (priocntl(0, 0, PC_SETDFLCL, clname) == -1)
366 fatalerr("%s: failed to set default class %s in kernel: %s\n",
367 cmdpath, clname, strerror(errno));
370 static void
371 set_default_class()
373 char *clname;
374 FILE *fp;
375 int fd;
377 if ((fd = open(CONFIGPATH, O_RDONLY, CONFIGPERM)) == -1) {
378 /* silently succeed, there is nothing to do */
379 if (errno == ENOENT)
380 return;
381 else
382 fatalerr("%s: Failed to open %s (%s)\n",
383 cmdpath, CONFIGPATH, strerror(errno));
386 if ((fp = fdopen(fd, "r")) == NULL)
387 fatalerr("%s: Failed to open stream for %s (%s)\n",
388 cmdpath, CONFIGPATH, strerror(errno));
390 if ((clname = read_default_file(fp)) != NULL) {
391 if (priocntl(0, 0, PC_SETDFLCL, clname) == -1)
392 fatalerr("%s: failed to set default class %s in "
393 "kernel: %s\n", cmdpath, clname, strerror(errno));