xref: /illumos-gate/usr/src/cmd/priocntl/iapriocntl.c (revision fe4627ef755b7c263f91a0e6f07cdca5d7083501)
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
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
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
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
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
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
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