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/>.
32 #include <sys/ioctl.h>
34 #include <linux/tiocl.h>
43 static bool is_vconsole(int fd) {
44 unsigned char data[1];
46 data[0] = TIOCL_GETFGCONSOLE;
47 return ioctl(fd, TIOCLINUX, data) >= 0;
50 static int disable_utf8(int fd) {
53 if (ioctl(fd, KDSKBMODE, K_XLATE) < 0)
56 if (loop_write(fd, "\033%@", 3, false) < 0)
59 k = write_one_line_file("/sys/module/vt/parameters/default_utf8", "0");
64 log_warning("Failed to disable UTF-8: %s", strerror(-r));
69 static int enable_utf8(int fd) {
72 if (ioctl(fd, KDSKBMODE, K_UNICODE) < 0)
75 if (loop_write(fd, "\033%G", 3, false) < 0)
78 k = write_one_line_file("/sys/module/vt/parameters/default_utf8", "1");
83 log_warning("Failed to enable UTF-8: %s", strerror(-r));
88 static int keymap_load(const char *vc, const char *map, const char *map_toggle, bool utf8, pid_t *_pid) {
94 /* An empty map means kernel map */
99 args[i++] = KBD_LOADKEYS;
107 args[i++] = map_toggle;
112 log_error("Failed to fork: %m");
114 } else if (pid == 0) {
115 execv(args[0], (char **) args);
123 static int font_load(const char *vc, const char *font, const char *map, const char *unimap, pid_t *_pid) {
129 /* An empty font means kernel font */
134 args[i++] = KBD_SETFONT;
150 log_error("Failed to fork: %m");
152 } else if (pid == 0) {
153 execv(args[0], (char **) args);
161 static void font_copy_to_all_vts(int fd, int from_vt) {
167 /* get 16 bit mask of used VT numbers */
169 r = ioctl(fd, VT_GETSTATE, &vts);
174 for (i = 1; i <= 16; i++) {
177 struct console_font_op cfo;
180 /* skip unused VTs */
189 snprintf(vtname , sizeof(vtname), "/dev/tty%i", i);
190 vtfd = open_terminal(vtname, O_RDWR|O_CLOEXEC);
194 /* copy font from from_vt to this VT */
196 cfo.op = KD_FONT_OP_COPY;
197 /* the index numbers seem to start at 0 for tty1 */
198 cfo.height = from_vt - 1;
199 ioctl(vtfd, KDFONTOP, &cfo);
201 close_nointr_nofail(vtfd);
205 int main(int argc, char **argv) {
207 char *vc_keymap = NULL;
208 char *vc_keymap_toggle = NULL;
209 char *vc_font = NULL;
210 char *vc_font_map = NULL;
211 char *vc_font_unimap = NULL;
214 pid_t font_pid = 0, keymap_pid = 0;
215 int font_copy_from_vt = 0;
216 int r = EXIT_FAILURE;
218 log_set_target(LOG_TARGET_AUTO);
219 log_parse_environment();
228 font_copy_from_vt = 1;
231 fd = open_terminal(vc, O_RDWR|O_CLOEXEC);
233 log_error("Failed to open %s: %m", vc);
237 if (!is_vconsole(fd)) {
238 log_error("Device %s is not a virtual console.", vc);
242 utf8 = is_locale_utf8();
246 if (detect_container(NULL) <= 0) {
247 r = parse_env_file("/proc/cmdline", WHITESPACE,
248 "vconsole.keymap", &vc_keymap,
249 "vconsole.keymap.toggle", &vc_keymap_toggle,
250 "vconsole.font", &vc_font,
251 "vconsole.font.map", &vc_font_map,
252 "vconsole.font.unimap", &vc_font_unimap,
255 if (r < 0 && r != -ENOENT)
256 log_warning("Failed to read /proc/cmdline: %s", strerror(-r));
259 /* Hmm, nothing set on the kernel cmd line? Then let's
260 * try /etc/vconsole.conf */
262 r = parse_env_file("/etc/vconsole.conf", NEWLINE,
263 "KEYMAP", &vc_keymap,
264 "KEYMAP_TOGGLE", &vc_keymap_toggle,
266 "FONT_MAP", &vc_font_map,
267 "FONT_UNIMAP", &vc_font_unimap,
270 if (r < 0 && r != -ENOENT)
271 log_warning("Failed to read /etc/vconsole.conf: %s", strerror(-r));
280 if (keymap_load(vc, vc_keymap, vc_keymap_toggle, utf8, &keymap_pid) >= 0 &&
281 font_load(vc, vc_font, vc_font_map, vc_font_unimap, &font_pid) >= 0)
286 wait_for_terminate_and_warn(KBD_LOADKEYS, keymap_pid);
289 wait_for_terminate_and_warn(KBD_SETFONT, font_pid);
290 if (font_copy_from_vt > 0)
291 font_copy_to_all_vts(fd, font_copy_from_vt);
297 free(vc_font_unimap);
300 close_nointr_nofail(fd);