chiark / gitweb /
vconsole: remove Frugalware legacy file support
[elogind.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 }