]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/vconsole/vconsole-setup.c
drop Arch Linux support for reading /etc/rc.conf
[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_ALTLINUX)
249 r = parse_env_file("/etc/sysconfig/keyboard", NEWLINE,
250 "KEYTABLE", &vc_keymap,
251 NULL)
252 if (r < 0 && r != -ENOENT)
253 log_warning("Failed to read /etc/sysconfig/keyboard: %s", strerror(-r));
254
255 r = parse_env_file("/etc/sysconfig/consolefont", NEWLINE,
256 "SYSFONT", &vc_font,
257 NULL);
258 if (r < 0 && r != -ENOENT)
259 log_warning("Failed to read /etc/sysconfig/consolefont: %s", strerror(-r));
260
261 #elif defined(TARGET_GENTOO)
262 r = parse_env_file("/etc/rc.conf", NEWLINE,
263 "unicode", &vc_unicode,
264 NULL);
265 if (r < 0 && r != -ENOENT)
266 log_warning("Failed to read /etc/rc.conf: %s", strerror(-r));
267
268 if (vc_unicode) {
269 int rc_unicode;
270
271 rc_unicode = parse_boolean(vc_unicode);
272 if (rc_unicode < 0)
273 log_warning("Unknown value for /etc/rc.conf unicode=%s", vc_unicode);
274 else {
275 if (rc_unicode && !utf8)
276 log_warning("/etc/rc.conf wants unicode, but current locale is not UTF-8 capable!");
277 else if (!rc_unicode && utf8) {
278 log_debug("/etc/rc.conf does not want unicode, leave it on in kernel but does not apply to vconsole.");
279 utf8 = false;
280 }
281 }
282 }
283
284 /* /etc/conf.d/consolefont comments and gentoo
285 * documentation mention uppercase, but the actual
286 * contents are lowercase. the existing
287 * /etc/init.d/consolefont tries both
288 */
289 r = parse_env_file("/etc/conf.d/consolefont", NEWLINE,
290 "CONSOLEFONT", &vc_font,
291 "consolefont", &vc_font,
292 "consoletranslation", &vc_font_map,
293 "CONSOLETRANSLATION", &vc_font_map,
294 "unicodemap", &vc_font_unimap,
295 "UNICODEMAP", &vc_font_unimap,
296 NULL);
297 if (r < 0 && r != -ENOENT)
298 log_warning("Failed to read /etc/conf.d/consolefont: %s", strerror(-r));
299
300 r = parse_env_file("/etc/conf.d/keymaps", NEWLINE,
301 "keymap", &vc_keymap,
302 "KEYMAP", &vc_keymap,
303 NULL);
304 if (r < 0 && r != -ENOENT)
305 log_warning("Failed to read /etc/conf.d/keymaps: %s", strerror(-r));
306
307 #elif defined(TARGET_MANDRIVA) || defined (TARGET_MAGEIA)
308
309 r = parse_env_file("/etc/sysconfig/i18n", NEWLINE,
310 "SYSFONT", &vc_font,
311 "SYSFONTACM", &vc_font_map,
312 "UNIMAP", &vc_font_unimap,
313 NULL);
314 if (r < 0 && r != -ENOENT)
315 log_warning("Failed to read /etc/sysconfig/i18n: %s", strerror(-r));
316
317 r = parse_env_file("/etc/sysconfig/keyboard", NEWLINE,
318 "KEYTABLE", &vc_keytable,
319 "KEYMAP", &vc_keymap,
320 "UNIKEYTABLE", &vc_keymap,
321 "GRP_TOGGLE", &vc_keymap_toggle,
322 NULL);
323 if (r < 0 && r != -ENOENT)
324 log_warning("Failed to read /etc/sysconfig/keyboard: %s", strerror(-r));
325
326 if (vc_keytable) {
327 free(vc_keymap);
328 if (utf8) {
329 if (endswith(vc_keytable, ".uni") || strstr(vc_keytable, ".uni."))
330 vc_keymap = strdup(vc_keytable);
331 else {
332 char *s;
333 s = strstr(vc_keytable, ".map");
334 if (s)
335 vc_keytable[s-vc_keytable+1] = '\0';
336 vc_keymap = strappend(vc_keytable, ".uni");
337 }
338 } else
339 vc_keymap = strdup(vc_keytable);
340
341 free(vc_keytable);
342
343 if (!vc_keymap) {
344 log_oom();
345 goto finish;
346 }
347 }
348
349 if (access("/etc/sysconfig/console/default.kmap", F_OK) >= 0) {
350 char *t;
351
352 t = strdup("/etc/sysconfig/console/default.kmap");
353 if (!t) {
354 log_oom();
355 goto finish;
356 }
357
358 free(vc_keymap);
359 vc_keymap = t;
360 }
361 #endif
362 }
363
364 r = EXIT_FAILURE;
365
366 if (utf8)
367 enable_utf8(fd);
368 else
369 disable_utf8(fd);
370
371
372 if (load_keymap(vc, vc_keymap, vc_keymap_toggle, utf8, &keymap_pid) >= 0 &&
373 load_font(vc, vc_font, vc_font_map, vc_font_unimap, &font_pid) >= 0)
374 r = EXIT_SUCCESS;
375
376 finish:
377 if (keymap_pid > 0)
378 wait_for_terminate_and_warn(KBD_LOADKEYS, keymap_pid);
379
380 if (font_pid > 0)
381 wait_for_terminate_and_warn(KBD_SETFONT, font_pid);
382
383 free(vc_keymap);
384 free(vc_font);
385 free(vc_font_map);
386 free(vc_font_unimap);
387
388 if (fd >= 0)
389 close_nointr_nofail(fd);
390
391 return r;
392 }