~ubuntu-branches/debian/jessie/systemd/jessie

« back to all changes in this revision

Viewing changes to src/vconsole/vconsole-setup.c

  • Committer: Package Import Robot
  • Author(s): Tollef Fog Heen, Tollef Fog Heen, Michael Biebl
  • Date: 2012-04-03 19:59:17 UTC
  • mfrom: (1.1.10) (6.1.3 experimental)
  • Revision ID: package-import@ubuntu.com-20120403195917-l532urrbg4pkreas
Tags: 44-1
[ Tollef Fog Heen ]
* New upstream version.
  - Backport 3492207: journal: PAGE_SIZE is not known on ppc and other
    archs
  - Backport 5a2a2a1: journal: react with immediate rotation to a couple
    of more errors
  - Backport 693ce21: util: never follow symlinks in rm_rf_children()
    Fixes CVE-2012-1174, closes: #664364
* Drop output message from init-functions hook, it's pointless.
* Only rmdir /lib/init/rw if it exists.
* Explicitly order debian-fixup before sysinit.target to prevent a
  possible race condition with the creation of sockets.  Thanks to
  Michael Biebl for debugging this.
* Always restart the initctl socket on upgrades, to mask sysvinit
  removing it.

[ Michael Biebl ]
* Remove workaround for non-interactive sessions from pam config again.
* Create compat /dev/initctl symlink in case we are upgrading from a system
  running a newer version of sysvinit (using /run/initctl) and sysvinit is
  replaced with systemd-sysv during the upgrade. Closes: #663219
* Install new man pages.
* Build-Depend on valac (>= 0.12) instead of valac-0.12. Closes: #663323

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 General Public License as published by
 
10
  the Free Software Foundation; either version 2 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
  General Public License for more details.
 
17
 
 
18
  You should have received a copy of the GNU 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 <locale.h>
 
33
#include <langinfo.h>
 
34
#include <sys/ioctl.h>
 
35
#include <sys/wait.h>
 
36
#include <linux/tiocl.h>
 
37
#include <linux/kd.h>
 
38
 
 
39
#include "util.h"
 
40
#include "log.h"
 
41
#include "macro.h"
 
42
#include "virt.h"
 
43
 
 
44
static bool is_vconsole(int fd) {
 
45
        unsigned char data[1];
 
46
 
 
47
        data[0] = TIOCL_GETFGCONSOLE;
 
48
        return ioctl(fd, TIOCLINUX, data) >= 0;
 
49
}
 
50
 
 
51
static bool is_locale_utf8(void) {
 
52
        const char *set;
 
53
 
 
54
        if (!setlocale(LC_ALL, ""))
 
55
                return true;
 
56
 
 
57
        set = nl_langinfo(CODESET);
 
58
        if (!set)
 
59
                return true;
 
60
 
 
61
        return streq(set, "UTF-8");
 
62
}
 
63
 
 
64
static int disable_utf8(int fd) {
 
65
        int r = 0, k;
 
66
 
 
67
        if (ioctl(fd, KDSKBMODE, K_XLATE) < 0)
 
68
                r = -errno;
 
69
 
 
70
        if (loop_write(fd, "\033%@", 3, false) < 0)
 
71
                r = -errno;
 
72
 
 
73
        if ((k = write_one_line_file("/sys/module/vt/parameters/default_utf8", "0")) < 0)
 
74
                r = k;
 
75
 
 
76
        if (r < 0)
 
77
                log_warning("Failed to disable UTF-8: %s", strerror(errno));
 
78
 
 
79
        return r;
 
80
}
 
