blob: a57cf7f26729860d5b6bebe4f702c22f7474c45b [file] [log] [blame]
/*
* 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/ptrace.h>
#include <sys/syscall.h>
#include <asm/unistd.h>
#include <err.h>
#include "nls.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
const char *to_prio[] = { "none", "realtime", "best-effort", "idle", };
static void ioprio_print(int pid)
{
int ioprio, ioclass;
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]);
}
}
static void ioprio_setpid(pid_t pid, int ioprio, int ioclass)
{
int rc = ioprio_set(IOPRIO_WHO_PROCESS, pid,
ioprio | ioclass << IOPRIO_CLASS_SHIFT);
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"
" ionice [ 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)
{
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;
}
int main(int argc, char *argv[])
{
int ioprio = 4, set = 0, ioclass = IOPRIO_CLASS_BE, c;
pid_t pid = 0;
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
while ((c = getopt(argc, argv, "+n:c:p:th")) != EOF) {
switch (c) {
case 'n':
ioprio = getnum(optarg);
set |= 1;
break;
case 'c':
ioclass = getnum(optarg);
set |= 2;
break;
case 'p':
pid = getnum(optarg);
break;
case 't':
tolerant = 1;
break;
case 'h':
usage(EXIT_SUCCESS);
default:
usage(EXIT_FAILURE);
}
}
switch (ioclass) {
case IOPRIO_CLASS_NONE:
if (set & 1)
warnx(_("ignoring given class data for none class"));
ioprio = 0;
break;
case IOPRIO_CLASS_RT:
case IOPRIO_CLASS_BE:
break;
case IOPRIO_CLASS_IDLE:
if (set & 1)
warnx(_("ignoring given class data for idle class"));
ioprio = 7;
break;
default:
errx(EXIT_FAILURE, _("bad prio class %d"), ioclass);
}
if (!set) {
ioprio_print(pid);
for(; argv[optind]; ++optind) {
pid = getnum(argv[optind]);
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"));
}
}
exit(EXIT_SUCCESS);
}