Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #include <errno.h>
4 : : #include <fcntl.h>
5 : : #include <string.h>
6 : : #include <unistd.h>
7 : :
8 : : #include "alloc-util.h"
9 : : #include "errno-util.h"
10 : : #include "fd-util.h"
11 : : #include "fileio.h"
12 : : #include "generator.h"
13 : : #include "log.h"
14 : : #include "mkdir.h"
15 : : #include "path-util.h"
16 : : #include "process-util.h"
17 : : #include "strv.h"
18 : : #include "terminal-util.h"
19 : : #include "unit-name.h"
20 : : #include "util.h"
21 : : #include "virt.h"
22 : :
23 : : static const char *arg_dest = NULL;
24 : :
25 : 0 : static int add_symlink(const char *fservice, const char *tservice) {
26 : : char *from, *to;
27 : : int r;
28 : :
29 [ # # ]: 0 : assert(fservice);
30 [ # # ]: 0 : assert(tservice);
31 : :
32 [ # # # # : 0 : from = strjoina(SYSTEM_DATA_UNIT_PATH "/", fservice);
# # # # #
# # # ]
33 [ # # # # : 0 : to = strjoina(arg_dest, "/getty.target.wants/", tservice);
# # # # #
# # # ]
34 : :
35 : 0 : mkdir_parents_label(to, 0755);
36 : :
37 : 0 : r = symlink(from, to);
38 [ # # ]: 0 : if (r < 0) {
39 : : /* In case console=hvc0 is passed this will very likely result in EEXIST */
40 [ # # ]: 0 : if (errno == EEXIST)
41 : 0 : return 0;
42 : :
43 [ # # ]: 0 : return log_error_errno(errno, "Failed to create symlink %s: %m", to);
44 : : }
45 : :
46 : 0 : return 0;
47 : : }
48 : :
49 : 0 : static int add_serial_getty(const char *tty) {
50 : 0 : _cleanup_free_ char *n = NULL;
51 : : int r;
52 : :
53 [ # # ]: 0 : assert(tty);
54 : :
55 [ # # ]: 0 : log_debug("Automatically adding serial getty for /dev/%s.", tty);
56 : :
57 : 0 : r = unit_name_from_path_instance("serial-getty", tty, ".service", &n);
58 [ # # ]: 0 : if (r < 0)
59 [ # # ]: 0 : return log_error_errno(r, "Failed to generate service name: %m");
60 : :
61 : 0 : return add_symlink("serial-getty@.service", n);
62 : : }
63 : :
64 : 0 : static int add_container_getty(const char *tty) {
65 : 0 : _cleanup_free_ char *n = NULL;
66 : : int r;
67 : :
68 [ # # ]: 0 : assert(tty);
69 : :
70 [ # # ]: 0 : log_debug("Automatically adding container getty for /dev/pts/%s.", tty);
71 : :
72 : 0 : r = unit_name_from_path_instance("container-getty", tty, ".service", &n);
73 [ # # ]: 0 : if (r < 0)
74 [ # # ]: 0 : return log_error_errno(r, "Failed to generate service name: %m");
75 : :
76 : 0 : return add_symlink("container-getty@.service", n);
77 : : }
78 : :
79 : 0 : static int verify_tty(const char *name) {
80 : 0 : _cleanup_close_ int fd = -1;
81 : : const char *p;
82 : :
83 : : /* Some TTYs are weird and have been enumerated but don't work
84 : : * when you try to use them, such as classic ttyS0 and
85 : : * friends. Let's check that and open the device and run
86 : : * isatty() on it. */
87 : :
88 [ # # # # : 0 : p = strjoina("/dev/", name);
# # # # #
# # # ]
89 : :
90 : : /* O_NONBLOCK is essential here, to make sure we don't wait
91 : : * for DCD */
92 : 0 : fd = open(p, O_RDWR|O_NONBLOCK|O_NOCTTY|O_CLOEXEC|O_NOFOLLOW);
93 [ # # ]: 0 : if (fd < 0)
94 : 0 : return -errno;
95 : :
96 : 0 : errno = 0;
97 [ # # ]: 0 : if (isatty(fd) <= 0)
98 : 0 : return errno_or_else(EIO);
99 : :
100 : 0 : return 0;
101 : : }
102 : :
103 : 0 : static int run(const char *dest, const char *dest_early, const char *dest_late) {
104 : 0 : _cleanup_free_ char *active = NULL;
105 : : const char *j;
106 : : int r;
107 : :
108 [ # # ]: 0 : assert_se(arg_dest = dest);
109 : :
110 [ # # ]: 0 : if (detect_container() > 0) {
111 : 0 : _cleanup_free_ char *container_ttys = NULL;
112 : :
113 [ # # ]: 0 : log_debug("Automatically adding console shell.");
114 : :
115 : 0 : r = add_symlink("console-getty.service", "console-getty.service");
116 [ # # ]: 0 : if (r < 0)
117 : 0 : return r;
118 : :
119 : : /* When $container_ttys is set for PID 1, spawn
120 : : * gettys on all ptys named therein. Note that despite
121 : : * the variable name we only support ptys here. */
122 : :
123 : 0 : r = getenv_for_pid(1, "container_ttys", &container_ttys);
124 [ # # ]: 0 : if (r > 0) {
125 : : const char *word, *state;
126 : : size_t l;
127 : :
128 [ # # ]: 0 : FOREACH_WORD(word, l, container_ttys, state) {
129 : : const char *t;
130 : 0 : char tty[l + 1];
131 : :
132 : 0 : memcpy(tty, word, l);
133 : 0 : tty[l] = 0;
134 : :
135 : : /* First strip off /dev/ if it is specified */
136 : 0 : t = path_startswith(tty, "/dev/");
137 [ # # ]: 0 : if (!t)
138 : 0 : t = tty;
139 : :
140 : : /* Then, make sure it's actually a pty */
141 : 0 : t = path_startswith(t, "pts/");
142 [ # # ]: 0 : if (!t)
143 : 0 : continue;
144 : :
145 : 0 : r = add_container_getty(t);
146 [ # # ]: 0 : if (r < 0)
147 : 0 : return r;
148 : : }
149 : : }
150 : :
151 : : /* Don't add any further magic if we are in a container */
152 : 0 : return 0;
153 : : }
154 : :
155 [ # # ]: 0 : if (read_one_line_file("/sys/class/tty/console/active", &active) >= 0) {
156 : : const char *word, *state;
157 : : size_t l;
158 : :
159 : : /* Automatically add in a serial getty on all active
160 : : * kernel consoles */
161 [ # # ]: 0 : FOREACH_WORD(word, l, active, state) {
162 [ # # # ]: 0 : _cleanup_free_ char *tty = NULL;
163 : :
164 : 0 : tty = strndup(word, l);
165 [ # # ]: 0 : if (!tty)
166 : 0 : return log_oom();
167 : :
168 : : /* We assume that gettys on virtual terminals are
169 : : * started via manual configuration and do this magic
170 : : * only for non-VC terminals. */
171 : :
172 [ # # # # ]: 0 : if (isempty(tty) || tty_is_vc(tty))
173 : 0 : continue;
174 : :
175 [ # # ]: 0 : if (verify_tty(tty) < 0)
176 : 0 : continue;
177 : :
178 : 0 : r = add_serial_getty(tty);
179 [ # # ]: 0 : if (r < 0)
180 : 0 : return r;
181 : : }
182 : : }
183 : :
184 : : /* Automatically add in a serial getty on the first
185 : : * virtualizer console */
186 [ # # ]: 0 : FOREACH_STRING(j,
187 : : "hvc0",
188 : : "xvc0",
189 : : "hvsi0",
190 : : "sclp_line0",
191 : : "ttysclp0",
192 : : "3270!tty1") {
193 [ # # # ]: 0 : _cleanup_free_ char *p = NULL;
194 : :
195 : 0 : p = path_join("/sys/class/tty", j);
196 [ # # ]: 0 : if (!p)
197 : 0 : return -ENOMEM;
198 [ # # ]: 0 : if (access(p, F_OK) < 0)
199 : 0 : continue;
200 : :
201 : 0 : r = add_serial_getty(j);
202 [ # # ]: 0 : if (r < 0)
203 : 0 : return r;
204 : : }
205 : :
206 : 0 : return 0;
207 : : }
208 : :
209 [ # # # # : 0 : DEFINE_MAIN_GENERATOR_FUNCTION(run);
# # # # #
# # # ]
|