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