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