xref: /openbsd/usr.bin/renice/renice.c (revision 425e94d5)
1 /*	$OpenBSD: renice.c,v 1.22 2022/08/12 00:24:07 cheloha Exp $	*/
2 
3 /*
4  * Copyright (c) 2009, 2015 Todd C. Miller <millert@openbsd.org>
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 #include <unistd.h>
32 
33 #define	RENICE_NONE		0
34 #define	RENICE_ABSOLUTE		1
35 #define	RENICE_INCREMENT	2
36 
37 struct renice_param {
38 	int pri;
39 	short pri_type;
40 	short id_type;
41 	id_t id;
42 };
43 
44 int main(int, char **);
45 static int renice(struct renice_param *, struct renice_param *);
46 __dead void usage(void);
47 
48 int
main(int argc,char ** argv)49 main(int argc, char **argv)
50 {
51 	struct renice_param *params, *p;
52 	struct passwd *pw;
53 	int ch, id_type = PRIO_PROCESS;
54 	int pri = 0, pri_type = RENICE_NONE;
55 	char *ep, *idstr;
56 	const char *errstr;
57 
58 	if (pledge("stdio getpw proc", NULL) == -1)
59 		err(1, "pledge");
60 
61 	if (argc < 3)
62 		usage();
63 
64 	/* Allocate enough space for the worst case. */
65 	params = p = reallocarray(NULL, argc - 1, sizeof(*params));
66 	if (params == NULL)
67 		err(1, NULL);
68 
69 	/* Backwards compatibility: first arg may be priority. */
70 	if (isdigit((unsigned char)argv[1][0]) ||
71 	    ((argv[1][0] == '+' || argv[1][0] == '-') &&
72 	    isdigit((unsigned char)argv[1][1]))) {
73 		pri = (int)strtol(argv[1], &ep, 10);
74 		if (*ep != '\0' || ep == argv[1]) {
75 			warnx("invalid priority %s", argv[1]);
76 			usage();
77 		}
78 		pri_type = RENICE_ABSOLUTE;
79 		optind = 2;
80 	}
81 
82 	/*
83 	 * Slightly tricky getopt() usage since it is legal to have
84 	 * option flags interleaved with arguments.
85 	 */
86 	for (;;) {
87 		if ((ch = getopt(argc, argv, "g:n:p:u:")) != -1) {
88 			switch (ch) {
89 			case 'g':
90 				id_type = PRIO_PGRP;
91 				idstr = optarg;
92 				break;
93 			case 'n':
94 				pri = (int)strtol(optarg, &ep, 10);
95 				if (*ep != '\0' || ep == optarg) {
96 					warnx("invalid increment %s", optarg);
97 					usage();
98 				}
99 
100 				/* Set priority for previous entries? */
101 				if (pri_type == RENICE_NONE) {
102 					struct renice_param *pp;
103 					for (pp = params; pp != p; pp++) {
104 						pp->pri = pri;
105 						pp->pri_type = RENICE_INCREMENT;
106 					}
107 				}
108 				pri_type = RENICE_INCREMENT;
109 				continue;
110 			case 'p':
111 				id_type = PRIO_PROCESS;
112 				idstr = optarg;
113 				break;
114 			case 'u':
115 				id_type = PRIO_USER;
116 				idstr = optarg;
117 				break;
118 			default:
119 				usage();
120 				break;
121 			}
122 		} else {
123 			idstr = argv[optind++];
124 			if (idstr == NULL)
125 				break;
126 		}
127 		p->id_type = id_type;
128 		p->pri = pri;
129 		p->pri_type = pri_type;
130 		if (id_type == PRIO_USER) {
131 			if ((pw = getpwnam(idstr)) == NULL) {
132 				uid_t id = strtonum(idstr, 0, UID_MAX, &errstr);
133 				if (!errstr)
134 					pw = getpwuid(id);
135 			}
136 			if (pw == NULL) {
137 				warnx("unknown user %s", idstr);
138 				continue;
139 			}
140 			p->id = pw->pw_uid;
141 		} else {
142 			p->id = strtonum(idstr, 0, UINT_MAX, &errstr);
143 			if (errstr) {
144 				warnx("%s is %s", idstr, errstr);
145 				continue;
146 			}
147 		}
148 		p++;
149 	}
150 	if (pri_type == RENICE_NONE)
151 		usage();
152 	return(renice(params, p));
153 }
154 
155 static int
renice(struct renice_param * p,struct renice_param * end)156 renice(struct renice_param *p, struct renice_param *end)
157 {
158 	int new, old, error = 0;
159 
160 	for (; p < end; p++) {
161 		errno = 0;
162 		old = getpriority(p->id_type, p->id);
163 		if (errno) {
164 			warn("getpriority: %d", p->id);
165 			error = 1;
166 			continue;
167 		}
168 		if (p->pri_type == RENICE_INCREMENT)
169 			p->pri += old;
170 		new = p->pri > PRIO_MAX ? PRIO_MAX :
171 		    p->pri < PRIO_MIN ? PRIO_MIN : p->pri;
172 		if (setpriority(p->id_type, p->id, new) == -1) {
173 			warn("setpriority: %d", p->id);
174 			error = 1;
175 			continue;
176 		}
177 		printf("%d: old priority %d, new priority %d\n",
178 		    p->id, old, new);
179 	}
180 	return error;
181 }
182 
183 __dead void
usage(void)184 usage(void)
185 {
186 	fprintf(stderr, "usage: renice [-n] increment [-gpu] id\n");
187 	exit(1);
188 }
189