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