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