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 2005 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 int 99 main(int argc, char *argv[]) 100 { 101 int c; 102 int optflag = 0; 103 int which = PRIO_PROCESS; 104 id_t who = 0; 105 int errs = 0; 106 char *end_ptr; 107 int incr = RENICE_DEFAULT_PRIORITY; 108 int prio_type = RENICE_PRIO_INCREMENT; 109 struct passwd *pwd; 110 struct group *grp; 111 112 (void) setlocale(LC_ALL, ""); 113 #if !defined(TEXT_DOMAIN) 114 #define TEXT_DOMAIN "SYS_TEST" 115 #endif 116 (void) textdomain(TEXT_DOMAIN); 117 118 if (argc < 2) 119 (void) usage(); 120 121 /* 122 * There is ambiguity in the renice options spec. 123 * If argv[1] is in the valid range of priority values then 124 * treat it as a priority. Otherwise, treat it as a pid. 125 */ 126 127 if (isdigit(argv[1][0])) { 128 if (strtol(argv[1], (char **)NULL, 10) > (PRIO_MAX+1)) { 129 argc--; /* renice pid ... */ 130 argv++; 131 prio_type = RENICE_PRIO_INCREMENT; 132 } else { /* renice priority ... */ 133 exit(parse_obsolete_options(argc, argv)); 134 } 135 } else if ((argv[1][0] == '-' || argv[1][0] == '+') && 136 isdigit(argv[1][1])) { /* renice priority ... */ 137 138 exit(parse_obsolete_options(argc, argv)); 139 140 } else { /* renice [-n increment] [-g|-p|-u] ID ... */ 141 142 while ((c = getopt(argc, argv, "n:gpui:")) != -1) { 143 switch (c) { 144 case 'n': 145 incr = strtol(optarg, &end_ptr, 10); 146 prio_type = RENICE_PRIO_INCREMENT; 147 if (*end_ptr != '\0') 148 usage(); 149 break; 150 case 'g': 151 which = PRIO_PGRP; 152 optflag++; 153 break; 154 case 'p': 155 which = PRIO_PROCESS; 156 optflag++; 157 break; 158 case 'u': 159 which = PRIO_USER; 160 optflag++; 161 break; 162 case 'i': 163 which = name2id(optarg); 164 optflag++; 165 break; 166 default: 167 usage(); 168 } 169 } 170 171 argc -= optind; 172 argv += optind; 173 174 if (argc == 0 || (optflag > 1)) 175 usage(); 176 } 177 178 for (; argc > 0; argc--, argv++) { 179 180 if (isdigit(argv[0][0])) { 181 who = strtol(*argv, &end_ptr, 10); 182 183 /* if a zone id, make sure it is valid */ 184 if (who >= 0 && end_ptr != *argv && 185 *end_ptr == '\0' && (which != PRIO_ZONE || 186 getzonenamebyid(who, NULL, 0) != -1) && 187 (which != PRIO_CONTRACT || who != 0)) { 188 errs += donice(which, who, incr, prio_type, 189 *argv); 190 continue; 191 } 192 } 193 194 switch (which) { 195 case PRIO_USER: 196 if ((pwd = getpwnam(*argv)) != NULL) { 197 who = pwd->pw_uid; 198 errs += donice(which, who, incr, prio_type, 199 *argv); 200 } else { 201 (void) fprintf(stderr, 202 gettext("renice: unknown user: %s\n"), 203 *argv); 204 errs++; 205 } 206 break; 207 case PRIO_GROUP: 208 if ((grp = getgrnam(*argv)) != NULL) { 209 who = grp->gr_gid; 210 errs += donice(which, who, incr, prio_type, 211 *argv); 212 } else { 213 (void) fprintf(stderr, 214 gettext("renice: unknown group: %s\n"), 215 *argv); 216 errs++; 217 } 218 break; 219 case PRIO_PROJECT: 220 if ((who = getprojidbyname(*argv)) != (id_t)-1) { 221 errs += donice(which, who, incr, prio_type, 222 *argv); 223 } else { 224 (void) fprintf(stderr, 225 gettext("renice: unknown project: %s\n"), 226 *argv); 227 errs++; 228 } 229 break; 230 case PRIO_ZONE: 231 if (zone_get_id(*argv, &who) != 0) { 232 (void) fprintf(stderr, 233 gettext("renice: unknown zone: %s\n"), 234 *argv); 235 errs++; 236 break; 237 } 238 errs += donice(which, who, incr, prio_type, *argv); 239 break; 240 default: 241 /* 242 * In all other cases it is invalid id or name 243 */ 244 (void) fprintf(stderr, 245 gettext("renice: bad value: %s\n"), *argv); 246 errs++; 247 } 248 } 249 250 return (errs != 0); 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