]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/getty-generator/getty-generator.c
Merge pull request #490 from pyssling/master
[thirdparty/systemd.git] / src / getty-generator / getty-generator.c
CommitLineData
2a796654
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 Lennart Poettering
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
2a796654
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.
2a796654 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
2a796654
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
2a796654 22#include <errno.h>
54340751 23#include <fcntl.h>
07630cea
LP
24#include <string.h>
25#include <unistd.h>
2a796654 26
b5efdb8a 27#include "alloc-util.h"
3ffd4af2 28#include "fd-util.h"
07630cea 29#include "fileio.h"
2a796654 30#include "log.h"
49e942b2 31#include "mkdir.h"
1d97ff7d 32#include "path-util.h"
0b452006 33#include "process-util.h"
07630cea 34#include "string-util.h"
288a74cc 35#include "terminal-util.h"
07630cea
LP
36#include "unit-name.h"
37#include "util.h"
38#include "virt.h"
2a796654 39
6a39419f 40static const char *arg_dest = "/tmp";
2a796654
LP
41
42static int add_symlink(const char *fservice, const char *tservice) {
f5650614 43 char *from, *to;
2a796654
LP
44 int r;
45
4dc380d1
LP
46 assert(fservice);
47 assert(tservice);
48
63c372cb
LP
49 from = strjoina(SYSTEM_DATA_UNIT_PATH "/", fservice);
50 to = strjoina(arg_dest, "/getty.target.wants/", tservice);
2a796654 51
d2e54fae 52 mkdir_parents_label(to, 0755);
2a796654 53
a17b785b
LP
54 r = symlink(from, to);
55 if (r < 0) {
7410616c 56 /* In case console=hvc0 is passed this will very likely result in EEXIST */
a17b785b 57 if (errno == EEXIST)
f85fc845 58 return 0;
7410616c
LP
59
60 return log_error_errno(errno, "Failed to create symlink %s: %m", to);
2a796654
LP
61 }
62
f85fc845 63 return 0;
2a796654
LP
64}
65
4dc380d1 66static int add_serial_getty(const char *tty) {
f85fc845 67 _cleanup_free_ char *n = NULL;
7410616c 68 int r;
4dc380d1
LP
69
70 assert(tty);
71
72 log_debug("Automatically adding serial getty for /dev/%s.", tty);
73
7410616c
LP
74 r = unit_name_from_path_instance("serial-getty", tty, ".service", &n);
75 if (r < 0)
76 return log_error_errno(r, "Failed to generate service name: %m");
4dc380d1 77
f85fc845 78 return add_symlink("serial-getty@.service", n);
4dc380d1
LP
79}
80
1d97ff7d
LP
81static int add_container_getty(const char *tty) {
82 _cleanup_free_ char *n = NULL;
7410616c 83 int r;
1d97ff7d
LP
84
85 assert(tty);
86
87 log_debug("Automatically adding container getty for /dev/pts/%s.", tty);
88
7410616c
LP
89 r = unit_name_from_path_instance("container-getty", tty, ".service", &n);
90 if (r < 0)
91 return log_error_errno(r, "Failed to generate service name: %m");
1d97ff7d
LP
92
93 return add_symlink("container-getty@.service", n);
94}
95
54340751
LP
96static int verify_tty(const char *name) {
97 _cleanup_close_ int fd = -1;
98 const char *p;
99
100 /* Some TTYs are weird and have been enumerated but don't work
101 * when you try to use them, such as classic ttyS0 and
102 * friends. Let's check that and open the device and run
103 * isatty() on it. */
104
63c372cb 105 p = strjoina("/dev/", name);
54340751
LP
106
107 /* O_NONBLOCK is essential here, to make sure we don't wait
108 * for DCD */
109 fd = open(p, O_RDWR|O_NONBLOCK|O_NOCTTY|O_CLOEXEC|O_NOFOLLOW);
110 if (fd < 0)
111 return -errno;
112
113 errno = 0;
114 if (isatty(fd) <= 0)
115 return errno ? -errno : -EIO;
116
117 return 0;
118}
119
2a796654 120int main(int argc, char *argv[]) {
3c20189a
LP
121
122 static const char virtualization_consoles[] =
123 "hvc0\0"
124 "xvc0\0"
07901fc1
HB
125 "hvsi0\0"
126 "sclp_line0\0"
fc6c7fe9
HB
127 "ttysclp0\0"
128 "3270!tty1\0";
3c20189a 129
f85fc845 130 _cleanup_free_ char *active = NULL;
3c20189a 131 const char *j;
1d97ff7d 132 int r;
2a796654 133
07719a21
LP
134 if (argc > 1 && argc != 4) {
135 log_error("This program takes three or no arguments.");
2a796654
LP
136 return EXIT_FAILURE;
137 }
138
07719a21
LP
139 if (argc > 1)
140 arg_dest = argv[1];
141
a6903061 142 log_set_target(LOG_TARGET_SAFE);
2a796654
LP
143 log_parse_environment();
144 log_open();
145
4c12626c
LP
146 umask(0022);
147
75f86906 148 if (detect_container() > 0) {
1d97ff7d
LP
149 _cleanup_free_ char *container_ttys = NULL;
150
6705c2df 151 log_debug("Automatically adding console shell.");
2a796654 152
337eebb9 153 if (add_symlink("console-getty.service", "console-getty.service") < 0)
f85fc845 154 return EXIT_FAILURE;
2a796654 155
1d97ff7d
LP
156 /* When $container_ttys is set for PID 1, spawn
157 * gettys on all ptys named therein. Note that despite
158 * the variable name we only support ptys here. */
159
160 r = getenv_for_pid(1, "container_ttys", &container_ttys);
207d1d09 161 if (r > 0) {
a2a5291b 162 const char *word, *state;
1d97ff7d
LP
163 size_t l;
164
a2a5291b 165 FOREACH_WORD(word, l, container_ttys, state) {
1d97ff7d
LP
166 const char *t;
167 char tty[l + 1];
168
a2a5291b 169 memcpy(tty, word, l);
1d97ff7d
LP
170 tty[l] = 0;
171
172 /* First strip off /dev/ if it is specified */
173 t = path_startswith(tty, "/dev/");
174 if (!t)
175 t = tty;
176
177 /* Then, make sure it's actually a pty */
3fa5dd6d 178 t = path_startswith(t, "pts/");
1d97ff7d
LP
179 if (!t)
180 continue;
181
182 if (add_container_getty(t) < 0)
183 return EXIT_FAILURE;
184 }
185 }
186
2a796654 187 /* Don't add any further magic if we are in a container */
f85fc845 188 return EXIT_SUCCESS;
2a796654
LP
189 }
190
191 if (read_one_line_file("/sys/class/tty/console/active", &active) >= 0) {
a2a5291b 192 const char *word, *state;
39f0570d
MM
193 size_t l;
194
195 /* Automatically add in a serial getty on all active
196 * kernel consoles */
a2a5291b 197 FOREACH_WORD(word, l, active, state) {
f85fc845 198 _cleanup_free_ char *tty = NULL;
2a796654 199
a2a5291b 200 tty = strndup(word, l);
39f0570d 201 if (!tty) {
f85fc845
LP
202 log_oom();
203 return EXIT_FAILURE;
39f0570d
MM
204 }
205
f85fc845 206 if (isempty(tty) || tty_is_vc(tty))
39f0570d 207 continue;
39f0570d 208
54340751
LP
209 if (verify_tty(tty) < 0)
210 continue;
211
2a796654
LP
212 /* We assume that gettys on virtual terminals are
213 * started via manual configuration and do this magic
214 * only for non-VC terminals. */
215
f85fc845
LP
216 if (add_serial_getty(tty) < 0)
217 return EXIT_FAILURE;
3c20189a 218 }
2a796654
LP
219 }
220
221 /* Automatically add in a serial getty on the first
222 * virtualizer console */
3c20189a 223 NULSTR_FOREACH(j, virtualization_consoles) {
f5650614 224 char *p;
980fc73d 225
63c372cb 226 p = strjoina("/sys/class/tty/", j);
f85fc845 227 if (access(p, F_OK) < 0)
3c20189a 228 continue;
980fc73d 229
f85fc845
LP
230 if (add_serial_getty(j) < 0)
231 return EXIT_FAILURE;
2a796654
LP
232 }
233
f85fc845 234 return EXIT_SUCCESS;
2a796654 235}