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 * University Copyright- Copyright (c) 1982, 1986, 1988 32 * The Regents of the University of California 33 * All Rights Reserved 34 * 35 * University Acknowledgment- Portions of this document are derived from 36 * software developed by the University of California, Berkeley, and its 37 * contributors. 38 */ 39 40 #pragma ident "%Z%%M% %I% %E% SMI" 41 42 #include <sys/types.h> 43 #include <sys/time.h> 44 #include <sys/resource.h> 45 #include <stdio.h> 46 #include <pwd.h> 47 #include <grp.h> 48 #include <project.h> 49 #include <nl_types.h> 50 #include <locale.h> 51 #include <errno.h> 52 #include <stdlib.h> 53 #include <string.h> 54 #include <unistd.h> 55 #include <ctype.h> 56 #include <zone.h> 57 #include <libzonecfg.h> 58 59 static void usage(void); 60 static int donice(int which, id_t who, int prio, int increment, char *who_s); 61 static int parse_obsolete_options(int argc, char **argv); 62 static int name2id(char *); 63 64 #define PRIO_MAX 19 65 #define PRIO_MIN -20 66 #define RENICE_DEFAULT_PRIORITY 10 67 #define RENICE_PRIO_INCREMENT 1 68 #define RENICE_PRIO_ABSOLUTE 0 69 70 typedef struct { 71 int id; 72 char *name; 73 } type_t; 74 75 static type_t types[] = { 76 { PRIO_PROCESS, "pid" }, 77 { PRIO_PGRP, "pgid" }, 78 { PRIO_USER, "uid" }, 79 { PRIO_USER, "user" }, 80 { PRIO_TASK, "taskid" }, 81 { PRIO_PROJECT, "projid" }, 82 { PRIO_PROJECT, "project" }, 83 { PRIO_GROUP, "gid" }, 84 { PRIO_GROUP, "group" }, 85 { PRIO_SESSION, "sid" }, 86 { PRIO_ZONE, "zone" }, 87 { PRIO_ZONE, "zoneid" }, 88 { PRIO_CONTRACT, "ctid" }, 89 { 0, NULL } 90 }; 91 92 /* 93 * Change the priority (nice) of processes 94 * or groups of processes which are already 95 * running. 96 */ 97 98 main(int argc, char *argv[]) 99 { 100 int c; 101 int optflag = 0; 102 int which = PRIO_PROCESS; 103 id_t who = 0; 104 int errs = 0; 105 char *end_ptr; 106 int incr = RENICE_DEFAULT_PRIORITY; 107 int prio_type = RENICE_PRIO_INCREMENT; 108 struct passwd *pwd; 109 struct group *grp; 110 111 (void) setlocale(LC_ALL, ""); 112 #if !defined(TEXT_DOMAIN) 113 #define TEXT_DOMAIN "SYS_TEST" 114 #endif 115 (void) textdomain(TEXT_DOMAIN); 116 117 if (argc < 2) 118 (void) usage(); 119 120 /* 121 * There is ambiguity in the renice options spec. 122 * If argv[1] is in the valid range of priority values then 123 * treat it as a priority. Otherwise, treat it as a pid. 124 */ 125 126 if (isdigit(argv[1][0])) { 127 if (strtol(argv[1], (char **)NULL, 10) > (PRIO_MAX+1)) { 128 argc--; /* renice pid ... */ 129 argv++; 130 prio_type = RENICE_PRIO_INCREMENT; 131 } else { /* renice priority ... */ 132 exit(parse_obsolete_options(argc, argv)); 133 } 134 } else if ((argv[1][0] == '-' || argv[1][0] == '+') && 135 isdigit(argv[1][1])) { /* renice priority ... */ 136 137 exit(parse_obsolete_options(argc, argv)); 138 139 } else { /* renice [-n increment] [-g|-p|-u] ID ... */ 140 141 while ((c = getopt(argc, argv, "n:gpui:")) != -1) { 142 switch (c) { 143 case 'n': 144 incr = strtol(optarg, &end_ptr, 10); 145 prio_type = RENICE_PRIO_INCREMENT; 146 if (*end_ptr != '\0') 147 usage(); 148 break; 149 case 'g': 150 which = PRIO_PGRP; 151 optflag++; 152 break; 153 case 'p': 154 which = PRIO_PROCESS; 155 optflag++; 156 break; 157 case 'u': 158 which = PRIO_USER; 159 optflag++; 160 break; 161 case 'i': 162 which = name2id(optarg); 163 optflag++; 164 break; 165 default: 166 usage(); 167 } 168 } 169 170 argc -= optind; 171 argv += optind; 172 173 if (argc == 0 || (optflag > 1)) 174 usage(); 175 } 176 177 for (; argc > 0; argc--, argv++) { 178 179 if (isdigit(argv[0][0])) { 180 who = strtol(*argv, &end_ptr, 10); 181 182 /* if a zone id, make sure it is valid */ 183 if (who >= 0 && end_ptr != *argv && 184 *end_ptr == '\0' && (which != PRIO_ZONE || 185 getzonenamebyid(who, NULL, 0) != -1) && 186 (which != PRIO_CONTRACT || who != 0)) { 187 errs += donice(which, who, incr, prio_type, 188 *argv); 189 continue; 190 } 191 } 192 193 switch (which) { 194 case PRIO_USER: 195 if ((pwd = getpwnam(*argv)) != NULL) { 196 who = pwd->pw_uid; 197 errs += donice(which, who, incr, prio_type, 198 *argv); 199 } else { 200 (void) fprintf(stderr, 201 gettext("renice: unknown user: %s\n"), 202 *argv); 203 errs++; 204 } 205 break; 206 case PRIO_GROUP: 207 if ((grp = getgrnam(*argv)) != NULL) { 208 who = grp->gr_gid; 209 errs += donice(which, who, incr, prio_type, 210 *argv); 211 } else { 212 (void) fprintf(stderr, 213 gettext("renice: unknown group: %s\n"), 214 *argv); 215 errs++; 216 } 217 break; 218 case PRIO_PROJECT: 219 if ((who = getprojidbyname(*argv)) != (id_t)-1) { 220 errs += donice(which, who, incr, prio_type, 221 *argv); 222 } else { 223 (void) fprintf(stderr, 224 gettext("renice: unknown project: %s\n"), 225 *argv); 226 errs++; 227 } 228 break; 229 case PRIO_ZONE: 230 if (zone_get_id(*argv, &who) != 0) { 231 (void) fprintf(stderr, 232 gettext("renice: unknown zone: %s\n"), 233 *argv); 234 errs++; 235 break; 236 } 237 errs += donice(which, who, incr, prio_type, *argv); 238 break; 239 default: 240 /* 241 * In all other cases it is invalid id or name 242 */ 243 (void) fprintf(stderr, 244 gettext("renice: bad value: %s\n"), *argv); 245 errs++; 246 } 247 } 248 249 return (errs != 0); 250 /* NOTREACHED */ 251 } 252 253 static int 254 parse_obsolete_options(int argc, char *argv[]) 255 { 256 int which = PRIO_PROCESS; 257 id_t who = 0; 258 int prio; 259 int errs = 0; 260 char *end_ptr; 261 262 argc--; 263 argv++; 264 265 if (argc < 2) { 266 usage(); 267 } 268 269 prio = strtol(*argv, &end_ptr, 10); 270 if (*end_ptr != '\0') { 271 usage(); 272 } 273 274 if (prio == 20) { 275 (void) fprintf(stderr, 276 gettext("renice: nice value 20 rounded down to 19\n")); 277 } 278 279 argc--; 280 argv++; 281 282 for (; argc > 0; argc--, argv++) { 283 if (strcmp(*argv, "-g") == 0) { 284 which = PRIO_PGRP; 285 continue; 286 } 287 if (strcmp(*argv, "-u") == 0) { 288 which = PRIO_USER; 289 continue; 290 } 291 if (strcmp(*argv, "-p") == 0) { 292 which = PRIO_PROCESS; 293 continue; 294 } 295 if (which == PRIO_USER && !isdigit(argv[0][0])) { 296 struct passwd *pwd = getpwnam(*argv); 297 298 if (pwd == NULL) { 299 (void) fprintf(stderr, 300 gettext("renice: unknown user: %s\n"), 301 *argv); 302 errs++; 303 continue; 304 } 305 who = pwd->pw_uid; 306 } else { 307 who = strtol(*argv, &end_ptr, 10); 308 if ((who < 0) || (*end_ptr != '\0')) { 309 (void) fprintf(stderr, 310 gettext("renice: bad value: %s\n"), *argv); 311 errs++; 312 continue; 313 } 314 } 315 errs += donice(which, who, prio, RENICE_PRIO_ABSOLUTE, *argv); 316 } 317 return (errs != 0); 318 } 319 320 321 322 static int 323 donice(int which, id_t who, int prio, int increment, char *who_s) 324 { 325 int oldprio; 326 327 oldprio = getpriority(which, who); 328 329 if (oldprio == -1 && errno) { 330 (void) fprintf(stderr, gettext("renice: %d:"), who); 331 perror("getpriority"); 332 return (1); 333 } 334 335 if (increment) 336 prio = oldprio + prio; 337 338 if (setpriority(which, who, prio) < 0) { 339 (void) fprintf(stderr, gettext("renice: %s:"), who_s); 340 if (errno == EPERM && prio < oldprio) 341 (void) fprintf(stderr, gettext( 342 " Cannot lower nice value.\n")); 343 else 344 perror("setpriority"); 345 return (1); 346 } 347 348 return (0); 349 } 350 351 static void 352 usage() 353 { 354 (void) fprintf(stderr, 355 gettext("usage: renice [-n increment] [-i idtype] ID ...\n")); 356 (void) fprintf(stderr, 357 gettext(" renice [-n increment] [-g | -p | -u] ID ...\n")); 358 (void) fprintf(stderr, 359 gettext(" renice priority " 360 "[-p] pid ... [-g pgrp ...] [-p pid ...] [-u user ...]\n")); 361 (void) fprintf(stderr, 362 gettext(" renice priority " 363 " -g pgrp ... [-g pgrp ...] [-p pid ...] [-u user ...]\n")); 364 (void) fprintf(stderr, 365 gettext(" renice priority " 366 " -u user ... [-g pgrp ...] [-p pid ...] [-u user ...]\n")); 367 (void) fprintf(stderr, 368 gettext(" where %d <= priority <= %d\n"), PRIO_MIN, PRIO_MAX); 369 exit(2); 370 } 371 372 static int 373 name2id(char *name) 374 { 375 type_t *type = types; 376 377 while (type->name != NULL) { 378 if (strcmp(type->name, name) == 0) 379 return (type->id); 380 type++; 381 } 382 (void) fprintf(stderr, gettext("renice: unknown id type: %s\n"), name); 383 exit(1); 384 /*NOTREACHED*/ 385 } 386