]>
git.proxmox.com Git - systemd.git/blob - src/vconsole/vconsole-setup.c
2 This file is part of systemd.
4 Copyright 2010 Kay Sievers
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 #include <linux/tiocl.h>
29 #include <sys/ioctl.h>
32 #include "alloc-util.h"
36 #include "locale-util.h"
38 #include "process-util.h"
39 #include "signal-util.h"
40 #include "stdio-util.h"
41 #include "string-util.h"
42 #include "terminal-util.h"
46 static bool is_vconsole(int fd
) {
47 unsigned char data
[1];
49 data
[0] = TIOCL_GETFGCONSOLE
;
50 return ioctl(fd
, TIOCLINUX
, data
) >= 0;
53 static int disable_utf8(int fd
) {
56 if (ioctl(fd
, KDSKBMODE
, K_XLATE
) < 0)
59 k
= loop_write(fd
, "\033%@", 3, false);
63 k
= write_string_file("/sys/module/vt/parameters/default_utf8", "0", 0);
68 log_warning_errno(r
, "Failed to disable UTF-8: %m");
73 static int enable_utf8(int fd
) {
77 if (ioctl(fd
, KDGKBMODE
, ¤t
) < 0 || current
== K_XLATE
) {
79 * Change the current keyboard to unicode, unless it
80 * is currently in raw or off mode anyway. We
81 * shouldn't interfere with X11's processing of the
84 * http://lists.freedesktop.org/archives/systemd-devel/2013-February/008573.html
88 if (ioctl(fd
, KDSKBMODE
, K_UNICODE
) < 0)
92 k
= loop_write(fd
, "\033%G", 3, false);
96 k
= write_string_file("/sys/module/vt/parameters/default_utf8", "1", 0);
101 log_warning_errno(r
, "Failed to enable UTF-8: %m");
106 static int keyboard_load_and_wait(const char *vc
, const char *map
, const char *map_toggle
, bool utf8
) {
111 /* An empty map means kernel map */
115 args
[i
++] = KBD_LOADKEYS
;
123 args
[i
++] = map_toggle
;
128 return log_error_errno(errno
, "Failed to fork: %m");
131 (void) reset_all_signal_handlers();
132 (void) reset_signal_mask();
134 execv(args
[0], (char **) args
);
138 r
= wait_for_terminate_and_warn(KBD_LOADKEYS
, pid
, true);
145 static int font_load_and_wait(const char *vc
, const char *font
, const char *map
, const char *unimap
) {
150 /* An empty font means kernel font */
154 args
[i
++] = KBD_SETFONT
;
170 return log_error_errno(errno
, "Failed to fork: %m");
173 (void) reset_all_signal_handlers();
174 (void) reset_signal_mask();
176 execv(args
[0], (char **) args
);
180 r
= wait_for_terminate_and_warn(KBD_SETFONT
, pid
, true);
188 * A newly allocated VT uses the font from the active VT. Here
189 * we update all possibly already allocated VTs with the configured
190 * font. It also allows to restart systemd-vconsole-setup.service,
191 * to apply a new font to all VTs.
193 static void font_copy_to_all_vcs(int fd
) {
194 struct vt_stat vcs
= {};
195 unsigned char map8
[E_TABSZ
];
196 unsigned short map16
[E_TABSZ
];
197 struct unimapdesc unimapd
;
198 struct unipair unipairs
[USHRT_MAX
];
201 /* get active, and 16 bit mask of used VT numbers */
202 r
= ioctl(fd
, VT_GETSTATE
, &vcs
);
204 log_debug_errno(errno
, "VT_GETSTATE failed, ignoring: %m");
208 for (i
= 1; i
<= 15; i
++) {
209 char vcname
[strlen("/dev/vcs") + DECIMAL_STR_MAX(int)];
210 _cleanup_close_
int vcfd
= -1;
211 struct console_font_op cfo
= {};
213 if (i
== vcs
.v_active
)
216 /* skip non-allocated ttys */
217 xsprintf(vcname
, "/dev/vcs%i", i
);
218 if (access(vcname
, F_OK
) < 0)
221 xsprintf(vcname
, "/dev/tty%i", i
);
222 vcfd
= open_terminal(vcname
, O_RDWR
|O_CLOEXEC
);
226 /* copy font from active VT, where the font was uploaded to */
227 cfo
.op
= KD_FONT_OP_COPY
;
228 cfo
.height
= vcs
.v_active
-1; /* tty1 == index 0 */
229 (void) ioctl(vcfd
, KDFONTOP
, &cfo
);
231 /* copy map of 8bit chars */
232 if (ioctl(fd
, GIO_SCRNMAP
, map8
) >= 0)
233 (void) ioctl(vcfd
, PIO_SCRNMAP
, map8
);
235 /* copy map of 8bit chars -> 16bit Unicode values */
236 if (ioctl(fd
, GIO_UNISCRNMAP
, map16
) >= 0)
237 (void) ioctl(vcfd
, PIO_UNISCRNMAP
, map16
);
239 /* copy unicode translation table */
240 /* unimapd is a ushort count and a pointer to an
241 array of struct unipair { ushort, ushort } */
242 unimapd
.entries
= unipairs
;
243 unimapd
.entry_ct
= USHRT_MAX
;
244 if (ioctl(fd
, GIO_UNIMAP
, &unimapd
) >= 0) {
245 struct unimapinit adv
= { 0, 0, 0 };
247 (void) ioctl(vcfd
, PIO_UNIMAPCLR
, &adv
);
248 (void) ioctl(vcfd
, PIO_UNIMAP
, &unimapd
);
253 int main(int argc
, char **argv
) {
256 *vc_keymap
= NULL
, *vc_keymap_toggle
= NULL
,
257 *vc_font
= NULL
, *vc_font_map
= NULL
, *vc_font_unimap
= NULL
;
258 _cleanup_close_
int fd
= -1;
259 bool utf8
, font_copy
= false, font_ok
, keyboard_ok
;
260 int r
= EXIT_FAILURE
;
262 log_set_target(LOG_TARGET_AUTO
);
263 log_parse_environment();
275 fd
= open_terminal(vc
, O_RDWR
|O_CLOEXEC
);
277 log_error_errno(fd
, "Failed to open %s: %m", vc
);
281 if (!is_vconsole(fd
)) {
282 log_error("Device %s is not a virtual console.", vc
);
286 utf8
= is_locale_utf8();
288 r
= parse_env_file("/etc/vconsole.conf", NEWLINE
,
289 "KEYMAP", &vc_keymap
,
290 "KEYMAP_TOGGLE", &vc_keymap_toggle
,
292 "FONT_MAP", &vc_font_map
,
293 "FONT_UNIMAP", &vc_font_unimap
,
296 if (r
< 0 && r
!= -ENOENT
)
297 log_warning_errno(r
, "Failed to read /etc/vconsole.conf: %m");
299 /* Let the kernel command line override /etc/vconsole.conf */
300 if (detect_container() <= 0) {
301 r
= parse_env_file("/proc/cmdline", WHITESPACE
,
302 "vconsole.keymap", &vc_keymap
,
303 "vconsole.keymap.toggle", &vc_keymap_toggle
,
304 "vconsole.font", &vc_font
,
305 "vconsole.font.map", &vc_font_map
,
306 "vconsole.font.unimap", &vc_font_unimap
,
309 if (r
< 0 && r
!= -ENOENT
)
310 log_warning_errno(r
, "Failed to read /proc/cmdline: %m");
314 (void) enable_utf8(fd
);
316 (void) disable_utf8(fd
);
318 font_ok
= font_load_and_wait(vc
, vc_font
, vc_font_map
, vc_font_unimap
) > 0;
319 keyboard_ok
= keyboard_load_and_wait(vc
, vc_keymap
, vc_keymap_toggle
, utf8
) > 0;
321 /* Only copy the font when we executed setfont successfully */
322 if (font_copy
&& font_ok
)
323 (void) font_copy_to_all_vcs(fd
);
325 return font_ok
&& keyboard_ok
? EXIT_SUCCESS
: EXIT_FAILURE
;