]>
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> | |
319563bf | 14 | #ifdef HAVE_SYS_SYSCALL_H |
48d7b13a | 15 | #include <sys/syscall.h> |
319563bf | 16 | #endif |
fe040397 | 17 | #include <ctype.h> |
5bd11d0d KZ |
18 | |
19 | #include "nls.h" | |
8abcf290 | 20 | #include "strutils.h" |
eb76ca98 | 21 | #include "c.h" |
ed8ec2a6 | 22 | #include "closestream.h" |
24295096 | 23 | |
ef0fe2e8 SM |
24 | static int tolerant; |
25 | ||
48d7b13a KZ |
26 | static inline int ioprio_set(int which, int who, int ioprio) |
27 | { | |
4dfadf9c | 28 | return syscall(SYS_ioprio_set, which, who, ioprio); |
48d7b13a KZ |
29 | } |
30 | ||
31 | static inline int ioprio_get(int which, int who) | |
32 | { | |
4dfadf9c | 33 | return syscall(SYS_ioprio_get, which, who); |
48d7b13a KZ |
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 | ||
560cdabb KZ |
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 | ||
2ba641e5 | 56 | static const char *to_prio[] = { |
560cdabb KZ |
57 | [IOPRIO_CLASS_NONE] = "none", |
58 | [IOPRIO_CLASS_RT] = "realtime", | |
59 | [IOPRIO_CLASS_BE] = "best-effort", | |
60 | [IOPRIO_CLASS_IDLE] = "idle" | |
61 | }; | |
48d7b13a | 62 | |
fe040397 KZ |
63 | static int parse_ioclass(const char *str) |
64 | { | |
cee12fc6 | 65 | size_t i; |
fe040397 KZ |
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 | ||
bd2ff3d2 | 73 | static void ioprio_print(int pid, int who) |
ef0fe2e8 | 74 | { |
bd2ff3d2 | 75 | int ioprio = ioprio_get(who, pid); |
ef0fe2e8 SM |
76 | |
77 | if (ioprio == -1) | |
78 | err(EXIT_FAILURE, _("ioprio_get failed")); | |
79 | else { | |
560cdabb | 80 | int ioclass = IOPRIO_PRIO_CLASS(ioprio); |
cbc1dc96 KZ |
81 | const char *name = _("unknown"); |
82 | ||
b422f5fe | 83 | if (ioclass >= 0 && (size_t) ioclass < ARRAY_SIZE(to_prio)) |
cbc1dc96 | 84 | name = to_prio[ioclass]; |
560cdabb KZ |
85 | |
86 | if (ioclass != IOPRIO_CLASS_IDLE) | |
65f25186 | 87 | printf(_("%s: prio %lu\n"), name, |
8c219bf4 | 88 | IOPRIO_PRIO_DATA(ioprio)); |
560cdabb | 89 | else |
cbc1dc96 | 90 | printf("%s\n", name); |
ef0fe2e8 SM |
91 | } |
92 | } | |
93 | ||
bd2ff3d2 | 94 | static void ioprio_setid(int which, int ioclass, int data, int who) |
ef0fe2e8 | 95 | { |
bd2ff3d2 | 96 | int rc = ioprio_set(who, which, |
560cdabb | 97 | IOPRIO_PRIO_VALUE(ioclass, data)); |
ef0fe2e8 SM |
98 | |
99 | if (rc == -1 && !tolerant) | |
100 | err(EXIT_FAILURE, _("ioprio_set failed")); | |
101 | } | |
102 | ||
6e1eda6f | 103 | static void __attribute__((__noreturn__)) usage(void) |
48d7b13a | 104 | { |
6e1eda6f | 105 | FILE *out = stdout; |
2d745ee6 BS |
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 | ||
451dbcfa BS |
112 | fputs(USAGE_SEPARATOR, out); |
113 | fputs(_("Show or change the I/O-scheduling class and priority of a process.\n"), out); | |
114 | ||
2d745ee6 BS |
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); | |
bad4c729 | 126 | fprintf(out, USAGE_HELP_OPTIONS(24)); |
2d745ee6 | 127 | |
bad4c729 | 128 | fprintf(out, USAGE_MAN_TAIL("ionice(1)")); |
976b7580 | 129 | |
6e1eda6f | 130 | exit(EXIT_SUCCESS); |
48d7b13a KZ |
131 | } |
132 | ||
a5e9b75f | 133 | int main(int argc, char **argv) |
48d7b13a | 134 | { |
560cdabb | 135 | int data = 4, set = 0, ioclass = IOPRIO_CLASS_BE, c; |
bd2ff3d2 MY |
136 | int which = 0, who = 0; |
137 | const char *invalid_msg = NULL; | |
48d7b13a | 138 | |
976b7580 SK |
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' }, | |
bd2ff3d2 MY |
145 | { "pgid", required_argument, NULL, 'P' }, |
146 | { "uid", required_argument, NULL, 'u' }, | |
976b7580 SK |
147 | { "version", no_argument, NULL, 'V' }, |
148 | { NULL, 0, NULL, 0 } | |
149 | }; | |
150 | ||
5bd11d0d KZ |
151 | setlocale(LC_ALL, ""); |
152 | bindtextdomain(PACKAGE, LOCALEDIR); | |
153 | textdomain(PACKAGE); | |
2c308875 | 154 | close_stdout_atexit(); |
5bd11d0d | 155 | |
bd2ff3d2 | 156 | while ((c = getopt_long(argc, argv, "+n:c:p:P:u:tVh", longopts, NULL)) != EOF) |
48d7b13a KZ |
157 | switch (c) { |
158 | case 'n': | |
630ed89d | 159 | data = strtos32_or_err(optarg, _("invalid class data argument")); |
8dbfe5a1 | 160 | set |= 1; |
48d7b13a KZ |
161 | break; |
162 | case 'c': | |
fe040397 | 163 | if (isdigit(*optarg)) |
630ed89d KZ |
164 | ioclass = strtos32_or_err(optarg, |
165 | _("invalid class argument")); | |
fe040397 KZ |
166 | else { |
167 | ioclass = parse_ioclass(optarg); | |
168 | if (ioclass < 0) | |
169 | errx(EXIT_FAILURE, | |
170 | _("unknown scheduling class: '%s'"), | |
171 | optarg); | |
172 | } | |
8dbfe5a1 | 173 | set |= 2; |
48d7b13a KZ |
174 | break; |
175 | case 'p': | |
bd2ff3d2 MY |
176 | if (who) |
177 | errx(EXIT_FAILURE, | |
2d745ee6 | 178 | _("can handle only one of pid, pgid or uid at once")); |
bd2ff3d2 MY |
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, | |
2d745ee6 | 186 | _("can handle only one of pid, pgid or uid at once")); |
bd2ff3d2 MY |
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, | |
2d745ee6 | 194 | _("can handle only one of pid, pgid or uid at once")); |
b6973e5d | 195 | invalid_msg = _("invalid UID argument"); |
bd2ff3d2 MY |
196 | which = strtos32_or_err(optarg, invalid_msg); |
197 | who = IOPRIO_WHO_USER; | |
48d7b13a | 198 | break; |
4d125dfc LK |
199 | case 't': |
200 | tolerant = 1; | |
201 | break; | |
2c308875 | 202 | |
976b7580 | 203 | case 'V': |
2c308875 | 204 | print_version(EXIT_SUCCESS); |
48d7b13a | 205 | case 'h': |
6e1eda6f | 206 | usage(); |
48d7b13a | 207 | default: |
677ec86c | 208 | errtryhelp(EXIT_FAILURE); |
48d7b13a | 209 | } |
48d7b13a | 210 | |
ef0fe2e8 | 211 | switch (ioclass) { |
48d7b13a | 212 | case IOPRIO_CLASS_NONE: |
cbc1dc96 | 213 | if ((set & 1) && !tolerant) |
5dc9371c | 214 | warnx(_("ignoring given class data for none class")); |
560cdabb | 215 | data = 0; |
48d7b13a KZ |
216 | break; |
217 | case IOPRIO_CLASS_RT: | |
218 | case IOPRIO_CLASS_BE: | |
219 | break; | |
220 | case IOPRIO_CLASS_IDLE: | |
cbc1dc96 | 221 | if ((set & 1) && !tolerant) |
5bd11d0d | 222 | warnx(_("ignoring given class data for idle class")); |
560cdabb | 223 | data = 7; |
48d7b13a KZ |
224 | break; |
225 | default: | |
cbc1dc96 KZ |
226 | if (!tolerant) |
227 | warnx(_("unknown prio class %d"), ioclass); | |
228 | break; | |
48d7b13a KZ |
229 | } |
230 | ||
bd2ff3d2 | 231 | if (!set && !which && optind == argc) |
fcc2b2da KZ |
232 | /* |
233 | * ionice without options, print the current ioprio | |
234 | */ | |
bd2ff3d2 MY |
235 | ioprio_print(0, IOPRIO_WHO_PROCESS); |
236 | else if (!set && who) { | |
fcc2b2da | 237 | /* |
bd2ff3d2 | 238 | * ionice -p|-P|-u ID [ID ...] |
fcc2b2da | 239 | */ |
bd2ff3d2 | 240 | ioprio_print(which, who); |
48d7b13a | 241 | |
ef0fe2e8 | 242 | for(; argv[optind]; ++optind) { |
bd2ff3d2 MY |
243 | which = strtos32_or_err(argv[optind], invalid_msg); |
244 | ioprio_print(which, who); | |
48d7b13a | 245 | } |
bd2ff3d2 | 246 | } else if (set && who) { |
fcc2b2da | 247 | /* |
bd2ff3d2 | 248 | * ionice -c CLASS -p|-P|-u ID [ID ...] |
fcc2b2da | 249 | */ |
bd2ff3d2 | 250 | ioprio_setid(which, ioclass, data, who); |
ef0fe2e8 | 251 | |
fcc2b2da | 252 | for(; argv[optind]; ++optind) { |
bd2ff3d2 MY |
253 | which = strtos32_or_err(argv[optind], invalid_msg); |
254 | ioprio_setid(which, ioclass, data, who); | |
2b258413 | 255 | } |
fcc2b2da KZ |
256 | } else if (argv[optind]) { |
257 | /* | |
258 | * ionice [-c CLASS] COMMAND | |
259 | */ | |
bd2ff3d2 | 260 | ioprio_setid(0, ioclass, data, IOPRIO_WHO_PROCESS); |
fcc2b2da | 261 | execvp(argv[optind], &argv[optind]); |
61b62222 | 262 | errexec(argv[optind]); |
6e1eda6f RM |
263 | } else { |
264 | warnx(_("bad usage")); | |
265 | errtryhelp(EXIT_FAILURE); | |
266 | } | |
48d7b13a | 267 | |
a5e9b75f | 268 | return EXIT_SUCCESS; |
48d7b13a | 269 | } |