(root)/
util-linux-2.39/
schedutils/
ionice.c
       1  /*
       2   * ionice: set or get process io scheduling class and priority
       3   *
       4   * Copyright (C) 2005 Jens Axboe <jens@axboe.dk>
       5   *
       6   * Released under the terms of the GNU General Public License version 2
       7   *
       8   */
       9  #include <stdio.h>
      10  #include <stdlib.h>
      11  #include <errno.h>
      12  #include <getopt.h>
      13  #include <unistd.h>
      14  #ifdef HAVE_SYS_SYSCALL_H
      15  #include <sys/syscall.h>
      16  #endif
      17  #include <ctype.h>
      18  
      19  #include "nls.h"
      20  #include "strutils.h"
      21  #include "c.h"
      22  #include "closestream.h"
      23  
      24  static int tolerant;
      25  
      26  static inline int ioprio_set(int which, int who, int ioprio)
      27  {
      28  	return syscall(SYS_ioprio_set, which, who, ioprio);
      29  }
      30  
      31  static inline int ioprio_get(int which, int who)
      32  {
      33  	return syscall(SYS_ioprio_get, which, who);
      34  }
      35  
      36  enum {
      37  	IOPRIO_CLASS_NONE,
      38  	IOPRIO_CLASS_RT,
      39  	IOPRIO_CLASS_BE,
      40  	IOPRIO_CLASS_IDLE,
      41  };
      42  
      43  enum {
      44  	IOPRIO_WHO_PROCESS = 1,
      45  	IOPRIO_WHO_PGRP,
      46  	IOPRIO_WHO_USER,
      47  };
      48  
      49  #define IOPRIO_CLASS_SHIFT	(13)
      50  #define IOPRIO_PRIO_MASK	((1UL << IOPRIO_CLASS_SHIFT) - 1)
      51  
      52  #define IOPRIO_PRIO_CLASS(mask)	((mask) >> IOPRIO_CLASS_SHIFT)
      53  #define IOPRIO_PRIO_DATA(mask)	((mask) & IOPRIO_PRIO_MASK)
      54  #define IOPRIO_PRIO_VALUE(class, data)	(((class) << IOPRIO_CLASS_SHIFT) | data)
      55  
      56  static const char *to_prio[] = {
      57  	[IOPRIO_CLASS_NONE] = "none",
      58  	[IOPRIO_CLASS_RT]   = "realtime",
      59  	[IOPRIO_CLASS_BE]   = "best-effort",
      60  	[IOPRIO_CLASS_IDLE] = "idle"
      61  };
      62  
      63  static int parse_ioclass(const char *str)
      64  {
      65  	size_t i;
      66  
      67  	for (i = 0; i < ARRAY_SIZE(to_prio); i++)
      68  		if (!strcasecmp(str, to_prio[i]))
      69  			return i;
      70  	return -1;
      71  }
      72  
      73  static void ioprio_print(int pid, int who)
      74  {
      75  	int ioprio = ioprio_get(who, pid);
      76  
      77  	if (ioprio == -1)
      78  		err(EXIT_FAILURE, _("ioprio_get failed"));
      79  	else {
      80  		int ioclass = IOPRIO_PRIO_CLASS(ioprio);
      81  		const char *name = _("unknown");
      82  
      83  		if (ioclass >= 0 && (size_t) ioclass < ARRAY_SIZE(to_prio))
      84  			name = to_prio[ioclass];
      85  
      86  		if (ioclass != IOPRIO_CLASS_IDLE)
      87  			printf(_("%s: prio %lu\n"), name,
      88  			       IOPRIO_PRIO_DATA(ioprio));
      89  		else
      90  			printf("%s\n", name);
      91  	}
      92  }
      93  
      94  static void ioprio_setid(int which, int ioclass, int data, int who)
      95  {
      96  	int rc = ioprio_set(who, which,
      97  			    IOPRIO_PRIO_VALUE(ioclass, data));
      98  
      99  	if (rc == -1 && !tolerant)
     100  		err(EXIT_FAILURE, _("ioprio_set failed"));
     101  }
     102  
     103  static void __attribute__((__noreturn__)) usage(void)
     104  {
     105  	FILE *out = stdout;
     106  	fputs(USAGE_HEADER, out);
     107  	fprintf(out,  _(" %1$s [options] -p <pid>...\n"
     108  			" %1$s [options] -P <pgid>...\n"
     109  			" %1$s [options] -u <uid>...\n"
     110  			" %1$s [options] <command>\n"), program_invocation_short_name);
     111  
     112  	fputs(USAGE_SEPARATOR, out);
     113  	fputs(_("Show or change the I/O-scheduling class and priority of a process.\n"), out);
     114  
     115  	fputs(USAGE_OPTIONS, out);
     116  	fputs(_(" -c, --class <class>    name or number of scheduling class,\n"
     117  		"                          0: none, 1: realtime, 2: best-effort, 3: idle\n"), out);
     118  	fputs(_(" -n, --classdata <num>  priority (0..7) in the specified scheduling class,\n"
     119  		"                          only for the realtime and best-effort classes\n"), out);
     120  	fputs(_(" -p, --pid <pid>...     act on these already running processes\n"), out);
     121  	fputs(_(" -P, --pgid <pgrp>...   act on already running processes in these groups\n"), out);
     122  	fputs(_(" -t, --ignore           ignore failures\n"), out);
     123  	fputs(_(" -u, --uid <uid>...     act on already running processes owned by these users\n"), out);
     124  
     125  	fputs(USAGE_SEPARATOR, out);
     126  	printf(USAGE_HELP_OPTIONS(24));
     127  
     128  	printf(USAGE_MAN_TAIL("ionice(1)"));
     129  
     130  	exit(EXIT_SUCCESS);
     131  }
     132  
     133  int main(int argc, char **argv)
     134  {
     135  	int data = 4, set = 0, ioclass = IOPRIO_CLASS_BE, c;
     136  	int which = 0, who = 0;
     137  	const char *invalid_msg = NULL;
     138  
     139  	static const struct option longopts[] = {
     140  		{ "classdata", required_argument, NULL, 'n' },
     141  		{ "class",     required_argument, NULL, 'c' },
     142  		{ "help",      no_argument,       NULL, 'h' },
     143  		{ "ignore",    no_argument,       NULL, 't' },
     144  		{ "pid",       required_argument, NULL, 'p' },
     145  		{ "pgid",      required_argument, NULL, 'P' },
     146  		{ "uid",       required_argument, NULL, 'u' },
     147  		{ "version",   no_argument,       NULL, 'V' },
     148  		{ NULL, 0, NULL, 0 }
     149  	};
     150  
     151  	setlocale(LC_ALL, "");
     152  	bindtextdomain(PACKAGE, LOCALEDIR);
     153  	textdomain(PACKAGE);
     154  	close_stdout_atexit();
     155  
     156  	while ((c = getopt_long(argc, argv, "+n:c:p:P:u:tVh", longopts, NULL)) != EOF)
     157  		switch (c) {
     158  		case 'n':
     159  			data = strtos32_or_err(optarg, _("invalid class data argument"));
     160  			set |= 1;
     161  			break;
     162  		case 'c':
     163  			if (isdigit(*optarg))
     164  				ioclass = strtos32_or_err(optarg,
     165  						_("invalid class argument"));
     166  			else {
     167  				ioclass = parse_ioclass(optarg);
     168  				if (ioclass < 0)
     169  					errx(EXIT_FAILURE,
     170  						_("unknown scheduling class: '%s'"),
     171  						optarg);
     172  			}
     173  			set |= 2;
     174  			break;
     175  		case 'p':
     176  			if (who)
     177  				errx(EXIT_FAILURE,
     178  				     _("can handle only one of pid, pgid or uid at once"));
     179  			invalid_msg = _("invalid PID argument");
     180  			which = strtos32_or_err(optarg, invalid_msg);
     181  			who = IOPRIO_WHO_PROCESS;
     182  			break;
     183  		case 'P':
     184  			if (who)
     185  				errx(EXIT_FAILURE,
     186  				     _("can handle only one of pid, pgid or uid at once"));
     187  			invalid_msg = _("invalid PGID argument");
     188  			which = strtos32_or_err(optarg, invalid_msg);
     189  			who = IOPRIO_WHO_PGRP;
     190  			break;
     191  		case 'u':
     192  			if (who)
     193  				errx(EXIT_FAILURE,
     194  				     _("can handle only one of pid, pgid or uid at once"));
     195  			invalid_msg = _("invalid UID argument");
     196  			which = strtos32_or_err(optarg, invalid_msg);
     197  			who = IOPRIO_WHO_USER;
     198  			break;
     199  		case 't':
     200  			tolerant = 1;
     201  			break;
     202  
     203  		case 'V':
     204  			print_version(EXIT_SUCCESS);
     205  		case 'h':
     206  			usage();
     207  		default:
     208  			errtryhelp(EXIT_FAILURE);
     209  		}
     210  
     211  	switch (ioclass) {
     212  		case IOPRIO_CLASS_NONE:
     213  			if ((set & 1) && !tolerant)
     214  				warnx(_("ignoring given class data for none class"));
     215  			data = 0;
     216  			break;
     217  		case IOPRIO_CLASS_RT:
     218  		case IOPRIO_CLASS_BE:
     219  			break;
     220  		case IOPRIO_CLASS_IDLE:
     221  			if ((set & 1) && !tolerant)
     222  				warnx(_("ignoring given class data for idle class"));
     223  			data = 7;
     224  			break;
     225  		default:
     226  			if (!tolerant)
     227  				warnx(_("unknown prio class %d"), ioclass);
     228  			break;
     229  	}
     230  
     231  	if (!set && !which && optind == argc)
     232  		/*
     233  		 * ionice without options, print the current ioprio
     234  		 */
     235  		ioprio_print(0, IOPRIO_WHO_PROCESS);
     236  	else if (!set && who) {
     237  		/*
     238  		 * ionice -p|-P|-u ID [ID ...]
     239  		 */
     240  		ioprio_print(which, who);
     241  
     242  		for(; argv[optind]; ++optind) {
     243  			which = strtos32_or_err(argv[optind], invalid_msg);
     244  			ioprio_print(which, who);
     245  		}
     246  	} else if (set && who) {
     247  		/*
     248  		 * ionice -c CLASS -p|-P|-u ID [ID ...]
     249  		 */
     250  		ioprio_setid(which, ioclass, data, who);
     251  
     252  		for(; argv[optind]; ++optind) {
     253  			which = strtos32_or_err(argv[optind], invalid_msg);
     254  			ioprio_setid(which, ioclass, data, who);
     255  		}
     256  	} else if (argv[optind]) {
     257  		/*
     258  		 * ionice [-c CLASS] COMMAND
     259  		 */
     260  		ioprio_setid(0, ioclass, data, IOPRIO_WHO_PROCESS);
     261  		execvp(argv[optind], &argv[optind]);
     262  		errexec(argv[optind]);
     263  	} else {
     264  		warnx(_("bad usage"));
     265  		errtryhelp(EXIT_FAILURE);
     266  	}
     267  
     268  	return EXIT_SUCCESS;
     269  }