1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2001-2002 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29
30 #include <stdio.h>
31 #include <string.h>
32 #include <libgen.h>
33 #include <unistd.h>
34 #include <sys/types.h>
35 #include <sys/procset.h>
36 #include <sys/priocntl.h>
37 #include <sys/fxpriocntl.h>
38 #include <limits.h>
39 #include <errno.h>
40
41 #include "priocntl.h"
42
43 /*
44 * This file contains the class specific code implementing
45 * the fixed-priority priocntl sub-command.
46 */
47
48 #define ADDKEYVAL(p, k, v) { (p[0]) = (k); (p[1]) = (v); p += 2; }
49
50 #define FX_KEYCNT 4 /* maximal number of (key, value) pairs */
51
52 /*
53 * control flags
54 */
55 #define FX_DOUPRILIM 0x01 /* user priority limit */
56 #define FX_DOUPRI 0x02 /* user priority */
57 #define FX_DOTQ 0x04 /* time quantum */
58
59
60
61 static void print_fxinfo();
62 static int print_fxprocs();
63 static int set_fxprocs(idtype_t, int, char **, uint_t, pri_t, pri_t, long,
64 long);
65 static void exec_fxcmd(char **, uint_t, pri_t, pri_t, long, long);
66 static int fx_priocntl(idtype_t, id_t, int, char *, uintptr_t *);
67
68 static char usage[] =
69 "usage: priocntl -l\n\
70 priocntl -d [-d idtype] [idlist]\n\
71 priocntl -s [-c FX] [-m fxuprilim] [-p fxupri] [-t tqntm [-r res]] \
72 [-i idtype] [idlist]\n\
73 priocntl -e [-c FX] [-m fxuprilim] [-p fxupri] [-t tqntm [-r res]] \
74 command [argument(s)]\n";
75
76 static char cmdpath[MAXPATHLEN];
77 static char basenm[BASENMSZ];
78
79 int
main(int argc,char * argv[])80 main(int argc, char *argv[])
81 {
82 extern char *optarg;
83 extern int optind;
84
85 int c;
86 int lflag, dflag, sflag, mflag, pflag, eflag, iflag, tflag;
87 int rflag;
88 pri_t fxuprilim;
89 pri_t fxupri;
90 char *idtypnm;
91 idtype_t idtype;
92 int idargc;
93 long res;
94 long tqntm;
95 uint_t cflags;
96
97 (void) strlcpy(cmdpath, argv[0], MAXPATHLEN);
98 (void) strlcpy(basenm, basename(argv[0]), BASENMSZ);
99 lflag = dflag = sflag = mflag = pflag = eflag = iflag = tflag = 0;
100 rflag = 0;
101 while ((c = getopt(argc, argv, "ldsm:p:ec:i:t:r:")) != -1) {
102 switch (c) {
103
104 case 'l':
105 lflag++;
106 break;
107
108 case 'd':
109 dflag++;
110 break;
111
112 case 's':
113 sflag++;
114 break;
115
116 case 'm':
117 mflag++;
118 fxuprilim = (pri_t)str2num(optarg, SHRT_MIN, SHRT_MAX);
119 if (errno)
120 fatalerr("%s: Specified user priority limit %s"
121 " out of configured range\n",
122 basenm, optarg);
123 break;
124
125 case 'p':
126 pflag++;
127 fxupri = (pri_t)str2num(optarg, SHRT_MIN, SHRT_MAX);
128 if (errno)
129 fatalerr("%s: Specified user priority %s out of"
130 " configured range\n", basenm, optarg);
131 break;
132
133 case 'e':
134 eflag++;
135 break;
136
137 case 'c':
138 if (strcmp(optarg, "FX") != 0)
139 fatalerr("error: %s executed for %s class, %s"
140 " is actually sub-command for FX class\n",
141 cmdpath, optarg, cmdpath);
142 break;
143
144 case 'i':
145 iflag++;
146 idtypnm = optarg;
147 break;
148 case 't':
149 tflag++;
150 tqntm = str2num(optarg, 1, INT_MAX);
151 if (errno)
152 fatalerr("%s: Invalid time quantum specified;"
153 " time quantum must be positive\n", basenm);
154 break;
155
156 case 'r':
157 rflag++;
158 res = str2num(optarg, 1, 1000000000);
159 if (errno)
160 fatalerr("%s: Invalid resolution specified;"
161 " resolution must be between"
162 " 1 and 1,000,000,000\n", basenm);
163
164 break;
165
166 case '?':
167 fatalerr(usage);
168
169 default:
170 break;
171 }
172 }
173
174 if (lflag) {
175 if (dflag || sflag || mflag || pflag || eflag || iflag ||
176 tflag || rflag)
177 fatalerr(usage);
178
179 print_fxinfo();
180
181 } else if (dflag) {
182 if (sflag || mflag || pflag || eflag)
183 fatalerr(usage);
184
185 return (print_fxprocs());
186
187 } else if (sflag) {
188 if (eflag)
189 fatalerr(usage);
190
191 if (iflag) {
192 if (str2idtyp(idtypnm, &idtype) == -1)
193 fatalerr("%s: Bad idtype %s\n", basenm,
194 idtypnm);
195 } else
196 idtype = P_PID;
197
198 cflags = (pflag ? FX_DOUPRI : 0);
199
200 if (mflag)
201 cflags |= FX_DOUPRILIM;
202
203 if (tflag)
204 cflags |= FX_DOTQ;
205
206 if (rflag == 0)
207 res = 1000;
208
209 if (optind < argc)
210 idargc = argc - optind;
211 else
212 idargc = 0;
213
214 return (set_fxprocs(idtype, idargc, &argv[optind], cflags,
215 fxuprilim, fxupri, tqntm, res));
216
217 } else if (eflag) {
218 if (iflag)
219 fatalerr(usage);
220
221 cflags = (pflag ? FX_DOUPRI : 0);
222
223 if (mflag)
224 cflags |= FX_DOUPRILIM;
225
226 if (tflag)
227 cflags |= FX_DOTQ;
228
229 if (rflag == 0)
230 res = 1000;
231
232 exec_fxcmd(&argv[optind], cflags, fxuprilim, fxupri, tqntm,
233 res);
234
235 } else {
236 fatalerr(usage);
237 }
238 return (0);
239 }
240
241
242 /*
243 * Print our class name and the configured user priority range.
244 */
245 static void
print_fxinfo()246 print_fxinfo()
247 {
248 pcinfo_t pcinfo;
249
250 (void) strcpy(pcinfo.pc_clname, "FX");
251
252 (void) printf("FX (Fixed priority)\n");
253
254 if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1)
255 fatalerr("\tCan't get configured FX user priority range\n");
256
257 (void) printf("\tConfigured FX User Priority Range: 0 through %d\n",
258 ((fxinfo_t *)pcinfo.pc_clinfo)->fx_maxupri);
259 }
260
261
262 /*
263 * Read a list of pids from stdin and print the user priority and user
264 * priority limit for each of the corresponding processes.
265 */
266 static int
print_fxprocs()267 print_fxprocs()
268 {
269 pid_t *pidlist;
270 size_t numread;
271 int i;
272 char clname[PC_CLNMSZ];
273 uint_t fx_tqsecs;
274 int fx_tqnsecs;
275 pri_t fx_uprilim;
276 pri_t fx_upri;
277 int error = 0;
278
279
280 /*
281 * Read a list of pids from stdin.
282 */
283 if ((pidlist = read_pidlist(&numread, stdin)) == NULL)
284 fatalerr("%s: Can't read pidlist.\n", basenm);
285
286 (void) printf("FIXED PRIORITY PROCESSES:\n PID FXUPRILIM "
287 "FXUPRI FXTQNTM\n");
288
289 if (numread == 0)
290 fatalerr("%s: No pids on input\n", basenm);
291
292
293 for (i = 0; i < numread; i++) {
294 (void) printf("%7ld", pidlist[i]);
295 if (priocntl(P_PID, pidlist[i], PC_GETXPARMS, "FX",
296 FX_KY_UPRI, &fx_upri, FX_KY_UPRILIM, &fx_uprilim,
297 FX_KY_TQSECS, &fx_tqsecs, FX_KY_TQNSECS,
298 &fx_tqnsecs, 0) != -1) {
299 (void) printf(" %5d %5d", fx_uprilim, fx_upri);
300
301 if (fx_tqnsecs == FX_TQINF)
302 (void) printf(" FX_TQINF\n");
303 else
304 (void) printf(" %11lld\n",
305 (longlong_t)fx_tqsecs * 1000 +
306 fx_tqnsecs / 1000000);
307
308 } else {
309 error = 1;
310
311 if (priocntl(P_PID, pidlist[i], PC_GETXPARMS, NULL,
312 PC_KY_CLNAME, clname, 0) != -1 &&
313 strcmp(clname, "FX")) {
314 /*
315 * Process from some class other than fixed priority.
316 * It has probably changed class while priocntl
317 * command was executing (otherwise we wouldn't
318 * have been passed its pid). Print the little
319 * we know about it.
320 */
321 (void) printf("\tChanged to class %s while priocntl"
322 " command executing\n", clname);
323 } else {
324 (void) printf("\tCan't get FX user priority\n");
325 }
326 }
327 }
328
329 free_pidlist(pidlist);
330 return (error);
331 }
332
333 /*
334 * Call priocntl() with command codes PC_SETXPARMS or PC_GETXPARMS.
335 * The first parameter behind the command code is always the class name.
336 * Each parameter is headed by a key, which determines the meaning of the
337 * following value. There are maximal FX_KEYCNT = 4 (key, value) pairs.
338 */
339 static int
fx_priocntl(idtype_t idtype,id_t id,int cmd,char * clname,uintptr_t * argsp)340 fx_priocntl(idtype_t idtype, id_t id, int cmd, char *clname, uintptr_t *argsp)
341 {
342 return (priocntl(idtype, id, cmd, clname, argsp[0], argsp[1],
343 argsp[2], argsp[3], argsp[4], argsp[5], argsp[6], argsp[7], 0));
344 }
345
346 /*
347 * Set all processes in the set specified by idtype/idargv to fixed-priority
348 * (if they aren't already fixed-priority) and set their user priority limit
349 * and user priority to those specified by fxuprilim and fxupri.
350 */
351 static int
set_fxprocs(idtype_t idtype,int idargc,char ** idargv,uint_t cflags,pri_t fxuprilim,pri_t fxupri,long tqntm,long res)352 set_fxprocs(idtype_t idtype, int idargc, char **idargv, uint_t cflags,
353 pri_t fxuprilim, pri_t fxupri, long tqntm, long res)
354 {
355 pcinfo_t pcinfo;
356 uintptr_t args[2*FX_KEYCNT+1];
357 uintptr_t *argsp = &args[0];
358 pri_t maxupri;
359 char idtypnm[PC_IDTYPNMSZ];
360 int i;
361 id_t id;
362 hrtimer_t hrtime;
363 int error = 0;
364
365 /*
366 * Get the fixed priority class ID and max configured user priority.
367 */
368 (void) strcpy(pcinfo.pc_clname, "FX");
369 if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1)
370 fatalerr("%s: Can't get FX class ID, priocntl system call"
371 " failed with errno %d\n", basenm, errno);
372 maxupri = ((fxinfo_t *)pcinfo.pc_clinfo)->fx_maxupri;
373
374 /*
375 * Validate the fxuprilim and fxupri arguments.
376 */
377 if ((cflags & FX_DOUPRILIM) != 0) {
378 if (fxuprilim > maxupri || fxuprilim < 0) {
379 fatalerr("%s: Specified user priority limit %d out of"
380 " configured range\n", basenm, fxuprilim);
381 }
382 ADDKEYVAL(argsp, FX_KY_UPRILIM, fxuprilim);
383 }
384
385 if ((cflags & FX_DOUPRI) != 0) {
386 if (fxupri > maxupri || fxupri < 0)
387 fatalerr("%s: Specified user priority %d out of "
388 "configured range\n", basenm, fxupri);
389 ADDKEYVAL(argsp, FX_KY_UPRI, fxupri);
390
391 }
392
393 if (cflags & FX_DOTQ) {
394 hrtime.hrt_secs = 0;
395 hrtime.hrt_rem = tqntm;
396 hrtime.hrt_res = res;
397 if (_hrtnewres(&hrtime, NANOSEC, HRT_RNDUP) == -1)
398 fatalerr("%s: Can't convert resolution.\n", basenm);
399 ADDKEYVAL(argsp, FX_KY_TQSECS, hrtime.hrt_secs);
400 ADDKEYVAL(argsp, FX_KY_TQNSECS, hrtime.hrt_rem);
401 }
402
403 *argsp = 0;
404
405 if (idtype == P_ALL) {
406 if (fx_priocntl(P_ALL, 0, PC_SETXPARMS, "FX", args) == -1) {
407 if (errno == EPERM) {
408 (void) fprintf(stderr,
409 "Permissions error encountered "
410 "on one or more processes.\n");
411 error = 1;
412 } else {
413 fatalerr("%s: Can't reset fixed priority"
414 " parameters\npriocntl system call failed "
415 " with errno %d\n", basenm, errno);
416 }
417 } else if ((cflags & (FX_DOUPRILIM|FX_DOUPRI)) == FX_DOUPRI) {
418 (void) verifyupri(idtype, 0, "FX", FX_KY_UPRILIM,
419 fxupri, basenm);
420 }
421 } else if (idargc == 0) {
422 if (fx_priocntl(idtype, P_MYID, PC_SETXPARMS, "FX",
423 args) == -1) {
424 if (errno == EPERM) {
425 (void) idtyp2str(idtype, idtypnm);
426 (void) fprintf(stderr, "Permissions error"
427 " encountered on current %s.\n", idtypnm);
428 error = 1;
429 } else {
430 fatalerr("%s: Can't reset fixed priority"
431 " parameters\npriocntl system call failed"
432 " with errno %d\n", basenm, errno);
433 }
434 } else if ((cflags & (FX_DOUPRILIM|FX_DOUPRI)) == FX_DOUPRI &&
435 getmyid(idtype, &id) != -1) {
436 (void) verifyupri(idtype, id, "FX", FX_KY_UPRILIM,
437 fxupri, basenm);
438 }
439 } else {
440 (void) idtyp2str(idtype, idtypnm);
441 for (i = 0; i < idargc; i++) {
442 if (idtype == P_CID) {
443 (void) strcpy(pcinfo.pc_clname, idargv[i]);
444 if (priocntl(0, 0, PC_GETCID,
445 (caddr_t)&pcinfo) == -1)
446 fatalerr("%s: Invalid or unconfigured"
447 " class %s, priocntl system call"
448 " failed with errno %d\n",
449 basenm, pcinfo.pc_clname, errno);
450 id = pcinfo.pc_cid;
451 } else {
452 id = (id_t)str2num(idargv[i], INT_MIN, INT_MAX);
453 }
454
455 if (fx_priocntl(idtype, id, PC_SETXPARMS, "FX", args)
456 == -1) {
457 if (errno == EPERM) {
458 (void) fprintf(stderr,
459 "Permissions error encountered on"
460 " %s %s.\n", idtypnm, idargv[i]);
461 error = 1;
462 } else {
463 fatalerr("%s: Can't reset fixed "
464 "priority"
465 " parameters\npriocntl system call"
466 " failed with errno %d\n",
467 basenm, errno);
468 }
469 } else if ((cflags & (FX_DOUPRILIM|FX_DOUPRI)) ==
470 FX_DOUPRI) {
471 (void) verifyupri(idtype, id, "FX",
472 FX_KY_UPRILIM, fxupri, basenm);
473 }
474 }
475 }
476 return (error);
477
478 }
479
480
481 /*
482 * Execute the command pointed to by cmdargv as a fixed-priority process
483 * with the user priority limit given by fxuprilim and user priority fxupri.
484 */
485 static void
exec_fxcmd(char ** cmdargv,uint_t cflags,pri_t fxuprilim,pri_t fxupri,long tqntm,long res)486 exec_fxcmd(char **cmdargv, uint_t cflags, pri_t fxuprilim, pri_t fxupri,
487 long tqntm, long res)
488 {
489 pcinfo_t pcinfo;
490 uintptr_t args[2*FX_KEYCNT+1];
491 uintptr_t *argsp = &args[0];
492
493 pri_t maxupri;
494 pri_t uprilim;
495 hrtimer_t hrtime;
496
497 /*
498 * Get the fixed priority class ID and max configured user priority.
499 */
500 (void) strcpy(pcinfo.pc_clname, "FX");
501 if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1)
502 fatalerr("%s: Can't get FX class ID, priocntl system call"
503 " failed with errno %d\n", basenm, errno);
504 maxupri = ((fxinfo_t *)pcinfo.pc_clinfo)->fx_maxupri;
505
506 if ((cflags & FX_DOUPRILIM) != 0) {
507 if (fxuprilim > maxupri || fxuprilim < 0)
508 fatalerr("%s: Specified user priority limit %d out of"
509 " configured range\n", basenm, fxuprilim);
510 ADDKEYVAL(argsp, FX_KY_UPRILIM, fxuprilim);
511 }
512
513 if ((cflags & FX_DOUPRI) != 0) {
514 if (fxupri > maxupri || fxupri < 0)
515 fatalerr("%s: Specified user priority %d out of"
516 " configured range\n", basenm, fxupri);
517 ADDKEYVAL(argsp, FX_KY_UPRI, fxupri);
518 }
519
520 if ((cflags & FX_DOTQ) != 0) {
521 hrtime.hrt_secs = 0;
522 hrtime.hrt_rem = tqntm;
523 hrtime.hrt_res = res;
524 if (_hrtnewres(&hrtime, NANOSEC, HRT_RNDUP) == -1)
525 fatalerr("%s: Can't convert resolution.\n", basenm);
526 ADDKEYVAL(argsp, FX_KY_TQSECS, hrtime.hrt_secs);
527 ADDKEYVAL(argsp, FX_KY_TQNSECS, hrtime.hrt_rem);
528
529 }
530 *argsp = 0;
531 if (fx_priocntl(P_PID, P_MYID, PC_SETXPARMS, "FX", args) == -1)
532 fatalerr("%s: Can't reset fixed priority parameters\n"
533 " priocntl system call failed with errno %d\n",
534 basenm, errno);
535
536 if ((cflags & (FX_DOUPRILIM|FX_DOUPRI)) == FX_DOUPRI) {
537 if (priocntl(P_PID, P_MYID, PC_GETXPARMS, "FX",
538 FX_KY_UPRILIM, &uprilim, 0) != -1 && fxupri > uprilim)
539 (void) fprintf(stderr,
540 "%s: Specified user priority %d exceeds"
541 " limit %d; set to %d (pid %d)\n",
542 basenm, fxupri, uprilim, uprilim, (int)getpid());
543 }
544
545 (void) execvp(cmdargv[0], cmdargv);
546 fatalerr("%s: Can't execute %s, exec failed with errno %d\n",
547 basenm, cmdargv[0], errno);
548 }
549