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]
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.
40 #include <sys/types.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).
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();
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();
83 main(int argc
, char **argv
)
86 extern int optind
, opterr
;
89 int uflag
, cflag
, dflag
, lflag
, csoptsflag
;
92 (void) strncpy(cmdpath
, argv
[0], PATH_MAX
);
93 (void) strncpy(basenm
, basename(argv
[0]), BASENMSZ
);
94 cflag
= dflag
= lflag
= uflag
= csoptsflag
= 0;
96 while ((c
= getopt(argc
, argv
, "c:dlu")) != -1) {
106 clname
= argv
[optind
];
120 * We assume for now that any option that
121 * getopt() doesn't recognize is intended for a
122 * class specific subcommand.
125 if (argv
[optind
] && argv
[optind
][0] != '-') {
129 * Class specific option takes an
130 * argument which we skip over for now.
142 if (uflag
|| cflag
|| dflag
|| csoptsflag
)
149 if (lflag
|| dflag
|| csoptsflag
)
157 exec_cscmd(clname
, argv
);
160 if (cflag
|| lflag
|| csoptsflag
)
162 set_scheduler(clname
);
173 * Print the heading for the class list and execute the
174 * class specific sub-command with the -l option for each
184 if ((nclass
= priocntl(0, 0, PC_GETCLINFO
, NULL
)) == -1)
185 fatalerr("%s: Can't get number of configured classes\n",
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
++) {
193 if (priocntl(0, 0, PC_GETCLINFO
, (caddr_t
)&pcinfo
) == -1)
194 fatalerr("%s: Can't get class name (class ID = %d)\n",
202 * Execute the appropriate class specific sub-command for the class
203 * specified by clname, passing it the arguments in subcmdargv.
206 exec_cscmd(char *clname
, char **subcmdargv
)
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
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
,
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
);
232 class_info(pcinfo_t
*pcinfo
)
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
);
253 * Return the current default scheduling class as specified in
254 * /etc/dispadmin.conf.
257 read_default_file(FILE *fp
)
262 for (line
= 1; fgets(buf
, BUFSZ
, fp
) != NULL
; line
++) {
263 char name
[BUFSZ
], value
[BUFSZ
];
266 if (buf
[0] == '#' || buf
[0] == '\n')
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
);
277 return (strdup(value
));
279 fatalerr("\"%s\", line %d: syntax error\n", CONFIGPATH
,
285 fatalerr("%s: %s is empty\n", cmdpath
, CONFIGPATH
);
290 * Set the default scheduling class for the system.
291 * Update /etc/dispadmin.conf if necessary.
294 set_scheduler(char *clname
)
300 if (getzoneid() != GLOBAL_ZONEID
)
301 fatalerr("%s: Operation not supported in non-global zones\n",
304 if (clname
== NULL
) {
305 if ((fd
= open(CONFIGPATH
, O_RDONLY
, CONFIGPERM
)) == -1) {
307 fatalerr("%s: Default scheduling class "
308 "is not set\n", cmdpath
);
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
);
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
,
335 if ((fd
= open(CONFIGPATH
, O_RDWR
| O_CREAT
, CONFIGPERM
)) == -1)
336 fatalerr("%s: Failed to open %s (%s)\n", cmdpath
, CONFIGPATH
,
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"
345 if ((fprintf(fp
, "%s=%s\n", TOKENNAME
, clname
)) == -1)
346 fatalerr("%s: Failed to write to %s\n", cmdpath
, CONFIGPATH
);
348 (void) fprintf(stderr
,
349 "%s: warning: failed to flush config file\n",
352 (void) fprintf(stderr
,
353 "%s: warning: failed to sync config file to disk\n",
355 if (fchmod(fd
, CONFIGPERM
) == -1)
356 (void) fprintf(stderr
,
357 "%s: warning: failed to reset config file mode\n",
359 if (fchown(fd
, CONFIGOWNER
, CONFIGGROUP
) == -1)
360 (void) fprintf(stderr
,
361 "%s: warning: failed to reset config file owner\n",
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
));
377 if ((fd
= open(CONFIGPATH
, O_RDONLY
, CONFIGPERM
)) == -1) {
378 /* silently succeed, there is nothing to do */
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
));