1/*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 1983, 1989, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include <sys/types.h>
33#include <sys/time.h>
34#include <sys/resource.h>
35
36#include <err.h>
37#include <errno.h>
38#include <limits.h>
39#include <pwd.h>
40#include <stdbool.h>
41#include <stdio.h>
42#include <stdlib.h>
43#include <string.h>
44
45static int	donice(int, int, int, bool);
46static int	getnum(const char *, const char *, int *);
47static void	usage(void);
48
49/*
50 * Change the priority (nice) of processes
51 * or groups of processes which are already
52 * running.
53 */
54int
55main(int argc, char *argv[])
56{
57	struct passwd *pwd;
58	bool havedelim = false, haveprio = false, incr = false;
59	int errs = 0, prio = 0, who = 0, which = PRIO_PROCESS;
60
61	for (argc--, argv++; argc > 0; argc--, argv++) {
62		if (!havedelim) {
63			/* can occur at any time prior to delimiter */
64			if (strcmp(*argv, "-g") == 0) {
65				which = PRIO_PGRP;
66				continue;
67			}
68			if (strcmp(*argv, "-u") == 0) {
69				which = PRIO_USER;
70				continue;
71			}
72			if (strcmp(*argv, "-p") == 0) {
73				which = PRIO_PROCESS;
74				continue;
75			}
76			if (strcmp(*argv, "--") == 0) {
77				havedelim = true;
78				continue;
79			}
80			if (strcmp(*argv, "-n") == 0) {
81				/* may occur only once, prior to priority */
82				if (haveprio || incr || argc < 2)
83					usage();
84				incr = true;
85				(void)argc--, argv++;
86				/* fall through to priority */
87			}
88		}
89		if (!haveprio) {
90			/* must occur exactly once, prior to target */
91			if (getnum("priority", *argv, &prio))
92				return (1);
93			haveprio = true;
94			continue;
95		}
96		if (which == PRIO_USER) {
97			if ((pwd = getpwnam(*argv)) != NULL)
98				who = pwd->pw_uid;
99			else if (getnum("uid", *argv, &who)) {
100				errs++;
101				continue;
102			} else if (who < 0) {
103				warnx("%s: bad value", *argv);
104				errs++;
105				continue;
106			}
107		} else {
108			if (getnum("pid", *argv, &who)) {
109				errs++;
110				continue;
111			}
112			if (who < 0) {
113				warnx("%s: bad value", *argv);
114				errs++;
115				continue;
116			}
117		}
118		errs += donice(which, who, prio, incr);
119	}
120	if (!haveprio)
121		usage();
122	exit(errs != 0);
123}
124
125static int
126donice(int which, int who, int prio, bool incr)
127{
128	int oldprio;
129
130	errno = 0;
131	oldprio = getpriority(which, who);
132	if (oldprio == -1 && errno) {
133		warn("%d: getpriority", who);
134		return (1);
135	}
136	if (incr)
137		prio = oldprio + prio;
138	if (prio > PRIO_MAX)
139		prio = PRIO_MAX;
140	if (prio < PRIO_MIN)
141		prio = PRIO_MIN;
142	if (setpriority(which, who, prio) < 0) {
143		warn("%d: setpriority", who);
144		return (1);
145	}
146	fprintf(stderr, "%d: old priority %d, new priority %d\n", who,
147	    oldprio, prio);
148	return (0);
149}
150
151static int
152getnum(const char *com, const char *str, int *val)
153{
154	long v;
155	char *ep;
156
157	errno = 0;
158	v = strtol(str, &ep, 10);
159	if (v < INT_MIN || v > INT_MAX || errno == ERANGE) {
160		warnx("%s argument %s is out of range.", com, str);
161		return (1);
162	}
163	if (ep == str || *ep != '\0' || errno != 0) {
164		warnx("%s argument %s is invalid.", com, str);
165		return (1);
166	}
167
168	*val = (int)v;
169	return (0);
170}
171
172static void
173usage(void)
174{
175	fprintf(stderr, "%s\n%s\n",
176"usage: renice priority [[-p] pid ...] [[-g] pgrp ...] [[-u] user ...]",
177"       renice -n increment [[-p] pid ...] [[-g] pgrp ...] [[-u] user ...]");
178	exit(1);
179}
180