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
main(int argc,char * argv[])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
parse_obsolete_options(int argc,char * argv[])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
donice(int which,id_t who,int prio,int increment,char * who_s)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
usage()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
name2id(char * name)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