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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 27 /* All Rights Reserved */ 28 29 /* 30 * University Copyright- Copyright (c) 1982, 1986, 1988 31 * The Regents of the University of California 32 * All Rights Reserved 33 * 34 * University Acknowledgment- Portions of this document are derived from 35 * software developed by the University of California, Berkeley, and its 36 * contributors. 37 */ 38 39 #pragma ident "%Z%%M% %I% %E% SMI" 40 41 #include <sys/types.h> 42 #include <sys/time.h> 43 #include <sys/resource.h> 44 #include <stdio.h> 45 #include <pwd.h> 46 #include <grp.h> 47 #include <project.h> 48 #include <nl_types.h> 49 #include <locale.h> 50 #include <errno.h> 51 #include <stdlib.h> 52 #include <string.h> 53 #include <unistd.h> 54 #include <ctype.h> 55 #include <zone.h> 56 #include <libzonecfg.h> 57 58 static void usage(void); 59 static int donice(int which, id_t who, int prio, int increment, char *who_s); 60 static int parse_obsolete_options(int argc, char **argv); 61 static int name2id(char *); 62 63 #define PRIO_MAX 19 64 #define PRIO_MIN -20 65 #define RENICE_DEFAULT_PRIORITY 10 66 #define RENICE_PRIO_INCREMENT 1 67 #define RENICE_PRIO_ABSOLUTE 0 68 69 typedef struct { 70 int id; 71 char *name; 72 } type_t; 73 74 static type_t types[] = { 75 { PRIO_PROCESS, "pid" }, 76 { PRIO_PGRP, "pgid" }, 77 { PRIO_USER, "uid" }, 78 { PRIO_USER, "user" }, 79 { PRIO_TASK, "taskid" }, 80 { PRIO_PROJECT, "projid" }, 81 { PRIO_PROJECT, "project" }, 82 { PRIO_GROUP, "gid" }, 83 { PRIO_GROUP, "group" }, 84 { PRIO_SESSION, "sid" }, 85 { PRIO_ZONE, "zone" }, 86 { PRIO_ZONE, "zoneid" }, 87 { PRIO_CONTRACT, "ctid" }, 88 { 0, NULL } 89 }; 90 91 /* 92 * Change the priority (nice) of processes 93 * or groups of processes which are already 94 * running. 95 */ 96 97 int 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 } 251 252 static int 253 parse_obsolete_options(int argc, char *argv[]) 254 { 255 int which = PRIO_PROCESS; 256 id_t who = 0; 257 int prio; 258 int errs = 0; 259 char *end_ptr; 260 261 argc--; 262 argv++; 263 264 if (argc < 2) { 265 usage(); 266 } 267 268 prio = strtol(*argv, &end_ptr, 10); 269 if (*end_ptr != '\0') { 270 usage(); 271 } 272 273 if (prio == 20) { 274 (void) fprintf(stderr, 275 gettext("renice: nice value 20 rounded down to 19\n")); 276 } 277 278 argc--; 279 argv++; 280 281 for (; argc > 0; argc--, argv++) { 282 if (strcmp(*argv, "-g") == 0) { 283 which = PRIO_PGRP; 284 continue; 285 } 286 if (strcmp(*argv, "-u") == 0) { 287 which = PRIO_USER; 288 continue; 289 } 290 if (strcmp(*argv, "-p") == 0) { 291 which = PRIO_PROCESS; 292 continue; 293 } 294 if (which == PRIO_USER && !isdigit(argv[0][0])) { 295 struct passwd *pwd = getpwnam(*argv); 296 297 if (pwd == NULL) { 298 (void) fprintf(stderr, 299 gettext("renice: unknown user: %s\n"), 300 *argv); 301 errs++; 302 continue; 303 } 304 who = pwd->pw_uid; 305 } else { 306 who = strtol(*argv, &end_ptr, 10); 307 if ((who < 0) || (*end_ptr != '\0')) { 308 (void) fprintf(stderr, 309 gettext("renice: bad value: %s\n"), *argv); 310 errs++; 311 continue; 312 } 313 } 314 errs += donice(which, who, prio, RENICE_PRIO_ABSOLUTE, *argv); 315 } 316 return (errs != 0); 317 } 318 319 320 321 static int 322 donice(int which, id_t who, int prio, int increment, char *who_s) 323 { 324 int oldprio; 325 326 oldprio = getpriority(which, who); 327 328 if (oldprio == -1 && errno) { 329 (void) fprintf(stderr, gettext("renice: %d:"), who); 330 perror("getpriority"); 331 return (1); 332 } 333 334 if (increment) 335 prio = oldprio + prio; 336 337 if (setpriority(which, who, prio) < 0) { 338 (void) fprintf(stderr, gettext("renice: %s:"), who_s); 339 if (errno == EACCES && prio < oldprio) 340 (void) fprintf(stderr, gettext( 341 " Cannot lower nice value.\n")); 342 else 343 perror("setpriority"); 344 return (1); 345 } 346 347 return (0); 348 } 349 350 static void 351 usage() 352 { 353 (void) fprintf(stderr, 354 gettext("usage: renice [-n increment] [-i idtype] ID ...\n")); 355 (void) fprintf(stderr, 356 gettext(" renice [-n increment] [-g | -p | -u] ID ...\n")); 357 (void) fprintf(stderr, 358 gettext(" renice priority " 359 "[-p] pid ... [-g pgrp ...] [-p pid ...] [-u user ...]\n")); 360 (void) fprintf(stderr, 361 gettext(" renice priority " 362 " -g pgrp ... [-g pgrp ...] [-p pid ...] [-u user ...]\n")); 363 (void) fprintf(stderr, 364 gettext(" renice priority " 365 " -u user ... [-g pgrp ...] [-p pid ...] [-u user ...]\n")); 366 (void) fprintf(stderr, 367 gettext(" where %d <= priority <= %d\n"), PRIO_MIN, PRIO_MAX); 368 exit(2); 369 } 370 371 static int 372 name2id(char *name) 373 { 374 type_t *type = types; 375 376 while (type->name != NULL) { 377 if (strcmp(type->name, name) == 0) 378 return (type->id); 379 type++; 380 } 381 (void) fprintf(stderr, gettext("renice: unknown id type: %s\n"), name); 382 exit(1); 383 /*NOTREACHED*/ 384 } 385