File: | build-scan/../src/getty-generator/getty-generator.c |
Warning: | line 179, column 17 Potential leak of memory pointed to by 'tty' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* SPDX-License-Identifier: LGPL-2.1+ */ | |||
2 | ||||
3 | #include <errno(*__errno_location ()).h> | |||
4 | #include <fcntl.h> | |||
5 | #include <string.h> | |||
6 | #include <unistd.h> | |||
7 | ||||
8 | #include "alloc-util.h" | |||
9 | #include "fd-util.h" | |||
10 | #include "fileio.h" | |||
11 | #include "log.h" | |||
12 | #include "mkdir.h" | |||
13 | #include "path-util.h" | |||
14 | #include "process-util.h" | |||
15 | #include "string-util.h" | |||
16 | #include "terminal-util.h" | |||
17 | #include "unit-name.h" | |||
18 | #include "util.h" | |||
19 | #include "virt.h" | |||
20 | ||||
21 | static const char *arg_dest = "/tmp"; | |||
22 | ||||
23 | static int add_symlink(const char *fservice, const char *tservice) { | |||
24 | char *from, *to; | |||
25 | int r; | |||
26 | ||||
27 | assert(fservice)do { if ((__builtin_expect(!!(!(fservice)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("fservice"), "../src/getty-generator/getty-generator.c" , 27, __PRETTY_FUNCTION__); } while (0); | |||
28 | assert(tservice)do { if ((__builtin_expect(!!(!(tservice)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("tservice"), "../src/getty-generator/getty-generator.c" , 28, __PRETTY_FUNCTION__); } while (0); | |||
29 | ||||
30 | from = strjoina(SYSTEM_DATA_UNIT_PATH "/", fservice)({ const char *_appendees_[] = { "/usr/lib/systemd/system" "/" , fservice }; char *_d_, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_ )/sizeof((_appendees_)[0]), ((void)0))) && _appendees_ [_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca (_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(_appendees_), typeof(& *(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0] ), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy (_p_, _appendees_[_i_]); *_p_ = 0; _d_; }); | |||
31 | to = strjoina(arg_dest, "/getty.target.wants/", tservice)({ const char *_appendees_[] = { arg_dest, "/getty.target.wants/" , tservice }; char *_d_, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_ )/sizeof((_appendees_)[0]), ((void)0))) && _appendees_ [_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca (_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(_appendees_), typeof(& *(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0] ), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy (_p_, _appendees_[_i_]); *_p_ = 0; _d_; }); | |||
32 | ||||
33 | mkdir_parents_label(to, 0755); | |||
34 | ||||
35 | r = symlink(from, to); | |||
36 | if (r < 0) { | |||
37 | /* In case console=hvc0 is passed this will very likely result in EEXIST */ | |||
38 | if (errno(*__errno_location ()) == EEXIST17) | |||
39 | return 0; | |||
40 | ||||
41 | return log_error_errno(errno, "Failed to create symlink %s: %m", to)({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/getty-generator/getty-generator.c" , 41, __func__, "Failed to create symlink %s: %m", to) : -abs (_e); }); | |||
42 | } | |||
43 | ||||
44 | return 0; | |||
45 | } | |||
46 | ||||
47 | static int add_serial_getty(const char *tty) { | |||
48 | _cleanup_free___attribute__((cleanup(freep))) char *n = NULL((void*)0); | |||
49 | int r; | |||
50 | ||||
51 | assert(tty)do { if ((__builtin_expect(!!(!(tty)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("tty"), "../src/getty-generator/getty-generator.c" , 51, __PRETTY_FUNCTION__); } while (0); | |||
52 | ||||
53 | log_debug("Automatically adding serial getty for /dev/%s.", tty)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/getty-generator/getty-generator.c", 53, __func__, "Automatically adding serial getty for /dev/%s." , tty) : -abs(_e); }); | |||
54 | ||||
55 | r = unit_name_from_path_instance("serial-getty", tty, ".service", &n); | |||
56 | if (r < 0) | |||
57 | return log_error_errno(r, "Failed to generate service name: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/getty-generator/getty-generator.c", 57, __func__, "Failed to generate service name: %m" ) : -abs(_e); }); | |||
58 | ||||
59 | return add_symlink("serial-getty@.service", n); | |||
60 | } | |||
61 | ||||
62 | static int add_container_getty(const char *tty) { | |||
63 | _cleanup_free___attribute__((cleanup(freep))) char *n = NULL((void*)0); | |||
64 | int r; | |||
65 | ||||
66 | assert(tty)do { if ((__builtin_expect(!!(!(tty)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("tty"), "../src/getty-generator/getty-generator.c" , 66, __PRETTY_FUNCTION__); } while (0); | |||
67 | ||||
68 | log_debug("Automatically adding container getty for /dev/pts/%s.", tty)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/getty-generator/getty-generator.c", 68, __func__, "Automatically adding container getty for /dev/pts/%s." , tty) : -abs(_e); }); | |||
69 | ||||
70 | r = unit_name_from_path_instance("container-getty", tty, ".service", &n); | |||
71 | if (r < 0) | |||
72 | return log_error_errno(r, "Failed to generate service name: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/getty-generator/getty-generator.c", 72, __func__, "Failed to generate service name: %m" ) : -abs(_e); }); | |||
73 | ||||
74 | return add_symlink("container-getty@.service", n); | |||
75 | } | |||
76 | ||||
77 | static int verify_tty(const char *name) { | |||
78 | _cleanup_close___attribute__((cleanup(closep))) int fd = -1; | |||
79 | const char *p; | |||
80 | ||||
81 | /* Some TTYs are weird and have been enumerated but don't work | |||
82 | * when you try to use them, such as classic ttyS0 and | |||
83 | * friends. Let's check that and open the device and run | |||
84 | * isatty() on it. */ | |||
85 | ||||
86 | p = strjoina("/dev/", name)({ const char *_appendees_[] = { "/dev/", name }; char *_d_, * _p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_ )/sizeof((_appendees_)[0]), ((void)0))) && _appendees_ [_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca (_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(_appendees_), typeof(& *(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0] ), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy (_p_, _appendees_[_i_]); *_p_ = 0; _d_; }); | |||
87 | ||||
88 | /* O_NONBLOCK is essential here, to make sure we don't wait | |||
89 | * for DCD */ | |||
90 | fd = open(p, O_RDWR02|O_NONBLOCK04000|O_NOCTTY0400|O_CLOEXEC02000000|O_NOFOLLOW0400000); | |||
91 | if (fd < 0) | |||
92 | return -errno(*__errno_location ()); | |||
93 | ||||
94 | errno(*__errno_location ()) = 0; | |||
95 | if (isatty(fd) <= 0) | |||
96 | return errno(*__errno_location ()) > 0 ? -errno(*__errno_location ()) : -EIO5; | |||
97 | ||||
98 | return 0; | |||
99 | } | |||
100 | ||||
101 | int main(int argc, char *argv[]) { | |||
102 | ||||
103 | static const char virtualization_consoles[] = | |||
104 | "hvc0\0" | |||
105 | "xvc0\0" | |||
106 | "hvsi0\0" | |||
107 | "sclp_line0\0" | |||
108 | "ttysclp0\0" | |||
109 | "3270!tty1\0"; | |||
110 | ||||
111 | _cleanup_free___attribute__((cleanup(freep))) char *active = NULL((void*)0); | |||
112 | const char *j; | |||
113 | int r; | |||
114 | ||||
115 | if (argc > 1 && argc != 4) { | |||
| ||||
116 | log_error("This program takes three or no arguments.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/getty-generator/getty-generator.c", 116, __func__, "This program takes three or no arguments." ) : -abs(_e); }); | |||
117 | return EXIT_FAILURE1; | |||
118 | } | |||
119 | ||||
120 | if (argc
| |||
121 | arg_dest = argv[1]; | |||
122 | ||||
123 | log_set_prohibit_ipc(true1); | |||
124 | log_set_target(LOG_TARGET_AUTO); | |||
125 | log_parse_environment()log_parse_environment_realm(LOG_REALM_SYSTEMD); | |||
126 | log_open(); | |||
127 | ||||
128 | umask(0022); | |||
129 | ||||
130 | if (detect_container() > 0) { | |||
131 | _cleanup_free___attribute__((cleanup(freep))) char *container_ttys = NULL((void*)0); | |||
132 | ||||
133 | log_debug("Automatically adding console shell.")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/getty-generator/getty-generator.c", 133, __func__, "Automatically adding console shell." ) : -abs(_e); }); | |||
134 | ||||
135 | if (add_symlink("console-getty.service", "console-getty.service") < 0) | |||
136 | return EXIT_FAILURE1; | |||
137 | ||||
138 | /* When $container_ttys is set for PID 1, spawn | |||
139 | * gettys on all ptys named therein. Note that despite | |||
140 | * the variable name we only support ptys here. */ | |||
141 | ||||
142 | r = getenv_for_pid(1, "container_ttys", &container_ttys); | |||
143 | if (r > 0) { | |||
144 | const char *word, *state; | |||
145 | size_t l; | |||
146 | ||||
147 | FOREACH_WORD(word, l, container_ttys, state)for ((state) = (container_ttys), (word) = split(&(state), &(l), (" \t\n\r"), (0)); (word); (word) = split(&(state ), &(l), (" \t\n\r"), (0))) { | |||
148 | const char *t; | |||
149 | char tty[l + 1]; | |||
150 | ||||
151 | memcpy(tty, word, l); | |||
152 | tty[l] = 0; | |||
153 | ||||
154 | /* First strip off /dev/ if it is specified */ | |||
155 | t = path_startswith(tty, "/dev/"); | |||
156 | if (!t) | |||
157 | t = tty; | |||
158 | ||||
159 | /* Then, make sure it's actually a pty */ | |||
160 | t = path_startswith(t, "pts/"); | |||
161 | if (!t) | |||
162 | continue; | |||
163 | ||||
164 | if (add_container_getty(t) < 0) | |||
165 | return EXIT_FAILURE1; | |||
166 | } | |||
167 | } | |||
168 | ||||
169 | /* Don't add any further magic if we are in a container */ | |||
170 | return EXIT_SUCCESS0; | |||
171 | } | |||
172 | ||||
173 | if (read_one_line_file("/sys/class/tty/console/active", &active) >= 0) { | |||
174 | const char *word, *state; | |||
175 | size_t l; | |||
176 | ||||
177 | /* Automatically add in a serial getty on all active | |||
178 | * kernel consoles */ | |||
179 | FOREACH_WORD(word, l, active, state)for ((state) = (active), (word) = split(&(state), &(l ), (" \t\n\r"), (0)); (word); (word) = split(&(state), & (l), (" \t\n\r"), (0))) { | |||
| ||||
180 | _cleanup_free___attribute__((cleanup(freep))) char *tty = NULL((void*)0); | |||
181 | ||||
182 | tty = strndup(word, l); | |||
183 | if (!tty) { | |||
184 | log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/getty-generator/getty-generator.c" , 184, __func__); | |||
185 | return EXIT_FAILURE1; | |||
186 | } | |||
187 | ||||
188 | /* We assume that gettys on virtual terminals are | |||
189 | * started via manual configuration and do this magic | |||
190 | * only for non-VC terminals. */ | |||
191 | ||||
192 | if (isempty(tty) || tty_is_vc(tty)) | |||
193 | continue; | |||
194 | ||||
195 | if (verify_tty(tty) < 0) | |||
196 | continue; | |||
197 | ||||
198 | if (add_serial_getty(tty) < 0) | |||
199 | return EXIT_FAILURE1; | |||
200 | } | |||
201 | } | |||
202 | ||||
203 | /* Automatically add in a serial getty on the first | |||
204 | * virtualizer console */ | |||
205 | NULSTR_FOREACH(j, virtualization_consoles)for ((j) = (virtualization_consoles); (j) && *(j); (j ) = strchr((j), 0)+1) { | |||
206 | char *p; | |||
207 | ||||
208 | p = strjoina("/sys/class/tty/", j)({ const char *_appendees_[] = { "/sys/class/tty/", j }; char *_d_, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_ )/sizeof((_appendees_)[0]), ((void)0))) && _appendees_ [_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca (_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(_appendees_), typeof(& *(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0] ), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy (_p_, _appendees_[_i_]); *_p_ = 0; _d_; }); | |||
209 | if (access(p, F_OK0) < 0) | |||
210 | continue; | |||
211 | ||||
212 | if (add_serial_getty(j) < 0) | |||
213 | return EXIT_FAILURE1; | |||
214 | } | |||
215 | ||||
216 | return EXIT_SUCCESS0; | |||
217 | } |