/*
* ionice: set or get process io scheduling class and priority
*
- * Copyright (C) 2005 Jens Axboe <axboe@suse.de> SUSE Labs
+ * Copyright (C) 2005 Jens Axboe <jens@axboe.dk>
*
* Released under the terms of the GNU General Public License version 2
*
#include <errno.h>
#include <getopt.h>
#include <unistd.h>
-#include <sys/ptrace.h>
#include <sys/syscall.h>
-#include <asm/unistd.h>
-
-#if !defined(SYS_ioprio_get) || !defined(SYS_ioprio_set)
-
-# if defined(__i386__)
-# define __NR_ioprio_set 289
-# define __NR_ioprio_get 290
-# elif defined(__powerpc__) || defined(__powerpc64__)
-# define __NR_ioprio_set 273
-# define __NR_ioprio_get 274
-# elif defined(__x86_64__)
-# define __NR_ioprio_set 251
-# define __NR_ioprio_get 252
-# elif defined(__ia64__)
-# define __NR_ioprio_set 1274
-# define __NR_ioprio_get 1275
-# elif defined(__alpha__)
-# define __NR_ioprio_set 442
-# define __NR_ioprio_get 443
-# elif defined(__s390x__) || defined(__s390__)
-# define __NR_ioprio_set 282
-# define __NR_ioprio_get 283
-# elif defined(__sparc__) || defined(__sparc64__)
-# define __NR_ioprio_set 196
-# define __NR_ioprio_get 218
-# else
-# error "Unsupported arch"
-# endif
-
-# define SYS_ioprio_get __NR_ioprio_get
-# define SYS_ioprio_set __NR_ioprio_set
-
-#endif /* !SYS_ioprio_get */
+#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)
{
IOPRIO_WHO_USER,
};
-#define IOPRIO_CLASS_SHIFT 13
+#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)
+
+static 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));
-const char *to_prio[] = { "none", "realtime", "best-effort", "idle", };
+ if (rc == -1 && !tolerant)
+ err(EXIT_FAILURE, _("ioprio_set failed"));
+}
-static void usage(void)
+static void __attribute__((__noreturn__)) usage(void)
{
- printf("Usage: ionice [OPTIONS] [COMMAND [ARG]...]\n");
- printf("Sets or gets process io scheduling class and priority.\n");
- printf("\n\t-n\tClass data (typically 0-7, lower being higher prio)\n");
- printf("\t-c\tScheduling class\n");
- printf("\t\t\t1: realtime, 2: best-effort, 3: idle\n");
- printf("\t-p\tProcess pid\n");
- printf("\t-h\tThis help page\n");
- printf("\nJens Axboe <axboe@suse.de> (C) 2005\n");
+ FILE *out = stdout;
+ 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);
+ printf(USAGE_HELP_OPTIONS(24));
+
+ printf(USAGE_MAN_TAIL("ionice(1)"));
+
+ exit(EXIT_SUCCESS);
}
-int main(int argc, char *argv[])
+int main(int argc, char **argv)
{
- int ioprio = 4, set = 0, ioprio_class = IOPRIO_CLASS_BE;
- int c, pid = 0;
+ 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 }
+ };
- while ((c = getopt(argc, argv, "+n:c:p:h")) != EOF) {
+ 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':
- ioprio = strtol(optarg, NULL, 10);
- set = 1;
+ data = strtos32_or_err(optarg, _("invalid class data argument"));
+ set |= 1;
break;
case 'c':
- ioprio_class = strtol(optarg, NULL, 10);
- set = 1;
+ 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':
- pid = strtol(optarg, NULL, 10);
+ 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':
- default:
usage();
- exit(0);
+ default:
+ errtryhelp(EXIT_FAILURE);
}
- }
- switch (ioprio_class) {
+ switch (ioclass) {
case IOPRIO_CLASS_NONE:
- ioprio_class = IOPRIO_CLASS_BE;
+ 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:
- ioprio = 7;
+ if ((set & 1) && !tolerant)
+ warnx(_("ignoring given class data for idle class"));
+ data = 7;
break;
default:
- printf("bad prio class %d\n", ioprio_class);
- return 1;
+ if (!tolerant)
+ warnx(_("unknown prio class %d"), ioclass);
+ break;
}
- if (!set) {
- if (!pid && argv[optind])
- pid = strtol(argv[optind], NULL, 10);
+ 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);
- ioprio = ioprio_get(IOPRIO_WHO_PROCESS, pid);
+ 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);
- if (ioprio == -1)
- perror("ioprio_get");
- else {
- ioprio_class = ioprio >> IOPRIO_CLASS_SHIFT;
- ioprio = ioprio & 0xff;
- printf("%s: prio %d\n", to_prio[ioprio_class], ioprio);
+ 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]);
+ errexec(argv[optind]);
} else {
- if (ioprio_set(IOPRIO_WHO_PROCESS, pid, ioprio | ioprio_class << IOPRIO_CLASS_SHIFT) == -1) {
- perror("ioprio_set");
- return 1;
- }
-
- if (argv[optind])
- execvp(argv[optind], &argv[optind]);
+ warnx(_("bad usage"));
+ errtryhelp(EXIT_FAILURE);
}
- return 0;
+ return EXIT_SUCCESS;
}