aboutsummaryrefslogtreecommitdiff
path: root/procps/renice.c
blob: 53dc5785536ef647557c2639d631c99c3c43d06f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/* vi: set sw=4 ts=4: */
/*
 * renice implementation for busybox
 *
 * Copyright (C) 2005  Manuel Novoa III  <mjn3@codepoet.org>
 *
 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
 */

/* Notes:
 *   Setting an absolute priority was obsoleted in SUSv2 and removed
 *   in SUSv3.  However, the common linux version of renice does
 *   absolute and not relative.  So we'll continue supporting absolute,
 *   although the stdout logging has been removed since both SUSv2 and
 *   SUSv3 specify that stdout isn't used.
 *
 *   This version is lenient in that it doesn't require any IDs.  The
 *   options -p, -g, and -u are treated as mode switches for the
 *   following IDs (if any).  Multiple switches are allowed.
 */

#include "busybox.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <errno.h>
#include <unistd.h>
#include <sys/resource.h>

#if (PRIO_PROCESS < CHAR_MIN) || (PRIO_PROCESS > CHAR_MAX)
#error Assumption violated : PRIO_PROCESS value
#endif
#if (PRIO_PGRP < CHAR_MIN) || (PRIO_PGRP > CHAR_MAX)
#error Assumption violated : PRIO_PGRP value
#endif
#if (PRIO_USER < CHAR_MIN) || (PRIO_USER > CHAR_MAX)
#error Assumption violated : PRIO_USER value
#endif

static inline int int_add_no_wrap(int a, int b)
{
	int s = a + b;

	if (b < 0) {
		if (s > a) s = INT_MIN;
	} else {
		if (s < a) s = INT_MAX;
	}

	return s;
}

int renice_main(int argc, char **argv)
{
	static const char Xetpriority_msg[] = "%d : %cetpriority";

	int retval = EXIT_SUCCESS;
	int which = PRIO_PROCESS;	/* Default 'which' value. */
	int use_relative = 0;
	int adjustment, new_priority;
	id_t who;

	++argv;

	/* Check if we are using a relative adjustment. */
	if (argv[0] && (argv[0][0] == '-') && (argv[0][1] == 'n') && !argv[0][2]) {
		use_relative = 1;
		++argv;
	}

	if (!*argv) {				/* No args?  Then show usage. */
		bb_show_usage();
	}

	/* Get the priority adjustment (absolute or relative). */
	adjustment = bb_xgetlarg(*argv, 10, INT_MIN, INT_MAX);

	while (*++argv) {
		/* Check for a mode switch. */
		if ((argv[0][0] == '-') && argv[0][1] && !argv[0][2]) {
			static const char opts[]
				= { 'p', 'g', 'u', 0, PRIO_PROCESS, PRIO_PGRP, PRIO_USER };
			const char *p;
			if ((p = strchr(opts, argv[0][1]))) {
				which = p[4];
				continue;
			}
		}

		/* Process an ID arg. */
		if (which == PRIO_USER) {
			struct passwd *p;
			if (!(p = getpwnam(*argv))) {
				bb_error_msg("unknown user: %s", *argv);
				goto HAD_ERROR;
			}
			who = p->pw_uid;
		} else {
			char *e;
			errno = 0;
			who = strtoul(*argv, &e, 10);
			if (*e || (*argv == e) || errno) {
				bb_error_msg("bad value: %s", *argv);
				goto HAD_ERROR;
			}
		}

		/* Get priority to use, and set it. */
		if (use_relative) {
			int old_priority;

			errno = 0;	 /* Needed for getpriority error detection. */
			old_priority = getpriority(which, who);
			if (errno) {
				bb_perror_msg(Xetpriority_msg, who, 'g');
				goto HAD_ERROR;
			}

			new_priority = int_add_no_wrap(old_priority, adjustment);
		} else {
			new_priority = adjustment;
		}

		if (setpriority(which, who, new_priority) == 0) {
			continue;
		}

		bb_perror_msg(Xetpriority_msg, who, 's');
	HAD_ERROR:
		retval = EXIT_FAILURE;
	}

	/* No need to check for errors outputing to stderr since, if it
	 * was used, the HAD_ERROR label was reached and retval was set. */

	return retval;
}