]>
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/>.
29 #include <sys/ioctl.h>
30 #include <linux/tiocl.h>
38 #include "process-util.h"
39 #include "terminal-util.h"
40 #include "signal-util.h"
42 static bool is_vconsole(int fd
) {
43 unsigned char data
[1];
45 data
[0] = TIOCL_GETFGCONSOLE
;
46 return ioctl(fd
, TIOCLINUX
, data
) >= 0;
49 static int disable_utf8(int fd
) {
52 if (ioctl(fd
, KDSKBMODE
, K_XLATE
) < 0)
55 k
= loop_write(fd
, "\033%@", 3, false);
59 k
= write_string_file("/sys/module/vt/parameters/default_utf8", "0");
64 log_warning_errno(r
, "Failed to disable UTF-8: %m");
69 static int enable_utf8(int fd
) {
73 if (ioctl(fd
, KDGKBMODE
, ¤t
) < 0 || current
== K_XLATE
) {
75 * Change the current keyboard to unicode, unless it
76 * is currently in raw or off mode anyway. We
77 * shouldn't interfere with X11's processing of the
80 * http://lists.freedesktop.org/archives/systemd-devel/2013-February/008573.html
84 if (ioctl(fd
, KDSKBMODE
, K_UNICODE
) < 0)
88 k
= loop_write(fd
, "\033%G", 3, false);
92 k
= write_string_file("/sys/module/vt/parameters/default_utf8", "1");
97 log_warning_errno(r
, "Failed to enable UTF-8: %m");
102 static int keyboard_load_and_wait(const char *vc
, const char *map
, const char *map_toggle
, bool utf8
) {
107 /* An empty map means kernel map */
111 args
[i
++] = KBD_LOADKEYS
;
119 args
[i
++] = map_toggle
;
124 return log_error_errno(errno
, "Failed to fork: %m");
127 (void) reset_all_signal_handlers();
128 (void) reset_signal_mask();
130 execv(args
[0], (char **) args
);
134 r
= wait_for_terminate_and_warn(KBD_LOADKEYS
, pid
, true);
141 static int font_load_and_wait(const char *vc
, const char *font
, const char *map
, const char *unimap
) {
146 /* An empty font means kernel font */
150 args
[i
++] = KBD_SETFONT
;
166 return log_error_errno(errno
, "Failed to fork: %m");
169 (void) reset_all_signal_handlers();
170 (void) reset_signal_mask();
172 execv(args
[0], (char **) args
);
176 r
= wait_for_terminate_and_warn(KBD_SETFONT
, pid
, true);
184 * A newly allocated VT uses the font from the active VT. Here
185 * we update all possibly already allocated VTs with the configured
186 * font. It also allows to restart systemd-vconsole-setup.service,
187 * to apply a new font to all VTs.
189 static void font_copy_to_all_vcs(int fd
) {
190 struct vt_stat vcs
= {};
191 unsigned char map8
[E_TABSZ
];
192 unsigned short map16
[E_TABSZ
];
193 struct unimapdesc unimapd
;
194 struct unipair unipairs
[USHRT_MAX
];
197 /* get active, and 16 bit mask of used VT numbers */
198 r
= ioctl(fd
, VT_GETSTATE
, &vcs
);
200 log_debug_errno(errno
, "VT_GETSTATE failed, ignoring: %m");
204 for (i
= 1; i
<= 15; i
++) {
205 char vcname
[strlen("/dev/vcs") + DECIMAL_STR_MAX(int)];
206 _cleanup_close_
int vcfd
= -1;
207 struct console_font_op cfo
= {};
209 if (i
== vcs
.v_active
)
212 /* skip non-allocated ttys */
213 snprintf(vcname
, sizeof(vcname
), "/dev/vcs%i", i
);
214 if (access(vcname
, F_OK
) < 0)
217 snprintf(vcname
, sizeof(vcname
), "/dev/tty%i", i
);
218 vcfd
= open_terminal(vcname
, O_RDWR
|O_CLOEXEC
);
222 /* copy font from active VT, where the font was uploaded to */
223 cfo
.op
= KD_FONT_OP_COPY
;
224 cfo
.height
= vcs
.v_active
-1; /* tty1 == index 0 */
225 (void) ioctl(vcfd
, KDFONTOP
, &cfo
);
227 /* copy map of 8bit chars */
228 if (ioctl(fd
, GIO_SCRNMAP
, map8
) >= 0)
229 (void) ioctl(vcfd
, PIO_SCRNMAP
, map8
);
231 /* copy map of 8bit chars -> 16bit Unicode values */
232 if (ioctl(fd
, GIO_UNISCRNMAP
, map16
) >= 0)
233 (void) ioctl(vcfd
, PIO_UNISCRNMAP
, map16
);
235 /* copy unicode translation table */
236 /* unimapd is a ushort count and a pointer to an
237 array of struct unipair { ushort, ushort } */
238 unimapd
.entries
= unipairs
;
239 unimapd
.entry_ct
= USHRT_MAX
;
240 if (ioctl(fd
, GIO_UNIMAP
, &unimapd
) >= 0) {
241 struct unimapinit adv
= { 0, 0, 0 };
243 (void) ioctl(vcfd
, PIO_UNIMAPCLR
, &adv
);
244 (void) ioctl(vcfd
, PIO_UNIMAP
, &unimapd
);
249 int main(int argc
, char **argv
) {
252 *vc_keymap
= NULL
, *vc_keymap_toggle
= NULL
,
253 *vc_font
= NULL
, *vc_font_map
= NULL
, *vc_font_unimap
= NULL
;
254 _cleanup_close_
int fd
= -1;
255 bool utf8
, font_copy
= false, font_ok
, keyboard_ok
;
256 int r
= EXIT_FAILURE
;
258 log_set_target(LOG_TARGET_AUTO
);
259 log_parse_environment();
271 fd
= open_terminal(vc
, O_RDWR
|O_CLOEXEC
);
273 log_error_errno(errno
, "Failed to open %s: %m", vc
);
277 if (!is_vconsole(fd
)) {
278 log_error("Device %s is not a virtual console.", vc
);
282 utf8
= is_locale_utf8();
284 r
= parse_env_file("/etc/vconsole.conf", NEWLINE
,
285 "KEYMAP", &vc_keymap
,
286 "KEYMAP_TOGGLE", &vc_keymap_toggle
,
288 "FONT_MAP", &vc_font_map
,
289 "FONT_UNIMAP", &vc_font_unimap
,
292 if (r
< 0 && r
!= -ENOENT
)
293 log_warning_errno(r
, "Failed to read /etc/vconsole.conf: %m");
295 /* Let the kernel command line override /etc/vconsole.conf */
296 if (detect_container(NULL
) <= 0) {
297 r
= parse_env_file("/proc/cmdline", WHITESPACE
,
298 "vconsole.keymap", &vc_keymap
,
299 "vconsole.keymap.toggle", &vc_keymap_toggle
,
300 "vconsole.font", &vc_font
,
301 "vconsole.font.map", &vc_font_map
,
302 "vconsole.font.unimap", &vc_font_unimap
,
305 if (r
< 0 && r
!= -ENOENT
)
306 log_warning_errno(r
, "Failed to read /proc/cmdline: %m");
310 (void) enable_utf8(fd
);
312 (void) disable_utf8(fd
);
314 font_ok
= font_load_and_wait(vc
, vc_font
, vc_font_map
, vc_font_unimap
) > 0;
315 keyboard_ok
= keyboard_load_and_wait(vc
, vc_keymap
, vc_keymap_toggle
, utf8
) > 0;
317 /* Only copy the font when we executed setfont successfully */
318 if (font_copy
&& font_ok
)
319 (void) font_copy_to_all_vcs(fd
);
321 return font_ok
&& keyboard_ok
? EXIT_SUCCESS
: EXIT_FAILURE
;