Update to upstream util-linux 2.20.1
[framework/base/util-linux-ng.git] / 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 #include <sys/syscall.h>
15 #include <ctype.h>
16
17 #include "nls.h"
18 #include "strutils.h"
19 #include "c.h"
20
21 static int tolerant;
22
23 static inline int ioprio_set(int which, int who, int ioprio)
24 {
25         return syscall(SYS_ioprio_set, which, who, ioprio);
26 }
27
28 static inline int ioprio_get(int which, int who)
29 {
30         return syscall(SYS_ioprio_get, which, who);
31 }
32
33 enum {
34         IOPRIO_CLASS_NONE,
35         IOPRIO_CLASS_RT,
36         IOPRIO_CLASS_BE,
37         IOPRIO_CLASS_IDLE,
38 };
39
40 enum {
41         IOPRIO_WHO_PROCESS = 1,
42         IOPRIO_WHO_PGRP,
43         IOPRIO_WHO_USER,
44 };
45
46 #define IOPRIO_CLASS_SHIFT      (13)
47 #define IOPRIO_PRIO_MASK        ((1UL << IOPRIO_CLASS_SHIFT) - 1)
48
49 #define IOPRIO_PRIO_CLASS(mask) ((mask) >> IOPRIO_CLASS_SHIFT)
50 #define IOPRIO_PRIO_DATA(mask)  ((mask) & IOPRIO_PRIO_MASK)
51 #define IOPRIO_PRIO_VALUE(class, data)  (((class) << IOPRIO_CLASS_SHIFT) | data)
52
53 const char *to_prio[] = {
54         [IOPRIO_CLASS_NONE] = "none",
55         [IOPRIO_CLASS_RT]   = "realtime",
56         [IOPRIO_CLASS_BE]   = "best-effort",
57         [IOPRIO_CLASS_IDLE] = "idle"
58 };
59
60 static int parse_ioclass(const char *str)
61 {
62         size_t i;
63
64         for (i = 0; i < ARRAY_SIZE(to_prio); i++)
65                 if (!strcasecmp(str, to_prio[i]))
66                         return i;
67         return -1;
68 }
69
70 static void ioprio_print(int pid)
71 {
72         int ioprio = ioprio_get(IOPRIO_WHO_PROCESS, pid);
73
74         if (ioprio == -1)
75                 err(EXIT_FAILURE, _("ioprio_get failed"));
76         else {
77                 int ioclass = IOPRIO_PRIO_CLASS(ioprio);
78                 const char *name = _("unknown");
79
80                 if (ioclass > 0 && (size_t) ioclass < ARRAY_SIZE(to_prio))
81                         name = to_prio[ioclass];
82
83                 if (ioclass != IOPRIO_CLASS_IDLE)
84                         printf("%s: prio %lu\n", name,
85                                         IOPRIO_PRIO_DATA(ioprio));
86                 else
87                         printf("%s\n", name);
88         }
89 }
90
91 static void ioprio_setpid(pid_t pid, int ioclass, int data)
92 {
93         int rc = ioprio_set(IOPRIO_WHO_PROCESS, pid,
94                             IOPRIO_PRIO_VALUE(ioclass, data));
95
96         if (rc == -1 && !tolerant)
97                 err(EXIT_FAILURE, _("ioprio_set failed"));
98 }
99
100 static void __attribute__ ((__noreturn__)) usage(FILE * out)
101 {
102         fprintf(out,
103                _("\n"
104                  "%1$s - sets or gets process io scheduling class and priority.\n"
105                  "\n"
106                  "Usage:\n"
107                  "  %1$s [OPTION] -p PID [PID...]\n"
108                  "  %1$s [OPTION] COMMAND\n"
109                  "\n"
110                  "Options:\n"
111                  "  -c, --class <class>   scheduling class name or number\n"
112                  "                           0: none, 1: realtime, 2: best-effort, 3: idle\n"
113                  "  -n, --classdata <num> scheduling class data\n"
114                  "                           0-7 for realtime and best-effort classes\n"
115                  "  -p, --pid=PID         view or modify already running process\n"
116                  "  -t, --ignore          ignore failures\n"
117                  "  -V, --version         output version information and exit\n"
118                  "  -h, --help            display this help and exit\n\n"),
119                 program_invocation_short_name);
120
121         exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
122 }
123
124 int main(int argc, char **argv)
125 {
126         int data = 4, set = 0, ioclass = IOPRIO_CLASS_BE, c;
127         pid_t pid = 0;
128
129         static const struct option longopts[] = {
130                 { "classdata", required_argument, NULL, 'n' },
131                 { "class",     required_argument, NULL, 'c' },
132                 { "help",      no_argument,       NULL, 'h' },
133                 { "ignore",    no_argument,       NULL, 't' },
134                 { "pid",       required_argument, NULL, 'p' },
135                 { "version",   no_argument,       NULL, 'V' },
136                 { NULL, 0, NULL, 0 }
137         };
138
139         setlocale(LC_ALL, "");
140         bindtextdomain(PACKAGE, LOCALEDIR);
141         textdomain(PACKAGE);
142
143         while ((c = getopt_long(argc, argv, "+n:c:p:tVh", longopts, NULL)) != EOF)
144                 switch (c) {
145                 case 'n':
146                         data = strtol_or_err(optarg, _("failed to parse class data"));
147                         set |= 1;
148                         break;
149                 case 'c':
150                         if (isdigit(*optarg))
151                                 ioclass = strtol_or_err(optarg,
152                                                 _("failed to parse class"));
153                         else {
154                                 ioclass = parse_ioclass(optarg);
155                                 if (ioclass < 0)
156                                         errx(EXIT_FAILURE,
157                                                 _("unknown scheduling class: '%s'"),
158                                                 optarg);
159                         }
160                         set |= 2;
161                         break;
162                 case 'p':
163                         pid = strtol_or_err(optarg, _("failed to parse pid"));
164                         break;
165                 case 't':
166                         tolerant = 1;
167                         break;
168                 case 'V':
169                         printf(_("%s from %s\n"),
170                                 program_invocation_short_name, PACKAGE_STRING);
171                         return EXIT_SUCCESS;
172                 case 'h':
173                         usage(stdout);
174                 default:
175                         usage(stderr);
176                 }
177
178         switch (ioclass) {
179                 case IOPRIO_CLASS_NONE:
180                         if ((set & 1) && !tolerant)
181                                 warnx(_("ignoring given class data for none class"));
182                         data = 0;
183                         break;
184                 case IOPRIO_CLASS_RT:
185                 case IOPRIO_CLASS_BE:
186                         break;
187                 case IOPRIO_CLASS_IDLE:
188                         if ((set & 1) && !tolerant)
189                                 warnx(_("ignoring given class data for idle class"));
190                         data = 7;
191                         break;
192                 default:
193                         if (!tolerant)
194                                 warnx(_("unknown prio class %d"), ioclass);
195                         break;
196         }
197
198         if (!set && !pid && optind == argc)
199                 /*
200                  * ionice without options, print the current ioprio
201                  */
202                 ioprio_print(0);
203
204         else if (!set && pid) {
205                 /*
206                  * ionice -p PID [PID ...]
207                  */
208                 ioprio_print(pid);
209
210                 for(; argv[optind]; ++optind) {
211                         pid = strtol_or_err(argv[optind], _("failed to parse pid"));
212                         ioprio_print(pid);
213                 }
214         } else if (set && pid) {
215                 /*
216                  * ionice -c CLASS -p PID [PID ...]
217                  */
218                 ioprio_setpid(pid, ioclass, data);
219
220                 for(; argv[optind]; ++optind) {
221                         pid = strtol_or_err(argv[optind], _("failed to parse pid"));
222                         ioprio_setpid(pid, ioclass, data);
223                 }
224         } else if (argv[optind]) {
225                 /*
226                  * ionice [-c CLASS] COMMAND
227                  */
228                 ioprio_setpid(0, ioclass, data);
229                 execvp(argv[optind], &argv[optind]);
230                 err(EXIT_FAILURE, _("executing %s failed"), argv[optind]);
231         } else
232                 usage(stderr);
233
234
235         return EXIT_SUCCESS;
236 }