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