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