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