]> git.ipfire.org Git - thirdparty/util-linux.git/blame - sys-utils/chcpu.c
chcpu: fix memory leak
[thirdparty/util-linux.git] / sys-utils / chcpu.c
CommitLineData
0b57c6c2
HC
1/*
2 * chcpu - CPU configuration tool
3 *
4 * Copyright IBM Corp. 2011
5 * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>,
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it would be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
7cebf0bb
SK
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
0b57c6c2
HC
20 */
21
22#include <ctype.h>
23#include <dirent.h>
24#include <errno.h>
25#include <fcntl.h>
26#include <getopt.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <sys/utsname.h>
31#include <unistd.h>
32#include <stdarg.h>
33#include <sys/types.h>
34#include <sys/stat.h>
35
36#include "cpuset.h"
37#include "nls.h"
38#include "xalloc.h"
39#include "c.h"
40#include "strutils.h"
41#include "bitops.h"
9bc2b4b1 42#include "path.h"
efb8854f 43#include "closestream.h"
264a6b0a
SK
44#include "optutils.h"
45
46#define EXCL_ERROR "--{configure,deconfigure,disable,dispatch,enable}"
0b57c6c2 47
48fc00c1
KZ
48/* partial success, otherwise we return regular EXIT_{SUCCESS,FAILURE} */
49#define CHCPU_EXIT_SOMEOK 64
50
0b57c6c2 51#define _PATH_SYS_CPU "/sys/devices/system/cpu"
0b57c6c2 52
5b88ce6a 53static cpu_set_t *onlinecpus;
4b11df2c 54static int maxcpus;
5b88ce6a
HC
55
56#define is_cpu_online(cpu) (CPU_ISSET_S((cpu), CPU_ALLOC_SIZE(maxcpus), onlinecpus))
57#define num_online_cpus() (CPU_COUNT_S(CPU_ALLOC_SIZE(maxcpus), onlinecpus))
58
0b57c6c2
HC
59enum {
60 CMD_CPU_ENABLE = 0,
61 CMD_CPU_DISABLE,
62 CMD_CPU_CONFIGURE,
63 CMD_CPU_DECONFIGURE,
64 CMD_CPU_RESCAN,
65 CMD_CPU_DISPATCH_HORIZONTAL,
66 CMD_CPU_DISPATCH_VERTICAL,
67};
68
48fc00c1
KZ
69/* returns: 0 = success
70 * < 0 = failure
71 * > 0 = partial success
72 */
a375d911 73static int cpu_enable(struct path_cxt *sys, cpu_set_t *cpu_set, size_t setsize, int enable)
0b57c6c2 74{
60727494 75 int cpu;
9bc2b4b1 76 int online, rc;
5b88ce6a 77 int configured = -1;
60727494 78 int fails = 0;
0b57c6c2 79
60727494 80 for (cpu = 0; cpu < maxcpus; cpu++) {
538b50cb 81 if (!CPU_ISSET_S(cpu, setsize, cpu_set))
0b57c6c2 82 continue;
a375d911 83 if (ul_path_accessf(sys, F_OK, "cpu%d", cpu) != 0) {
e3ca1312 84 warnx(_("CPU %u does not exist"), cpu);
48fc00c1 85 fails++;
0b57c6c2
HC
86 continue;
87 }
a375d911 88 if (ul_path_accessf(sys, F_OK, "cpu%d/online", cpu) != 0) {
e3ca1312 89 warnx(_("CPU %u is not hot pluggable"), cpu);
48fc00c1 90 fails++;
0b57c6c2
HC
91 continue;
92 }
a375d911
KZ
93 if (ul_path_readf_s32(sys, &online, "cpu%d/online", cpu) == 0
94 && online == 1
95 && enable == 1) {
e3ca1312 96 printf(_("CPU %u is already enabled\n"), cpu);
0b57c6c2
HC
97 continue;
98 }
a375d911 99 if (online == 0 && enable == 0) {
e3ca1312 100 printf(_("CPU %u is already disabled\n"), cpu);
0b57c6c2
HC
101 continue;
102 }
a375d911
KZ
103 if (ul_path_accessf(sys, F_OK, "cpu%d/configure", cpu) == 0)
104 ul_path_readf_s32(sys, &configured, "cpu%d/configure", cpu);
0b57c6c2 105 if (enable) {
a375d911
KZ
106 rc = ul_path_writef_string(sys, "1", "cpu%d/online", cpu);
107 if (rc != 0 && configured == 0) {
e3ca1312 108 warn(_("CPU %u enable failed (CPU is deconfigured)"), cpu);
48fc00c1 109 fails++;
a375d911 110 } else if (rc != 0) {
e3ca1312 111 warn(_("CPU %u enable failed"), cpu);
48fc00c1
KZ
112 fails++;
113 } else
e3ca1312 114 printf(_("CPU %u enabled\n"), cpu);
0b57c6c2 115 } else {
5b88ce6a 116 if (onlinecpus && num_online_cpus() == 1) {
e3ca1312 117 warnx(_("CPU %u disable failed (last enabled CPU)"), cpu);
48fc00c1 118 fails++;
5b88ce6a
HC
119 continue;
120 }
a375d911
KZ
121 rc = ul_path_writef_string(sys, "0", "cpu%d/online", cpu);
122 if (rc != 0) {
e3ca1312 123 warn(_("CPU %u disable failed"), cpu);
48fc00c1
KZ
124 fails++;
125 } else {
e3ca1312 126 printf(_("CPU %u disabled\n"), cpu);
5b88ce6a 127 if (onlinecpus)
538b50cb 128 CPU_CLR_S(cpu, setsize, onlinecpus);
5b88ce6a 129 }
0b57c6c2 130 }
0b57c6c2 131 }
48fc00c1 132
60727494 133 return fails == 0 ? 0 : fails == maxcpus ? -1 : 1;
0b57c6c2
HC
134}
135
a375d911 136static int cpu_rescan(struct path_cxt *sys)
0b57c6c2 137{
a375d911 138 if (ul_path_access(sys, F_OK, "rescan") != 0)
0b57c6c2 139 errx(EXIT_FAILURE, _("This system does not support rescanning of CPUs"));
a375d911
KZ
140
141 if (ul_path_write_string(sys, "1", "rescan") != 0)
0b57c6c2 142 err(EXIT_FAILURE, _("Failed to trigger rescan of CPUs"));
a375d911 143
5b88ce6a 144 printf(_("Triggered rescan of CPUs\n"));
48fc00c1 145 return 0;
0b57c6c2
HC
146}
147
a375d911 148static int cpu_set_dispatch(struct path_cxt *sys, int mode)
0b57c6c2 149{
a375d911 150 if (ul_path_access(sys, F_OK, "dispatching") != 0)
0b57c6c2
HC
151 errx(EXIT_FAILURE, _("This system does not support setting "
152 "the dispatching mode of CPUs"));
0b57c6c2 153 if (mode == 0) {
a375d911 154 if (ul_path_write_string(sys, "0", "dispatching") != 0)
0b57c6c2 155 err(EXIT_FAILURE, _("Failed to set horizontal dispatch mode"));
a375d911 156
7007991f 157 printf(_("Successfully set horizontal dispatching mode\n"));
0b57c6c2 158 } else {
a375d911 159 if (ul_path_write_string(sys, "1", "dispatching") != 0)
0b57c6c2 160 err(EXIT_FAILURE, _("Failed to set vertical dispatch mode"));
a375d911 161
7007991f 162 printf(_("Successfully set vertical dispatching mode\n"));
0b57c6c2 163 }
48fc00c1 164 return 0;
0b57c6c2
HC
165}
166
48fc00c1
KZ
167/* returns: 0 = success
168 * < 0 = failure
169 * > 0 = partial success
170 */
a375d911 171static int cpu_configure(struct path_cxt *sys, cpu_set_t *cpu_set, size_t setsize, int configure)
0b57c6c2 172{
60727494 173 int cpu;
9bc2b4b1 174 int rc, current;
60727494 175 int fails = 0;
0b57c6c2 176
60727494 177 for (cpu = 0; cpu < maxcpus; cpu++) {
538b50cb 178 if (!CPU_ISSET_S(cpu, setsize, cpu_set))
0b57c6c2 179 continue;
a375d911 180 if (ul_path_accessf(sys, F_OK, "cpu%d", cpu) != 0) {
e3ca1312 181 warnx(_("CPU %u does not exist"), cpu);
48fc00c1 182 fails++;
0b57c6c2
HC
183 continue;
184 }
a375d911 185 if (ul_path_accessf(sys, F_OK, "cpu%d/configure", cpu) != 0) {
e3ca1312 186 warnx(_("CPU %u is not configurable"), cpu);
48fc00c1 187 fails++;
0b57c6c2
HC
188 continue;
189 }
a375d911
KZ
190 ul_path_readf_s32(sys, &current, "cpu%d/configure", cpu);
191 if (current == 1 && configure == 1) {
e3ca1312 192 printf(_("CPU %u is already configured\n"), cpu);
0b57c6c2
HC
193 continue;
194 }
a375d911 195 if (current == 0 && configure == 0) {
e3ca1312 196 printf(_("CPU %u is already deconfigured\n"), cpu);
0b57c6c2
HC
197 continue;
198 }
a375d911 199 if (current == 1 && configure == 0 && onlinecpus &&
5b88ce6a 200 is_cpu_online(cpu)) {
e3ca1312 201 warnx(_("CPU %u deconfigure failed (CPU is enabled)"), cpu);
48fc00c1 202 fails++;
5b88ce6a
HC
203 continue;
204 }
0b57c6c2 205 if (configure) {
a375d911
KZ
206 rc = ul_path_writef_string(sys, "1", "cpu%d/configure", cpu);
207 if (rc != 0) {
e3ca1312 208 warn(_("CPU %u configure failed"), cpu);
48fc00c1
KZ
209 fails++;
210 } else
e3ca1312 211 printf(_("CPU %u configured\n"), cpu);
0b57c6c2 212 } else {
a375d911
KZ
213 rc = ul_path_writef_string(sys, "0", "cpu%d/configure", cpu);
214 if (rc != 0) {
e3ca1312 215 warn(_("CPU %u deconfigure failed"), cpu);
48fc00c1
KZ
216 fails++;
217 } else
e3ca1312 218 printf(_("CPU %u deconfigured\n"), cpu);
0b57c6c2 219 }
0b57c6c2 220 }
48fc00c1 221
60727494 222 return fails == 0 ? 0 : fails == maxcpus ? -1 : 1;
0b57c6c2
HC
223}
224
59fb133a
HC
225static void cpu_parse(char *cpu_string, cpu_set_t *cpu_set, size_t setsize)
226{
227 int rc;
228
229 rc = cpulist_parse(cpu_string, cpu_set, setsize, 1);
230 if (rc == 0)
231 return;
232 if (rc == 2)
233 errx(EXIT_FAILURE, _("invalid CPU number in CPU list: %s"), cpu_string);
234 errx(EXIT_FAILURE, _("failed to parse CPU list: %s"), cpu_string);
235}
236
6e1eda6f 237static void __attribute__((__noreturn__)) usage(void)
0b57c6c2 238{
6e1eda6f 239 FILE *out = stdout;
0b57c6c2
HC
240 fprintf(out, _(
241 "\nUsage:\n"
242 " %s [options]\n"), program_invocation_short_name);
243
451dbcfa
BS
244 fputs(USAGE_SEPARATOR, out);
245 fputs(_("Configure CPUs in a multi-processor system.\n"), out);
246
b3054454
RM
247 fputs(USAGE_OPTIONS, stdout);
248 fputs(_(
249 " -e, --enable <cpu-list> enable cpus\n"
250 " -d, --disable <cpu-list> disable cpus\n"
251 " -c, --configure <cpu-list> configure cpus\n"
252 " -g, --deconfigure <cpu-list> deconfigure cpus\n"
253 " -p, --dispatch <mode> set dispatching mode\n"
254 " -r, --rescan trigger rescan of cpus\n"
255 ), stdout);
f45f3ec3 256 printf(USAGE_HELP_OPTIONS(31));
0b57c6c2 257
b3054454 258 printf(USAGE_MAN_TAIL("chcpu(8)"));
6e1eda6f 259 exit(EXIT_SUCCESS);
0b57c6c2
HC
260}
261
262int main(int argc, char *argv[])
263{
a375d911 264 struct path_cxt *sys = NULL; /* _PATH_SYS_CPU handler */
7f8787d0 265 cpu_set_t *cpu_set = NULL;
0b57c6c2
HC
266 size_t setsize;
267 int cmd = -1;
48fc00c1 268 int c, rc;
0b57c6c2
HC
269
270 static const struct option longopts[] = {
87918040
SK
271 { "configure", required_argument, NULL, 'c' },
272 { "deconfigure",required_argument, NULL, 'g' },
273 { "disable", required_argument, NULL, 'd' },
274 { "dispatch", required_argument, NULL, 'p' },
275 { "enable", required_argument, NULL, 'e' },
276 { "help", no_argument, NULL, 'h' },
277 { "rescan", no_argument, NULL, 'r' },
278 { "version", no_argument, NULL, 'V' },
279 { NULL, 0, NULL, 0 }
0b57c6c2
HC
280 };
281
a7349ee3 282 static const ul_excl_t excl[] = { /* rows and cols in ASCII order */
20da61dc
KZ
283 { 'c','d','e','g','p' },
284 { 0 }
285 };
286 int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
287
0b57c6c2
HC
288 setlocale(LC_ALL, "");
289 bindtextdomain(PACKAGE, LOCALEDIR);
290 textdomain(PACKAGE);
efb8854f 291 atexit(close_stdout);
0b57c6c2 292
a375d911
KZ
293 ul_path_init_debug();
294 sys = ul_new_path(_PATH_SYS_CPU);
295 if (!sys)
296 err(EXIT_FAILURE, _("failed to initialize sysfs handler"));
297
5b88ce6a 298 maxcpus = get_max_number_of_cpus();
4b11df2c 299 if (maxcpus < 1)
0b57c6c2 300 errx(EXIT_FAILURE, _("cannot determine NR_CPUS; aborting"));
a375d911
KZ
301
302 if (ul_path_access(sys, F_OK, "online") == 0)
303 ul_path_readf_cpulist(sys, &cpu_set, maxcpus, "online");
7f8787d0
KZ
304 else
305 cpu_set = CPU_ALLOC(maxcpus);
0b57c6c2
HC
306 if (!cpu_set)
307 err(EXIT_FAILURE, _("cpuset_alloc failed"));
308
7f8787d0
KZ
309 setsize = CPU_ALLOC_SIZE(maxcpus);
310
0b57c6c2 311 while ((c = getopt_long(argc, argv, "c:d:e:g:hp:rV", longopts, NULL)) != -1) {
20da61dc
KZ
312
313 err_exclusive_options(c, longopts, excl, excl_st);
314
0b57c6c2
HC
315 switch (c) {
316 case 'c':
317 cmd = CMD_CPU_CONFIGURE;
59fb133a 318 cpu_parse(argv[optind - 1], cpu_set, setsize);
0b57c6c2
HC
319 break;
320 case 'd':
321 cmd = CMD_CPU_DISABLE;
59fb133a 322 cpu_parse(argv[optind - 1], cpu_set, setsize);
0b57c6c2
HC
323 break;
324 case 'e':
325 cmd = CMD_CPU_ENABLE;
59fb133a 326 cpu_parse(argv[optind - 1], cpu_set, setsize);
0b57c6c2
HC
327 break;
328 case 'g':
329 cmd = CMD_CPU_DECONFIGURE;
59fb133a 330 cpu_parse(argv[optind - 1], cpu_set, setsize);
0b57c6c2
HC
331 break;
332 case 'h':
6e1eda6f 333 usage();
0b57c6c2
HC
334 case 'p':
335 if (strcmp("horizontal", argv[optind - 1]) == 0)
336 cmd = CMD_CPU_DISPATCH_HORIZONTAL;
337 else if (strcmp("vertical", argv[optind - 1]) == 0)
338 cmd = CMD_CPU_DISPATCH_VERTICAL;
339 else
340 errx(EXIT_FAILURE, _("unsupported argument: %s"),
341 argv[optind -1 ]);
342 break;
343 case 'r':
344 cmd = CMD_CPU_RESCAN;
345 break;
346 case 'V':
f6277500 347 printf(UTIL_LINUX_VERSION);
0b57c6c2
HC
348 return EXIT_SUCCESS;
349 default:
677ec86c 350 errtryhelp(EXIT_FAILURE);
0b57c6c2
HC
351 }
352 }
353
6e1eda6f
RM
354 if ((argc == 1) || (argc != optind)) {
355 warnx(_("bad usage"));
356 errtryhelp(EXIT_FAILURE);
357 }
0b57c6c2
HC
358
359 switch (cmd) {
360 case CMD_CPU_ENABLE:
a375d911 361 rc = cpu_enable(sys, cpu_set, maxcpus, 1);
48fc00c1 362 break;
0b57c6c2 363 case CMD_CPU_DISABLE:
a375d911 364 rc = cpu_enable(sys, cpu_set, maxcpus, 0);
48fc00c1 365 break;
0b57c6c2 366 case CMD_CPU_CONFIGURE:
a375d911 367 rc = cpu_configure(sys, cpu_set, maxcpus, 1);
48fc00c1 368 break;
0b57c6c2 369 case CMD_CPU_DECONFIGURE:
a375d911 370 rc = cpu_configure(sys, cpu_set, maxcpus, 0);
48fc00c1 371 break;
0b57c6c2 372 case CMD_CPU_RESCAN:
a375d911 373 rc = cpu_rescan(sys);
48fc00c1 374 break;
0b57c6c2 375 case CMD_CPU_DISPATCH_HORIZONTAL:
a375d911 376 rc = cpu_set_dispatch(sys, 0);
48fc00c1 377 break;
0b57c6c2 378 case CMD_CPU_DISPATCH_VERTICAL:
a375d911 379 rc = cpu_set_dispatch(sys, 1);
48fc00c1
KZ
380 break;
381 default:
382 rc = -EINVAL;
383 break;
0b57c6c2 384 }
48fc00c1 385
a375d911
KZ
386 ul_unref_path(sys);
387
48fc00c1
KZ
388 return rc == 0 ? EXIT_SUCCESS :
389 rc < 0 ? EXIT_FAILURE : CHCPU_EXIT_SOMEOK;
0b57c6c2 390}