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