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