]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/vconsole-setup.c
umask: change default umask to 0022 just to be sure, and set it explicitly in all...
[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
944d4c91
LP
86 if (isempty(map)) {
87 /* An empty map means kernel map */
88 *_pid = 0;
89 return 0;
90 }
91
9841e8e3 92 args[i++] = KBD_LOADKEYS;
97c4a07d
LP
93 args[i++] = "-q";
94 args[i++] = "-C";
95 args[i++] = vc;
96 if (utf8)
97 args[i++] = "-u";
98 args[i++] = map;
5b396b06
AB
99 if (map_toggle)
100 args[i++] = map_toggle;
97c4a07d
LP
101 args[i++] = NULL;
102
103 if ((pid = fork()) < 0) {
104 log_error("Failed to fork: %m");
105 return -errno;
106 } else if (pid == 0) {
107 execv(args[0], (char **) args);
108 _exit(EXIT_FAILURE);
109 }
110
111 *_pid = pid;
112 return 0;
113}
114
115static int load_font(const char *vc, const char *font, const char *map, const char *unimap, pid_t *_pid) {
116 const char *args[9];
117 int i = 0;
118 pid_t pid;
119
944d4c91
LP
120 if (isempty(font)) {
121 /* An empty font means kernel font */
122 *_pid = 0;
123 return 0;
124 }
125
9841e8e3 126 args[i++] = KBD_SETFONT;
97c4a07d
LP
127 args[i++] = "-C";
128 args[i++] = vc;
129 args[i++] = font;
dd36de4d 130 if (map) {
97c4a07d
LP
131 args[i++] = "-m";
132 args[i++] = map;
133 }
dd36de4d 134 if (unimap) {
97c4a07d
LP
135 args[i++] = "-u";
136 args[i++] = unimap;
137 }
138 args[i++] = NULL;
139
140 if ((pid = fork()) < 0) {
141 log_error("Failed to fork: %m");
142 return -errno;
143 } else if (pid == 0) {
144 execv(args[0], (char **) args);
145 _exit(EXIT_FAILURE);
146 }
147
148 *_pid = pid;
149 return 0;
150}
151
152int main(int argc, char **argv) {
153 const char *vc;
154 char *vc_keymap = NULL;
5b396b06 155 char *vc_keymap_toggle = NULL;
97c4a07d
LP
156 char *vc_font = NULL;
157 char *vc_font_map = NULL;
158 char *vc_font_unimap = NULL;
9841e8e3
GSB
159#ifdef TARGET_GENTOO
160 char *vc_unicode = NULL;
1de4d79b
AB
161#endif
162#ifdef TARGET_MANDRIVA
163 char *vc_keytable = NULL;
9841e8e3 164#endif
97c4a07d
LP
165 int fd = -1;
166 bool utf8;
167 int r = EXIT_FAILURE;
168 pid_t font_pid = 0, keymap_pid = 0;
169
944d4c91 170 log_set_target(LOG_TARGET_AUTO);
97c4a07d
LP
171 log_parse_environment();
172 log_open();
173
4c12626c
LP
174 umask(0022);
175
97c4a07d
LP
176 if (argv[1])
177 vc = argv[1];
178 else
179 vc = "/dev/tty0";
180
a96257af 181 if ((fd = open_terminal(vc, O_RDWR|O_CLOEXEC)) < 0) {
97c4a07d
LP
182 log_error("Failed to open %s: %m", vc);
183 goto finish;
184 }
185
653ab83b 186 if (!is_vconsole(fd)) {
97c4a07d
LP
187 log_error("Device %s is not a virtual console.", vc);
188 goto finish;
189 }
190
653ab83b 191 utf8 = is_locale_utf8();
97c4a07d 192
944d4c91
LP
193 vc_keymap = strdup("us");
194 vc_font = strdup(DEFAULT_FONT);
195
196 if (!vc_keymap || !vc_font) {
197 log_error("Failed to allocate strings.");
198 goto finish;
199 }
200
201 r = 0;
202
03aea2ae 203 if (detect_container(NULL) <= 0)
2fc97846 204 if ((r = parse_env_file("/proc/cmdline", WHITESPACE,
54e4fdef 205#if defined(TARGET_FEDORA) || defined(TARGET_MEEGO)
2fc97846
LP
206 "SYSFONT", &vc_font,
207 "KEYTABLE", &vc_keymap,
653ab83b 208#endif
2fc97846
LP
209 "vconsole.keymap", &vc_keymap,
210 "vconsole.keymap.toggle", &vc_keymap_toggle,
211 "vconsole.font", &vc_font,
212 "vconsole.font.map", &vc_font_map,
213 "vconsole.font.unimap", &vc_font_unimap,
214 NULL)) < 0) {
215
216 if (r != -ENOENT)
217 log_warning("Failed to read /proc/cmdline: %s", strerror(-r));
218 }
1ebdf5b6 219
653ab83b 220 /* Hmm, nothing set on the kernel cmd line? Then let's
fd5bf055 221 * try /etc/vconsole.conf */
653ab83b 222 if (r <= 0 &&
fd5bf055 223 (r = parse_env_file("/etc/vconsole.conf", NEWLINE,
ae509abc 224 "KEYMAP", &vc_keymap,
5b396b06 225 "KEYMAP_TOGGLE", &vc_keymap_toggle,
653ab83b
LP
226 "FONT", &vc_font,
227 "FONT_MAP", &vc_font_map,
228 "FONT_UNIMAP", &vc_font_unimap,
1ebdf5b6
LP
229 NULL)) < 0) {
230
231 if (r != -ENOENT)
fd5bf055 232 log_warning("Failed to read /etc/vconsole.conf: %s", strerror(-r));
1ebdf5b6 233 }
ae509abc 234
653ab83b 235 if (r <= 0) {
54e4fdef 236#if defined(TARGET_FEDORA) || defined(TARGET_MEEGO)
653ab83b
LP
237 if ((r = parse_env_file("/etc/sysconfig/i18n", NEWLINE,
238 "SYSFONT", &vc_font,
239 "SYSFONTACM", &vc_font_map,
240 "UNIMAP", &vc_font_unimap,
241 NULL)) < 0) {
242
243 if (r != -ENOENT)
244 log_warning("Failed to read /etc/sysconfig/i18n: %s", strerror(-r));
ae509abc
LP
245 }
246
653ab83b
LP
247 if ((r = parse_env_file("/etc/sysconfig/keyboard", NEWLINE,
248 "KEYTABLE", &vc_keymap,
249 "KEYMAP", &vc_keymap,
250 NULL)) < 0) {
42431350 251
653ab83b
LP
252 if (r != -ENOENT)
253 log_warning("Failed to read /etc/sysconfig/i18n: %s", strerror(-r));
254 }
9841e8e3 255
653ab83b
LP
256 if (access("/etc/sysconfig/console/default.kmap", F_OK) >= 0) {
257 char *t;
258
259 if (!(t = strdup("/etc/sysconfig/console/default.kmap"))) {
260 log_error("Out of memory.");
261 goto finish;
9841e8e3 262 }
653ab83b
LP
263
264 free(vc_keymap);
265 vc_keymap = t;
9841e8e3 266 }
9841e8e3 267
03aeb5be
KS
268#elif defined(TARGET_SUSE)
269 if ((r = parse_env_file("/etc/sysconfig/keyboard", NEWLINE,
270 "KEYTABLE", &vc_keymap,
271 NULL)) < 0) {
272
273 if (r != -ENOENT)
274 log_warning("Failed to read /etc/sysconfig/keyboard: %s", strerror(-r));
275 }
276
277 if ((r = parse_env_file("/etc/sysconfig/console", NEWLINE,
278 "CONSOLE_FONT", &vc_font,
279 "CONSOLE_SCREENMAP", &vc_font_map,
280 "CONSOLE_UNICODEMAP", &vc_font_unimap,
281 NULL)) < 0) {
282
283 if (r != -ENOENT)
284 log_warning("Failed to read /etc/sysconfig/console: %s", strerror(-r));
285 }
286
653ab83b
LP
287#elif defined(TARGET_ARCH)
288 if ((r = parse_env_file("/etc/rc.conf", NEWLINE,
289 "KEYMAP", &vc_keymap,
290 "CONSOLEFONT", &vc_font,
291 "CONSOLEMAP", &vc_font_map,
292 NULL)) < 0) {
293
294 if (r != -ENOENT)
295 log_warning("Failed to read /etc/rc.conf: %s", strerror(-r));
296 }
9841e8e3 297
f5c88ec1
MV
298#elif defined(TARGET_FRUGALWARE)
299 if ((r = parse_env_file("/etc/sysconfig/keymap", NEWLINE,
300 "keymap", &vc_keymap,
301 NULL)) < 0) {
302 if (r != -ENOENT)
303 log_warning("Failed to read /etc/sysconfig/keymap: %s", strerror(-r));
304 }
305 if ((r = parse_env_file("/etc/sysconfig/font", NEWLINE,
306 "font", &vc_font,
307 NULL)) < 0) {
308 if (r != -ENOENT)
309 log_warning("Failed to read /etc/sysconfig/font: %s", strerror(-r));
310 }
a338bab5
AS
311
312#elif defined(TARGET_ALTLINUX)
313 if ((r = parse_env_file("/etc/sysconfig/keyboard", NEWLINE,
314 "KEYTABLE", &vc_keymap,
315 NULL)) < 0) {
316
317 if (r != -ENOENT)
318 log_warning("Failed to read /etc/sysconfig/keyboard: %s", strerror(-r));
319 }
320
321 if ((r = parse_env_file("/etc/sysconfig/consolefont", NEWLINE,
322 "SYSFONT", &vc_font,
323 NULL)) < 0) {
324
325 if (r != -ENOENT)
326 log_warning("Failed to read /etc/sysconfig/console: %s", strerror(-r));
327 }
328
653ab83b
LP
329#elif defined(TARGET_GENTOO)
330 if ((r = parse_env_file("/etc/rc.conf", NEWLINE,
331 "unicode", &vc_unicode,
332 NULL)) < 0) {
333 if (r != -ENOENT)
334 log_warning("Failed to read /etc/rc.conf: %s", strerror(-r));
335 }
1ebdf5b6 336
653ab83b
LP
337 if (vc_unicode) {
338 int rc_unicode;
339
340 if ((rc_unicode = parse_boolean(vc_unicode)) < 0)
341 log_error("Unknown value for /etc/rc.conf unicode=%s", vc_unicode);
342 else {
343 if (rc_unicode && !utf8)
344 log_warning("/etc/rc.conf wants unicode, but current locale is not UTF-8 capable!");
345 else if (!rc_unicode && utf8) {
346 log_debug("/etc/rc.conf does not want unicode, leave it on in kernel but does not apply to vconsole.");
347 utf8 = false;
348 }
349 }
350 }
97c4a07d 351
653ab83b
LP
352 /* /etc/conf.d/consolefont comments and gentoo
353 * documentation mention uppercase, but the actual
354 * contents are lowercase. the existing
355 * /etc/init.d/consolefont tries both
356 */
357 if ((r = parse_env_file("/etc/conf.d/consolefont", NEWLINE,
358 "CONSOLEFONT", &vc_font,
359 "consolefont", &vc_font,
360 "consoletranslation", &vc_font_map,
361 "CONSOLETRANSLATION", &vc_font_map,
362 "unicodemap", &vc_font_unimap,
363 "UNICODEMAP", &vc_font_unimap,
364 NULL)) < 0) {
365 if (r != -ENOENT)
366 log_warning("Failed to read /etc/conf.d/consolefont: %s", strerror(-r));
367 }
97c4a07d 368
653ab83b
LP
369 if ((r = parse_env_file("/etc/conf.d/keymaps", NEWLINE,
370 "keymap", &vc_keymap,
371 "KEYMAP", &vc_keymap,
372 NULL)) < 0) {
373 if (r != -ENOENT)
374 log_warning("Failed to read /etc/conf.d/keymaps: %s", strerror(-r));
375 }
1de4d79b
AB
376
377#elif defined(TARGET_MANDRIVA)
378
379 if ((r = parse_env_file("/etc/sysconfig/i18n", NEWLINE,
380 "SYSFONT", &vc_font,
381 "SYSFONTACM", &vc_font_map,
382 "UNIMAP", &vc_font_unimap,
383 NULL)) < 0) {
384
385 if (r != -ENOENT)
386 log_warning("Failed to read /etc/sysconfig/i18n: %s", strerror(-r));
387 }
388
389 if ((r = parse_env_file("/etc/sysconfig/keyboard", NEWLINE,
390 "KEYTABLE", &vc_keytable,
391 "KEYMAP", &vc_keymap,
392 "UNIKEYTABLE", &vc_keymap,
393 "GRP_TOGGLE", &vc_keymap_toggle,
394 NULL)) < 0) {
395
396 if (r != -ENOENT)
397 log_warning("Failed to read /etc/sysconfig/i18n: %s", strerror(-r));
398 }
399
400 if (vc_keytable) {
401 if (vc_keymap)
402 free(vc_keymap);
403 if (utf8) {
404 if (endswith(vc_keytable, ".uni") || strstr(vc_keytable, ".uni."))
405 vc_keymap = strdup(vc_keytable);
406 else {
407 char *s;
408 if ((s = strstr(vc_keytable, ".map")))
409 vc_keytable[s-vc_keytable+1] = '\0';
410 vc_keymap = strappend(vc_keytable, ".uni");
411 }
412 } else
413 vc_keymap = strdup(vc_keytable);
414
415 free(vc_keytable);
416
417 if (!vc_keymap) {
418 log_error("Out of memory.");
419 goto finish;
420 }
421 }
422
423 if (access("/etc/sysconfig/console/default.kmap", F_OK) >= 0) {
424 char *t;
425
426 if (!(t = strdup("/etc/sysconfig/console/default.kmap"))) {
427 log_error("Out of memory.");
428 goto finish;
429 }
430
431 free(vc_keymap);
432 vc_keymap = t;
433 }
97c4a07d 434#endif
97c4a07d
LP
435 }
436
944d4c91 437 r = EXIT_FAILURE;
97c4a07d 438
653ab83b
LP
439 if (!utf8)
440 disable_utf8(fd);
441
5b396b06 442 if (load_keymap(vc, vc_keymap, vc_keymap_toggle, utf8, &keymap_pid) >= 0 &&
97c4a07d
LP
443 load_font(vc, vc_font, vc_font_map, vc_font_unimap, &font_pid) >= 0)
444 r = EXIT_SUCCESS;
445
446finish:
447 if (keymap_pid > 0)
9841e8e3 448 wait_for_terminate_and_warn(KBD_LOADKEYS, keymap_pid);
97c4a07d
LP
449
450 if (font_pid > 0)
9841e8e3 451 wait_for_terminate_and_warn(KBD_SETFONT, font_pid);
97c4a07d
LP
452
453 free(vc_keymap);
454 free(vc_font);
455 free(vc_font_map);
456 free(vc_font_unimap);
457
458 if (fd >= 0)
459 close_nointr_nofail(fd);
460
461 return r;
462}