]> git.ipfire.org Git - thirdparty/util-linux.git/blob - sys-utils/chcpu.c
Merge branch 'close_stream' of git://github.com/kerolasa/lelux-utiliteetit
[thirdparty/util-linux.git] / sys-utils / chcpu.c
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 *
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.
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"
42 #include "path.h"
43 #include "closestream.h"
44
45 #define _PATH_SYS_CPU "/sys/devices/system/cpu"
46 #define _PATH_SYS_CPU_ONLINE _PATH_SYS_CPU "/online"
47 #define _PATH_SYS_CPU_RESCAN _PATH_SYS_CPU "/rescan"
48 #define _PATH_SYS_CPU_DISPATCH _PATH_SYS_CPU "/dispatching"
49
50 static cpu_set_t *onlinecpus;
51 static int maxcpus;
52
53 #define is_cpu_online(cpu) (CPU_ISSET_S((cpu), CPU_ALLOC_SIZE(maxcpus), onlinecpus))
54 #define num_online_cpus() (CPU_COUNT_S(CPU_ALLOC_SIZE(maxcpus), onlinecpus))
55
56 enum {
57 CMD_CPU_ENABLE = 0,
58 CMD_CPU_DISABLE,
59 CMD_CPU_CONFIGURE,
60 CMD_CPU_DECONFIGURE,
61 CMD_CPU_RESCAN,
62 CMD_CPU_DISPATCH_HORIZONTAL,
63 CMD_CPU_DISPATCH_VERTICAL,
64 };
65
66 static int cpu_enable(cpu_set_t *cpu_set, size_t setsize, int enable)
67 {
68 unsigned int cpu;
69 int online, rc;
70 int configured = -1;
71
72 for (cpu = 0; cpu < setsize; cpu++) {
73 if (!CPU_ISSET(cpu, cpu_set))
74 continue;
75 if (!path_exist(_PATH_SYS_CPU "/cpu%d", cpu)) {
76 printf(_("CPU %d does not exist\n"), cpu);
77 continue;
78 }
79 if (!path_exist(_PATH_SYS_CPU "/cpu%d/online", cpu)) {
80 printf(_("CPU %d is not hot pluggable\n"), cpu);
81 continue;
82 }
83 online = path_getnum(_PATH_SYS_CPU "/cpu%d/online", cpu);
84 if ((online == 1) && (enable == 1)) {
85 printf(_("CPU %d is already enabled\n"), cpu);
86 continue;
87 }
88 if ((online == 0) && (enable == 0)) {
89 printf(_("CPU %d is already disabled\n"), cpu);
90 continue;
91 }
92 if (path_exist(_PATH_SYS_CPU "/cpu%d/configure", cpu))
93 configured = path_getnum(_PATH_SYS_CPU "/cpu%d/configure", cpu);
94 if (enable) {
95 rc = path_writestr("1", _PATH_SYS_CPU "/cpu%d/online", cpu);
96 if ((rc == -1) && (configured == 0))
97 printf(_("CPU %d enable failed "
98 "(CPU is deconfigured)\n"), cpu);
99 else if (rc == -1)
100 printf(_("CPU %d enable failed (%m)\n"), cpu);
101 else
102 printf(_("CPU %d enabled\n"), cpu);
103 } else {
104 if (onlinecpus && num_online_cpus() == 1) {
105 printf(_("CPU %d disable failed "
106 "(last enabled CPU)\n"), cpu);
107 continue;
108 }
109 rc = path_writestr("0", _PATH_SYS_CPU "/cpu%d/online", cpu);
110 if (rc == -1)
111 printf(_("CPU %d disable failed (%m)\n"), cpu);
112 else {
113 printf(_("CPU %d disabled\n"), cpu);
114 if (onlinecpus)
115 CPU_CLR(cpu, onlinecpus);
116 }
117 }
118 }
119 return EXIT_SUCCESS;
120 }
121
122 static int cpu_rescan(void)
123 {
124 if (!path_exist(_PATH_SYS_CPU_RESCAN))
125 errx(EXIT_FAILURE, _("This system does not support rescanning of CPUs"));
126 if (path_writestr("1", _PATH_SYS_CPU_RESCAN) == -1)
127 err(EXIT_FAILURE, _("Failed to trigger rescan of CPUs"));
128 printf(_("Triggered rescan of CPUs\n"));
129 return EXIT_SUCCESS;
130 }
131
132 static int cpu_set_dispatch(int mode)
133 {
134 if (!path_exist(_PATH_SYS_CPU_DISPATCH))
135 errx(EXIT_FAILURE, _("This system does not support setting "
136 "the dispatching mode of CPUs"));
137 if (mode == 0) {
138 if (path_writestr("0", _PATH_SYS_CPU_DISPATCH) == -1)
139 err(EXIT_FAILURE, _("Failed to set horizontal dispatch mode"));
140 printf(_("Succesfully set horizontal dispatching mode\n"));
141 } else {
142 if (path_writestr("1", _PATH_SYS_CPU_DISPATCH) == -1)
143 err(EXIT_FAILURE, _("Failed to set vertical dispatch mode"));
144 printf(_("Succesfully set vertical dispatching mode\n"));
145 }
146 return EXIT_SUCCESS;
147 }
148
149 static int cpu_configure(cpu_set_t *cpu_set, size_t setsize, int configure)
150 {
151 unsigned int cpu;
152 int rc, current;
153
154 for (cpu = 0; cpu < setsize; cpu++) {
155 if (!CPU_ISSET(cpu, cpu_set))
156 continue;
157 if (!path_exist(_PATH_SYS_CPU "/cpu%d", cpu)) {
158 printf(_("CPU %d does not exist\n"), cpu);
159 continue;
160 }
161 if (!path_exist(_PATH_SYS_CPU "/cpu%d/configure", cpu)) {
162 printf(_("CPU %d is not configurable\n"), cpu);
163 continue;
164 }
165 current = path_getnum(_PATH_SYS_CPU "/cpu%d/configure", cpu);
166 if ((current == 1) && (configure == 1)) {
167 printf(_("CPU %d is already configured\n"), cpu);
168 continue;
169 }
170 if ((current == 0) && (configure == 0)) {
171 printf(_("CPU %d is already deconfigured\n"), cpu);
172 continue;
173 }
174 if ((current == 1) && (configure == 0) && onlinecpus &&
175 is_cpu_online(cpu)) {
176 printf(_("CPU %d deconfigure failed "
177 "(CPU is enabled)\n"), cpu);
178 continue;
179 }
180 if (configure) {
181 rc = path_writestr("1", _PATH_SYS_CPU "/cpu%d/configure", cpu);
182 if (rc == -1)
183 printf(_("CPU %d configure failed (%m)\n"), cpu);
184 else
185 printf(_("CPU %d configured\n"), cpu);
186 } else {
187 rc = path_writestr("0", _PATH_SYS_CPU "/cpu%d/configure", cpu);
188 if (rc == -1)
189 printf(_("CPU %d deconfigure failed (%m)\n"), cpu);
190 else
191 printf(_("CPU %d deconfigured\n"), cpu);
192 }
193 }
194 return EXIT_SUCCESS;
195 }
196
197 static void cpu_parse(char *cpu_string, cpu_set_t *cpu_set, size_t setsize)
198 {
199 int rc;
200
201 rc = cpulist_parse(cpu_string, cpu_set, setsize, 1);
202 if (rc == 0)
203 return;
204 if (rc == 2)
205 errx(EXIT_FAILURE, _("invalid CPU number in CPU list: %s"), cpu_string);
206 errx(EXIT_FAILURE, _("failed to parse CPU list: %s"), cpu_string);
207 }
208
209 static void __attribute__((__noreturn__)) usage(FILE *out)
210 {
211 fprintf(out, _(
212 "\nUsage:\n"
213 " %s [options]\n"), program_invocation_short_name);
214
215 puts(_( "\nOptions:\n"
216 " -h, --help print this help\n"
217 " -e, --enable <cpu-list> enable cpus\n"
218 " -d, --disable <cpu-list> disable cpus\n"
219 " -c, --configure <cpu-list> configure cpus\n"
220 " -g, --deconfigure <cpu-list> deconfigure cpus\n"
221 " -p, --dispatch <mode> set dispatching mode\n"
222 " -r, --rescan trigger rescan of cpus\n"
223 " -V, --version output version information and exit\n"));
224
225 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
226 }
227
228 int main(int argc, char *argv[])
229 {
230 cpu_set_t *cpu_set;
231 size_t setsize;
232 int cmd = -1;
233 int c;
234
235 static const struct option longopts[] = {
236 { "configure", required_argument, 0, 'c' },
237 { "deconfigure",required_argument, 0, 'g' },
238 { "disable", required_argument, 0, 'd' },
239 { "dispatch", required_argument, 0, 'p' },
240 { "enable", required_argument, 0, 'e' },
241 { "help", no_argument, 0, 'h' },
242 { "rescan", no_argument, 0, 'r' },
243 { "version", no_argument, 0, 'V' },
244 { NULL, 0, 0, 0 }
245 };
246
247 setlocale(LC_ALL, "");
248 bindtextdomain(PACKAGE, LOCALEDIR);
249 textdomain(PACKAGE);
250 atexit(close_stdout);
251
252 maxcpus = get_max_number_of_cpus();
253 if (maxcpus < 1)
254 errx(EXIT_FAILURE, _("cannot determine NR_CPUS; aborting"));
255 if (path_exist(_PATH_SYS_CPU_ONLINE))
256 onlinecpus = path_cpulist(maxcpus, _PATH_SYS_CPU_ONLINE);
257 setsize = CPU_ALLOC_SIZE(maxcpus);
258 cpu_set = CPU_ALLOC(maxcpus);
259 if (!cpu_set)
260 err(EXIT_FAILURE, _("cpuset_alloc failed"));
261
262 while ((c = getopt_long(argc, argv, "c:d:e:g:hp:rV", longopts, NULL)) != -1) {
263 if (cmd != -1 && strchr("cdegpr", c))
264 errx(EXIT_FAILURE,
265 _("configure, deconfigure, disable, dispatch, enable "
266 "and rescan are mutually exclusive"));
267 switch (c) {
268 case 'c':
269 cmd = CMD_CPU_CONFIGURE;
270 cpu_parse(argv[optind - 1], cpu_set, setsize);
271 break;
272 case 'd':
273 cmd = CMD_CPU_DISABLE;
274 cpu_parse(argv[optind - 1], cpu_set, setsize);
275 break;
276 case 'e':
277 cmd = CMD_CPU_ENABLE;
278 cpu_parse(argv[optind - 1], cpu_set, setsize);
279 break;
280 case 'g':
281 cmd = CMD_CPU_DECONFIGURE;
282 cpu_parse(argv[optind - 1], cpu_set, setsize);
283 break;
284 case 'h':
285 usage(stdout);
286 case 'p':
287 if (strcmp("horizontal", argv[optind - 1]) == 0)
288 cmd = CMD_CPU_DISPATCH_HORIZONTAL;
289 else if (strcmp("vertical", argv[optind - 1]) == 0)
290 cmd = CMD_CPU_DISPATCH_VERTICAL;
291 else
292 errx(EXIT_FAILURE, _("unsupported argument: %s"),
293 argv[optind -1 ]);
294 break;
295 case 'r':
296 cmd = CMD_CPU_RESCAN;
297 break;
298 case 'V':
299 printf(_("%s from %s\n"), program_invocation_short_name,
300 PACKAGE_STRING);
301 return EXIT_SUCCESS;
302 default:
303 usage(stderr);
304 }
305 }
306
307 if ((argc == 1) || (argc != optind))
308 usage(stderr);
309
310 switch (cmd) {
311 case CMD_CPU_ENABLE:
312 return cpu_enable(cpu_set, maxcpus, 1);
313 case CMD_CPU_DISABLE:
314 return cpu_enable(cpu_set, maxcpus, 0);
315 case CMD_CPU_CONFIGURE:
316 return cpu_configure(cpu_set, maxcpus, 1);
317 case CMD_CPU_DECONFIGURE:
318 return cpu_configure(cpu_set, maxcpus, 0);
319 case CMD_CPU_RESCAN:
320 return cpu_rescan();
321 case CMD_CPU_DISPATCH_HORIZONTAL:
322 return cpu_set_dispatch(0);
323 case CMD_CPU_DISPATCH_VERTICAL:
324 return cpu_set_dispatch(1);
325 }
326 return EXIT_SUCCESS;
327 }