81
 
 
82
static int load_keymap(const char *vc, const char *map, const char *map_toggle, bool utf8, pid_t *_pid) {
 
83
        const char *args[8];
 
84
        int i = 0;
 
85
        pid_t pid;
 
86
 
 
87
        if (isempty(map)) {
 
88
                /* An empty map means kernel map */
 
89
                *_pid = 0;
 
90
                return 0;
 
91
        }
 
92
 
 
93
        args[i++] = KBD_LOADKEYS;
 
94
        args[i++] = "-q";
 
95
        args[i++] = "-C";
 
96
        args[i++] = vc;
 
97
        if (utf8)
 
98
                args[i++] = "-u";
 
99
        args[i++] = map;
 
100
        if (map_toggle)
 
101
                args[i++] = map_toggle;
 
102
        args[i++] = NULL;
 
103
 
 
104
        if ((pid = fork()) < 0) {
 
105
                log_error("Failed to fork: %m");
 
106
                return -errno;
 
107
        } else if (pid == 0) {
 
108
                execv(args[0], (char **) args);
 
109
                _exit(EXIT_FAILURE);
 
110
        }
 
111
 
 
112
        *_pid = pid;
 
113
        return 0;
 
114
}
 
115
 
 
116
static int load_font(const char *vc, const char *font, const char *map, const char *unimap, pid_t *_pid) {
 
117
        const char *args[9];
 
118
        int i = 0;
 
119
        pid_t pid;
 
120
 
 
121
        if (isempty(font)) {
 
122
                /* An empty font means kernel font */
 
123
                *_pid = 0;
 
124
                return 0;
 
125
        }
 
126
 
 
127
        args[i++] = KBD_SETFONT;
 
128
        args[i++] = "-C";
 
129
        args[i++] = vc;
 
130
        args[i++] = font;
 
131
        if (map) {
 
132
                args[i++] = "-m";
 
133
                args[i++] = map;
 
134
        }
 
135
        if (unimap) {
 
136
                args[i++] = "-u";
 
137
                args[i++] = unimap;
 
138
        }
 
139
        args[i++] = NULL;
 
140
 
 
141
        if ((pid = fork()) < 0) {
 
142
                log_error("Failed to fork: %m");
 
143
                return -errno;
 
144
        } else if (pid == 0) {
 
145
                execv(args[0], (char **) args);
 
146
                _exit(EXIT_FAILURE);
 
147
        }
 
148
 
 
149
        *_pid = pid;
 
150
        return 0;
 
151
}
 
