]>
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>
34 #include "alloc-util.h"
38 #include "locale-util.h"
40 #include "process-util.h"
41 #include "signal-util.h"
42 #include "stdio-util.h"
43 #include "string-util.h"
44 #include "terminal-util.h"
48 static bool is_vconsole(int fd
) {
49 unsigned char data
[1];
51 data
[0] = TIOCL_GETFGCONSOLE
;
52 return ioctl(fd
, TIOCLINUX
, data
) >= 0;
55 static int disable_utf8(int fd
) {
58 if (ioctl(fd
, KDSKBMODE
, K_XLATE
) < 0)
61 k
= loop_write(fd
, "\033%@", 3, false);
65 k
= write_string_file("/sys/module/vt/parameters/default_utf8", "0", 0);
70 log_warning_errno(r
, "Failed to disable UTF-8: %m");
75 static int enable_utf8(int fd
) {
79 if (ioctl(fd
, KDGKBMODE
, ¤t
) < 0 || current
== K_XLATE
) {
81 * Change the current keyboard to unicode, unless it
82 * is currently in raw or off mode anyway. We
83 * shouldn't interfere with X11's processing of the
86 * http://lists.freedesktop.org/archives/systemd-devel/2013-February/008573.html
90 if (ioctl(fd
, KDSKBMODE
, K_UNICODE
) < 0)
94 k
= loop_write(fd
, "\033%G", 3, false);
98 k
= write_string_file("/sys/module/vt/parameters/default_utf8", "1", 0);
103 log_warning_errno(r
, "Failed to enable UTF-8: %m");
108 static int keyboard_load_and_wait(const char *vc
, const char *map
, const char *map_toggle
, bool utf8
) {
113 /* An empty map means kernel map */
117 args
[i
++] = KBD_LOADKEYS
;
125 args
[i
++] = map_toggle
;
130 return log_error_errno(errno
, "Failed to fork: %m");
133 (void) reset_all_signal_handlers();
134 (void) reset_signal_mask();
136 execv(args
[0], (char **) args
);
140 r
= wait_for_terminate_and_warn(KBD_LOADKEYS
, pid
, true);
147 static int font_load_and_wait(const char *vc
, const char *font
, const char *map
, const char *unimap
) {
152 /* An empty font means kernel font */
156 args
[i
++] = KBD_SETFONT
;
172 return log_error_errno(errno
, "Failed to fork: %m");
175 (void) reset_all_signal_handlers();
176 (void) reset_signal_mask();
178 execv(args
[0], (char **) args
);
182 r
= wait_for_terminate_and_warn(KBD_SETFONT
, pid
, true);
190 * A newly allocated VT uses the font from the active VT. Here
191 * we update all possibly already allocated VTs with the configured
192 * font. It also allows to restart systemd-vconsole-setup.service,
193 * to apply a new font to all VTs.
195 static void font_copy_to_all_vcs(int fd
) {
196 struct vt_stat vcs
= {};
197 unsigned char map8
[E_TABSZ
];
198 unsigned short map16
[E_TABSZ
];
199 struct unimapdesc unimapd
;
200 struct unipair unipairs
[USHRT_MAX
];
203 /* get active, and 16 bit mask of used VT numbers */
204 r
= ioctl(fd
, VT_GETSTATE
, &vcs
);
206 log_debug_errno(errno
, "VT_GETSTATE failed, ignoring: %m");
210 for (i
= 1; i
<= 15; i
++) {
211 char vcname
[strlen("/dev/vcs") + DECIMAL_STR_MAX(int)];
212 _cleanup_close_
int vcfd
= -1;
213 struct console_font_op cfo
= {};
215 if (i
== vcs
.v_active
)
218 /* skip non-allocated ttys */
219 xsprintf(vcname
, "/dev/vcs%i", i
);
220 if (access(vcname
, F_OK
) < 0)
223 xsprintf(vcname
, "/dev/tty%i", i
);
224 vcfd
= open_terminal(vcname
, O_RDWR
|O_CLOEXEC
);
228 /* copy font from active VT, where the font was uploaded to */
229 cfo
.op
= KD_FONT_OP_COPY
;
230 cfo
.height
= vcs
.v_active
-1; /* tty1 == index 0 */
231 (void) ioctl(vcfd
, KDFONTOP
, &cfo
);
233 /* copy map of 8bit chars */
234 if (ioctl(fd
, GIO_SCRNMAP
, map8
) >= 0)
235 (void) ioctl(vcfd
, PIO_SCRNMAP
, map8
);
237 /* copy map of 8bit chars -> 16bit Unicode values */
238 if (ioctl(fd
, GIO_UNISCRNMAP
, map16
) >= 0)
239 (void) ioctl(vcfd
, PIO_UNISCRNMAP
, map16
);
241 /* copy unicode translation table */
242 /* unimapd is a ushort count and a pointer to an
243 array of struct unipair { ushort, ushort } */
244 unimapd
.entries
= unipairs
;
245 unimapd
.entry_ct
= USHRT_MAX
;
246 if (ioctl(fd
, GIO_UNIMAP
, &unimapd
) >= 0) {
247 struct unimapinit adv
= { 0, 0, 0 };
249 (void) ioctl(vcfd
, PIO_UNIMAPCLR
, &adv
);
250 (void) ioctl(vcfd
, PIO_UNIMAP
, &unimapd
);
255 int main(int argc
, char **argv
) {
258 *vc_keymap
= NULL
, *vc_keymap_toggle
= NULL
,
259 *vc_font
= NULL
, *vc_font_map
= NULL
, *vc_font_unimap
= NULL
;
260 _cleanup_close_
int fd
= -1;
261 bool utf8
, font_copy
= false, font_ok
, keyboard_ok
;
262 int r
= EXIT_FAILURE
;
264 log_set_target(LOG_TARGET_AUTO
);
265 log_parse_environment();
277 fd
= open_terminal(vc
, O_RDWR
|O_CLOEXEC
);
279 log_error_errno(fd
, "Failed to open %s: %m", vc
);
283 if (!is_vconsole(fd
)) {
284 log_error("Device %s is not a virtual console.", vc
);
288 utf8
= is_locale_utf8();
290 r
= parse_env_file("/etc/vconsole.conf", NEWLINE
,
291 "KEYMAP", &vc_keymap
,
292 "KEYMAP_TOGGLE", &vc_keymap_toggle
,
294 "FONT_MAP", &vc_font_map
,
295 "FONT_UNIMAP", &vc_font_unimap
,
298 if (r
< 0 && r
!= -ENOENT
)
299 log_warning_errno(r
, "Failed to read /etc/vconsole.conf: %m");
301 /* Let the kernel command line override /etc/vconsole.conf */
302 if (detect_container() <= 0) {
303 r
= parse_env_file("/proc/cmdline", WHITESPACE
,
304 "vconsole.keymap", &vc_keymap
,
305 "vconsole.keymap.toggle", &vc_keymap_toggle
,
306 "vconsole.font", &vc_font
,
307 "vconsole.font.map", &vc_font_map
,
308 "vconsole.font.unimap", &vc_font_unimap
,
311 if (r
< 0 && r
!= -ENOENT
)
312 log_warning_errno(r
, "Failed to read /proc/cmdline: %m");
316 (void) enable_utf8(fd
);
318 (void) disable_utf8(fd
);
320 font_ok
= font_load_and_wait(vc
, vc_font
, vc_font_map
, vc_font_unimap
) > 0;
321 keyboard_ok
= keyboard_load_and_wait(vc
, vc_keymap
, vc_keymap_toggle
, utf8
) > 0;
323 /* Only copy the font when we executed setfont successfully */
324 if (font_copy
&& font_ok
)
325 (void) font_copy_to_all_vcs(fd
);
327 return font_ok
&& keyboard_ok
? EXIT_SUCCESS
: EXIT_FAILURE
;