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