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