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