busybox/procps/renice.c
<<
>>
Prefs
   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 GPLv2 or later, see file LICENSE in this source tree.
   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//usage:#define renice_trivial_usage
  23//usage:       "{{-n INCREMENT} | PRIORITY} [[-p | -g | -u] ID...]"
  24//usage:#define renice_full_usage "\n\n"
  25//usage:       "Change scheduling priority for a running process\n"
  26//usage:     "\n        -n      Adjust current nice value (smaller is faster)"
  27//usage:     "\n        -p      Process id(s) (default)"
  28//usage:     "\n        -g      Process group id(s)"
  29//usage:     "\n        -u      Process user name(s) and/or id(s)"
  30
  31#include "libbb.h"
  32#include <sys/resource.h>
  33
  34void BUG_bad_PRIO_PROCESS(void);
  35void BUG_bad_PRIO_PGRP(void);
  36void BUG_bad_PRIO_USER(void);
  37
  38int renice_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  39int renice_main(int argc UNUSED_PARAM, char **argv)
  40{
  41        static const char Xetpriority_msg[] ALIGN1 = "%cetpriority";
  42
  43        int retval = EXIT_SUCCESS;
  44        int which = PRIO_PROCESS;  /* Default 'which' value. */
  45        int use_relative = 0;
  46        int adjustment, new_priority;
  47        unsigned who;
  48        char *arg;
  49
  50        /* Yes, they are not #defines in glibc 2.4! #if won't work */
  51        if (PRIO_PROCESS < CHAR_MIN || PRIO_PROCESS > CHAR_MAX)
  52                BUG_bad_PRIO_PROCESS();
  53        if (PRIO_PGRP < CHAR_MIN || PRIO_PGRP > CHAR_MAX)
  54                BUG_bad_PRIO_PGRP();
  55        if (PRIO_USER < CHAR_MIN || PRIO_USER > CHAR_MAX)
  56                BUG_bad_PRIO_USER();
  57
  58        arg = *++argv;
  59
  60        /* Check if we are using a relative adjustment. */
  61        if (arg && arg[0] == '-' && arg[1] == 'n') {
  62                use_relative = 1;
  63                if (!arg[2])
  64                        arg = *++argv;
  65                else
  66                        arg += 2;
  67        }
  68
  69        if (!arg) {  /* No args?  Then show usage. */
  70                bb_show_usage();
  71        }
  72
  73        /* Get the priority adjustment (absolute or relative). */
  74        adjustment = xatoi_range(arg, INT_MIN/2, INT_MAX/2);
  75
  76        while ((arg = *++argv) != NULL) {
  77                /* Check for a mode switch. */
  78                if (arg[0] == '-' && arg[1]) {
  79                        static const char opts[] ALIGN1 = {
  80                                'p', 'g', 'u', 0, PRIO_PROCESS, PRIO_PGRP, PRIO_USER
  81                        };
  82                        const char *p = strchr(opts, arg[1]);
  83                        if (p) {
  84                                which = p[4];
  85                                if (!arg[2])
  86                                        continue;
  87                                arg += 2;
  88                        }
  89                }
  90
  91                /* Process an ID arg. */
  92                if (which == PRIO_USER) {
  93                        struct passwd *p;
  94                        p = getpwnam(arg);
  95                        if (!p) {
  96                                bb_error_msg("unknown user %s", arg);
  97                                goto HAD_ERROR;
  98                        }
  99                        who = p->pw_uid;
 100                } else {
 101                        who = bb_strtou(arg, NULL, 10);
 102                        if (errno) {
 103                                bb_error_msg("invalid number '%s'", arg);
 104                                goto HAD_ERROR;
 105                        }
 106                }
 107
 108                /* Get priority to use, and set it. */
 109                if (use_relative) {
 110                        int old_priority;
 111
 112                        errno = 0;  /* Needed for getpriority error detection. */
 113                        old_priority = getpriority(which, who);
 114                        if (errno) {
 115                                bb_perror_msg(Xetpriority_msg, 'g');
 116                                goto HAD_ERROR;
 117                        }
 118
 119                        new_priority = old_priority + adjustment;
 120                } else {
 121                        new_priority = adjustment;
 122                }
 123
 124                if (setpriority(which, who, new_priority) == 0) {
 125                        continue;
 126                }
 127
 128                bb_perror_msg(Xetpriority_msg, 's');
 129 HAD_ERROR:
 130                retval = EXIT_FAILURE;
 131        }
 132
 133        /* No need to check for errors outputing to stderr since, if it
 134         * was used, the HAD_ERROR label was reached and retval was set. */
 135
 136        return retval;
 137}
 138