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 General Public License as published by
10 the Free Software Foundation; either version 2 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 General Public License for more details.
18 You should have received a copy of the GNU 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 #ifdef TARGET_MANDRIVA
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 #if defined(TARGET_FEDORA) || defined(TARGET_MEEGO)
208 "KEYTABLE", &vc_keymap,
210 "vconsole.keymap", &vc_keymap,
211 "vconsole.keymap.toggle", &vc_keymap_toggle,
212 "vconsole.font", &vc_font,
213 "vconsole.font.map", &vc_font_map,
214 "vconsole.font.unimap", &vc_font_unimap,
218 log_warning("Failed to read /proc/cmdline: %s", strerror(-r));
221 /* Hmm, nothing set on the kernel cmd line? Then let's
222 * try /etc/vconsole.conf */
224 (r = parse_env_file("/etc/vconsole.conf", NEWLINE,
225 "KEYMAP", &vc_keymap,
226 "KEYMAP_TOGGLE", &vc_keymap_toggle,
228 "FONT_MAP", &vc_font_map,
229 "FONT_UNIMAP", &vc_font_unimap,
233 log_warning("Failed to read /etc/vconsole.conf: %s", strerror(-r));
237 #if defined(TARGET_FEDORA) || defined(TARGET_MEEGO)
238 if ((r = parse_env_file("/etc/sysconfig/i18n", NEWLINE,
240 "SYSFONTACM", &vc_font_map,
241 "UNIMAP", &vc_font_unimap,
245 log_warning("Failed to read /etc/sysconfig/i18n: %s", strerror(-r));
248 if ((r = parse_env_file("/etc/sysconfig/keyboard", NEWLINE,
249 "KEYTABLE", &vc_keymap,
250 "KEYMAP", &vc_keymap,
254 log_warning("Failed to read /etc/sysconfig/i18n: %s", strerror(-r));
257 if (access("/etc/sysconfig/console/default.kmap", F_OK) >= 0) {
260 if (!(t = strdup("/etc/sysconfig/console/default.kmap"))) {
261 log_error("Out of memory.");
269 #elif defined(TARGET_SUSE)
270 if ((r = parse_env_file("/etc/sysconfig/keyboard", NEWLINE,
271 "KEYTABLE", &vc_keymap,
275 log_warning("Failed to read /etc/sysconfig/keyboard: %s", strerror(-r));
278 if ((r = parse_env_file("/etc/sysconfig/console", NEWLINE,
279 "CONSOLE_FONT", &vc_font,
280 "CONSOLE_SCREENMAP", &vc_font_map,
281 "CONSOLE_UNICODEMAP", &vc_font_unimap,
285 log_warning("Failed to read /etc/sysconfig/console: %s", strerror(-r));
288 #elif defined(TARGET_ARCH)
289 if ((r = parse_env_file("/etc/rc.conf", NEWLINE,
290 "KEYMAP", &vc_keymap,
291 "CONSOLEFONT", &vc_font,
292 "CONSOLEMAP", &vc_font_map,
296 log_warning("Failed to read /etc/rc.conf: %s", strerror(-r));
299 #elif defined(TARGET_FRUGALWARE)
300 if ((r = parse_env_file("/etc/sysconfig/keymap", NEWLINE,
301 "keymap", &vc_keymap,
304 log_warning("Failed to read /etc/sysconfig/keymap: %s", strerror(-r));
306 if ((r = parse_env_file("/etc/sysconfig/font", NEWLINE,
310 log_warning("Failed to read /etc/sysconfig/font: %s", strerror(-r));
313 #elif defined(TARGET_ALTLINUX)
314 if ((r = parse_env_file("/etc/sysconfig/keyboard", NEWLINE,
315 "KEYTABLE", &vc_keymap,
319 log_warning("Failed to read /etc/sysconfig/keyboard: %s", strerror(-r));
322 if ((r = parse_env_file("/etc/sysconfig/consolefont", NEWLINE,
327 log_warning("Failed to read /etc/sysconfig/console: %s", strerror(-r));
330 #elif defined(TARGET_GENTOO)
331 if ((r = parse_env_file("/etc/rc.conf", NEWLINE,
332 "unicode", &vc_unicode,
335 log_warning("Failed to read /etc/rc.conf: %s", strerror(-r));
341 if ((rc_unicode = parse_boolean(vc_unicode)) < 0)
342 log_error("Unknown value for /etc/rc.conf unicode=%s", vc_unicode);
344 if (rc_unicode && !utf8)
345 log_warning("/etc/rc.conf wants unicode, but current locale is not UTF-8 capable!");
346 else if (!rc_unicode && utf8) {
347 log_debug("/etc/rc.conf does not want unicode, leave it on in kernel but does not apply to vconsole.");
353 /* /etc/conf.d/consolefont comments and gentoo
354 * documentation mention uppercase, but the actual
355 * contents are lowercase. the existing
356 * /etc/init.d/consolefont tries both
358 if ((r = parse_env_file("/etc/conf.d/consolefont", NEWLINE,
359 "CONSOLEFONT", &vc_font,
360 "consolefont", &vc_font,
361 "consoletranslation", &vc_font_map,
362 "CONSOLETRANSLATION", &vc_font_map,
363 "unicodemap", &vc_font_unimap,
364 "UNICODEMAP", &vc_font_unimap,
367 log_warning("Failed to read /etc/conf.d/consolefont: %s", strerror(-r));
370 if ((r = parse_env_file("/etc/conf.d/keymaps", NEWLINE,
371 "keymap", &vc_keymap,
372 "KEYMAP", &vc_keymap,
375 log_warning("Failed to read /etc/conf.d/keymaps: %s", strerror(-r));
378 #elif defined(TARGET_MANDRIVA)
380 if ((r = parse_env_file("/etc/sysconfig/i18n", NEWLINE,
382 "SYSFONTACM", &vc_font_map,
383 "UNIMAP", &vc_font_unimap,
387 log_warning("Failed to read /etc/sysconfig/i18n: %s", strerror(-r));
390 if ((r = parse_env_file("/etc/sysconfig/keyboard", NEWLINE,
391 "KEYTABLE", &vc_keytable,
392 "KEYMAP", &vc_keymap,
393 "UNIKEYTABLE", &vc_keymap,
394 "GRP_TOGGLE", &vc_keymap_toggle,
398 log_warning("Failed to read /etc/sysconfig/i18n: %s", strerror(-r));
405 if (endswith(vc_keytable, ".uni") || strstr(vc_keytable, ".uni."))
406 vc_keymap = strdup(vc_keytable);
409 if ((s = strstr(vc_keytable, ".map")))
410 vc_keytable[s-vc_keytable+1] = '\0';
411 vc_keymap = strappend(vc_keytable, ".uni");
414 vc_keymap = strdup(vc_keytable);
419 log_error("Out of memory.");
424 if (access("/etc/sysconfig/console/default.kmap", F_OK) >= 0) {
427 if (!(t = strdup("/etc/sysconfig/console/default.kmap"))) {
428 log_error("Out of memory.");
443 if (load_keymap(vc, vc_keymap, vc_keymap_toggle, utf8, &keymap_pid) >= 0 &&
444 load_font(vc, vc_font, vc_font_map, vc_font_unimap, &font_pid) >= 0)
449 wait_for_terminate_and_warn(KBD_LOADKEYS, keymap_pid);
452 wait_for_terminate_and_warn(KBD_SETFONT, font_pid);
457 free(vc_font_unimap);
460 close_nointr_nofail(fd);