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