]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/vconsole-setup.c
nspawn: don't fail when we receive SIGCHLD
[thirdparty/systemd.git] / src / vconsole-setup.c
CommitLineData
97c4a07d
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Kay Sievers
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <stdio.h>
23#include <unistd.h>
24#include <stdlib.h>
25#include <errno.h>
26#include <string.h>
27#include <fcntl.h>
28#include <ctype.h>
29#include <stdbool.h>
30#include <stdarg.h>
31#include <limits.h>
32#include <locale.h>
33#include <langinfo.h>
34#include <sys/ioctl.h>
35#include <sys/wait.h>
36#include <linux/tiocl.h>
37#include <linux/kd.h>
38
39#include "util.h"
40#include "log.h"
41#include "macro.h"
42
653ab83b 43static bool is_vconsole(int fd) {
97c4a07d
LP
44 unsigned char data[1];
45
46 data[0] = TIOCL_GETFGCONSOLE;
47 return ioctl(fd, TIOCLINUX, data) >= 0;
48}
49
50static bool is_locale_utf8(void) {
51 const char *set;
52
53 if (!setlocale(LC_ALL, ""))
54 return true;
55
56 set = nl_langinfo(CODESET);
57 if (!set)
58 return true;
59
60 return streq(set, "UTF-8");
61}
62
63static int disable_utf8(int fd) {
64 int r = 0, k;
65
66 if (ioctl(fd, KDSKBMODE, K_XLATE) < 0)
67 r = -errno;
68
69 if (loop_write(fd, "\033%@", 3, false) < 0)
70 r = -errno;
71
72 if ((k = write_one_line_file("/sys/module/vt/parameters/default_utf8", "0")) < 0)
73 r = k;
74
75 if (r < 0)
76 log_warning("Failed to disable UTF-8: %s", strerror(errno));
77
78 return r;
79}
80
5b396b06
AB
81static int load_keymap(const char *vc, const char *map, const char *map_toggle, bool utf8, pid_t *_pid) {
82 const char *args[8];
97c4a07d
LP
83 int i = 0;
84 pid_t pid;
85
9841e8e3 86 args[i++] = KBD_LOADKEYS;
97c4a07d
LP
87 args[i++] = "-q";
88 args[i++] = "-C";
89 args[i++] = vc;
90 if (utf8)
91 args[i++] = "-u";
92 args[i++] = map;
5b396b06
AB
93 if (map_toggle)
94 args[i++] = map_toggle;
97c4a07d
LP
95 args[i++] = NULL;
96
97 if ((pid = fork()) < 0) {
98 log_error("Failed to fork: %m");
99 return -errno;
100 } else if (pid == 0) {
101 execv(args[0], (char **) args);
102 _exit(EXIT_FAILURE);
103 }
104
105 *_pid = pid;
106 return 0;
107}
108
109static int load_font(const char *vc, const char *font, const char *map, const char *unimap, pid_t *_pid) {
110 const char *args[9];
111 int i = 0;
112 pid_t pid;
113
9841e8e3 114 args[i++] = KBD_SETFONT;
97c4a07d
LP
115 args[i++] = "-C";
116 args[i++] = vc;
117 args[i++] = font;
dd36de4d 118 if (map) {
97c4a07d
LP
119 args[i++] = "-m";
120 args[i++] = map;
121 }
dd36de4d 122 if (unimap) {
97c4a07d
LP
123 args[i++] = "-u";
124 args[i++] = unimap;
125 }
126 args[i++] = NULL;
127
128 if ((pid = fork()) < 0) {
129 log_error("Failed to fork: %m");
130 return -errno;
131 } else if (pid == 0) {
132 execv(args[0], (char **) args);
133 _exit(EXIT_FAILURE);
134 }
135
136 *_pid = pid;
137 return 0;
138}
139
140int main(int argc, char **argv) {
141 const char *vc;
142 char *vc_keymap = NULL;
5b396b06 143 char *vc_keymap_toggle = NULL;
97c4a07d
LP
144 char *vc_font = NULL;
145 char *vc_font_map = NULL;
146 char *vc_font_unimap = NULL;
9841e8e3
GSB
147#ifdef TARGET_GENTOO
148 char *vc_unicode = NULL;
1de4d79b
AB
149#endif
150#ifdef TARGET_MANDRIVA
151 char *vc_keytable = NULL;
9841e8e3 152#endif
97c4a07d
LP
153 int fd = -1;
154 bool utf8;
155 int r = EXIT_FAILURE;
156 pid_t font_pid = 0, keymap_pid = 0;
157
158 log_set_target(LOG_TARGET_SYSLOG_OR_KMSG);
159 log_parse_environment();
160 log_open();
161
162 if (argv[1])
163 vc = argv[1];
164 else
165 vc = "/dev/tty0";
166
167 if ((fd = open(vc, O_RDWR|O_CLOEXEC)) < 0) {
168 log_error("Failed to open %s: %m", vc);
169 goto finish;
170 }
171
653ab83b 172 if (!is_vconsole(fd)) {
97c4a07d
LP
173 log_error("Device %s is not a virtual console.", vc);
174 goto finish;
175 }
176
653ab83b 177 utf8 = is_locale_utf8();
97c4a07d 178
03aea2ae 179 if (detect_container(NULL) <= 0)
2fc97846 180 if ((r = parse_env_file("/proc/cmdline", WHITESPACE,
54e4fdef 181#if defined(TARGET_FEDORA) || defined(TARGET_MEEGO)
2fc97846
LP
182 "SYSFONT", &vc_font,
183 "KEYTABLE", &vc_keymap,
653ab83b 184#endif
2fc97846
LP
185 "vconsole.keymap", &vc_keymap,
186 "vconsole.keymap.toggle", &vc_keymap_toggle,
187 "vconsole.font", &vc_font,
188 "vconsole.font.map", &vc_font_map,
189 "vconsole.font.unimap", &vc_font_unimap,
190 NULL)) < 0) {
191
192 if (r != -ENOENT)
193 log_warning("Failed to read /proc/cmdline: %s", strerror(-r));
194 }
1ebdf5b6 195
653ab83b 196 /* Hmm, nothing set on the kernel cmd line? Then let's
fd5bf055 197 * try /etc/vconsole.conf */
653ab83b 198 if (r <= 0 &&
fd5bf055 199 (r = parse_env_file("/etc/vconsole.conf", NEWLINE,
ae509abc 200 "KEYMAP", &vc_keymap,
5b396b06 201 "KEYMAP_TOGGLE", &vc_keymap_toggle,
653ab83b
LP
202 "FONT", &vc_font,
203 "FONT_MAP", &vc_font_map,
204 "FONT_UNIMAP", &vc_font_unimap,
1ebdf5b6
LP
205 NULL)) < 0) {
206
207 if (r != -ENOENT)
fd5bf055 208 log_warning("Failed to read /etc/vconsole.conf: %s", strerror(-r));
1ebdf5b6 209 }
ae509abc 210
653ab83b 211 if (r <= 0) {
54e4fdef 212#if defined(TARGET_FEDORA) || defined(TARGET_MEEGO)
653ab83b
LP
213 if ((r = parse_env_file("/etc/sysconfig/i18n", NEWLINE,
214 "SYSFONT", &vc_font,
215 "SYSFONTACM", &vc_font_map,
216 "UNIMAP", &vc_font_unimap,
217 NULL)) < 0) {
218
219 if (r != -ENOENT)
220 log_warning("Failed to read /etc/sysconfig/i18n: %s", strerror(-r));
ae509abc
LP
221 }
222
653ab83b
LP
223 if ((r = parse_env_file("/etc/sysconfig/keyboard", NEWLINE,
224 "KEYTABLE", &vc_keymap,
225 "KEYMAP", &vc_keymap,
226 NULL)) < 0) {
42431350 227
653ab83b
LP
228 if (r != -ENOENT)
229 log_warning("Failed to read /etc/sysconfig/i18n: %s", strerror(-r));
230 }
9841e8e3 231
653ab83b
LP
232 if (access("/etc/sysconfig/console/default.kmap", F_OK) >= 0) {
233 char *t;
234
235 if (!(t = strdup("/etc/sysconfig/console/default.kmap"))) {
236 log_error("Out of memory.");
237 goto finish;
9841e8e3 238 }
653ab83b
LP
239
240 free(vc_keymap);
241 vc_keymap = t;
9841e8e3 242 }
9841e8e3 243
03aeb5be
KS
244#elif defined(TARGET_SUSE)
245 if ((r = parse_env_file("/etc/sysconfig/keyboard", NEWLINE,
246 "KEYTABLE", &vc_keymap,
247 NULL)) < 0) {
248
249 if (r != -ENOENT)
250 log_warning("Failed to read /etc/sysconfig/keyboard: %s", strerror(-r));
251 }
252
253 if ((r = parse_env_file("/etc/sysconfig/console", NEWLINE,
254 "CONSOLE_FONT", &vc_font,
255 "CONSOLE_SCREENMAP", &vc_font_map,
256 "CONSOLE_UNICODEMAP", &vc_font_unimap,
257 NULL)) < 0) {
258
259 if (r != -ENOENT)
260 log_warning("Failed to read /etc/sysconfig/console: %s", strerror(-r));
261 }
262
653ab83b
LP
263#elif defined(TARGET_ARCH)
264 if ((r = parse_env_file("/etc/rc.conf", NEWLINE,
265 "KEYMAP", &vc_keymap,
266 "CONSOLEFONT", &vc_font,
267 "CONSOLEMAP", &vc_font_map,
268 NULL)) < 0) {
269
270 if (r != -ENOENT)
271 log_warning("Failed to read /etc/rc.conf: %s", strerror(-r));
272 }
9841e8e3 273
f5c88ec1
MV
274#elif defined(TARGET_FRUGALWARE)
275 if ((r = parse_env_file("/etc/sysconfig/keymap", NEWLINE,
276 "keymap", &vc_keymap,
277 NULL)) < 0) {
278 if (r != -ENOENT)
279 log_warning("Failed to read /etc/sysconfig/keymap: %s", strerror(-r));
280 }
281 if ((r = parse_env_file("/etc/sysconfig/font", NEWLINE,
282 "font", &vc_font,
283 NULL)) < 0) {
284 if (r != -ENOENT)
285 log_warning("Failed to read /etc/sysconfig/font: %s", strerror(-r));
286 }
a338bab5
AS
287
288#elif defined(TARGET_ALTLINUX)
289 if ((r = parse_env_file("/etc/sysconfig/keyboard", NEWLINE,
290 "KEYTABLE", &vc_keymap,
291 NULL)) < 0) {
292
293 if (r != -ENOENT)
294 log_warning("Failed to read /etc/sysconfig/keyboard: %s", strerror(-r));
295 }
296
297 if ((r = parse_env_file("/etc/sysconfig/consolefont", NEWLINE,
298 "SYSFONT", &vc_font,
299 NULL)) < 0) {
300
301 if (r != -ENOENT)
302 log_warning("Failed to read /etc/sysconfig/console: %s", strerror(-r));
303 }
304
653ab83b
LP
305#elif defined(TARGET_GENTOO)
306 if ((r = parse_env_file("/etc/rc.conf", NEWLINE,
307 "unicode", &vc_unicode,
308 NULL)) < 0) {
309 if (r != -ENOENT)
310 log_warning("Failed to read /etc/rc.conf: %s", strerror(-r));
311 }
1ebdf5b6 312
653ab83b
LP
313 if (vc_unicode) {
314 int rc_unicode;
315
316 if ((rc_unicode = parse_boolean(vc_unicode)) < 0)
317 log_error("Unknown value for /etc/rc.conf unicode=%s", vc_unicode);
318 else {
319 if (rc_unicode && !utf8)
320 log_warning("/etc/rc.conf wants unicode, but current locale is not UTF-8 capable!");
321 else if (!rc_unicode && utf8) {
322 log_debug("/etc/rc.conf does not want unicode, leave it on in kernel but does not apply to vconsole.");
323 utf8 = false;
324 }
325 }
326 }
97c4a07d 327
653ab83b
LP
328 /* /etc/conf.d/consolefont comments and gentoo
329 * documentation mention uppercase, but the actual
330 * contents are lowercase. the existing
331 * /etc/init.d/consolefont tries both
332 */
333 if ((r = parse_env_file("/etc/conf.d/consolefont", NEWLINE,
334 "CONSOLEFONT", &vc_font,
335 "consolefont", &vc_font,
336 "consoletranslation", &vc_font_map,
337 "CONSOLETRANSLATION", &vc_font_map,
338 "unicodemap", &vc_font_unimap,
339 "UNICODEMAP", &vc_font_unimap,
340 NULL)) < 0) {
341 if (r != -ENOENT)
342 log_warning("Failed to read /etc/conf.d/consolefont: %s", strerror(-r));
343 }
97c4a07d 344
653ab83b
LP
345 if ((r = parse_env_file("/etc/conf.d/keymaps", NEWLINE,
346 "keymap", &vc_keymap,
347 "KEYMAP", &vc_keymap,
348 NULL)) < 0) {
349 if (r != -ENOENT)
350 log_warning("Failed to read /etc/conf.d/keymaps: %s", strerror(-r));
351 }
1de4d79b
AB
352
353#elif defined(TARGET_MANDRIVA)
354
355 if ((r = parse_env_file("/etc/sysconfig/i18n", NEWLINE,
356 "SYSFONT", &vc_font,
357 "SYSFONTACM", &vc_font_map,
358 "UNIMAP", &vc_font_unimap,
359 NULL)) < 0) {
360
361 if (r != -ENOENT)
362 log_warning("Failed to read /etc/sysconfig/i18n: %s", strerror(-r));
363 }
364
365 if ((r = parse_env_file("/etc/sysconfig/keyboard", NEWLINE,
366 "KEYTABLE", &vc_keytable,
367 "KEYMAP", &vc_keymap,
368 "UNIKEYTABLE", &vc_keymap,
369 "GRP_TOGGLE", &vc_keymap_toggle,
370 NULL)) < 0) {
371
372 if (r != -ENOENT)
373 log_warning("Failed to read /etc/sysconfig/i18n: %s", strerror(-r));
374 }
375
376 if (vc_keytable) {
377 if (vc_keymap)
378 free(vc_keymap);
379 if (utf8) {
380 if (endswith(vc_keytable, ".uni") || strstr(vc_keytable, ".uni."))
381 vc_keymap = strdup(vc_keytable);
382 else {
383 char *s;
384 if ((s = strstr(vc_keytable, ".map")))
385 vc_keytable[s-vc_keytable+1] = '\0';
386 vc_keymap = strappend(vc_keytable, ".uni");
387 }
388 } else
389 vc_keymap = strdup(vc_keytable);
390
391 free(vc_keytable);
392
393 if (!vc_keymap) {
394 log_error("Out of memory.");
395 goto finish;
396 }
397 }
398
399 if (access("/etc/sysconfig/console/default.kmap", F_OK) >= 0) {
400 char *t;
401
402 if (!(t = strdup("/etc/sysconfig/console/default.kmap"))) {
403 log_error("Out of memory.");
404 goto finish;
405 }
406
407 free(vc_keymap);
408 vc_keymap = t;
409 }
97c4a07d 410#endif
97c4a07d
LP
411 }
412
413 if (!vc_keymap)
414 vc_keymap = strdup("us");
415 if (!vc_font)
9841e8e3 416 vc_font = strdup(DEFAULT_FONT);
97c4a07d
LP
417
418 if (!vc_keymap || !vc_font) {
419 log_error("Failed to allocate strings.");
420 goto finish;
421 }
422
653ab83b
LP
423 if (!utf8)
424 disable_utf8(fd);
425
5b396b06 426 if (load_keymap(vc, vc_keymap, vc_keymap_toggle, utf8, &keymap_pid) >= 0 &&
97c4a07d
LP
427 load_font(vc, vc_font, vc_font_map, vc_font_unimap, &font_pid) >= 0)
428 r = EXIT_SUCCESS;
429
430finish:
431 if (keymap_pid > 0)
9841e8e3 432 wait_for_terminate_and_warn(KBD_LOADKEYS, keymap_pid);
97c4a07d
LP
433
434 if (font_pid > 0)
9841e8e3 435 wait_for_terminate_and_warn(KBD_SETFONT, font_pid);
97c4a07d
LP
436
437 free(vc_keymap);
438 free(vc_font);
439 free(vc_font_map);
440 free(vc_font_unimap);
441
442 if (fd >= 0)
443 close_nointr_nofail(fd);
444
445 return r;
446}