Update to upstream util-linux 2.20.1
[framework/base/util-linux-ng.git] / schedutils / ionice.c
index 082b23b..1852975 100644 (file)
 #include <errno.h>
 #include <getopt.h>
 #include <unistd.h>
-#include <sys/ptrace.h>
 #include <sys/syscall.h>
-#include <asm/unistd.h>
-#include <err.h>
+#include <ctype.h>
 
 #include "nls.h"
+#include "strutils.h"
+#include "c.h"
 
 static int tolerant;
 
@@ -43,150 +43,194 @@ enum {
        IOPRIO_WHO_USER,
 };
 
-#define IOPRIO_CLASS_SHIFT     13
+#define IOPRIO_CLASS_SHIFT     (13)
+#define IOPRIO_PRIO_MASK       ((1UL << IOPRIO_CLASS_SHIFT) - 1)
 
-const char *to_prio[] = { "none", "realtime", "best-effort", "idle", };
+#define IOPRIO_PRIO_CLASS(mask)        ((mask) >> IOPRIO_CLASS_SHIFT)
+#define IOPRIO_PRIO_DATA(mask) ((mask) & IOPRIO_PRIO_MASK)
+#define IOPRIO_PRIO_VALUE(class, data) (((class) << IOPRIO_CLASS_SHIFT) | data)
 
-static void ioprio_print(int pid)
+const char *to_prio[] = {
+       [IOPRIO_CLASS_NONE] = "none",
+       [IOPRIO_CLASS_RT]   = "realtime",
+       [IOPRIO_CLASS_BE]   = "best-effort",
+       [IOPRIO_CLASS_IDLE] = "idle"
+};
+
+static int parse_ioclass(const char *str)
 {
-       int ioprio, ioclass;
+       size_t i;
 
-       ioprio = ioprio_get(IOPRIO_WHO_PROCESS, pid);
+       for (i = 0; i < ARRAY_SIZE(to_prio); i++)
+               if (!strcasecmp(str, to_prio[i]))
+                       return i;
+       return -1;
+}
+
+static void ioprio_print(int pid)
+{
+       int ioprio = ioprio_get(IOPRIO_WHO_PROCESS, pid);
 
        if (ioprio == -1)
                err(EXIT_FAILURE, _("ioprio_get failed"));
        else {
-               ioclass = ioprio >> IOPRIO_CLASS_SHIFT;
-               if (ioclass != IOPRIO_CLASS_IDLE) {
-                       ioprio = ioprio & 0xff;
-                       printf("%s: prio %d\n", to_prio[ioclass], ioprio);
-               } else
-                       printf("%s\n", to_prio[ioclass]);
+               int ioclass = IOPRIO_PRIO_CLASS(ioprio);
+               const char *name = _("unknown");
+
+               if (ioclass > 0 && (size_t) ioclass < ARRAY_SIZE(to_prio))
+                       name = to_prio[ioclass];
+
+               if (ioclass != IOPRIO_CLASS_IDLE)
+                       printf("%s: prio %lu\n", name,
+                                       IOPRIO_PRIO_DATA(ioprio));
+               else
+                       printf("%s\n", name);
        }
 }
 
-
-static void ioprio_setpid(pid_t pid, int ioprio, int ioclass)
+static void ioprio_setpid(pid_t pid, int ioclass, int data)
 {
        int rc = ioprio_set(IOPRIO_WHO_PROCESS, pid,
-                       ioprio | ioclass << IOPRIO_CLASS_SHIFT);
+                           IOPRIO_PRIO_VALUE(ioclass, data));
 
        if (rc == -1 && !tolerant)
                err(EXIT_FAILURE, _("ioprio_set failed"));
 }
 
-static void usage(int rc)
-{
-       fprintf(stdout, _(
-       "\nionice - sets or gets process io scheduling class and priority.\n"
-       "\nUsage:\n"
-       "  ionice [ options ] -p <pid> [<pid> ...]\n"
-       "  ionoce [ options ] <command> [<arg> ...]\n"
-       "\nOptions:\n"
-       "  -n <classdata>      class data (0-7, lower being higher prio)\n"
-       "  -c <class>          scheduling class\n"
-       "                      0: none, 1: realtime, 2: best-effort, 3: idle\n"
-       "  -t                  ignore failures\n"
-       "  -h                  this help\n\n"));
-       exit(rc);
-}
-
-static long getnum(const char *str)
+static void __attribute__ ((__noreturn__)) usage(FILE * out)
 {
-       long num;
-       char *end = NULL;
-
-       if (str == NULL || *str == '\0')
-               goto err;
-       errno = 0;
-       num = strtol(str, &end, 10);
-
-       if (errno || (end && *end))
-               goto err;
-
-       return num;
-err:
-       if (errno)
-               err(EXIT_SUCCESS, _("cannot parse number '%s'"), str);
-       else
-               errx(EXIT_SUCCESS, _("cannot parse number '%s'"), str);
-       return 0;
+       fprintf(out,
+              _("\n"
+                "%1$s - sets or gets process io scheduling class and priority.\n"
+                "\n"
+                "Usage:\n"
+                "  %1$s [OPTION] -p PID [PID...]\n"
+                "  %1$s [OPTION] COMMAND\n"
+                "\n"
+                "Options:\n"
+                "  -c, --class <class>   scheduling class name or number\n"
+                "                           0: none, 1: realtime, 2: best-effort, 3: idle\n"
+                "  -n, --classdata <num> scheduling class data\n"
+                "                           0-7 for realtime and best-effort classes\n"
+                "  -p, --pid=PID         view or modify already running process\n"
+                "  -t, --ignore          ignore failures\n"
+                "  -V, --version         output version information and exit\n"
+                "  -h, --help            display this help and exit\n\n"),
+               program_invocation_short_name);
+
+       exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
 }
 
