xref: /openbsd-src/usr.bin/renice/renice.c (revision d13be5d47e4149db2549a9828e244d59dbc43f15)
1 /*	$OpenBSD: renice.c,v 1.15 2009/10/27 23:59:42 deraadt Exp $	*/
2 
3 /*
4  * Copyright (c) 2009 Todd C. Miller <Todd.Miller@courtesan.com>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 #include <sys/time.h>
21 #include <sys/resource.h>
22 
23 #include <ctype.h>
24 #include <err.h>
25 #include <errno.h>
26 #include <limits.h>
27 #include <pwd.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 
32 struct renice_param {
33 	int pri;
34 	int type;
35 	id_t id;
36 };
37 
38 int main(int, char **);
39 static int renice(struct renice_param *, struct renice_param *);
40 __dead void usage(void);
41 
42 int
43 main(int argc, char **argv)
44 {
45 	struct renice_param *params, *p;
46 	struct passwd *pw;
47 	int ch, type = PRIO_PROCESS;
48 	int nflag = 0, pri = 0;
49 	char *ep, *idstr;
50 	const char *errstr;
51 	long l;
52 
53 	if (argc < 3)
54 		usage();
55 
56 	/* Allocate enough space for the worst case. */
57 	params = p = calloc(argc - 1, sizeof(*params));
58 	if (params == NULL)
59 		err(1, NULL);
60 
61 	/* Backwards compatibility: first arg may be priority. */
62 	if (isdigit((unsigned char)argv[1][0]) ||
63 	    (argv[1][0] == '-' && isdigit((unsigned char)argv[1][1]))) {
64 		argv[0] = "-n";
65 		argc++;
66 		argv--;
67 	}
68 
69 	/*
70 	 * Slightly tricky getopt() usage since it is legal to have
71 	 * option flags interleaved with arguments.
72 	 */
73 	for (;;) {
74 		if ((ch = getopt(argc, argv, "g:n:p:u:")) != -1) {
75 			switch (ch) {
76 			case 'g':
77 				type = PRIO_PGRP;
78 				idstr = optarg;
79 				break;
80 			case 'n':
81 				l = strtol(optarg, &ep, 10);
82 				if (*ep != '\0' || ep == optarg) {
83 					warnx("invalid increment %s", optarg);
84 					usage();
85 				}
86 				pri = l > PRIO_MAX ? PRIO_MAX :
87 				    l < PRIO_MIN ? PRIO_MIN : (int)l;
88 
89 				/* Set priority for previous entries? */
90 				if (!nflag) {
91 					struct renice_param *pp;
92 					for (pp = params; pp != p; pp++) {
93 						pp->pri = pri;
94 					}
95 				}
96 				nflag = 1;
97 				continue;
98 			case 'p':
99 				type = PRIO_PROCESS;
100 				idstr = optarg;
101 				break;
102 			case 'u':
103 				type = PRIO_USER;
104 				idstr = optarg;
105 				break;
106 			default:
107 				usage();
108 				break;
109 			}
110 		} else {
111 			idstr = argv[optind++];
112 			if (idstr == NULL)
113 				break;
114 		}
115 		p->type = type;
116 		p->pri = pri;
117 		if (type == PRIO_USER) {
118 			if ((pw = getpwnam(idstr)) == NULL) {
119 				uid_t id = strtonum(idstr, 0, UID_MAX, &errstr);
120 				if (!errstr)
121 					pw = getpwuid(id);
122 			}
123 			if (pw == NULL) {
124 				warnx("unknown user %s", idstr);
125 				continue;
126 			}
127 			p->id = pw->pw_uid;
128 		} else {
129 			p->id = strtonum(idstr, 0, UINT_MAX, &errstr);
130 			if (errstr) {
131 				warnx("%s is %s", idstr, errstr);
132 				continue;
133 			}
134 		}
135 		p++;
136 	}
137 	if (!nflag)
138 		usage();
139 	exit(renice(params, p));
140 }
141 
142 static int
143 renice(struct renice_param *p, struct renice_param *end)
144 {
145 	int old, errors = 0;
146 
147 	for (; p < end; p++) {
148 		errno = 0;
149 		old = getpriority(p->type, p->id);
150 		if (errno) {
151 			warn("getpriority: %d", p->id);
152 			errors++;
153 			continue;
154 		}
155 		if (setpriority(p->type, p->id, p->pri) == -1) {
156 			warn("setpriority: %d", p->id);
157 			errors++;
158 			continue;
159 		}
160 		printf("%d: old priority %d, new priority %d\n",
161 		    p->id, old, p->pri);
162 	}
163 	return (errors);
164 }
165 
166 __dead void
167 usage(void)
168 {
169 	fprintf(stderr, "usage: renice -n increment [[-g] pgrp ...] "
170 	    "[[-p] pid ...] [[-u] user ...]\n");
171 	exit(1);
172 }
173