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);
162 * A newly allocated VT uses the font from the active VT. Here
163 * we update all possibly already allocated VTs with the configured
164 * font. It also allows to restart systemd-vconsole-setup.service,
165 * to apply a new font to all VTs.
167 static void font_copy_to_all_vcs(int fd) {
172 /* get active, and 16 bit mask of used VT numbers */
174 r = ioctl(fd, VT_GETSTATE, &vcs);
178 for (i = 1; i <= 15; i++) {
181 struct console_font_op cfo;
183 if (i == vcs.v_active)
186 /* skip non-allocated ttys */
187 snprintf(vcname, sizeof(vcname), "/dev/vcs%i", i);
188 if (access(vcname, F_OK) < 0)
191 snprintf(vcname, sizeof(vcname), "/dev/tty%i", i);
192 vcfd = open_terminal(vcname, O_RDWR|O_CLOEXEC);
196 /* copy font from active VT, where the font was uploaded to */
198 cfo.op = KD_FONT_OP_COPY;
199 cfo.height = vcs.v_active-1; /* tty1 == index 0 */
200 ioctl(vcfd, KDFONTOP, &cfo);
202 close_nointr_nofail(vcfd);
206 int main(int argc, char **argv) {
208 char *vc_keymap = NULL;
209 char *vc_keymap_toggle = NULL;
210 char *vc_font = NULL;
211 char *vc_font_map = NULL;
212 char *vc_font_unimap = NULL;
215 pid_t font_pid = 0, keymap_pid = 0;
216 bool font_copy = false;
217 int r = EXIT_FAILURE;
219 log_set_target(LOG_TARGET_AUTO);
220 log_parse_environment();
232 fd = open_terminal(vc, O_RDWR|O_CLOEXEC);
234 log_error("Failed to open %s: %m", vc);
238 if (!is_vconsole(fd)) {
239 log_error("Device %s is not a virtual console.", vc);
243 utf8 = is_locale_utf8();
247 if (detect_container(NULL) <= 0) {
248 r = parse_env_file("/proc/cmdline", WHITESPACE,
249 "vconsole.keymap", &vc_keymap,
250 "vconsole.keymap.toggle", &vc_keymap_toggle,
251 "vconsole.font", &vc_font,
252 "vconsole.font.map", &vc_font_map,
253 "vconsole.font.unimap", &vc_font_unimap,
256 if (r < 0 && r != -ENOENT)
257 log_warning("Failed to read /proc/cmdline: %s", strerror(-r));
260 /* Hmm, nothing set on the kernel cmd line? Then let's
261 * try /etc/vconsole.conf */
263 r = parse_env_file("/etc/vconsole.conf", NEWLINE,
264 "KEYMAP", &vc_keymap,
265 "KEYMAP_TOGGLE", &vc_keymap_toggle,
267 "FONT_MAP", &vc_font_map,
268 "FONT_UNIMAP", &vc_font_unimap,
271 if (r < 0 && r != -ENOENT)
272 log_warning("Failed to read /etc/vconsole.conf: %s", strerror(-r));
281 if (keymap_load(vc, vc_keymap, vc_keymap_toggle, utf8, &keymap_pid) >= 0 &&
282 font_load(vc, vc_font, vc_font_map, vc_font_unimap, &font_pid) >= 0)
287 wait_for_terminate_and_warn(KBD_LOADKEYS, keymap_pid);
290 wait_for_terminate_and_warn(KBD_SETFONT, font_pid);
292 font_copy_to_all_vcs(fd);
298 free(vc_font_unimap);
301 close_nointr_nofail(fd);