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