summaryrefslogtreecommitdiff
path: root/procps/renice.c
blob: 2b690e0ed0744707a1b263cb8695a163f43c4147 (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 GPLv2 or later, see file LICENSE in this source tree.
 */

/* 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.
 */

//usage:#define renice_trivial_usage
//usage:       "[-n] PRIORITY [[-p | -g | -u] ID...]..."
//usage:#define renice_full_usage "\n\n"
//usage:       "Change scheduling priority of a running process\n"
//usage:     "\n	-n	Add PRIORITY to current nice value"
//usage:     "\n		Without -n, nice value is set to PRIORITY"
//usage:     "\n	-p	Process ids (default)"
//usage:     "\n	-g	Process group ids"
//usage:     "\n	-u	Process user names"

#include "libbb.h"
#include <sys/resource.h>

void BUG_bad_PRIO_PROCESS(void);
void BUG_bad_PRIO_PGRP(void);
void BUG_bad_PRIO_USER(void);

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

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

	/* Yes, they are not #defines in glibc 2.4! #if won't work */
	if (PRIO_PROCESS < CHAR_MIN || PRIO_PROCESS > CHAR_MAX)
		BUG_bad_PRIO_PROCESS();
	if (PRIO_PGRP < CHAR_MIN || PRIO_PGRP > CHAR_MAX)
		BUG_bad_PRIO_PGRP();
	if (PRIO_USER < CHAR_MIN || PRIO_USER > CHAR_MAX)
		BUG_bad_PRIO_USER();

	arg = *++argv;

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

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

	/* Get the priority adjustment (absolute or relative). */
	adjustment = xatoi_range(arg, INT_MIN/2, INT_MAX/2);

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

		/* Process an ID arg. */
		if (which == PRIO_USER) {
			struct passwd *p;
			p = getpwnam(arg);
			if (!p) {
				bb_error_msg("unknown user %s", arg);
				goto HAD_ERROR;
			}
			who = p->pw_uid;
		} else {
			who = bb_strtou(arg, NULL, 10);
			if (errno) {
				bb_error_msg("invalid number '%s'", arg);
				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, 'g');
				goto HAD_ERROR;
			}

			new_priority = old_priority + adjustment;
		} else {
			new_priority = adjustment;
		}

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

		bb_perror_msg(Xetpriority_msg, '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;
}