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