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