chiark / gitweb /
nspawn: split out pty forwaring logic into ptyfwd.c
[elogind.git] / src / getty-generator / getty-generator.c
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
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
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
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
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>
25
26 #include "log.h"
27 #include "util.h"
28 #include "mkdir.h"
29 #include "unit-name.h"
30 #include "virt.h"
31 #include "fileio.h"
32
33 static const char *arg_dest = "/tmp";
34
35 static int add_symlink(const char *fservice, const char *tservice) {
36         char *from = NULL, *to = NULL;
37         int r;
38
39         assert(fservice);
40         assert(tservice);
41
42         from = strappend(SYSTEM_DATA_UNIT_PATH "/", fservice);
43         to = strjoin(arg_dest,"/getty.target.wants/", tservice, NULL);
44
45         if (!from || !to) {
46                 r = log_oom();
47                 goto finish;
48         }
49
50         mkdir_parents_label(to, 0755);
51
52         r = symlink(from, to);
53         if (r < 0) {
54                 if (errno == EEXIST)
55                         /* In case console=hvc0 is passed this will very likely result in EEXIST */
56                         r = 0;
57                 else {
58                         log_error("Failed to create symlink %s: %m", to);
59                         r = -errno;
60                 }
61         }
62
63 finish:
64
65         free(from);
66         free(to);
67
68         return r;
69 }
70
71 static int add_serial_getty(const char *tty) {
72         char *n;
73         int r;
74
75         assert(tty);
76
77         log_debug("Automatically adding serial getty for /dev/%s.", tty);
78
79         n = unit_name_replace_instance("serial-getty@.service", tty);
80         if (!n)
81                 return log_oom();
82
83         r = add_symlink("serial-getty@.service", n);
84         free(n);
85
86         return r;
87 }
88
89 int main(int argc, char *argv[]) {
90
91         static const char virtualization_consoles[] =
92                 "hvc0\0"
93                 "xvc0\0"
94                 "hvsi0\0";
95
96         int r = EXIT_SUCCESS;
97         char *active;
98         const char *j;
99
100         if (argc > 1 && argc != 4) {
101                 log_error("This program takes three or no arguments.");
102                 return EXIT_FAILURE;
103         }
104
105         if (argc > 1)
106                 arg_dest = argv[1];
107
108         log_set_target(LOG_TARGET_SAFE);
109         log_parse_environment();
110         log_open();
111
112         umask(0022);
113
114         if (detect_container(NULL) > 0) {
115                 log_debug("Automatically adding console shell.");
116
117                 if (add_symlink("console-getty.service", "console-getty.service") < 0)
118                         r = EXIT_FAILURE;
119
120                 /* Don't add any further magic if we are in a container */
121                 goto finish;
122         }
123
124         if (read_one_line_file("/sys/class/tty/console/active", &active) >= 0) {
125                 char *w, *state;
126                 size_t l;
127
128                 /* Automatically add in a serial getty on all active
129                  * kernel consoles */
130                 FOREACH_WORD(w, l, active, state) {
131                         char *tty;
132                         int k;
133
134                         tty = strndup(w, l);
135                         if (!tty) {
136                             log_oom();
137                             free(active);
138                             r = EXIT_FAILURE;
139                             goto finish;
140                         }
141
142                         if (isempty(tty) || tty_is_vc(tty)) {
143                                 free(tty);
144                                 continue;
145                         }
146
147                         /* We assume that gettys on virtual terminals are
148                          * started via manual configuration and do this magic
149                          * only for non-VC terminals. */
150
151                         k = add_serial_getty(tty);
152
153                         if (k < 0) {
154                                 free(tty);
155                                 free(active);
156                                 r = EXIT_FAILURE;
157                                 goto finish;
158                         }
159                 }
160                 free(active);
161         }
162
163         /* Automatically add in a serial getty on the first
164          * virtualizer console */
165         NULSTR_FOREACH(j, virtualization_consoles) {
166                 char *p;
167                 int k;
168
169                 if (asprintf(&p, "/sys/class/tty/%s", j) < 0) {
170                         log_oom();
171                         r = EXIT_FAILURE;
172                         goto finish;
173                 }
174
175                 k = access(p, F_OK);
176                 free(p);
177
178                 if (k < 0)
179                         continue;
180
181                 k = add_serial_getty(j);
182                 if (k < 0) {
183                         r = EXIT_FAILURE;
184                         goto finish;
185                 }
186         }
187
188 finish:
189         return r;
190 }