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