]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/vconsole/vconsole-setup.c
hwdb: add touchpad resolution for Lenovo E530 (#3265)
[thirdparty/systemd.git] / src / vconsole / vconsole-setup.c
CommitLineData
97c4a07d
LP
1/***
2 This file is part of systemd.
3
4 Copyright 2010 Kay Sievers
5
6 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
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
97c4a07d
LP
9 (at your option) any later version.
10
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
5430f7f2 14 Lesser General Public License for more details.
97c4a07d 15
5430f7f2 16 You should have received a copy of the GNU Lesser General Public License
97c4a07d
LP
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18***/
19
97c4a07d 20#include <errno.h>
97c4a07d 21#include <fcntl.h>
97c4a07d 22#include <limits.h>
97c4a07d 23#include <linux/kd.h>
07630cea 24#include <linux/tiocl.h>
dd04aac9 25#include <linux/vt.h>
07630cea
LP
26#include <stdbool.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <sys/ioctl.h>
30#include <unistd.h>
97c4a07d 31
b5efdb8a 32#include "alloc-util.h"
3ffd4af2 33#include "fd-util.h"
a5c32cff 34#include "fileio.h"
c004493c 35#include "io-util.h"
8752c575 36#include "locale-util.h"
07630cea 37#include "log.h"
0b452006 38#include "process-util.h"
ce30c8dc 39#include "signal-util.h"
d054f0a4 40#include "stdio-util.h"
07630cea
LP
41#include "string-util.h"
42#include "terminal-util.h"
43#include "util.h"
44#include "virt.h"
97c4a07d 45
653ab83b 46static bool is_vconsole(int fd) {
97c4a07d
LP
47 unsigned char data[1];
48
49 data[0] = TIOCL_GETFGCONSOLE;
50 return ioctl(fd, TIOCLINUX, data) >= 0;
97c4a07d
LP
51}
52
53static int disable_utf8(int fd) {
54 int r = 0, k;
55
56 if (ioctl(fd, KDSKBMODE, K_XLATE) < 0)
57 r = -errno;
58
553acb7b
ZJS
59 k = loop_write(fd, "\033%@", 3, false);
60 if (k < 0)
61 r = k;
97c4a07d 62
ad118bda 63 k = write_string_file("/sys/module/vt/parameters/default_utf8", "0", 0);
741f8cf6 64 if (k < 0)
97c4a07d
LP
65 r = k;
66
67 if (r < 0)
da927ba9 68 log_warning_errno(r, "Failed to disable UTF-8: %m");
97c4a07d
LP
69
70 return r;
71}
72
d305a67b
TG
73static int enable_utf8(int fd) {
74 int r = 0, k;
a25d4d0e
LP
75 long current = 0;
76
77 if (ioctl(fd, KDGKBMODE, &current) < 0 || current == K_XLATE) {
78 /*
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
82 * key events.
83 *
84 * http://lists.freedesktop.org/archives/systemd-devel/2013-February/008573.html
85 *
86 */
87
88 if (ioctl(fd, KDSKBMODE, K_UNICODE) < 0)
89 r = -errno;
90 }
d305a67b 91
553acb7b
ZJS
92 k = loop_write(fd, "\033%G", 3, false);
93 if (k < 0)
94 r = k;
d305a67b 95
ad118bda 96 k = write_string_file("/sys/module/vt/parameters/default_utf8", "1", 0);
d305a67b
TG
97 if (k < 0)
98 r = k;
99
100 if (r < 0)
da927ba9 101 log_warning_errno(r, "Failed to enable UTF-8: %m");
d305a67b
TG
102
103 return r;
104}
105
aecb6fcb 106static int keyboard_load_and_wait(const char *vc, const char *map, const char *map_toggle, bool utf8) {
5b396b06 107 const char *args[8];
aecb6fcb 108 int i = 0, r;
97c4a07d
LP
109 pid_t pid;
110
8931278c
LDM
111 /* An empty map means kernel map */
112 if (isempty(map))
aecb6fcb 113 return 1;
944d4c91 114
9841e8e3 115 args[i++] = KBD_LOADKEYS;
97c4a07d
LP
116 args[i++] = "-q";
117 args[i++] = "-C";
118 args[i++] = vc;
119 if (utf8)
120 args[i++] = "-u";
121 args[i++] = map;
5b396b06
AB
122 if (map_toggle)
123 args[i++] = map_toggle;
97c4a07d
LP
124 args[i++] = NULL;
125
741f8cf6 126 pid = fork();
aecb6fcb
LP
127 if (pid < 0)
128 return log_error_errno(errno, "Failed to fork: %m");
129 else if (pid == 0) {
ce30c8dc
LP
130
131 (void) reset_all_signal_handlers();
132 (void) reset_signal_mask();
133
97c4a07d
LP
134 execv(args[0], (char **) args);
135 _exit(EXIT_FAILURE);
136 }
137
aecb6fcb
LP
138 r = wait_for_terminate_and_warn(KBD_LOADKEYS, pid, true);
139 if (r < 0)
140 return r;
141
142 return r == 0;
97c4a07d
LP
143}
144
aecb6fcb 145static int font_load_and_wait(const char *vc, const char *font, const char *map, const char *unimap) {
97c4a07d 146 const char *args[9];
aecb6fcb 147 int i = 0, r;
97c4a07d
LP
148 pid_t pid;
149
8931278c
LDM
150 /* An empty font means kernel font */
151 if (isempty(font))
aecb6fcb 152 return 1;
944d4c91 153
9841e8e3 154 args[i++] = KBD_SETFONT;
97c4a07d
LP
155 args[i++] = "-C";
156 args[i++] = vc;
157 args[i++] = font;
dd36de4d 158 if (map) {
97c4a07d
LP
159 args[i++] = "-m";
160 args[i++] = map;
161 }
dd36de4d 162 if (unimap) {
97c4a07d
LP
163 args[i++] = "-u";
164 args[i++] = unimap;
165 }
166 args[i++] = NULL;
167
741f8cf6 168 pid = fork();
aecb6fcb
LP
169 if (pid < 0)
170 return log_error_errno(errno, "Failed to fork: %m");
171 else if (pid == 0) {
ce30c8dc
LP
172
173 (void) reset_all_signal_handlers();
174 (void) reset_signal_mask();
175
97c4a07d
LP
176 execv(args[0], (char **) args);
177 _exit(EXIT_FAILURE);
178 }
179
aecb6fcb
LP
180 r = wait_for_terminate_and_warn(KBD_SETFONT, pid, true);
181 if (r < 0)
182 return r;
183
184 return r == 0;
97c4a07d
LP
185}
186
d3b37e84
KS
187/*
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.
192 */
193static void font_copy_to_all_vcs(int fd) {
b92bea5d 194 struct vt_stat vcs = {};
ff452e76
CS
195 unsigned char map8[E_TABSZ];
196 unsigned short map16[E_TABSZ];
197 struct unimapdesc unimapd;
198 struct unipair unipairs[USHRT_MAX];
b92bea5d 199 int i, r;
dd04aac9 200
d3b37e84 201 /* get active, and 16 bit mask of used VT numbers */
d3b37e84 202 r = ioctl(fd, VT_GETSTATE, &vcs);
ab51b943
LP
203 if (r < 0) {
204 log_debug_errno(errno, "VT_GETSTATE failed, ignoring: %m");
dd04aac9 205 return;
ab51b943 206 }
dd04aac9 207
d3b37e84 208 for (i = 1; i <= 15; i++) {
ab51b943 209 char vcname[strlen("/dev/vcs") + DECIMAL_STR_MAX(int)];
7fd1b19b 210 _cleanup_close_ int vcfd = -1;
b92bea5d 211 struct console_font_op cfo = {};
dd04aac9 212
d3b37e84 213 if (i == vcs.v_active)
dd04aac9
KS
214 continue;
215
10ffbc99 216 /* skip non-allocated ttys */
d054f0a4 217 xsprintf(vcname, "/dev/vcs%i", i);
10ffbc99 218 if (access(vcname, F_OK) < 0)
dd04aac9
KS
219 continue;
220
d054f0a4 221 xsprintf(vcname, "/dev/tty%i", i);
d3b37e84
KS
222 vcfd = open_terminal(vcname, O_RDWR|O_CLOEXEC);
223 if (vcfd < 0)
dd04aac9
KS
224 continue;
225
d3b37e84 226 /* copy font from active VT, where the font was uploaded to */
dd04aac9 227 cfo.op = KD_FONT_OP_COPY;
d3b37e84 228 cfo.height = vcs.v_active-1; /* tty1 == index 0 */
791a4fd8 229 (void) ioctl(vcfd, KDFONTOP, &cfo);
ff452e76
CS
230
231 /* copy map of 8bit chars */
232 if (ioctl(fd, GIO_SCRNMAP, map8) >= 0)
ab51b943 233 (void) ioctl(vcfd, PIO_SCRNMAP, map8);
ff452e76
CS
234
235 /* copy map of 8bit chars -> 16bit Unicode values */
236 if (ioctl(fd, GIO_UNISCRNMAP, map16) >= 0)
ab51b943 237 (void) ioctl(vcfd, PIO_UNISCRNMAP, map16);
ff452e76
CS
238
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 };
246
791a4fd8
TA
247 (void) ioctl(vcfd, PIO_UNIMAPCLR, &adv);
248 (void) ioctl(vcfd, PIO_UNIMAP, &unimapd);
ff452e76 249 }
dd04aac9
KS
250 }
251}
252
97c4a07d
LP
253int main(int argc, char **argv) {
254 const char *vc;
abee28c5
ZJS
255 _cleanup_free_ char
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;
ab51b943 259 bool utf8, font_copy = false, font_ok, keyboard_ok;
dd04aac9 260 int r = EXIT_FAILURE;
97c4a07d 261
944d4c91 262 log_set_target(LOG_TARGET_AUTO);
97c4a07d
LP
263 log_parse_environment();
264 log_open();
265
4c12626c
LP
266 umask(0022);
267
97c4a07d
LP
268 if (argv[1])
269 vc = argv[1];
dd04aac9 270 else {
d3b37e84
KS
271 vc = "/dev/tty0";
272 font_copy = true;
dd04aac9 273 }
97c4a07d 274
741f8cf6
LP
275 fd = open_terminal(vc, O_RDWR|O_CLOEXEC);
276 if (fd < 0) {
709f6e46 277 log_error_errno(fd, "Failed to open %s: %m", vc);
abee28c5 278 return EXIT_FAILURE;
97c4a07d
LP
279 }
280
653ab83b 281 if (!is_vconsole(fd)) {
97c4a07d 282 log_error("Device %s is not a virtual console.", vc);
abee28c5 283 return EXIT_FAILURE;
97c4a07d
LP
284 }
285
653ab83b 286 utf8 = is_locale_utf8();
97c4a07d 287
2034ec42
MS
288 r = parse_env_file("/etc/vconsole.conf", NEWLINE,
289 "KEYMAP", &vc_keymap,
290 "KEYMAP_TOGGLE", &vc_keymap_toggle,
291 "FONT", &vc_font,
292 "FONT_MAP", &vc_font_map,
293 "FONT_UNIMAP", &vc_font_unimap,
294 NULL);
295
296 if (r < 0 && r != -ENOENT)
da927ba9 297 log_warning_errno(r, "Failed to read /etc/vconsole.conf: %m");
2034ec42
MS
298
299 /* Let the kernel command line override /etc/vconsole.conf */
75f86906 300 if (detect_container() <= 0) {
741f8cf6
LP
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,
307 NULL);
308
309 if (r < 0 && r != -ENOENT)
da927ba9 310 log_warning_errno(r, "Failed to read /proc/cmdline: %m");
741f8cf6 311 }
1ebdf5b6 312
d305a67b 313 if (utf8)
ab51b943 314 (void) enable_utf8(fd);
d305a67b 315 else
ab51b943 316 (void) disable_utf8(fd);
653ab83b 317
aecb6fcb
LP
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;
97c4a07d 320
8931278c
LDM
321 /* Only copy the font when we executed setfont successfully */
322 if (font_copy && font_ok)
ab51b943 323 (void) font_copy_to_all_vcs(fd);
97c4a07d 324
8931278c 325 return font_ok && keyboard_ok ? EXIT_SUCCESS : EXIT_FAILURE;
97c4a07d 326}