start_stop_daemon: add -N <nice> compat
[oweals/busybox.git] / procps / renice.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * renice implementation for busybox
4  *
5  * Copyright (C) 2005  Manuel Novoa III  <mjn3@codepoet.org>
6  *
7  * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
8  */
9
10 /* Notes:
11  *   Setting an absolute priority was obsoleted in SUSv2 and removed
12  *   in SUSv3.  However, the common linux version of renice does
13  *   absolute and not relative.  So we'll continue supporting absolute,
14  *   although the stdout logging has been removed since both SUSv2 and
15  *   SUSv3 specify that stdout isn't used.
16  *
17  *   This version is lenient in that it doesn't require any IDs.  The
18  *   options -p, -g, and -u are treated as mode switches for the
19  *   following IDs (if any).  Multiple switches are allowed.
20  */
21
22 #include "busybox.h"
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <limits.h>
27 #include <errno.h>
28 #include <unistd.h>
29 #include <sys/resource.h>
30
31 #if (PRIO_PROCESS < CHAR_MIN) || (PRIO_PROCESS > CHAR_MAX)
32 #error Assumption violated : PRIO_PROCESS value
33 #endif
34 #if (PRIO_PGRP < CHAR_MIN) || (PRIO_PGRP > CHAR_MAX)
35 #error Assumption violated : PRIO_PGRP value
36 #endif
37 #if (PRIO_USER < CHAR_MIN) || (PRIO_USER > CHAR_MAX)
38 #error Assumption violated : PRIO_USER value
39 #endif
40
41 int renice_main(int argc, char **argv)
42 {
43         static const char Xetpriority_msg[] = "%cetpriority";
44
45         int retval = EXIT_SUCCESS;
46         int which = PRIO_PROCESS;       /* Default 'which' value. */
47         int use_relative = 0;
48         int adjustment, new_priority;
49         unsigned who;
50         char *arg;
51
52         arg = *++argv;
53
54         /* Check if we are using a relative adjustment. */
55         if (arg && arg[0] == '-' && arg[1] == 'n') {
56                 use_relative = 1;
57                 if (!arg[2])
58                         arg = *++argv;
59                 else
60                         arg += 2;
61         }
62
63         if (!arg) {                             /* No args?  Then show usage. */
64                 bb_show_usage();
65         }
66
67         /* Get the priority adjustment (absolute or relative). */
68         adjustment = xatoi_range(arg, INT_MIN/2, INT_MAX/2);
69
70         while ((arg = *++argv) != NULL) {
71                 /* Check for a mode switch. */
72                 if (arg[0] == '-' && arg[1]) {
73                         static const char opts[]
74                                 = { 'p', 'g', 'u', 0, PRIO_PROCESS, PRIO_PGRP, PRIO_USER };
75                         const char *p = strchr(opts, arg[1]);
76                         if (p) {
77                                 which = p[4];
78                                 if (!arg[2])
79                                         continue;
80                                 arg += 2;
81                         }
82                 }
83
84                 /* Process an ID arg. */
85                 if (which == PRIO_USER) {
86                         struct passwd *p;
87                         p = getpwnam(arg);
88                         if (!p) {
89                                 bb_error_msg("unknown user: %s", arg);
90                                 goto HAD_ERROR;
91                         }
92                         who = p->pw_uid;
93                 } else {
94                         if (safe_strtou(arg, &who)) {
95                                 bb_error_msg("bad value: %s", arg);
96                                 goto HAD_ERROR;
97                         }
98                 }
99
100                 /* Get priority to use, and set it. */
101                 if (use_relative) {
102                         int old_priority;
103
104                         errno = 0;       /* Needed for getpriority error detection. */
105                         old_priority = getpriority(which, who);
106                         if (errno) {
107                                 bb_perror_msg(Xetpriority_msg, 'g');
108                                 goto HAD_ERROR;
109                         }
110
111                         new_priority = old_priority + adjustment;
112                 } else {
113                         new_priority = adjustment;
114                 }
115
116                 if (setpriority(which, who, new_priority) == 0) {
117                         continue;
118                 }
119
120                 bb_perror_msg(Xetpriority_msg, 's');
121  HAD_ERROR:
122                 retval = EXIT_FAILURE;
123         }
124
125         /* No need to check for errors outputing to stderr since, if it
126          * was used, the HAD_ERROR label was reached and retval was set. */
127
128         return retval;
129 }