]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/vconsole/vconsole-setup.c
016cf004a096db1ef333ab24e6460e087cc61b89
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>
33 #include "alloc-util.h"
37 #include "locale-util.h"
39 #include "process-util.h"
40 #include "signal-util.h"
41 #include "stdio-util.h"
42 #include "string-util.h"
43 #include "terminal-util.h"
47 static bool is_vconsole(int fd
) {
48 unsigned char data
[1];
50 data
[0] = TIOCL_GETFGCONSOLE
;
51 return ioctl(fd
, TIOCLINUX
, data
) >= 0;
54 static int toggle_utf8(int fd
, bool utf8
) {
56 struct termios tc
= {};
58 r
= ioctl(fd
, KDSKBMODE
, utf8
? K_UNICODE
: K_XLATE
);
60 return log_warning_errno(errno
, "Failed to %s UTF-8 kbdmode: %m", utf8
? "enable" : "disable");
62 r
= loop_write(fd
, utf8
? "\033%G" : "\033%@", 3, false);
64 return log_warning_errno(r
, "Failed to %s UTF-8 term processing: %m", utf8
? "enable" : "disable");
66 r
= tcgetattr(fd
, &tc
);
72 r
= tcsetattr(fd
, TCSANOW
, &tc
);
75 return log_warning_errno(errno
, "Failed to %s iutf8 flag: %m", utf8
? "enable" : "disable");
80 static int toggle_utf8_sysfs(bool utf8
) {
83 r
= write_string_file("/sys/module/vt/parameters/default_utf8", one_zero(utf8
), 0);
85 log_warning_errno(r
, "Failed to %s sysfs UTF-8 flag: %m", utf8
? "enable" : "disable");
89 static int keyboard_load_and_wait(const char *vc
, const char *map
, const char *map_toggle
, bool utf8
) {
94 /* An empty map means kernel map */
98 args
[i
++] = KBD_LOADKEYS
;
106 args
[i
++] = map_toggle
;
111 return log_error_errno(errno
, "Failed to fork: %m");
114 (void) reset_all_signal_handlers();
115 (void) reset_signal_mask();
117 execv(args
[0], (char **) args
);
121 r
= wait_for_terminate_and_warn(KBD_LOADKEYS
, pid
, true);
128 static int font_load_and_wait(const char *vc
, const char *font
, const char *map
, const char *unimap
) {
133 /* An empty font means kernel font */
137 args
[i
++] = KBD_SETFONT
;
153 return log_error_errno(errno
, "Failed to fork: %m");
156 (void) reset_all_signal_handlers();
157 (void) reset_signal_mask();
159 execv(args
[0], (char **) args
);
163 r
= wait_for_terminate_and_warn(KBD_SETFONT
, pid
, true);
171 * A newly allocated VT uses the font from the active VT. Here
172 * we update all possibly already allocated VTs with the configured
173 * font. It also allows to restart systemd-vconsole-setup.service,
174 * to apply a new font to all VTs.
176 static void font_copy_to_all_vcs(int fd
) {
177 struct vt_stat vcs
= {};
178 struct unimapdesc unimapd
;
179 _cleanup_free_
struct unipair
* unipairs
= NULL
;
182 unipairs
= new(struct unipair
, USHRT_MAX
);
188 /* get active, and 16 bit mask of used VT numbers */
189 r
= ioctl(fd
, VT_GETSTATE
, &vcs
);
191 log_debug_errno(errno
, "VT_GETSTATE failed, ignoring: %m");
195 for (i
= 1; i
<= 63; i
++) {
196 char vcname
[strlen("/dev/vcs") + DECIMAL_STR_MAX(int)];
197 _cleanup_close_
int vcfd
= -1;
198 struct console_font_op cfo
= {};
200 if (i
== vcs
.v_active
)
203 /* skip non-allocated ttys */
204 xsprintf(vcname
, "/dev/vcs%i", i
);
205 if (access(vcname
, F_OK
) < 0)
208 xsprintf(vcname
, "/dev/tty%i", i
);
209 vcfd
= open_terminal(vcname
, O_RDWR
|O_CLOEXEC
);
213 /* copy font from active VT, where the font was uploaded to */
214 cfo
.op
= KD_FONT_OP_COPY
;
215 cfo
.height
= vcs
.v_active
-1; /* tty1 == index 0 */
216 (void) ioctl(vcfd
, KDFONTOP
, &cfo
);
218 /* copy unicode translation table */
219 /* unimapd is a ushort count and a pointer to an
220 array of struct unipair { ushort, ushort } */
221 unimapd
.entries
= unipairs
;
222 unimapd
.entry_ct
= USHRT_MAX
;
223 if (ioctl(fd
, GIO_UNIMAP
, &unimapd
) >= 0) {
224 struct unimapinit adv
= { 0, 0, 0 };
226 (void) ioctl(vcfd
, PIO_UNIMAPCLR
, &adv
);
227 (void) ioctl(vcfd
, PIO_UNIMAP
, &unimapd
);
232 int main(int argc
, char **argv
) {
235 *vc_keymap
= NULL
, *vc_keymap_toggle
= NULL
,
236 *vc_font
= NULL
, *vc_font_map
= NULL
, *vc_font_unimap
= NULL
;
237 _cleanup_close_
int fd
= -1;
238 bool utf8
, font_copy
= false, font_ok
, keyboard_ok
;
239 int r
= EXIT_FAILURE
;
241 log_set_target(LOG_TARGET_AUTO
);
242 log_parse_environment();
254 fd
= open_terminal(vc
, O_RDWR
|O_CLOEXEC
);
256 log_error_errno(fd
, "Failed to open %s: %m", vc
);
260 if (!is_vconsole(fd
)) {
261 log_error("Device %s is not a virtual console.", vc
);
265 utf8
= is_locale_utf8();
267 r
= parse_env_file("/etc/vconsole.conf", NEWLINE
,
268 "KEYMAP", &vc_keymap
,
269 "KEYMAP_TOGGLE", &vc_keymap_toggle
,
271 "FONT_MAP", &vc_font_map
,
272 "FONT_UNIMAP", &vc_font_unimap
,
275 if (r
< 0 && r
!= -ENOENT
)
276 log_warning_errno(r
, "Failed to read /etc/vconsole.conf: %m");
278 /* Let the kernel command line override /etc/vconsole.conf */
279 if (detect_container() <= 0) {
280 r
= parse_env_file("/proc/cmdline", WHITESPACE
,
281 "vconsole.keymap", &vc_keymap
,
282 "vconsole.keymap.toggle", &vc_keymap_toggle
,
283 "vconsole.font", &vc_font
,
284 "vconsole.font.map", &vc_font_map
,
285 "vconsole.font.unimap", &vc_font_unimap
,
288 if (r
< 0 && r
!= -ENOENT
)
289 log_warning_errno(r
, "Failed to read /proc/cmdline: %m");
292 toggle_utf8_sysfs(utf8
);
293 toggle_utf8(fd
, utf8
);
295 font_ok
= font_load_and_wait(vc
, vc_font
, vc_font_map
, vc_font_unimap
) > 0;
296 keyboard_ok
= keyboard_load_and_wait(vc
, vc_keymap
, vc_keymap_toggle
, utf8
) > 0;
298 /* Only copy the font when we executed setfont successfully */
299 if (font_copy
&& font_ok
)
300 (void) font_copy_to_all_vcs(fd
);
302 return font_ok
&& keyboard_ok
? EXIT_SUCCESS
: EXIT_FAILURE
;