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