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 unused VTs above tty6 to avoid allocating them */
187 if (i > 6 && ((vcs.v_state >> i) & 1) == 0)
190 snprintf(vcname , sizeof(vcname), "/dev/tty%i", i);
191 vcfd = open_terminal(vcname, O_RDWR|O_CLOEXEC);
195 /* copy font from active VT, where the font was uploaded to */
197 cfo.op = KD_FONT_OP_COPY;
198 cfo.height = vcs.v_active-1; /* tty1 == index 0 */
199 ioctl(vcfd, KDFONTOP, &cfo);
201 close_nointr_nofail(vcfd);
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 bool font_copy = false;
216 int r = EXIT_FAILURE;
218 log_set_target(LOG_TARGET_AUTO);
219 log_parse_environment();
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);
291 font_copy_to_all_vcs(fd);
297 free(vc_font_unimap);
300 close_nointr_nofail(fd);