1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Kay Sievers
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.
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.
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/>.
34 #include <sys/ioctl.h>
36 #include <linux/tiocl.h>
44 static bool is_vconsole(int fd) {
45 unsigned char data[1];
47 data[0] = TIOCL_GETFGCONSOLE;
48 return ioctl(fd, TIOCLINUX, data) >= 0;
51 static bool is_locale_utf8(void) {
54 if (!setlocale(LC_ALL, ""))
57 set = nl_langinfo(CODESET);
61 return streq(set, "UTF-8");
64 static int disable_utf8(int fd) {
67 if (ioctl(fd, KDSKBMODE, K_XLATE) < 0)
70 if (loop_write(fd, "\033%@", 3, false) < 0)
73 if ((k = write_one_line_file("/sys/module/vt/parameters/default_utf8", "0")) < 0)
77 log_warning("Failed to disable UTF-8: %s", strerror(errno));
82 static int load_keymap(const char *vc, const char *map, const char *map_toggle, bool utf8, pid_t *_pid) {
88 /* An empty map means kernel map */
93 args[i++] = KBD_LOADKEYS;
101 args[i++] = map_toggle;
104 if ((pid = fork()) < 0) {
105 log_error("Failed to fork: %m");
107 } else if (pid == 0) {
108 execv(args[0], (char **) args);
116 static int load_font(const char *vc, const char *font, const char *map, const char *unimap, pid_t *_pid) {
122 /* An empty font means kernel font */
127 args[i++] = KBD_SETFONT;
141 if ((pid = fork()) < 0) {
142 log_error("Failed to fork: %m");
144 } else if (pid == 0) {
145 execv(args[0], (char **) args);
153 int main(int argc, char **argv) {
155 char *vc_keymap = NULL;
156 char *vc_keymap_toggle = NULL;
157 char *vc_font = NULL;
158 char *vc_font_map = NULL;
159 char *vc_font_unimap = NULL;
161 char *vc_unicode = NULL;
163 #if defined(TARGET_MANDRIVA) || defined(TARGET_MAGEIA)
164 char *vc_keytable = NULL;
168 int r = EXIT_FAILURE;
169 pid_t font_pid = 0, keymap_pid = 0;
171 log_set_target(LOG_TARGET_AUTO);
172 log_parse_environment();
182 if ((fd = open_terminal(vc, O_RDWR|O_CLOEXEC)) < 0) {
183 log_error("Failed to open %s: %m", vc);
187 if (!is_vconsole(fd)) {
188 log_error("Device %s is not a virtual console.", vc);
192 utf8 = is_locale_utf8();
194 vc_keymap = strdup("us");
195 vc_font = strdup(DEFAULT_FONT);
197 if (!vc_keymap || !vc_font) {
198 log_error("Failed to allocate strings.");
204 if (detect_container(NULL) <= 0)
205 if ((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,
214 log_warning("Failed to read /proc/cmdline: %s", strerror(-r));
217 /* Hmm, nothing set on the kernel cmd line? Then let's
218 * try /etc/vconsole.conf */
220 (r = parse_env_file("/etc/vconsole.conf", NEWLINE,
221 "KEYMAP", &vc_keymap,
222 "KEYMAP_TOGGLE", &vc_keymap_toggle,
224 "FONT_MAP", &vc_font_map,
225 "FONT_UNIMAP", &vc_font_unimap,
229 log_warning("Failed to read /etc/vconsole.conf: %s", strerror(-r));
233 #if defined(TARGET_FEDORA) || defined(TARGET_MEEGO)
234 if ((r = parse_env_file("/etc/sysconfig/i18n", NEWLINE,
236 "SYSFONTACM", &vc_font_map,
237 "UNIMAP", &vc_font_unimap,
241 log_warning("Failed to read /etc/sysconfig/i18n: %s", strerror(-r));
244 if ((r = parse_env_file("/etc/sysconfig/keyboard", NEWLINE,
245 "KEYTABLE", &vc_keymap,
246 "KEYMAP", &vc_keymap,
250 log_warning("Failed to read /etc/sysconfig/i18n: %s", strerror(-r));
253 if (access("/etc/sysconfig/console/default.kmap", F_OK) >= 0) {
256 if (!(t = strdup("/etc/sysconfig/console/default.kmap"))) {
257 log_error("Out of memory.");
265 #elif defined(TARGET_SUSE)
266 if ((r = parse_env_file("/etc/sysconfig/keyboard", NEWLINE,
267 "KEYTABLE", &vc_keymap,
271 log_warning("Failed to read /etc/sysconfig/keyboard: %s", strerror(-r));
274 if ((r = parse_env_file("/etc/sysconfig/console", NEWLINE,
275 "CONSOLE_FONT", &vc_font,
276 "CONSOLE_SCREENMAP", &vc_font_map,
277 "CONSOLE_UNICODEMAP", &vc_font_unimap,
281 log_warning("Failed to read /etc/sysconfig/console: %s", strerror(-r));
284 #elif defined(TARGET_ARCH)
285 if ((r = parse_env_file("/etc/rc.conf", NEWLINE,
286 "KEYMAP", &vc_keymap,
287 "CONSOLEFONT", &vc_font,
288 "CONSOLEMAP", &vc_font_map,
292 log_warning("Failed to read /etc/rc.conf: %s", strerror(-r));
295 #elif defined(TARGET_FRUGALWARE)
296 if ((r = parse_env_file("/etc/sysconfig/keymap", NEWLINE,
297 "keymap", &vc_keymap,
300 log_warning("Failed to read /etc/sysconfig/keymap: %s", strerror(-r));
302 if ((r = parse_env_file("/etc/sysconfig/font", NEWLINE,
306 log_warning("Failed to read /etc/sysconfig/font: %s", strerror(-r));
309 #elif defined(TARGET_ALTLINUX)
310 if ((r = parse_env_file("/etc/sysconfig/keyboard", NEWLINE,
311 "KEYTABLE", &vc_keymap,
315 log_warning("Failed to read /etc/sysconfig/keyboard: %s", strerror(-r));
318 if ((r = parse_env_file("/etc/sysconfig/consolefont", NEWLINE,
323 log_warning("Failed to read /etc/sysconfig/console: %s", strerror(-r));
326 #elif defined(TARGET_GENTOO)
327 if ((r = parse_env_file("/etc/rc.conf", NEWLINE,
328 "unicode", &vc_unicode,
331 log_warning("Failed to read /etc/rc.conf: %s", strerror(-r));
337 if ((rc_unicode = parse_boolean(vc_unicode)) < 0)
338 log_error("Unknown value for /etc/rc.conf unicode=%s", vc_unicode);
340 if (rc_unicode && !utf8)
341 log_warning("/etc/rc.conf wants unicode, but current locale is not UTF-8 capable!");
342 else if (!rc_unicode && utf8) {
343 log_debug("/etc/rc.conf does not want unicode, leave it on in kernel but does not apply to vconsole.");
349 /* /etc/conf.d/consolefont comments and gentoo
350 * documentation mention uppercase, but the actual
351 * contents are lowercase. the existing
352 * /etc/init.d/consolefont tries both
354 if ((r = parse_env_file("/etc/conf.d/consolefont", NEWLINE,
355 "CONSOLEFONT", &vc_font,
356 "consolefont", &vc_font,
357 "consoletranslation", &vc_font_map,
358 "CONSOLETRANSLATION", &vc_font_map,
359 "unicodemap", &vc_font_unimap,
360 "UNICODEMAP", &vc_font_unimap,
363 log_warning("Failed to read /etc/conf.d/consolefont: %s", strerror(-r));
366 if ((r = parse_env_file("/etc/conf.d/keymaps", NEWLINE,
367 "keymap", &vc_keymap,
368 "KEYMAP", &vc_keymap,
371 log_warning("Failed to read /etc/conf.d/keymaps: %s", strerror(-r));
374 #elif defined(TARGET_MANDRIVA) || defined (TARGET_MAGEIA)
376 if ((r = parse_env_file("/etc/sysconfig/i18n", NEWLINE,
378 "SYSFONTACM", &vc_font_map,
379 "UNIMAP", &vc_font_unimap,
383 log_warning("Failed to read /etc/sysconfig/i18n: %s", strerror(-r));
386 if ((r = parse_env_file("/etc/sysconfig/keyboard", NEWLINE,
387 "KEYTABLE", &vc_keytable,
388 "KEYMAP", &vc_keymap,
389 "UNIKEYTABLE", &vc_keymap,
390 "GRP_TOGGLE", &vc_keymap_toggle,
394 log_warning("Failed to read /etc/sysconfig/i18n: %s", strerror(-r));
401 if (endswith(vc_keytable, ".uni") || strstr(vc_keytable, ".uni."))
402 vc_keymap = strdup(vc_keytable);
405 if ((s = strstr(vc_keytable, ".map")))
406 vc_keytable[s-vc_keytable+1] = '\0';
407 vc_keymap = strappend(vc_keytable, ".uni");
410 vc_keymap = strdup(vc_keytable);
415 log_error("Out of memory.");
420 if (access("/etc/sysconfig/console/default.kmap", F_OK) >= 0) {
423 if (!(t = strdup("/etc/sysconfig/console/default.kmap"))) {
424 log_error("Out of memory.");
439 if (load_keymap(vc, vc_keymap, vc_keymap_toggle, utf8, &keymap_pid) >= 0 &&
440 load_font(vc, vc_font, vc_font_map, vc_font_unimap, &font_pid) >= 0)
445 wait_for_terminate_and_warn(KBD_LOADKEYS, keymap_pid);
448 wait_for_terminate_and_warn(KBD_SETFONT, font_pid);
453 free(vc_font_unimap);
456 close_nointr_nofail(fd);