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