152
 
 
153
int main(int argc, char **argv) {
 
154
        const char *vc;
 
155
        char *vc_keymap = NULL;
 
156
        char *vc_keymap_toggle = NULL;
 
157
        char *vc_font = NULL;
 
158
        char *vc_font_map = NULL;
 
159
        char *vc_font_unimap = NULL;
 
160
#ifdef TARGET_GENTOO
 
161
        char *vc_unicode = NULL;
 
162
#endif
 
163
#if defined(TARGET_MANDRIVA) || defined(TARGET_MAGEIA)
 
164
        char *vc_keytable = NULL;
 
165
#endif
 
166
        int fd = -1;
 
167
        bool utf8;
 
168
        int r = EXIT_FAILURE;
 
169
        pid_t font_pid = 0, keymap_pid = 0;
 
170
 
 
171
        log_set_target(LOG_TARGET_AUTO);
 
172
        log_parse_environment();
 
173
        log_open();
 
174
 
 
175
        umask(0022);
 
176
 
 
177
        if (argv[1])
 
178
                vc = argv[1];
 
179
        else
 
180
                vc = "/dev/tty0";
 
181
 
 
182
        if ((fd = open_terminal(vc, O_RDWR|O_CLOEXEC)) < 0) {
 
183
                log_error("Failed to open %s: %m", vc);
 
184
                goto finish;
 
185
        }
 
186
 
 
187
        if (!is_vconsole(fd)) {
 
188
                log_error("Device %s is not a virtual console.", vc);
 
189
                goto finish;
 
190
        }
 
191
 
 
192
        utf8 = is_locale_utf8();
 
193
 
 
194
        vc_keymap = strdup("us");
 
195
        vc_font = strdup(DEFAULT_FONT);
 
196
 
 
197
        if (!vc_keymap || !vc_font) {
 
198
                log_error("Failed to allocate strings.");
 
199
                goto finish;
 
200
        }
 
201
 
 
202
        r = 0;
 
203
 
 
204
        if (detect_container(NULL) <= 0)
 
205
                if ((r = parse_env_file("/proc/cmdline", WHITESPACE,
 
206
                                        "vconsole.keymap", &vc_keymap,
 
207
                                        "vconsole.keymap.toggle", &vc_keymap_toggle,
 
208
                                        "vconsole.font", &vc_font,
 
209
                                        "vconsole.font.map", &vc_font_map,
 
210
                                        "vconsole.font.unimap", &vc_font_unimap,
 
211
                                        NULL)) < 0) {
 
212
 
 
213
                        if (r != -ENOENT)
 
214
                                log_warning("Failed to read /proc/cmdline: %s", strerror(-r));
 
215
                }
 
216
 
 
217
        /* Hmm, nothing set on the kernel cmd line? Then let's
 
218
         * try /etc/vconsole.conf */
 
219
        if (r <= 0 &&
 
220
            (r = parse_env_file("/etc/vconsole.conf", NEWLINE,
 
221
                                "KEYMAP", &vc_keymap,
 
222
                                "KEYMAP_TOGGLE", &vc_keymap_toggle,
 
223
                                "FONT", &vc_font,
 
224
                                "FONT_MAP", &vc_font_map,
 
225
                                "FONT_UNIMAP", &vc_font_unimap,
 
226
                                NULL)) < 0) {
 
227
 
 
228
                if (r != -ENOENT)
 
229
                        log_warning("Failed to read /etc/vconsole.conf: %s", strerror(-r));
 
230
        }
 
231
 
 
232
        if (r <= 0) {
 
233
#if defined(TARGET_FEDORA) || defined(TARGET_MEEGO)
 
234
                if ((r = parse_env_file("/etc/sysconfig/i18n", NEWLINE,
 
235
                                        "SYSFONT", &vc_font,
 
236
                                        "SYSFONTACM", &vc_font_map,
 
237
                                        "UNIMAP", &vc_font_unimap,
 
238
                                        NULL)) < 0) {
 
239
 
 
240
                        if (r != -ENOENT)
 
241
                                log_warning("Failed to read /etc/sysconfig/i18n: %s", strerror(-r));
 
242
                }
 
243
 
 
244
                if ((r = parse_env_file("/etc/sysconfig/keyboard", NEWLINE,
 
245
                                        "KEYTABLE", &vc_keymap,
 
246
                                        "KEYMAP", &vc_keymap,
 
247
                                        NULL)) < 0) {
 
248
 
 
249
                        if (r != -ENOENT)
 
250
                                log_warning("Failed to read /etc/sysconfig/i18n: %s", strerror(-r));
 
251
                }
 
252
 
 
253
                if (access("/etc/sysconfig/console/default.kmap", F_OK) >= 0) {
 
254
                        char *t;
 
255
 
 
256
                        if (!(t = strdup("/etc/sysconfig/console/default.kmap"))) {
 
257
                                log_error("Out of memory.");
 
258
                                goto finish;
 
259
                        }
 
260
 
 
261
                        free(vc_keymap);
 
262
                        vc_keymap = t;
 
263
                }
 
264
 
 
265
#elif defined(TARGET_SUSE)
 
266
                if ((r = parse_env_file("/etc/sysconfig/keyboard", NEWLINE,
 
267
                                        "KEYTABLE", &vc_keymap,
 
268
                                        NULL)) < 0) {
 
269
 
 
270
                        if (r != -ENOENT)
 
271
                                log_warning("Failed to read /etc/sysconfig/keyboard: %s", strerror(-r));
 
272
                }
 
273
 
 
274
                if ((r = parse_env_file("/etc/sysconfig/console", NEWLINE,
 
275
                                        "CONSOLE_FONT", &vc_font,
 
276
                                        "CONSOLE_SCREENMAP", &vc_font_map,
 
277
                                        "CONSOLE_UNICODEMAP", &vc_font_unimap,
 
278
                                        NULL)) < 0) {
 
279
 
 
280
                        if (r != -ENOENT)
 
281
                                log_warning("Failed to read /etc/sysconfig/console: %s", strerror(-r));
 
282
                }
 
283
 
 
284
#elif defined(TARGET_ARCH)
 
285
                if ((r = parse_env_file("/etc/rc.conf", NEWLINE,
 
286
                                        "KEYMAP", &vc_keymap,
 
287
                                        "CONSOLEFONT", &vc_font,
 
288
                                        "CONSOLEMAP", &vc_font_map,
 
289
                                        NULL)) < 0) {
 
290
 
 
291
                        if (r != -ENOENT)
 
292
                                log_warning("Failed to read /etc/rc.conf: %s", strerror(-r));
 
293
                }
 
294
 
 
295
#elif defined(TARGET_FRUGALWARE)
 
296
                if ((r = parse_env_file("/etc/sysconfig/keymap", NEWLINE,
 
297
                                        "keymap", &vc_keymap,
 
298
                                        NULL)) < 0) {
 
299
                        if (r != -ENOENT)
 
300
                                log_warning("Failed to read /etc/sysconfig/keymap: %s", strerror(-r));
 
301
                }
 
302
                if ((r = parse_env_file("/etc/sysconfig/font", NEWLINE,
 
303
                                        "font", &vc_font,
 
304
                                        NULL)) < 0) {
 
305
                        if (r != -ENOENT)
 
306
                                log_warning("Failed to read /etc/sysconfig/font: %s", strerror(-r));
 
307
                }
 
308
 
 
309
#elif defined(TARGET_ALTLINUX)
 
310
                if ((r = parse_env_file("/etc/sysconfig/keyboard", NEWLINE,
 
311
                                        "KEYTABLE", &vc_keymap,
 
312
                                        NULL)) < 0) {
 
313
 
 
314
                        if (r != -ENOENT)
 
315
                                log_warning("Failed to read /etc/sysconfig/keyboard: %s", strerror(-r));
 
316
                }
 
317
 
 
318
                if ((r = parse_env_file("/etc/sysconfig/consolefont", NEWLINE,
 
319
                                        "SYSFONT", &vc_font,
 
320
                                        NULL)) < 0) {
 
321
 
 
322
                        if (r != -ENOENT)
 
323
                                log_warning("Failed to read /etc/sysconfig/console: %s", strerror(-r));
 
324
                }
 
325
 
 
326
#elif defined(TARGET_GENTOO)
 
327
                if ((r = parse_env_file("/etc/rc.conf", NEWLINE,
 
328
                                        "unicode", &vc_unicode,
 
329
                                        NULL)) < 0) {
 
330
                        if (r != -ENOENT)
 
331
                                log_warning("Failed to read /etc/rc.conf: %s", strerror(-r));
 
332
                }
 
333
 
 
334
                if (vc_unicode) {
 
335
                        int rc_unicode;
 
336
 
 
337
                        if ((rc_unicode = parse_boolean(vc_unicode)) < 0)
 
338
                                log_error("Unknown value for /etc/rc.conf unicode=%s", vc_unicode);
 
339
                        else {
 
340
                                if (rc_unicode && !utf8)
 
341
                                        log_warning("/etc/rc.conf wants unicode, but current locale is not UTF-8 capable!");
 
342
                                else if (!rc_unicode && utf8) {
 
343
                                        log_debug("/etc/rc.conf does not want unicode, leave it on in kernel but does not apply to vconsole.");
 
344
                                        utf8 = false;
 
345
                                }
 
346
                        }
 
347
                }
 
348
 
 
349
                /* /etc/conf.d/consolefont comments and gentoo
 
350
                 * documentation mention uppercase, but the actual
 
351
                 * contents are lowercase.  the existing
 
352
                 * /etc/init.d/consolefont tries both
 
353
                 */
 
354
                if ((r = parse_env_file("/etc/conf.d/consolefont", NEWLINE,
 
355
                                        "CONSOLEFONT", &vc_font,
 
356
                                        "consolefont", &vc_font,
 
357
                                        "consoletranslation", &vc_font_map,
 
358
                                        "CONSOLETRANSLATION", &vc_font_map,
 
359
                                        "unicodemap", &vc_font_unimap,
 
360
                                        "UNICODEMAP", &vc_font_unimap,
 
361
                                        NULL)) < 0) {
 
362
                        if (r != -ENOENT)
 
363
                                log_warning("Failed to read /etc/conf.d/consolefont: %s", strerror(-r));
 
364
                }
 
365
 
 
366
                if ((r = parse_env_file("/etc/conf.d/keymaps", NEWLINE,
 
367
                                        "keymap", &vc_keymap,
 
368
                                        "KEYMAP", &vc_keymap,
 
369
                                        NULL)) < 0) {
 
370
                        if (r != -ENOENT)
 
371
                                log_warning("Failed to read /etc/conf.d/keymaps: %s", strerror(-r));
 
372
                }
 
373
 
 
374
#elif defined(TARGET_MANDRIVA) || defined (TARGET_MAGEIA)
 
375
 
 
376
                if ((r = parse_env_file("/etc/sysconfig/i18n", NEWLINE,
 
377
                                        "SYSFONT", &vc_font,
 
378
                                        "SYSFONTACM", &vc_font_map,
 
379
                                        "UNIMAP", &vc_font_unimap,
 
380
                                        NULL)) < 0) {
 
381
 
 
382
                        if (r != -ENOENT)
 
383
                                log_warning("Failed to read /etc/sysconfig/i18n: %s", strerror(-r));
 
384
                }
 
385
 
 
386
                if ((r = parse_env_file("/etc/sysconfig/keyboard", NEWLINE,
 
387
                                        "KEYTABLE", &vc_keytable,
 
388
                                        "KEYMAP", &vc_keymap,
 
389
                                        "UNIKEYTABLE", &vc_keymap,
 
390
                                        "GRP_TOGGLE", &vc_keymap_toggle,
 
391
                                        NULL)) < 0) {
 
392
 
 
393
                        if (r != -ENOENT)
 
394
                                log_warning("Failed to read /etc/sysconfig/i18n: %s", strerror(-r));
 
395
                }
 
396
 
 
397
                if (vc_keytable) {
 
398
                        if (vc_keymap)
 
399
                                free(vc_keymap);
 
400
                        if (utf8) {
 
401
                                if (endswith(vc_keytable, ".uni") || strstr(vc_keytable, ".uni."))
 
402
                                        vc_keymap = strdup(vc_keytable);
 
403
                                else {
 
404
                                        char *s;
 
405
                                        if ((s = strstr(vc_keytable, ".map")))
 
406
                                                vc_keytable[s-vc_keytable+1] = '\0';
 
407
                                        vc_keymap = strappend(vc_keytable, ".uni");
 
408
                                }
 
409
                        } else
 
410
                                vc_keymap = strdup(vc_keytable);
 
411
 
 
412
                        free(vc_keytable);
 
413
 
 
414
                        if (!vc_keymap) {
 
415
                                log_error("Out of memory.");
 
416
                                goto finish;
 
417
                        }
 
418
                }
 
419
 
 
420
                if (access("/etc/sysconfig/console/default.kmap", F_OK) >= 0) {
 
421
                        char *t;
 
422
 
 
423
                        if (!(t = strdup("/etc/sysconfig/console/default.kmap"))) {
 
424
                                log_error("Out of memory.");
 
425
                                goto finish;
 
426
                        }
 
427
 
 
428
                        free(vc_keymap);
 
429
                        vc_keymap = t;
 
430
                }
 
431
#endif
 
432
        }
 
433
 
 
434
        r = EXIT_FAILURE;
 
435
 
 
436
        if (!utf8)
 
437
                disable_utf8(fd);
 
438
 
 
439
        if (load_keymap(vc, vc_keymap, vc_keymap_toggle, utf8, &keymap_pid) >= 0 &&
 
440
            load_font(vc, vc_font, vc_font_map, vc_font_unimap, &font_pid) >= 0)
 
441
                r = EXIT_SUCCESS;
 
442
 
 
443
finish:
 
444
        if (keymap_pid > 0)
 
445
                wait_for_terminate_and_warn(KBD_LOADKEYS, keymap_pid);
 
446
 
 
447
        if (font_pid > 0)
 
448
                wait_for_terminate_and_warn(KBD_SETFONT, font_pid);
 
449
 
 
450
        free(vc_keymap);
 
451
        free(vc_font);
 
452
        free(vc_font_map);
 
453
        free(vc_font_unimap);
 
454
 
 
455
        if (fd >= 0)
 
456
                close_nointr_nofail(fd);
 
457
 
 
458
        return r;
 
459
}