chiark / gitweb /
core: drop support for old per-distro configuration files for console, hostname,...
[elogind.git] / src / vconsole / vconsole-setup.c
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
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.
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
16   Lesser General Public License for more details.
17
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/>.
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>
32 #include <sys/ioctl.h>
33 #include <sys/wait.h>
34 #include <linux/tiocl.h>
35 #include <linux/kd.h>
36
37 #include "util.h"
38 #include "log.h"
39 #include "macro.h"
40 #include "virt.h"
41
42 static bool is_vconsole(int fd) {
43         unsigned char data[1];
44
45         data[0] = TIOCL_GETFGCONSOLE;
46         return ioctl(fd, TIOCLINUX, data) >= 0;
47 }
48
49 static int disable_utf8(int fd) {
50         int r = 0, k;
51
52         if (ioctl(fd, KDSKBMODE, K_XLATE) < 0)
53                 r = -errno;
54
55         if (loop_write(fd, "\033%@", 3, false) < 0)
56                 r = -errno;
57
58         k = write_one_line_file("/sys/module/vt/parameters/default_utf8", "0");
59         if (k < 0)
60                 r = k;
61
62         if (r < 0)
63                 log_warning("Failed to disable UTF-8: %s", strerror(-r));
64
65         return r;
66 }
67
68 static int enable_utf8(int fd) {
69         int r = 0, k;
70
71         if (ioctl(fd, KDSKBMODE, K_UNICODE) < 0)
72                 r = -errno;
73
74         if (loop_write(fd, "\033%G", 3, false) < 0)
75                 r = -errno;
76
77         k = write_one_line_file("/sys/module/vt/parameters/default_utf8", "1");
78         if (k < 0)
79                 r = k;
80
81         if (r < 0)
82                 log_warning("Failed to enable UTF-8: %s", strerror(-r));
83
84         return r;
85 }
86
87 static int load_keymap(const char *vc, const char *map, const char *map_toggle, bool utf8, pid_t *_pid) {
88         const char *args[8];
89         int i = 0;
90         pid_t pid;
91
92         if (isempty(map)) {
93                 /* An empty map means kernel map */
94                 *_pid = 0;
95                 return 0;
96         }
97
98         args[i++] = KBD_LOADKEYS;
99         args[i++] = "-q";
100         args[i++] = "-C";
101         args[i++] = vc;
102         if (utf8)
103                 args[i++] = "-u";
104         args[i++] = map;
105         if (map_toggle)
106                 args[i++] = map_toggle;
107         args[i++] = NULL;
108
109         pid = fork();
110         if (pid < 0) {
111                 log_error("Failed to fork: %m");
112                 return -errno;
113         } else if (pid == 0) {
114                 execv(args[0], (char **) args);
115                 _exit(EXIT_FAILURE);
116         }
117
118         *_pid = pid;
119         return 0;
120 }
121
122 static int load_font(const char *vc, const char *font, const char *map, const char *unimap, pid_t *_pid) {
123         const char *args[9];
124         int i = 0;
125         pid_t pid;
126
127         if (isempty(font)) {
128                 /* An empty font means kernel font */
129                 *_pid = 0;
130                 return 0;
131         }
132
133         args[i++] = KBD_SETFONT;
134         args[i++] = "-C";
135         args[i++] = vc;
136         args[i++] = font;
137         if (map) {
138                 args[i++] = "-m";
139                 args[i++] = map;
140         }
141         if (unimap) {
142                 args[i++] = "-u";
143                 args[i++] = unimap;
144         }
145         args[i++] = NULL;
146
147         pid = fork();
148         if (pid < 0) {
149                 log_error("Failed to fork: %m");
150                 return -errno;
151         } else if (pid == 0) {
152                 execv(args[0], (char **) args);
153                 _exit(EXIT_FAILURE);
154         }
155
156         *_pid = pid;
157         return 0;
158 }
159
160 int main(int argc, char **argv) {
161         const char *vc;
162         char *vc_keymap = NULL;
163         char *vc_keymap_toggle = NULL;
164         char *vc_font = NULL;
165         char *vc_font_map = NULL;
166         char *vc_font_unimap = NULL;
167         int fd = -1;
168         bool utf8;
169         int r = EXIT_FAILURE;
170         pid_t font_pid = 0, keymap_pid = 0;
171
172         log_set_target(LOG_TARGET_AUTO);
173         log_parse_environment();
174         log_open();
175
176         umask(0022);
177
178         if (argv[1])
179                 vc = argv[1];
180         else
181                 vc = "/dev/tty0";
182
183         fd = open_terminal(vc, O_RDWR|O_CLOEXEC);
184         if (fd < 0) {
185                 log_error("Failed to open %s: %m", vc);
186                 goto finish;
187         }
188
189         if (!is_vconsole(fd)) {
190                 log_error("Device %s is not a virtual console.", vc);
191                 goto finish;
192         }
193
194         utf8 = is_locale_utf8();
195
196         r = 0;
197
198         if (detect_container(NULL) <= 0) {
199                 r = parse_env_file("/proc/cmdline", WHITESPACE,
200                                    "vconsole.keymap", &vc_keymap,
201                                    "vconsole.keymap.toggle", &vc_keymap_toggle,
202                                    "vconsole.font", &vc_font,
203                                    "vconsole.font.map", &vc_font_map,
204                                    "vconsole.font.unimap", &vc_font_unimap,
205                                    NULL);
206
207                 if (r < 0 && r != -ENOENT)
208                         log_warning("Failed to read /proc/cmdline: %s", strerror(-r));
209         }
210
211         /* Hmm, nothing set on the kernel cmd line? Then let's
212          * try /etc/vconsole.conf */
213         if (r <= 0) {
214                 r = parse_env_file("/etc/vconsole.conf", NEWLINE,
215                                    "KEYMAP", &vc_keymap,
216                                    "KEYMAP_TOGGLE", &vc_keymap_toggle,
217                                    "FONT", &vc_font,
218                                    "FONT_MAP", &vc_font_map,
219                                    "FONT_UNIMAP", &vc_font_unimap,
220                                    NULL);
221
222                 if (r < 0 && r != -ENOENT)
223                         log_warning("Failed to read /etc/vconsole.conf: %s", strerror(-r));
224         }
225
226         if (r <= 0) {
227         }
228
229         r = EXIT_FAILURE;
230
231         if (utf8)
232                 enable_utf8(fd);
233         else
234                 disable_utf8(fd);
235
236
237         if (load_keymap(vc, vc_keymap, vc_keymap_toggle, utf8, &keymap_pid) >= 0 &&
238             load_font(vc, vc_font, vc_font_map, vc_font_unimap, &font_pid) >= 0)
239                 r = EXIT_SUCCESS;
240
241 finish:
242         if (keymap_pid > 0)
243                 wait_for_terminate_and_warn(KBD_LOADKEYS, keymap_pid);
244
245         if (font_pid > 0)
246                 wait_for_terminate_and_warn(KBD_SETFONT, font_pid);
247
248         free(vc_keymap);
249         free(vc_font);
250         free(vc_font_map);
251         free(vc_font_unimap);
252
253         if (fd >= 0)
254                 close_nointr_nofail(fd);
255
256         return r;
257 }