|  | /* | 
|  | * ionice: set or get process io scheduling class and priority | 
|  | * | 
|  | * Copyright (C) 2005 Jens Axboe <jens@axboe.dk> | 
|  | * | 
|  | * Released under the terms of the GNU General Public License version 2 | 
|  | * | 
|  | */ | 
|  | #include <stdio.h> | 
|  | #include <stdlib.h> | 
|  | #include <errno.h> | 
|  | #include <getopt.h> | 
|  | #include <unistd.h> | 
|  | #include <sys/syscall.h> | 
|  | #include <ctype.h> | 
|  |  | 
|  | #include "nls.h" | 
|  | #include "strutils.h" | 
|  | #include "c.h" | 
|  | #include "closestream.h" | 
|  |  | 
|  | static int tolerant; | 
|  |  | 
|  | static inline int ioprio_set(int which, int who, int ioprio) | 
|  | { | 
|  | return syscall(SYS_ioprio_set, which, who, ioprio); | 
|  | } | 
|  |  | 
|  | static inline int ioprio_get(int which, int who) | 
|  | { | 
|  | return syscall(SYS_ioprio_get, which, who); | 
|  | } | 
|  |  | 
|  | enum { | 
|  | IOPRIO_CLASS_NONE, | 
|  | IOPRIO_CLASS_RT, | 
|  | IOPRIO_CLASS_BE, | 
|  | IOPRIO_CLASS_IDLE, | 
|  | }; | 
|  |  | 
|  | enum { | 
|  | IOPRIO_WHO_PROCESS = 1, | 
|  | IOPRIO_WHO_PGRP, | 
|  | IOPRIO_WHO_USER, | 
|  | }; | 
|  |  | 
|  | #define IOPRIO_CLASS_SHIFT	(13) | 
|  | #define IOPRIO_PRIO_MASK	((1UL << IOPRIO_CLASS_SHIFT) - 1) | 
|  |  | 
|  | #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) | 
|  |  | 
|  | 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) | 
|  | { | 
|  | size_t i; | 
|  |  | 
|  | 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 who) | 
|  | { | 
|  | int ioprio = ioprio_get(who, pid); | 
|  |  | 
|  | if (ioprio == -1) | 
|  | err(EXIT_FAILURE, _("ioprio_get failed")); | 
|  | else { | 
|  | 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_setid(int which, int ioclass, int data, int who) | 
|  | { | 
|  | int rc = ioprio_set(who, which, | 
|  | IOPRIO_PRIO_VALUE(ioclass, data)); | 
|  |  | 
|  | if (rc == -1 && !tolerant) | 
|  | err(EXIT_FAILURE, _("ioprio_set failed")); | 
|  | } | 
|  |  | 
|  | static void __attribute__ ((__noreturn__)) usage(FILE * out) | 
|  | { | 
|  | fputs(USAGE_HEADER, out); | 
|  | fprintf(out,  _(" %1$s [options] -p <pid>...\n" | 
|  | " %1$s [options] -P <pgid>...\n" | 
|  | " %1$s [options] -u <uid>...\n" | 
|  | " %1$s [options] <command>\n"), program_invocation_short_name); | 
|  |  | 
|  | fputs(USAGE_SEPARATOR, out); | 
|  | fputs(_("Show or change the I/O-scheduling class and priority of a process.\n"), out); | 
|  |  | 
|  | fputs(USAGE_OPTIONS, out); | 
|  | fputs(_(" -c, --class <class>    name or number of scheduling class,\n" | 
|  | "                          0: none, 1: realtime, 2: best-effort, 3: idle\n"), out); | 
|  | fputs(_(" -n, --classdata <num>  priority (0..7) in the specified scheduling class,\n" | 
|  | "                          only for the realtime and best-effort classes\n"), out); | 
|  | fputs(_(" -p, --pid <pid>...     act on these already running processes\n"), out); | 
|  | fputs(_(" -P, --pgid <pgrp>...   act on already running processes in these groups\n"), out); | 
|  | fputs(_(" -t, --ignore           ignore failures\n"), out); | 
|  | fputs(_(" -u, --uid <uid>...     act on already running processes owned by these users\n"), out); | 
|  |  | 
|  | fputs(USAGE_SEPARATOR, out); | 
|  | fputs(USAGE_HELP, out); | 
|  | fputs(USAGE_VERSION, out); | 
|  |  | 
|  | fprintf(out, USAGE_MAN_TAIL("ionice(1)")); | 
|  |  | 
|  | exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS); | 
|  | } | 
|  |  | 
|  | int main(int argc, char **argv) | 
|  | { | 
|  | int data = 4, set = 0, ioclass = IOPRIO_CLASS_BE, c; | 
|  | int which = 0, who = 0; | 
|  | const char *invalid_msg = NULL; | 
|  |  | 
|  | 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' }, | 
|  | { "pgid",      required_argument, NULL, 'P' }, | 
|  | { "uid",       required_argument, NULL, 'u' }, | 
|  | { "version",   no_argument,       NULL, 'V' }, | 
|  | { NULL, 0, NULL, 0 } | 
|  | }; | 
|  |  | 
|  | setlocale(LC_ALL, ""); | 
|  | bindtextdomain(PACKAGE, LOCALEDIR); | 
|  | textdomain(PACKAGE); | 
|  | atexit(close_stdout); | 
|  |  | 
|  | while ((c = getopt_long(argc, argv, "+n:c:p:P:u:tVh", longopts, NULL)) != EOF) | 
|  | switch (c) { | 
|  | case 'n': | 
|  | data = strtos32_or_err(optarg, _("invalid class data argument")); | 
|  | set |= 1; | 
|  | break; | 
|  | case 'c': | 
|  | if (isdigit(*optarg)) | 
|  | ioclass = strtos32_or_err(optarg, | 
|  | _("invalid class argument")); | 
|  | else { | 
|  | ioclass = parse_ioclass(optarg); | 
|  | if (ioclass < 0) | 
|  | errx(EXIT_FAILURE, | 
|  | _("unknown scheduling class: '%s'"), | 
|  | optarg); | 
|  | } | 
|  | set |= 2; | 
|  | break; | 
|  | case 'p': | 
|  | if (who) | 
|  | errx(EXIT_FAILURE, | 
|  | _("can handle only one of pid, pgid or uid at once")); | 
|  | invalid_msg = _("invalid PID argument"); | 
|  | which = strtos32_or_err(optarg, invalid_msg); | 
|  | who = IOPRIO_WHO_PROCESS; | 
|  | break; | 
|  | case 'P': | 
|  | if (who) | 
|  | errx(EXIT_FAILURE, | 
|  | _("can handle only one of pid, pgid or uid at once")); | 
|  | invalid_msg = _("invalid PGID argument"); | 
|  | which = strtos32_or_err(optarg, invalid_msg); | 
|  | who = IOPRIO_WHO_PGRP; | 
|  | break; | 
|  | case 'u': | 
|  | if (who) | 
|  | errx(EXIT_FAILURE, | 
|  | _("can handle only one of pid, pgid or uid at once")); | 
|  | invalid_msg = _("invalid UID argument"); | 
|  | which = strtos32_or_err(optarg, invalid_msg); | 
|  | who = IOPRIO_WHO_USER; | 
|  | break; | 
|  | case 't': | 
|  | tolerant = 1; | 
|  | break; | 
|  | case 'V': | 
|  | printf(UTIL_LINUX_VERSION); | 
|  | return EXIT_SUCCESS; | 
|  | case 'h': | 
|  | usage(stdout); | 
|  | default: | 
|  | usage(stderr); | 
|  | } | 
|  |  | 
|  | switch (ioclass) { | 
|  | case IOPRIO_CLASS_NONE: | 
|  | if ((set & 1) && !tolerant) | 
|  | warnx(_("ignoring given class data for none class")); | 
|  | data = 0; | 
|  | break; | 
|  | case IOPRIO_CLASS_RT: | 
|  | case IOPRIO_CLASS_BE: | 
|  | break; | 
|  | case IOPRIO_CLASS_IDLE: | 
|  | if ((set & 1) && !tolerant) | 
|  | warnx(_("ignoring given class data for idle class")); | 
|  | data = 7; | 
|  | break; | 
|  | default: | 
|  | if (!tolerant) | 
|  | warnx(_("unknown prio class %d"), ioclass); | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (!set && !which && optind == argc) | 
|  | /* | 
|  | * ionice without options, print the current ioprio | 
|  | */ | 
|  | ioprio_print(0, IOPRIO_WHO_PROCESS); | 
|  | else if (!set && who) { | 
|  | /* | 
|  | * ionice -p|-P|-u ID [ID ...] | 
|  | */ | 
|  | ioprio_print(which, who); | 
|  |  | 
|  | for(; argv[optind]; ++optind) { | 
|  | which = strtos32_or_err(argv[optind], invalid_msg); | 
|  | ioprio_print(which, who); | 
|  | } | 
|  | } else if (set && who) { | 
|  | /* | 
|  | * ionice -c CLASS -p|-P|-u ID [ID ...] | 
|  | */ | 
|  | ioprio_setid(which, ioclass, data, who); | 
|  |  | 
|  | for(; argv[optind]; ++optind) { | 
|  | which = strtos32_or_err(argv[optind], invalid_msg); | 
|  | ioprio_setid(which, ioclass, data, who); | 
|  | } | 
|  | } else if (argv[optind]) { | 
|  | /* | 
|  | * ionice [-c CLASS] COMMAND | 
|  | */ | 
|  | ioprio_setid(0, ioclass, data, IOPRIO_WHO_PROCESS); | 
|  | execvp(argv[optind], &argv[optind]); | 
|  | err(EXIT_FAILURE, _("failed to execute %s"), argv[optind]); | 
|  | } else | 
|  | usage(stderr); | 
|  |  | 
|  |  | 
|  | return EXIT_SUCCESS; | 
|  | } |