]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/vconsole/vconsole-setup.c
honor SELinux labels, when creating and writing config files
[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"
a5c32cff 42#include "fileio.h"
97c4a07d 43
653ab83b 44static bool is_vconsole(int fd) {
97c4a07d
LP
45 unsigned char data[1];
46
47 data[0] = TIOCL_GETFGCONSOLE;
48 return ioctl(fd, TIOCLINUX, data) >= 0;
97c4a07d
LP
49}
50
51static int disable_utf8(int fd) {
52 int r = 0, k;
53
54 if (ioctl(fd, KDSKBMODE, K_XLATE) < 0)
55 r = -errno;
56
57 if (loop_write(fd, "\033%@", 3, false) < 0)
58 r = -errno;
59
741f8cf6
LP
60 k = write_one_line_file("/sys/module/vt/parameters/default_utf8", "0");
61 if (k < 0)
97c4a07d
LP
62 r = k;
63
64 if (r < 0)
741f8cf6 65 log_warning("Failed to disable UTF-8: %s", strerror(-r));
97c4a07d
LP
66
67 return r;
68}
69
d305a67b
TG
70static int enable_utf8(int fd) {
71 int r = 0, k;
a25d4d0e
LP
72 long current = 0;
73
74 if (ioctl(fd, KDGKBMODE, &current) < 0 || current == K_XLATE) {
75 /*
76 * Change the current keyboard to unicode, unless it
77 * is currently in raw or off mode anyway. We
78 * shouldn't interfere with X11's processing of the
79 * key events.
80 *
81 * http://lists.freedesktop.org/archives/systemd-devel/2013-February/008573.html
82 *
83 */
84
85 if (ioctl(fd, KDSKBMODE, K_UNICODE) < 0)
86 r = -errno;
87 }
d305a67b
TG
88
89 if (loop_write(fd, "\033%G", 3, false) < 0)
90 r = -errno;
91
92 k = write_one_line_file("/sys/module/vt/parameters/default_utf8", "1");
93 if (k < 0)
94 r = k;
95
96 if (r < 0)
97 log_warning("Failed to enable UTF-8: %s", strerror(-r));
98
99 return r;
100}
101
dd04aac9 102static int keymap_load(const char *vc, const char *map, const char *map_toggle, bool utf8, pid_t *_pid) {
5b396b06 103 const char *args[8];
97c4a07d
LP
104 int i = 0;
105 pid_t pid;
106
944d4c91
LP
107 if (isempty(map)) {
108 /* An empty map means kernel map */
109 *_pid = 0;
110 return 0;
111 }
112
9841e8e3 113 args[i++] = KBD_LOADKEYS;
97c4a07d
LP
114 args[i++] = "-q";
115 args[i++] = "-C";
116 args[i++] = vc;
117 if (utf8)
118 args[i++] = "-u";
119 args[i++] = map;
5b396b06
AB
120 if (map_toggle)
121 args[i++] = map_toggle;
97c4a07d
LP
122 args[i++] = NULL;
123
741f8cf6
LP
124 pid = fork();
125 if (pid < 0) {
97c4a07d
LP
126 log_error("Failed to fork: %m");
127 return -errno;
128 } else if (pid == 0) {
129 execv(args[0], (char **) args);
130 _exit(EXIT_FAILURE);
131 }
132
133 *_pid = pid;
134 return 0;
135}
136
dd04aac9 137static int font_load(const char *vc, const char *font, const char *map, const char *unimap, pid_t *_pid) {
97c4a07d
LP
138 const char *args[9];
139 int i = 0;
140 pid_t pid;
141
944d4c91
LP
142 if (isempty(font)) {
143 /* An empty font means kernel font */
144 *_pid = 0;
145 return 0;
146 }
147
9841e8e3 148 args[i++] = KBD_SETFONT;
97c4a07d
LP
149 args[i++] = "-C";
150 args[i++] = vc;
151 args[i++] = font;
dd36de4d 152 if (map) {
97c4a07d
LP
153 args[i++] = "-m";
154 args[i++] = map;
155 }
dd36de4d 156 if (unimap) {
97c4a07d
LP
157 args[i++] = "-u";
158 args[i++] = unimap;
159 }
160 args[i++] = NULL;
161
741f8cf6
LP
162 pid = fork();
163 if (pid < 0) {
97c4a07d
LP
164 log_error("Failed to fork: %m");
165 return -errno;
166 } else if (pid == 0) {
167 execv(args[0], (char **) args);
168 _exit(EXIT_FAILURE);
169 }
170
171 *_pid = pid;
172 return 0;
173}
174
d3b37e84
KS
175/*
176 * A newly allocated VT uses the font from the active VT. Here
177 * we update all possibly already allocated VTs with the configured
178 * font. It also allows to restart systemd-vconsole-setup.service,
179 * to apply a new font to all VTs.
180 */
181static void font_copy_to_all_vcs(int fd) {
182 struct vt_stat vcs;
dd04aac9
KS
183 int i;
184 int r;
185
d3b37e84
KS
186 /* get active, and 16 bit mask of used VT numbers */
187 zero(vcs);
188 r = ioctl(fd, VT_GETSTATE, &vcs);
dd04aac9
KS
189 if (r < 0)
190 return;
191
d3b37e84
KS
192 for (i = 1; i <= 15; i++) {
193 char vcname[16];
194 int vcfd;
dd04aac9 195 struct console_font_op cfo;
dd04aac9 196
d3b37e84 197 if (i == vcs.v_active)
dd04aac9
KS
198 continue;
199
10ffbc99
KS
200 /* skip non-allocated ttys */
201 snprintf(vcname, sizeof(vcname), "/dev/vcs%i", i);
202 if (access(vcname, F_OK) < 0)
dd04aac9
KS
203 continue;
204
10ffbc99 205 snprintf(vcname, sizeof(vcname), "/dev/tty%i", i);
d3b37e84
KS
206 vcfd = open_terminal(vcname, O_RDWR|O_CLOEXEC);
207 if (vcfd < 0)
dd04aac9
KS
208 continue;
209
d3b37e84 210 /* copy font from active VT, where the font was uploaded to */
dd04aac9
KS
211 zero(cfo);
212 cfo.op = KD_FONT_OP_COPY;
d3b37e84
KS
213 cfo.height = vcs.v_active-1; /* tty1 == index 0 */
214 ioctl(vcfd, KDFONTOP, &cfo);
dd04aac9 215
d3b37e84 216 close_nointr_nofail(vcfd);
dd04aac9
KS
217 }
218}
219
97c4a07d
LP
220int main(int argc, char **argv) {
221 const char *vc;
222 char *vc_keymap = NULL;
5b396b06 223 char *vc_keymap_toggle = NULL;
97c4a07d
LP
224 char *vc_font = NULL;
225 char *vc_font_map = NULL;
226 char *vc_font_unimap = NULL;
227 int fd = -1;
228 bool utf8;
97c4a07d 229 pid_t font_pid = 0, keymap_pid = 0;
d3b37e84 230 bool font_copy = false;
dd04aac9 231 int r = EXIT_FAILURE;
97c4a07d 232
944d4c91 233 log_set_target(LOG_TARGET_AUTO);
97c4a07d
LP
234 log_parse_environment();
235 log_open();
236
4c12626c
LP
237 umask(0022);
238
97c4a07d
LP
239 if (argv[1])
240 vc = argv[1];
dd04aac9 241 else {
d3b37e84
KS
242 vc = "/dev/tty0";
243 font_copy = true;
dd04aac9 244 }
97c4a07d 245
741f8cf6
LP
246 fd = open_terminal(vc, O_RDWR|O_CLOEXEC);
247 if (fd < 0) {
97c4a07d
LP
248 log_error("Failed to open %s: %m", vc);
249 goto finish;
250 }
251
653ab83b 252 if (!is_vconsole(fd)) {
97c4a07d
LP
253 log_error("Device %s is not a virtual console.", vc);
254 goto finish;
255 }
256
653ab83b 257 utf8 = is_locale_utf8();
97c4a07d 258
944d4c91
LP
259 r = 0;
260
741f8cf6
LP
261 if (detect_container(NULL) <= 0) {
262 r = parse_env_file("/proc/cmdline", WHITESPACE,
263 "vconsole.keymap", &vc_keymap,
264 "vconsole.keymap.toggle", &vc_keymap_toggle,
265 "vconsole.font", &vc_font,
266 "vconsole.font.map", &vc_font_map,
267 "vconsole.font.unimap", &vc_font_unimap,
268 NULL);
269
270 if (r < 0 && r != -ENOENT)
271 log_warning("Failed to read /proc/cmdline: %s", strerror(-r));
272 }
1ebdf5b6 273
653ab83b 274 /* Hmm, nothing set on the kernel cmd line? Then let's
fd5bf055 275 * try /etc/vconsole.conf */
741f8cf6
LP
276 if (r <= 0) {
277 r = parse_env_file("/etc/vconsole.conf", NEWLINE,
278 "KEYMAP", &vc_keymap,
279 "KEYMAP_TOGGLE", &vc_keymap_toggle,
280 "FONT", &vc_font,
281 "FONT_MAP", &vc_font_map,
282 "FONT_UNIMAP", &vc_font_unimap,
283 NULL);
284
285 if (r < 0 && r != -ENOENT)
fd5bf055 286 log_warning("Failed to read /etc/vconsole.conf: %s", strerror(-r));
1ebdf5b6 287 }
ae509abc 288
d305a67b
TG
289 if (utf8)
290 enable_utf8(fd);
291 else
653ab83b
LP
292 disable_utf8(fd);
293
dd04aac9
KS
294 r = EXIT_FAILURE;
295 if (keymap_load(vc, vc_keymap, vc_keymap_toggle, utf8, &keymap_pid) >= 0 &&
296 font_load(vc, vc_font, vc_font_map, vc_font_unimap, &font_pid) >= 0)
97c4a07d
LP
297 r = EXIT_SUCCESS;
298
299finish:
300 if (keymap_pid > 0)
9841e8e3 301 wait_for_terminate_and_warn(KBD_LOADKEYS, keymap_pid);
97c4a07d 302
dd04aac9 303 if (font_pid > 0) {
9841e8e3 304 wait_for_terminate_and_warn(KBD_SETFONT, font_pid);
d3b37e84
KS
305 if (font_copy)
306 font_copy_to_all_vcs(fd);
dd04aac9 307 }
97c4a07d
LP
308
309 free(vc_keymap);
310 free(vc_font);
311 free(vc_font_map);
312 free(vc_font_unimap);
313
314 if (fd >= 0)
315 close_nointr_nofail(fd);
316
317 return r;
318}