]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/vconsole/vconsole-setup.c
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/>.
26 #include <linux/tiocl.h>
31 #include <sys/ioctl.h>
37 #include "process-util.h"
38 #include "signal-util.h"
39 #include "string-util.h"
40 #include "terminal-util.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 int disable_utf8(int fd
) {
54 if (ioctl(fd
, KDSKBMODE
, K_XLATE
) < 0)
57 k
= loop_write(fd
, "\033%@", 3, false);
61 k
= write_string_file("/sys/module/vt/parameters/default_utf8", "0", 0);
66 log_warning_errno(r
, "Failed to disable UTF-8: %m");
71 static int enable_utf8(int fd
) {
75 if (ioctl(fd
, KDGKBMODE
, ¤t
) < 0 || current
== K_XLATE
) {
77 * Change the current keyboard to unicode, unless it
78 * is currently in raw or off mode anyway. We
79 * shouldn't interfere with X11's processing of the
82 * http://lists.freedesktop.org/archives/systemd-devel/2013-February/008573.html
86 if (ioctl(fd
, KDSKBMODE
, K_UNICODE
) < 0)
90 k
= loop_write(fd
, "\033%G", 3, false);
94 k
= write_string_file("/sys/module/vt/parameters/default_utf8", "1", 0);
99 log_warning_errno(r
, "Failed to enable UTF-8: %m");
104 static int keyboard_load_and_wait(const char *vc
, const char *map
, const char *map_toggle
, bool utf8
) {
109 /* An empty map means kernel map */
113 args
[i
++] = KBD_LOADKEYS
;
121 args
[i
++] = map_toggle
;
126 return log_error_errno(errno
, "Failed to fork: %m");
129 (void) reset_all_signal_handlers();
130 (void) reset_signal_mask();
132 execv(args
[0], (char **) args
);
136 r
= wait_for_terminate_and_warn(KBD_LOADKEYS
, pid
, true);
143 static int font_load_and_wait(const char *vc
, const char *font
, const char *map
, const char *unimap
) {
148 /* An empty font means kernel font */
152 args
[i
++] = KBD_SETFONT
;
168 return log_error_errno(errno
, "Failed to fork: %m");
171 (void) reset_all_signal_handlers();
172 (void) reset_signal_mask();
174 execv(args
[0], (char **) args
);
178 r
= wait_for_terminate_and_warn(KBD_SETFONT
, pid
, true);
186 * A newly allocated VT uses the font from the active VT. Here
187 * we update all possibly already allocated VTs with the configured
188 * font. It also allows to restart systemd-vconsole-setup.service,
189 * to apply a new font to all VTs.
191 static void font_copy_to_all_vcs(int fd
) {
192 struct vt_stat vcs
= {};
193 unsigned char map8
[E_TABSZ
];
194 unsigned short map16
[E_TABSZ
];
195 struct unimapdesc unimapd
;
196 struct unipair unipairs
[USHRT_MAX
];
199 /* get active, and 16 bit mask of used VT numbers */
200 r
= ioctl(fd
, VT_GETSTATE
, &vcs
);
202 log_debug_errno(errno
, "VT_GETSTATE failed, ignoring: %m");
206 for (i
= 1; i
<= 15; i
++) {
207 char vcname
[strlen("/dev/vcs") + DECIMAL_STR_MAX(int)];
208 _cleanup_close_
int vcfd
= -1;
209 struct console_font_op cfo
= {};
211 if (i
== vcs
.v_active
)
214 /* skip non-allocated ttys */
215 snprintf(vcname
, sizeof(vcname
), "/dev/vcs%i", i
);
216 if (access(vcname
, F_OK
) < 0)
219 snprintf(vcname
, sizeof(vcname
), "/dev/tty%i", i
);
220 vcfd
= open_terminal(vcname
, O_RDWR
|O_CLOEXEC
);
224 /* copy font from active VT, where the font was uploaded to */
225 cfo
.op
= KD_FONT_OP_COPY
;
226 cfo
.height
= vcs
.v_active
-1; /* tty1 == index 0 */
227 (void) ioctl(vcfd
, KDFONTOP
, &cfo
);
229 /* copy map of 8bit chars */
230 if (ioctl(fd
, GIO_SCRNMAP
, map8
) >= 0)
231 (void) ioctl(vcfd
, PIO_SCRNMAP
, map8
);
233 /* copy map of 8bit chars -> 16bit Unicode values */
234 if (ioctl(fd
, GIO_UNISCRNMAP
, map16
) >= 0)
235 (void) ioctl(vcfd
, PIO_UNISCRNMAP
, map16
);
237 /* copy unicode translation table */
238 /* unimapd is a ushort count and a pointer to an
239 array of struct unipair { ushort, ushort } */
240 unimapd
.entries
= unipairs
;
241 unimapd
.entry_ct
= USHRT_MAX
;
242 if (ioctl(fd
, GIO_UNIMAP
, &unimapd
) >= 0) {
243 struct unimapinit adv
= { 0, 0, 0 };
245 (void) ioctl(vcfd
, PIO_UNIMAPCLR
, &adv
);
246 (void) ioctl(vcfd
, PIO_UNIMAP
, &unimapd
);
251 int main(int argc
, char **argv
) {
254 *vc_keymap
= NULL
, *vc_keymap_toggle
= NULL
,
255 *vc_font
= NULL
, *vc_font_map
= NULL
, *vc_font_unimap
= NULL
;
256 _cleanup_close_
int fd
= -1;
257 bool utf8
, font_copy
= false, font_ok
, keyboard_ok
;
258 int r
= EXIT_FAILURE
;
260 log_set_target(LOG_TARGET_AUTO
);
261 log_parse_environment();
273 fd
= open_terminal(vc
, O_RDWR
|O_CLOEXEC
);
275 log_error_errno(errno
, "Failed to open %s: %m", vc
);
279 if (!is_vconsole(fd
)) {
280 log_error("Device %s is not a virtual console.", vc
);
284 utf8
= is_locale_utf8();
286 r
= parse_env_file("/etc/vconsole.conf", NEWLINE
,
287 "KEYMAP", &vc_keymap
,
288 "KEYMAP_TOGGLE", &vc_keymap_toggle
,
290 "FONT_MAP", &vc_font_map
,
291 "FONT_UNIMAP", &vc_font_unimap
,
294 if (r
< 0 && r
!= -ENOENT
)
295 log_warning_errno(r
, "Failed to read /etc/vconsole.conf: %m");
297 /* Let the kernel command line override /etc/vconsole.conf */
298 if (detect_container() <= 0) {
299 r
= parse_env_file("/proc/cmdline", WHITESPACE
,
300 "vconsole.keymap", &vc_keymap
,
301 "vconsole.keymap.toggle", &vc_keymap_toggle
,
302 "vconsole.font", &vc_font
,
303 "vconsole.font.map", &vc_font_map
,
304 "vconsole.font.unimap", &vc_font_unimap
,
307 if (r
< 0 && r
!= -ENOENT
)
308 log_warning_errno(r
, "Failed to read /proc/cmdline: %m");
312 (void) enable_utf8(fd
);
314 (void) disable_utf8(fd
);
316 font_ok
= font_load_and_wait(vc
, vc_font
, vc_font_map
, vc_font_unimap
) > 0;
317 keyboard_ok
= keyboard_load_and_wait(vc
, vc_keymap
, vc_keymap_toggle
, utf8
) > 0;
319 /* Only copy the font when we executed setfont successfully */
320 if (font_copy
&& font_ok
)
321 (void) font_copy_to_all_vcs(fd
);
323 return font_ok
&& keyboard_ok
? EXIT_SUCCESS
: EXIT_FAILURE
;