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 k = write_one_line_file("/sys/module/vt/parameters/default_utf8", "0");
78 log_warning("Failed to disable UTF-8: %s", strerror(-r));
83 static int enable_utf8(int fd) {
86 if (ioctl(fd, KDSKBMODE, K_UNICODE) < 0)
89 if (loop_write(fd, "\033%G", 3, false) < 0)
92 k = write_one_line_file("/sys/module/vt/parameters/default_utf8", "1");
97 log_warning("Failed to enable UTF-8: %s", strerror(-r));
102 static int load_keymap(const char *vc, const char *map, const char *map_toggle, bool utf8, pid_t *_pid) {
108 /* An empty map means kernel map */
113 args[i++] = KBD_LOADKEYS;
121 args[i++] = map_toggle;
126 log_error("Failed to fork: %m");
128 } else if (pid == 0) {
129 execv(args[0], (char **) args);
137 static int load_font(const char *vc, const char *font, const char *map, const char *unimap, pid_t *_pid) {
143 /* An empty font means kernel font */
148 args[i++] = KBD_SETFONT;
164 log_error("Failed to fork: %m");
166 } else if (pid == 0) {
167 execv(args[0], (char **) args);
175 int main(int argc, char **argv) {
177 char *vc_keymap = NULL;
178 char *vc_keymap_toggle = NULL;
179 char *vc_font = NULL;
180 char *vc_font_map = NULL;
181 char *vc_font_unimap = NULL;
183 char *vc_unicode = NULL;
185 #if defined(TARGET_MANDRIVA) || defined(TARGET_MAGEIA)
186 char *vc_keytable = NULL;
190 int r = EXIT_FAILURE;
191 pid_t font_pid = 0, keymap_pid = 0;
193 log_set_target(LOG_TARGET_AUTO);
194 log_parse_environment();
204 fd = open_terminal(vc, O_RDWR|O_CLOEXEC);
206 log_error("Failed to open %s: %m", vc);
210 if (!is_vconsole(fd)) {
211 log_error("Device %s is not a virtual console.", vc);
215 utf8 = is_locale_utf8();
217 vc_keymap = strdup("us");
218 vc_font = strdup(DEFAULT_FONT);
220 if (!vc_keymap || !vc_font) {
221 log_error("Failed to allocate strings.");
227 if (detect_container(NULL) <= 0) {
228 r = parse_env_file("/proc/cmdline", WHITESPACE,
229 "vconsole.keymap", &vc_keymap,
230 "vconsole.keymap.toggle", &vc_keymap_toggle,
231 "vconsole.font", &vc_font,
232 "vconsole.font.map", &vc_font_map,
233 "vconsole.font.unimap", &vc_font_unimap,
236 if (r < 0 && r != -ENOENT)
237 log_warning("Failed to read /proc/cmdline: %s", strerror(-r));
240 /* Hmm, nothing set on the kernel cmd line? Then let's
241 * try /etc/vconsole.conf */
243 r = parse_env_file("/etc/vconsole.conf", NEWLINE,
244 "KEYMAP", &vc_keymap,
245 "KEYMAP_TOGGLE", &vc_keymap_toggle,
247 "FONT_MAP", &vc_font_map,
248 "FONT_UNIMAP", &vc_font_unimap,
251 if (r < 0 && r != -ENOENT)
252 log_warning("Failed to read /etc/vconsole.conf: %s", strerror(-r));
256 #if defined(TARGET_FEDORA) || defined(TARGET_MEEGO)
257 r = parse_env_file("/etc/sysconfig/i18n", NEWLINE,
259 "SYSFONTACM", &vc_font_map,
260 "UNIMAP", &vc_font_unimap,
262 if (r < 0 && r != -ENOENT)
263 log_warning("Failed to read /etc/sysconfig/i18n: %s", strerror(-r));
265 r = parse_env_file("/etc/sysconfig/keyboard", NEWLINE,
266 "KEYTABLE", &vc_keymap,
267 "KEYMAP", &vc_keymap,
269 if (r < 0 && r != -ENOENT)
270 log_warning("Failed to read /etc/sysconfig/keyboard: %s", strerror(-r));
272 if (access("/etc/sysconfig/console/default.kmap", F_OK) >= 0) {
275 t = strdup("/etc/sysconfig/console/default.kmap");
277 log_error("Out of memory.");
285 #elif defined(TARGET_SUSE)
286 r = parse_env_file("/etc/sysconfig/keyboard", NEWLINE,
287 "KEYTABLE", &vc_keymap,
289 if (r < 0 && r != -ENOENT)
290 log_warning("Failed to read /etc/sysconfig/keyboard: %s", strerror(-r));
292 r = parse_env_file("/etc/sysconfig/console", NEWLINE,
293 "CONSOLE_FONT", &vc_font,
294 "CONSOLE_SCREENMAP", &vc_font_map,
295 "CONSOLE_UNICODEMAP", &vc_font_unimap,
297 if (r < 0 && r != -ENOENT)
298 log_warning("Failed to read /etc/sysconfig/console: %s", strerror(-r));
300 #elif defined(TARGET_ARCH)
301 r = parse_env_file("/etc/rc.conf", NEWLINE,
302 "KEYMAP", &vc_keymap,
303 "CONSOLEFONT", &vc_font,
304 "CONSOLEMAP", &vc_font_map,
306 if (r < 0 && r != -ENOENT)
307 log_warning("Failed to read /etc/rc.conf: %s", strerror(-r));
309 #elif defined(TARGET_FRUGALWARE)
310 r = parse_env_file("/etc/sysconfig/keymap", NEWLINE,
311 "keymap", &vc_keymap,
313 if (r < 0 && r != -ENOENT)
314 log_warning("Failed to read /etc/sysconfig/keymap: %s", strerror(-r));
316 r = parse_env_file("/etc/sysconfig/font", NEWLINE,
319 if (r < 0 && r != -ENOENT)
320 log_warning("Failed to read /etc/sysconfig/font: %s", strerror(-r));
322 #elif defined(TARGET_ALTLINUX)
323 r = parse_env_file("/etc/sysconfig/keyboard", NEWLINE,
324 "KEYTABLE", &vc_keymap,
326 if (r < 0 && r != -ENOENT)
327 log_warning("Failed to read /etc/sysconfig/keyboard: %s", strerror(-r));
329 r = parse_env_file("/etc/sysconfig/consolefont", NEWLINE,
332 if (r < 0 && r != -ENOENT)
333 log_warning("Failed to read /etc/sysconfig/consolefont: %s", strerror(-r));
335 #elif defined(TARGET_GENTOO)
336 r = parse_env_file("/etc/rc.conf", NEWLINE,
337 "unicode", &vc_unicode,
339 if (r < 0 && r != -ENOENT)
340 log_warning("Failed to read /etc/rc.conf: %s", strerror(-r));
345 rc_unicode = parse_boolean(vc_unicode);
347 log_warning("Unknown value for /etc/rc.conf unicode=%s", vc_unicode);
349 if (rc_unicode && !utf8)
350 log_warning("/etc/rc.conf wants unicode, but current locale is not UTF-8 capable!");
351 else if (!rc_unicode && utf8) {
352 log_debug("/etc/rc.conf does not want unicode, leave it on in kernel but does not apply to vconsole.");
358 /* /etc/conf.d/consolefont comments and gentoo
359 * documentation mention uppercase, but the actual
360 * contents are lowercase. the existing
361 * /etc/init.d/consolefont tries both
363 r = parse_env_file("/etc/conf.d/consolefont", NEWLINE,
364 "CONSOLEFONT", &vc_font,
365 "consolefont", &vc_font,
366 "consoletranslation", &vc_font_map,
367 "CONSOLETRANSLATION", &vc_font_map,
368 "unicodemap", &vc_font_unimap,
369 "UNICODEMAP", &vc_font_unimap,
371 if (r < 0 && r != -ENOENT)
372 log_warning("Failed to read /etc/conf.d/consolefont: %s", strerror(-r));
374 r = parse_env_file("/etc/conf.d/keymaps", NEWLINE,
375 "keymap", &vc_keymap,
376 "KEYMAP", &vc_keymap,
378 if (r < 0 && r != -ENOENT)
379 log_warning("Failed to read /etc/conf.d/keymaps: %s", strerror(-r));
381 #elif defined(TARGET_MANDRIVA) || defined (TARGET_MAGEIA)
383 r = parse_env_file("/etc/sysconfig/i18n", NEWLINE,
385 "SYSFONTACM", &vc_font_map,
386 "UNIMAP", &vc_font_unimap,
388 if (r < 0 && r != -ENOENT)
389 log_warning("Failed to read /etc/sysconfig/i18n: %s", strerror(-r));
391 r = parse_env_file("/etc/sysconfig/keyboard", NEWLINE,
392 "KEYTABLE", &vc_keytable,
393 "KEYMAP", &vc_keymap,
394 "UNIKEYTABLE", &vc_keymap,
395 "GRP_TOGGLE", &vc_keymap_toggle,
397 if (r < 0 && r != -ENOENT)
398 log_warning("Failed to read /etc/sysconfig/keyboard: %s", strerror(-r));
403 if (endswith(vc_keytable, ".uni") || strstr(vc_keytable, ".uni."))
404 vc_keymap = strdup(vc_keytable);
407 s = strstr(vc_keytable, ".map");
409 vc_keytable[s-vc_keytable+1] = '\0';
410 vc_keymap = strappend(vc_keytable, ".uni");
413 vc_keymap = strdup(vc_keytable);
418 log_error("Out of memory.");
423 if (access("/etc/sysconfig/console/default.kmap", F_OK) >= 0) {
426 t = strdup("/etc/sysconfig/console/default.kmap");
428 log_error("Out of memory.");
446 if (load_keymap(vc, vc_keymap, vc_keymap_toggle, utf8, &keymap_pid) >= 0 &&
447 load_font(vc, vc_font, vc_font_map, vc_font_unimap, &font_pid) >= 0)
452 wait_for_terminate_and_warn(KBD_LOADKEYS, keymap_pid);
455 wait_for_terminate_and_warn(KBD_SETFONT, font_pid);
460 free(vc_font_unimap);
463 close_nointr_nofail(fd);