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