]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/vconsole/vconsole-setup.c
Typo fix
[thirdparty/systemd.git] / src / vconsole / vconsole-setup.c
CommitLineData
97c4a07d
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Kay Sievers
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
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
97c4a07d
LP
11 (at your option) any later version.
12
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
5430f7f2 16 Lesser General Public License for more details.
97c4a07d 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
97c4a07d
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <stdio.h>
23#include <unistd.h>
24#include <stdlib.h>
25#include <errno.h>
26#include <string.h>
27#include <fcntl.h>
28#include <ctype.h>
29#include <stdbool.h>
30#include <stdarg.h>
31#include <limits.h>
97c4a07d
LP
32#include <sys/ioctl.h>
33#include <sys/wait.h>
34#include <linux/tiocl.h>
35#include <linux/kd.h>
dd04aac9 36#include <linux/vt.h>
97c4a07d
LP
37
38#include "util.h"
39#include "log.h"
40#include "macro.h"
b52aae1d 41#include "virt.h"
97c4a07d 42
653ab83b 43static bool is_vconsole(int fd) {
97c4a07d
LP
44 unsigned char data[1];
45
46 data[0] = TIOCL_GETFGCONSOLE;
47 return ioctl(fd, TIOCLINUX, data) >= 0;
97c4a07d
LP
48}
49
50static int disable_utf8(int fd) {
51 int r = 0, k;
52
53 if (ioctl(fd, KDSKBMODE, K_XLATE) < 0)
54 r = -errno;
55
56 if (loop_write(fd, "\033%@", 3, false) < 0)
57 r = -errno;
58
741f8cf6
LP
59 k = write_one_line_file("/sys/module/vt/parameters/default_utf8", "0");
60 if (k < 0)
97c4a07d
LP
61 r = k;
62
63 if (r < 0)
741f8cf6 64 log_warning("Failed to disable UTF-8: %s", strerror(-r));
97c4a07d
LP
65
66 return r;
67}
68
d305a67b
TG
69static int enable_utf8(int fd) {
70 int r = 0, k;
71
72 if (ioctl(fd, KDSKBMODE, K_UNICODE) < 0)
73 r = -errno;
74
75 if (loop_write(fd, "\033%G", 3, false) < 0)
76 r = -errno;
77
78 k = write_one_line_file("/sys/module/vt/parameters/default_utf8", "1");
79 if (k < 0)
80 r = k;
81
82 if (r < 0)
83 log_warning("Failed to enable UTF-8: %s", strerror(-r));
84
85 return r;
86}
87
dd04aac9 88static int keymap_load(const char *vc, const char *map, const char *map_toggle, bool utf8, pid_t *_pid) {
5b396b06 89 const char *args[8];
97c4a07d
LP
90 int i = 0;
91 pid_t pid;
92
944d4c91
LP
93 if (isempty(map)) {
94 /* An empty map means kernel map */
95 *_pid = 0;
96 return 0;
97 }
98
9841e8e3 99 args[i++] = KBD_LOADKEYS;
97c4a07d
LP
100 args[i++] = "-q";
101 args[i++] = "-C";
102 args[i++] = vc;
103 if (utf8)
104 args[i++] = "-u";
105 args[i++] = map;
5b396b06
AB
106 if (map_toggle)
107 args[i++] = map_toggle;
97c4a07d
LP
108 args[i++] = NULL;
109
741f8cf6
LP
110 pid = fork();
111 if (pid < 0) {
97c4a07d
LP
112 log_error("Failed to fork: %m");
113 return -errno;
114 } else if (pid == 0) {
115 execv(args[0], (char **) args);
116 _exit(EXIT_FAILURE);
117 }
118
119 *_pid = pid;
120 return 0;
121}
122
dd04aac9 123static int font_load(const char *vc, const char *font, const char *map, const char *unimap, pid_t *_pid) {
97c4a07d
LP
124 const char *args[9];
125 int i = 0;
126 pid_t pid;
127
944d4c91
LP
128 if (isempty(font)) {
129 /* An empty font means kernel font */
130 *_pid = 0;
131 return 0;
132 }
133
9841e8e3 134 args[i++] = KBD_SETFONT;
97c4a07d
LP
135 args[i++] = "-C";
136 args[i++] = vc;
137 args[i++] = font;
dd36de4d 138 if (map) {
97c4a07d
LP
139 args[i++] = "-m";
140 args[i++] = map;
141 }
dd36de4d 142 if (unimap) {
97c4a07d
LP
143 args[i++] = "-u";
144 args[i++] = unimap;
145 }
146 args[i++] = NULL;
147
741f8cf6
LP
148 pid = fork();
149 if (pid < 0) {
97c4a07d
LP
150 log_error("Failed to fork: %m");
151 return -errno;
152 } else if (pid == 0) {
153 execv(args[0], (char **) args);
154 _exit(EXIT_FAILURE);
155 }
156
157 *_pid = pid;
158 return 0;
159}
160
dd04aac9
KS
161static void font_copy_to_all_vts(int fd, int from_vt) {
162 struct vt_stat vts;
163 unsigned short bits;
164 int i;
165 int r;
166
167 /* get 16 bit mask of used VT numbers */
168 zero(vts);
169 r = ioctl(fd, VT_GETSTATE, &vts);
170 if (r < 0)
171 return;
172
173 bits = vts.v_state;
174 for (i = 1; i <= 16; i++) {
175 char vtname[16];
176 int vtfd;
177 struct console_font_op cfo;
178 bool used;
179
180 /* skip unused VTs */
181 used = bits & 1;
182 bits >>= 1;
183 if (!used)
184 continue;
185
186 if (i == from_vt)
187 continue;
188
189 snprintf(vtname , sizeof(vtname), "/dev/tty%i", i);
190 vtfd = open_terminal(vtname, O_RDWR|O_CLOEXEC);
191 if (vtfd < 0)
192 continue;
193
194 /* copy font from from_vt to this VT */
195 zero(cfo);
196 cfo.op = KD_FONT_OP_COPY;
197 /* the index numbers seem to start at 0 for tty1 */
198 cfo.height = from_vt - 1;
199 ioctl(vtfd, KDFONTOP, &cfo);
200
201 close_nointr_nofail(vtfd);
202 }
203}
204
97c4a07d
LP
205int main(int argc, char **argv) {
206 const char *vc;
207 char *vc_keymap = NULL;
5b396b06 208 char *vc_keymap_toggle = NULL;
97c4a07d
LP
209 char *vc_font = NULL;
210 char *vc_font_map = NULL;
211 char *vc_font_unimap = NULL;
212 int fd = -1;
213 bool utf8;
97c4a07d 214 pid_t font_pid = 0, keymap_pid = 0;
dd04aac9
KS
215 int font_copy_from_vt = 0;
216 int r = EXIT_FAILURE;
97c4a07d 217
944d4c91 218 log_set_target(LOG_TARGET_AUTO);
97c4a07d
LP
219 log_parse_environment();
220 log_open();
221
4c12626c
LP
222 umask(0022);
223
97c4a07d
LP
224 if (argv[1])
225 vc = argv[1];
dd04aac9
KS
226 else {
227 vc = "/dev/tty1";
228 font_copy_from_vt = 1;
229 }
97c4a07d 230
741f8cf6
LP
231 fd = open_terminal(vc, O_RDWR|O_CLOEXEC);
232 if (fd < 0) {
97c4a07d
LP
233 log_error("Failed to open %s: %m", vc);
234 goto finish;
235 }
236
653ab83b 237 if (!is_vconsole(fd)) {
97c4a07d
LP
238 log_error("Device %s is not a virtual console.", vc);
239 goto finish;
240 }
241
653ab83b 242 utf8 = is_locale_utf8();
97c4a07d 243
944d4c91
LP
244 r = 0;
245
741f8cf6
LP
246 if (detect_container(NULL) <= 0) {
247 r = parse_env_file("/proc/cmdline", WHITESPACE,
248 "vconsole.keymap", &vc_keymap,
249 "vconsole.keymap.toggle", &vc_keymap_toggle,
250 "vconsole.font", &vc_font,
251 "vconsole.font.map", &vc_font_map,
252 "vconsole.font.unimap", &vc_font_unimap,
253 NULL);
254
255 if (r < 0 && r != -ENOENT)
256 log_warning("Failed to read /proc/cmdline: %s", strerror(-r));
257 }
1ebdf5b6 258
653ab83b 259 /* Hmm, nothing set on the kernel cmd line? Then let's
fd5bf055 260 * try /etc/vconsole.conf */
741f8cf6
LP
261 if (r <= 0) {
262 r = parse_env_file("/etc/vconsole.conf", NEWLINE,
263 "KEYMAP", &vc_keymap,
264 "KEYMAP_TOGGLE", &vc_keymap_toggle,
265 "FONT", &vc_font,
266 "FONT_MAP", &vc_font_map,
267 "FONT_UNIMAP", &vc_font_unimap,
268 NULL);
269
270 if (r < 0 && r != -ENOENT)
fd5bf055 271 log_warning("Failed to read /etc/vconsole.conf: %s", strerror(-r));
1ebdf5b6 272 }
ae509abc 273
d305a67b
TG
274 if (utf8)
275 enable_utf8(fd);
276 else
653ab83b
LP
277 disable_utf8(fd);
278
dd04aac9
KS
279 r = EXIT_FAILURE;
280 if (keymap_load(vc, vc_keymap, vc_keymap_toggle, utf8, &keymap_pid) >= 0 &&
281 font_load(vc, vc_font, vc_font_map, vc_font_unimap, &font_pid) >= 0)
97c4a07d
LP
282 r = EXIT_SUCCESS;
283
284finish:
285 if (keymap_pid > 0)
9841e8e3 286 wait_for_terminate_and_warn(KBD_LOADKEYS, keymap_pid);
97c4a07d 287
dd04aac9 288 if (font_pid > 0) {
9841e8e3 289 wait_for_terminate_and_warn(KBD_SETFONT, font_pid);
dd04aac9
KS
290 if (font_copy_from_vt > 0)
291 font_copy_to_all_vts(fd, font_copy_from_vt);
292 }
97c4a07d
LP
293
294 free(vc_keymap);
295 free(vc_font);
296 free(vc_font_map);
297 free(vc_font_unimap);
298
299 if (fd >= 0)
300 close_nointr_nofail(fd);
301
302 return r;
303}