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