]> git.ipfire.org Git - thirdparty/util-linux.git/blob - schedutils/ionice.c
misc: consolidate version printing and close_stdout()
[thirdparty/util-linux.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 #include "closestream.h"
21
22 static int tolerant;
23
24 static inline int ioprio_set(int which, int who, int ioprio)
25 {
26 return syscall(SYS_ioprio_set, which, who, ioprio);
27 }
28
29 static inline int ioprio_get(int which, int who)
30 {
31 return syscall(SYS_ioprio_get, which, who);
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
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
54 static const char *to_prio[] = {
55 [IOPRIO_CLASS_NONE] = "none",
56 [IOPRIO_CLASS_RT] = "realtime",
57 [IOPRIO_CLASS_BE] = "best-effort",
58 [IOPRIO_CLASS_IDLE] = "idle"
59 };
60
61 static int parse_ioclass(const char *str)
62 {
63 size_t i;
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
71 static void ioprio_print(int pid, int who)
72 {
73 int ioprio = ioprio_get(who, pid);
74
75 if (ioprio == -1)
76 err(EXIT_FAILURE, _("ioprio_get failed"));
77 else {
78 int ioclass = IOPRIO_PRIO_CLASS(ioprio);
79 const char *name = _("unknown");
80
81 if (ioclass >= 0 && (size_t) ioclass < ARRAY_SIZE(to_prio))
82 name = to_prio[ioclass];
83
84 if (ioclass != IOPRIO_CLASS_IDLE)
85 printf(_("%s: prio %lu\n"), name,
86 IOPRIO_PRIO_DATA(ioprio));
87 else
88 printf("%s\n", name);
89 }
90 }
91
92 static void ioprio_setid(int which, int ioclass, int data, int who)
93 {
94 int rc = ioprio_set(who, which,
95 IOPRIO_PRIO_VALUE(ioclass, data));
96
97 if (rc == -1 && !tolerant)
98 err(EXIT_FAILURE, _("ioprio_set failed"));
99 }
100
101 static void __attribute__((__noreturn__)) usage(void)
102 {
103 FILE *out = stdout;
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
110 fputs(USAGE_SEPARATOR, out);
111 fputs(_("Show or change the I/O-scheduling class and priority of a process.\n"), out);
112
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);
124 printf(USAGE_HELP_OPTIONS(24));
125
126 printf(USAGE_MAN_TAIL("ionice(1)"));
127
128 exit(EXIT_SUCCESS);
129 }
130
131 int main(int argc, char **argv)
132 {
133 int data = 4, set = 0, ioclass = IOPRIO_CLASS_BE, c;
134 int which = 0, who = 0;
135 const char *invalid_msg = NULL;
136
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' },
143 { "pgid", required_argument, NULL, 'P' },
144 { "uid", required_argument, NULL, 'u' },
145 { "version", no_argument, NULL, 'V' },
146 { NULL, 0, NULL, 0 }
147 };
148
149 setlocale(LC_ALL, "");
150 bindtextdomain(PACKAGE, LOCALEDIR);
151 textdomain(PACKAGE);
152 close_stdout_atexit();
153
154 while ((c = getopt_long(argc, argv, "+n:c:p:P:u:tVh", longopts, NULL)) != EOF)
155 switch (c) {
156 case 'n':
157 data = strtos32_or_err(optarg, _("invalid class data argument"));
158 set |= 1;
159 break;
160 case 'c':
161 if (isdigit(*optarg))
162 ioclass = strtos32_or_err(optarg,
163 _("invalid class argument"));
164 else {
165 ioclass = parse_ioclass(optarg);
166 if (ioclass < 0)
167 errx(EXIT_FAILURE,
168 _("unknown scheduling class: '%s'"),
169 optarg);
170 }
171 set |= 2;
172 break;
173 case 'p':
174 if (who)
175 errx(EXIT_FAILURE,
176 _("can handle only one of pid, pgid or uid at once"));
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,
184 _("can handle only one of pid, pgid or uid at once"));
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,
192 _("can handle only one of pid, pgid or uid at once"));
193 invalid_msg = _("invalid UID argument");
194 which = strtos32_or_err(optarg, invalid_msg);
195 who = IOPRIO_WHO_USER;
196 break;
197 case 't':
198 tolerant = 1;
199 break;
200
201 case 'V':
202 print_version(EXIT_SUCCESS);
203 case 'h':
204 usage();
205 default:
206 errtryhelp(EXIT_FAILURE);
207 }
208
209 switch (ioclass) {
210 case IOPRIO_CLASS_NONE:
211 if ((set & 1) && !tolerant)
212 warnx(_("ignoring given class data for none class"));
213 data = 0;
214 break;
215 case IOPRIO_CLASS_RT:
216 case IOPRIO_CLASS_BE:
217 break;
218 case IOPRIO_CLASS_IDLE:
219 if ((set & 1) && !tolerant)
220 warnx(_("ignoring given class data for idle class"));
221 data = 7;
222 break;
223 default:
224 if (!tolerant)
225 warnx(_("unknown prio class %d"), ioclass);
226 break;
227 }
228
229 if (!set && !which && optind == argc)
230 /*
231 * ionice without options, print the current ioprio
232 */
233 ioprio_print(0, IOPRIO_WHO_PROCESS);
234 else if (!set && who) {
235 /*
236 * ionice -p|-P|-u ID [ID ...]
237 */
238 ioprio_print(which, who);
239
240 for(; argv[optind]; ++optind) {
241 which = strtos32_or_err(argv[optind], invalid_msg);
242 ioprio_print(which, who);
243 }
244 } else if (set && who) {
245 /*
246 * ionice -c CLASS -p|-P|-u ID [ID ...]
247 */
248 ioprio_setid(which, ioclass, data, who);
249
250 for(; argv[optind]; ++optind) {
251 which = strtos32_or_err(argv[optind], invalid_msg);
252 ioprio_setid(which, ioclass, data, who);
253 }
254 } else if (argv[optind]) {
255 /*
256 * ionice [-c CLASS] COMMAND
257 */
258 ioprio_setid(0, ioclass, data, IOPRIO_WHO_PROCESS);
259 execvp(argv[optind], &argv[optind]);
260 errexec(argv[optind]);
261 } else {
262 warnx(_("bad usage"));
263 errtryhelp(EXIT_FAILURE);
264 }
265
266 return EXIT_SUCCESS;
267 }