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 load_keymap(const char *vc, const char *map, const char *map_toggle, bool utf8, pid_t *_pid) {
89 /* An empty map means kernel map */
94 args[i++] = KBD_LOADKEYS;
102 args[i++] = map_toggle;
107 log_error("Failed to fork: %m");
109 } else if (pid == 0) {
110 execv(args[0], (char **) args);
118 static int load_font(const char *vc, const char *font, const char *map, const char *unimap, pid_t *_pid) {
124 /* An empty font means kernel font */
129 args[i++] = KBD_SETFONT;
145 log_error("Failed to fork: %m");
147 } else if (pid == 0) {
148 execv(args[0], (char **) args);
156 int main(int argc, char **argv) {
158 char *vc_keymap = NULL;
159 char *vc_keymap_toggle = NULL;
160 char *vc_font = NULL;
161 char *vc_font_map = NULL;
162 char *vc_font_unimap = NULL;
164 char *vc_unicode = NULL;
166 #if defined(TARGET_MANDRIVA) || defined(TARGET_MAGEIA)
167 char *vc_keytable = NULL;
171 int r = EXIT_FAILURE;
172 pid_t font_pid = 0, keymap_pid = 0;
174 log_set_target(LOG_TARGET_AUTO);
175 log_parse_environment();
185 fd = open_terminal(vc, O_RDWR|O_CLOEXEC);
187 log_error("Failed to open %s: %m", vc);
191 if (!is_vconsole(fd)) {
192 log_error("Device %s is not a virtual console.", vc);
196 utf8 = is_locale_utf8();
198 vc_keymap = strdup("us");
199 vc_font = strdup(DEFAULT_FONT);
201 if (!vc_keymap || !vc_font) {
202 log_error("Failed to allocate strings.");
208 if (detect_container(NULL) <= 0) {
209 r = parse_env_file("/proc/cmdline", WHITESPACE,
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,
217 if (r < 0 && r != -ENOENT)
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,
232 if (r < 0 && r != -ENOENT)
233 log_warning("Failed to read /etc/vconsole.conf: %s", strerror(-r));
237 #if defined(TARGET_FEDORA) || defined(TARGET_MEEGO)
238 r = parse_env_file("/etc/sysconfig/i18n", NEWLINE,
240 "SYSFONTACM", &vc_font_map,
241 "UNIMAP", &vc_font_unimap,
243 if (r < 0 && r != -ENOENT)
244 log_warning("Failed to read /etc/sysconfig/i18n: %s", strerror(-r));
246 r = parse_env_file("/etc/sysconfig/keyboard", NEWLINE,
247 "KEYTABLE", &vc_keymap,
248 "KEYMAP", &vc_keymap,
250 if (r < 0 && r != -ENOENT)
251 log_warning("Failed to read /etc/sysconfig/keyboard: %s", strerror(-r));
253 if (access("/etc/sysconfig/console/default.kmap", F_OK) >= 0) {
256 t = strdup("/etc/sysconfig/console/default.kmap");
258 log_error("Out of memory.");
266 #elif defined(TARGET_SUSE)
267 r = parse_env_file("/etc/sysconfig/keyboard", NEWLINE,
268 "KEYTABLE", &vc_keymap,
270 if (r < 0 && r != -ENOENT)
271 log_warning("Failed to read /etc/sysconfig/keyboard: %s", strerror(-r));
273 r = parse_env_file("/etc/sysconfig/console", NEWLINE,
274 "CONSOLE_FONT", &vc_font,
275 "CONSOLE_SCREENMAP", &vc_font_map,
276 "CONSOLE_UNICODEMAP", &vc_font_unimap,
278 if (r < 0 && r != -ENOENT)
279 log_warning("Failed to read /etc/sysconfig/console: %s", strerror(-r));
281 #elif defined(TARGET_ARCH)
282 r = parse_env_file("/etc/rc.conf", NEWLINE,
283 "KEYMAP", &vc_keymap,
284 "CONSOLEFONT", &vc_font,
285 "CONSOLEMAP", &vc_font_map,
287 if (r < 0 && r != -ENOENT)
288 log_warning("Failed to read /etc/rc.conf: %s", strerror(-r));
290 #elif defined(TARGET_FRUGALWARE)
291 r = parse_env_file("/etc/sysconfig/keymap", NEWLINE,
292 "keymap", &vc_keymap,
294 if (r < 0 && r != -ENOENT)
295 log_warning("Failed to read /etc/sysconfig/keymap: %s", strerror(-r));
297 r = parse_env_file("/etc/sysconfig/font", NEWLINE,
300 if (r < 0 && r != -ENOENT)
301 log_warning("Failed to read /etc/sysconfig/font: %s", strerror(-r));
303 #elif defined(TARGET_ALTLINUX)
304 r = parse_env_file("/etc/sysconfig/keyboard", NEWLINE,
305 "KEYTABLE", &vc_keymap,
307 if (r < 0 && r != -ENOENT)
308 log_warning("Failed to read /etc/sysconfig/keyboard: %s", strerror(-r));
310 r = parse_env_file("/etc/sysconfig/consolefont", NEWLINE,
313 if (r < 0 && r != -ENOENT)
314 log_warning("Failed to read /etc/sysconfig/consolefont: %s", strerror(-r));
316 #elif defined(TARGET_GENTOO)
317 r = parse_env_file("/etc/rc.conf", NEWLINE,
318 "unicode", &vc_unicode,
320 if (r < 0 && r != -ENOENT)
321 log_warning("Failed to read /etc/rc.conf: %s", strerror(-r));
326 rc_unicode = parse_boolean(vc_unicode);
328 log_warning("Unknown value for /etc/rc.conf unicode=%s", vc_unicode);
330 if (rc_unicode && !utf8)
331 log_warning("/etc/rc.conf wants unicode, but current locale is not UTF-8 capable!");
332 else if (!rc_unicode && utf8) {
333 log_debug("/etc/rc.conf does not want unicode, leave it on in kernel but does not apply to vconsole.");
339 /* /etc/conf.d/consolefont comments and gentoo
340 * documentation mention uppercase, but the actual
341 * contents are lowercase. the existing
342 * /etc/init.d/consolefont tries both
344 r = parse_env_file("/etc/conf.d/consolefont", NEWLINE,
345 "CONSOLEFONT", &vc_font,
346 "consolefont", &vc_font,
347 "consoletranslation", &vc_font_map,
348 "CONSOLETRANSLATION", &vc_font_map,
349 "unicodemap", &vc_font_unimap,
350 "UNICODEMAP", &vc_font_unimap,
352 if (r < 0 && r != -ENOENT)
353 log_warning("Failed to read /etc/conf.d/consolefont: %s", strerror(-r));
355 r = parse_env_file("/etc/conf.d/keymaps", NEWLINE,
356 "keymap", &vc_keymap,
357 "KEYMAP", &vc_keymap,
359 if (r < 0 && r != -ENOENT)
360 log_warning("Failed to read /etc/conf.d/keymaps: %s", strerror(-r));
362 #elif defined(TARGET_MANDRIVA) || defined (TARGET_MAGEIA)
364 r = parse_env_file("/etc/sysconfig/i18n", NEWLINE,
366 "SYSFONTACM", &vc_font_map,
367 "UNIMAP", &vc_font_unimap,
369 if (r < 0 && r != -ENOENT)
370 log_warning("Failed to read /etc/sysconfig/i18n: %s", strerror(-r));
372 r = parse_env_file("/etc/sysconfig/keyboard", NEWLINE,
373 "KEYTABLE", &vc_keytable,
374 "KEYMAP", &vc_keymap,
375 "UNIKEYTABLE", &vc_keymap,
376 "GRP_TOGGLE", &vc_keymap_toggle,
378 if (r < 0 && r != -ENOENT)
379 log_warning("Failed to read /etc/sysconfig/keyboard: %s", strerror(-r));
384 if (endswith(vc_keytable, ".uni") || strstr(vc_keytable, ".uni."))
385 vc_keymap = strdup(vc_keytable);
388 s = strstr(vc_keytable, ".map");
390 vc_keytable[s-vc_keytable+1] = '\0';
391 vc_keymap = strappend(vc_keytable, ".uni");
394 vc_keymap = strdup(vc_keytable);
399 log_error("Out of memory.");
404 if (access("/etc/sysconfig/console/default.kmap", F_OK) >= 0) {
407 t = strdup("/etc/sysconfig/console/default.kmap");
409 log_error("Out of memory.");
424 if (load_keymap(vc, vc_keymap, vc_keymap_toggle, utf8, &keymap_pid) >= 0 &&
425 load_font(vc, vc_font, vc_font_map, vc_font_unimap, &font_pid) >= 0)
430 wait_for_terminate_and_warn(KBD_LOADKEYS, keymap_pid);
433 wait_for_terminate_and_warn(KBD_SETFONT, font_pid);
438 free(vc_font_unimap);
441 close_nointr_nofail(fd);