-int main(int argc, char *argv[])
+int main(int argc, char **argv)
 {
-       int ioprio = 4, set = 0, ioclass = IOPRIO_CLASS_BE, c;
+       int data = 4, set = 0, ioclass = IOPRIO_CLASS_BE, c;
        pid_t pid = 0;
 
+       static const struct option longopts[] = {
+               { "classdata", required_argument, NULL, 'n' },
+               { "class",     required_argument, NULL, 'c' },
+               { "help",      no_argument,       NULL, 'h' },
+               { "ignore",    no_argument,       NULL, 't' },
+               { "pid",       required_argument, NULL, 'p' },
+               { "version",   no_argument,       NULL, 'V' },
+               { NULL, 0, NULL, 0 }
+       };
+
        setlocale(LC_ALL, "");
        bindtextdomain(PACKAGE, LOCALEDIR);
        textdomain(PACKAGE);
 
-       while ((c = getopt(argc, argv, "+n:c:p:th")) != EOF) {
+       while ((c = getopt_long(argc, argv, "+n:c:p:tVh", longopts, NULL)) != EOF)
                switch (c) {
                case 'n':
-                       ioprio = getnum(optarg);
+                       data = strtol_or_err(optarg, _("failed to parse class data"));
                        set |= 1;
                        break;
                case 'c':
-                       ioclass = getnum(optarg);
+                       if (isdigit(*optarg))
+                               ioclass = strtol_or_err(optarg,
+                                               _("failed to parse class"));
+                       else {
+                               ioclass = parse_ioclass(optarg);
+                               if (ioclass < 0)
+                                       errx(EXIT_FAILURE,
+                                               _("unknown scheduling class: '%s'"),
+                                               optarg);
+                       }
                        set |= 2;
                        break;
                case 'p':
-                       pid = getnum(optarg);
+                       pid = strtol_or_err(optarg, _("failed to parse pid"));
                        break;
                case 't':
                        tolerant = 1;
                        break;
+               case 'V':
+                       printf(_("%s from %s\n"),
+                               program_invocation_short_name, PACKAGE_STRING);
+                       return EXIT_SUCCESS;
                case 'h':
-                       usage(EXIT_SUCCESS);
+                       usage(stdout);
                default:
-                       usage(EXIT_FAILURE);
+                       usage(stderr);
                }
-       }
 
        switch (ioclass) {
                case IOPRIO_CLASS_NONE:
-                       if (set & 1)
+                       if ((set & 1) && !tolerant)
                                warnx(_("ignoring given class data for none class"));
-                       ioprio = 0;
+                       data = 0;
                        break;
                case IOPRIO_CLASS_RT:
                case IOPRIO_CLASS_BE:
                        break;
                case IOPRIO_CLASS_IDLE:
-                       if (set & 1)
+                       if ((set & 1) && !tolerant)
                                warnx(_("ignoring given class data for idle class"));
-                       ioprio = 7;
+                       data = 7;
                        break;
                default:
-                       errx(EXIT_FAILURE, _("bad prio class %d"), ioclass);
+                       if (!tolerant)
+                               warnx(_("unknown prio class %d"), ioclass);
+                       break;
        }
 
-       if (!set) {
+       if (!set && !pid && optind == argc)
+               /*
+                * ionice without options, print the current ioprio
+                */
+               ioprio_print(0);
+
+       else if (!set && pid) {
+               /*
+                * ionice -p PID [PID ...]
+                */
                ioprio_print(pid);
 
                for(; argv[optind]; ++optind) {
-                       pid = getnum(argv[optind]);
+                       pid = strtol_or_err(argv[optind], _("failed to parse pid"));
                        ioprio_print(pid);
                }
-       } else {
-               if (pid) {
-                       ioprio_setpid(pid, ioprio, ioclass);
-
-                       for(; argv[optind]; ++optind)
-                       {
-                               pid = getnum(argv[optind]);
-                               ioprio_setpid(pid, ioprio, ioclass);
-                       }
-               }
-               else if (argv[optind]) {
-                       ioprio_setpid(0, ioprio, ioclass);
-                       execvp(argv[optind], &argv[optind]);
-                       /* execvp should never return */
-                       err(EXIT_FAILURE, _("execvp failed"));
-               }
-       }
+       } else if (set && pid) {
+               /*
+                * ionice -c CLASS -p PID [PID ...]
+                */
+               ioprio_setpid(pid, ioclass, data);
 
-       exit(EXIT_SUCCESS);
+               for(; argv[optind]; ++optind) {
+                       pid = strtol_or_err(argv[optind], _("failed to parse pid"));
+                       ioprio_setpid(pid, ioclass, data);
+               }
+       } else if (argv[optind]) {
+               /*
+                * ionice [-c CLASS] COMMAND
+                */
+               ioprio_setpid(0, ioclass, data);
+               execvp(argv[optind], &argv[optind]);
+               err(EXIT_FAILURE, _("executing %s failed"), argv[optind]);
+       } else
+               usage(stderr);
+
+
+       return EXIT_SUCCESS;
 }