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