File: | build-scan/../src/activate/activate.c |
Warning: | line 151, column 40 Potential leak of memory pointed to by 'envp' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* SPDX-License-Identifier: LGPL-2.1+ */ | |||
2 | ||||
3 | #include <getopt.h> | |||
4 | #include <sys/epoll.h> | |||
5 | #include <sys/prctl.h> | |||
6 | #include <sys/socket.h> | |||
7 | #include <sys/wait.h> | |||
8 | #include <unistd.h> | |||
9 | ||||
10 | #include "sd-daemon.h" | |||
11 | ||||
12 | #include "alloc-util.h" | |||
13 | #include "escape.h" | |||
14 | #include "fd-util.h" | |||
15 | #include "log.h" | |||
16 | #include "macro.h" | |||
17 | #include "process-util.h" | |||
18 | #include "signal-util.h" | |||
19 | #include "socket-util.h" | |||
20 | #include "string-util.h" | |||
21 | #include "strv.h" | |||
22 | ||||
23 | static char** arg_listen = NULL((void*)0); | |||
24 | static bool_Bool arg_accept = false0; | |||
25 | static int arg_socket_type = SOCK_STREAMSOCK_STREAM; | |||
26 | static char** arg_args = NULL((void*)0); | |||
27 | static char** arg_setenv = NULL((void*)0); | |||
28 | static char **arg_fdnames = NULL((void*)0); | |||
29 | static bool_Bool arg_inetd = false0; | |||
30 | ||||
31 | static int add_epoll(int epoll_fd, int fd) { | |||
32 | struct epoll_event ev = { | |||
33 | .events = EPOLLINEPOLLIN, | |||
34 | .data.fd = fd, | |||
35 | }; | |||
36 | ||||
37 | assert(epoll_fd >= 0)do { if ((__builtin_expect(!!(!(epoll_fd >= 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("epoll_fd >= 0"), "../src/activate/activate.c" , 37, __PRETTY_FUNCTION__); } while (0); | |||
38 | assert(fd >= 0)do { if ((__builtin_expect(!!(!(fd >= 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("fd >= 0"), "../src/activate/activate.c" , 38, __PRETTY_FUNCTION__); } while (0); | |||
39 | ||||
40 | if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD1, fd, &ev) < 0) | |||
41 | return log_error_errno(errno, "Failed to add event on epoll fd:%d for fd:%d: %m", epoll_fd, fd)({ 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/activate/activate.c", 41, __func__ , "Failed to add event on epoll fd:%d for fd:%d: %m", epoll_fd , fd) : -abs(_e); }); | |||
42 | ||||
43 | return 0; | |||
44 | } | |||
45 | ||||
46 | static int open_sockets(int *epoll_fd, bool_Bool accept) { | |||
47 | char **address; | |||
48 | int n, fd, r; | |||
49 | int count = 0; | |||
50 | ||||
51 | n = sd_listen_fds(true1); | |||
52 | if (n < 0) | |||
53 | return log_error_errno(n, "Failed to read listening file descriptors from environment: %m")({ int _level = ((3)), _e = ((n)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/activate/activate.c", 53, __func__, "Failed to read listening file descriptors from environment: %m" ) : -abs(_e); }); | |||
54 | if (n > 0) { | |||
55 | log_info("Received %i descriptors via the environment.", n)({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/activate/activate.c", 55, __func__, "Received %i descriptors via the environment." , n) : -abs(_e); }); | |||
56 | ||||
57 | for (fd = SD_LISTEN_FDS_START3; fd < SD_LISTEN_FDS_START3 + n; fd++) { | |||
58 | r = fd_cloexec(fd, arg_accept); | |||
59 | if (r < 0) | |||
60 | return r; | |||
61 | ||||
62 | count++; | |||
63 | } | |||
64 | } | |||
65 | ||||
66 | /* Close logging and all other descriptors */ | |||
67 | if (arg_listen) { | |||
68 | int except[3 + n]; | |||
69 | ||||
70 | for (fd = 0; fd < SD_LISTEN_FDS_START3 + n; fd++) | |||
71 | except[fd] = fd; | |||
72 | ||||
73 | log_close(); | |||
74 | close_all_fds(except, 3 + n); | |||
75 | } | |||
76 | ||||
77 | /** Note: we leak some fd's on error here. I doesn't matter | |||
78 | * much, since the program will exit immediately anyway, but | |||
79 | * would be a pain to fix. | |||
80 | */ | |||
81 | ||||
82 | STRV_FOREACH(address, arg_listen)for ((address) = (arg_listen); (address) && *(address ); (address)++) { | |||
83 | fd = make_socket_fd(LOG_DEBUG7, *address, arg_socket_type, (arg_accept*SOCK_CLOEXECSOCK_CLOEXEC)); | |||
84 | if (fd < 0) { | |||
85 | log_open(); | |||
86 | return log_error_errno(fd, "Failed to open '%s': %m", *address)({ int _level = ((3)), _e = ((fd)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/activate/activate.c", 86, __func__, "Failed to open '%s': %m" , *address) : -abs(_e); }); | |||
87 | } | |||
88 | ||||
89 | assert(fd == SD_LISTEN_FDS_START + count)do { if ((__builtin_expect(!!(!(fd == 3 + count)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("fd == SD_LISTEN_FDS_START + count"), "../src/activate/activate.c" , 89, __PRETTY_FUNCTION__); } while (0); | |||
90 | count++; | |||
91 | } | |||
92 | ||||
93 | if (arg_listen) | |||
94 | log_open(); | |||
95 | ||||
96 | *epoll_fd = epoll_create1(EPOLL_CLOEXECEPOLL_CLOEXEC); | |||
97 | if (*epoll_fd < 0) | |||
98 | return log_error_errno(errno, "Failed to create epoll object: %m")({ 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/activate/activate.c", 98, __func__ , "Failed to create epoll object: %m") : -abs(_e); }); | |||
99 | ||||
100 | for (fd = SD_LISTEN_FDS_START3; fd < SD_LISTEN_FDS_START3 + count; fd++) { | |||
101 | _cleanup_free___attribute__((cleanup(freep))) char *name = NULL((void*)0); | |||
102 | ||||
103 | getsockname_pretty(fd, &name); | |||
104 | log_info("Listening on %s as %i.", strna(name), fd)({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/activate/activate.c", 104, __func__, "Listening on %s as %i." , strna(name), fd) : -abs(_e); }); | |||
105 | ||||
106 | r = add_epoll(*epoll_fd, fd); | |||
107 | if (r < 0) | |||
108 | return r; | |||
109 | } | |||
110 | ||||
111 | return count; | |||
112 | } | |||
113 | ||||
114 | static int exec_process(const char* name, char **argv, char **env, int start_fd, size_t n_fds) { | |||
115 | ||||
116 | _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **envp = NULL((void*)0); | |||
117 | _cleanup_free___attribute__((cleanup(freep))) char *joined = NULL((void*)0); | |||
118 | size_t n_env = 0, length; | |||
119 | const char *tocopy; | |||
120 | char **s; | |||
121 | int r; | |||
122 | ||||
123 | if (arg_inetd
| |||
124 | log_error("--inetd only supported for single file descriptors.")({ 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/activate/activate.c", 124, __func__, "--inetd only supported for single file descriptors." ) : -abs(_e); }); | |||
125 | return -EINVAL22; | |||
126 | } | |||
127 | ||||
128 | length = strv_length(arg_setenv); | |||
129 | ||||
130 | /* PATH, TERM, HOME, USER, LISTEN_FDS, LISTEN_PID, LISTEN_FDNAMES, NULL */ | |||
131 | envp = new0(char *, length + 8)((char **) calloc((length + 8), sizeof(char *))); | |||
132 | if (!envp) | |||
133 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/activate/activate.c" , 133, __func__); | |||
134 | ||||
135 | STRV_FOREACH(s, arg_setenv)for ((s) = (arg_setenv); (s) && *(s); (s)++) { | |||
136 | ||||
137 | if (strchr(*s, '=')) { | |||
138 | char *k; | |||
139 | ||||
140 | k = strdup(*s); | |||
141 | if (!k) | |||
142 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/activate/activate.c" , 142, __func__); | |||
143 | ||||
144 | envp[n_env++] = k; | |||
145 | } else { | |||
146 | _cleanup_free___attribute__((cleanup(freep))) char *p; | |||
147 | const char *n; | |||
148 | ||||
149 | p = strappend(*s, "="); | |||
150 | if (!p) | |||
151 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/activate/activate.c" , 151, __func__); | |||
| ||||
152 | ||||
153 | n = strv_find_prefix(env, p); | |||
154 | if (!n) | |||
155 | continue; | |||
156 | ||||
157 | envp[n_env] = strdup(n); | |||
158 | if (!envp[n_env]) | |||
159 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/activate/activate.c" , 159, __func__); | |||
160 | ||||
161 | n_env++; | |||
162 | } | |||
163 | } | |||
164 | ||||
165 | FOREACH_STRING(tocopy, "TERM=", "PATH=", "USER=", "HOME=")for (char **_l = ({ char **_ll = ((char**) ((const char*[]) { "TERM=", "PATH=", "USER=", "HOME=", ((void*)0) })); tocopy = _ll ? _ll[0] : ((void*)0); _ll; }); _l && *_l; tocopy = ({ _l ++; _l[0]; })) { | |||
166 | const char *n; | |||
167 | ||||
168 | n = strv_find_prefix(env, tocopy); | |||
169 | if (!n) | |||
170 | continue; | |||
171 | ||||
172 | envp[n_env] = strdup(n); | |||
173 | if (!envp[n_env]) | |||
174 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/activate/activate.c" , 174, __func__); | |||
175 | ||||
176 | n_env++; | |||
177 | } | |||
178 | ||||
179 | if (arg_inetd) { | |||
180 | assert(n_fds == 1)do { if ((__builtin_expect(!!(!(n_fds == 1)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("n_fds == 1"), "../src/activate/activate.c" , 180, __PRETTY_FUNCTION__); } while (0); | |||
181 | ||||
182 | r = rearrange_stdio(start_fd, start_fd, STDERR_FILENO2); /* invalidates start_fd on success + error */ | |||
183 | if (r < 0) | |||
184 | return log_error_errno(r, "Failed to move fd to stdin+stdout: %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/activate/activate.c", 184, __func__, "Failed to move fd to stdin+stdout: %m" ) : -abs(_e); }); | |||
185 | ||||
186 | } else { | |||
187 | if (start_fd != SD_LISTEN_FDS_START3) { | |||
188 | assert(n_fds == 1)do { if ((__builtin_expect(!!(!(n_fds == 1)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("n_fds == 1"), "../src/activate/activate.c" , 188, __PRETTY_FUNCTION__); } while (0); | |||
189 | ||||
190 | if (dup2(start_fd, SD_LISTEN_FDS_START3) < 0) | |||
191 | return log_error_errno(errno, "Failed to dup connection: %m")({ 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/activate/activate.c", 191, __func__ , "Failed to dup connection: %m") : -abs(_e); }); | |||
192 | ||||
193 | safe_close(start_fd); | |||
194 | start_fd = SD_LISTEN_FDS_START3; | |||
195 | } | |||
196 | ||||
197 | if (asprintf((char**)(envp + n_env++), "LISTEN_FDS=%zu", n_fds) < 0) | |||
198 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/activate/activate.c" , 198, __func__); | |||
199 | ||||
200 | if (asprintf((char**)(envp + n_env++), "LISTEN_PID=" PID_FMT"%" "i", getpid_cached()) < 0) | |||
201 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/activate/activate.c" , 201, __func__); | |||
202 | ||||
203 | if (arg_fdnames) { | |||
204 | _cleanup_free___attribute__((cleanup(freep))) char *names = NULL((void*)0); | |||
205 | size_t len; | |||
206 | char *e; | |||
207 | ||||
208 | len = strv_length(arg_fdnames); | |||
209 | if (len == 1) { | |||
210 | size_t i; | |||
211 | ||||
212 | for (i = 1; i < n_fds; i++) { | |||
213 | r = strv_extend(&arg_fdnames, arg_fdnames[0]); | |||
214 | if (r < 0) | |||
215 | return log_error_errno(r, "Failed to extend strv: %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/activate/activate.c", 215, __func__, "Failed to extend strv: %m" ) : -abs(_e); }); | |||
216 | } | |||
217 | } else if (len != n_fds) | |||
218 | log_warning("The number of fd names is different than number of fds: %zu vs %zu", len, n_fds)({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/activate/activate.c", 218, __func__, "The number of fd names is different than number of fds: %zu vs %zu" , len, n_fds) : -abs(_e); }); | |||
219 | ||||
220 | names = strv_join(arg_fdnames, ":"); | |||
221 | if (!names) | |||
222 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/activate/activate.c" , 222, __func__); | |||
223 | ||||
224 | e = strappend("LISTEN_FDNAMES=", names); | |||
225 | if (!e) | |||
226 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/activate/activate.c" , 226, __func__); | |||
227 | ||||
228 | envp[n_env++] = e; | |||
229 | } | |||
230 | } | |||
231 | ||||
232 | joined = strv_join(argv, " "); | |||
233 | if (!joined) | |||
234 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/activate/activate.c" , 234, __func__); | |||
235 | ||||
236 | log_info("Execing %s (%s)", name, joined)({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/activate/activate.c", 236, __func__, "Execing %s (%s)" , name, joined) : -abs(_e); }); | |||
237 | execvpe(name, argv, envp); | |||
238 | ||||
239 | return log_error_errno(errno, "Failed to execp %s (%s): %m", name, joined)({ 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/activate/activate.c", 239, __func__ , "Failed to execp %s (%s): %m", name, joined) : -abs(_e); }); | |||
240 | } | |||
241 | ||||
242 | static int fork_and_exec_process(const char* child, char** argv, char **env, int fd) { | |||
243 | _cleanup_free___attribute__((cleanup(freep))) char *joined = NULL((void*)0); | |||
244 | pid_t child_pid; | |||
245 | int r; | |||
246 | ||||
247 | joined = strv_join(argv, " "); | |||
248 | if (!joined) | |||
249 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/activate/activate.c" , 249, __func__); | |||
250 | ||||
251 | r = safe_fork("(activate)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG, &child_pid); | |||
252 | if (r < 0) | |||
253 | return r; | |||
254 | if (r == 0) { | |||
255 | /* In the child */ | |||
256 | exec_process(child, argv, env, fd, 1); | |||
257 | _exit(EXIT_FAILURE1); | |||
258 | } | |||
259 | ||||
260 | log_info("Spawned %s (%s) as PID " PID_FMT ".", child, joined, child_pid)({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/activate/activate.c", 260, __func__, "Spawned %s (%s) as PID " "%" "i" ".", child, joined, child_pid) : -abs(_e); }); | |||
261 | return 0; | |||
262 | } | |||
263 | ||||
264 | static int do_accept(const char* name, char **argv, char **envp, int fd) { | |||
265 | _cleanup_free___attribute__((cleanup(freep))) char *local = NULL((void*)0), *peer = NULL((void*)0); | |||
266 | _cleanup_close___attribute__((cleanup(closep))) int fd_accepted = -1; | |||
267 | ||||
268 | fd_accepted = accept4(fd, NULL((void*)0), NULL((void*)0), 0); | |||
269 | if (fd_accepted < 0) | |||
270 | return log_error_errno(errno, "Failed to accept connection on fd:%d: %m", fd)({ 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/activate/activate.c", 270, __func__ , "Failed to accept connection on fd:%d: %m", fd) : -abs(_e); }); | |||
271 | ||||
272 | getsockname_pretty(fd_accepted, &local); | |||
273 | getpeername_pretty(fd_accepted, true1, &peer); | |||
274 | log_info("Connection from %s to %s", strna(peer), strna(local))({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/activate/activate.c", 274, __func__, "Connection from %s to %s" , strna(peer), strna(local)) : -abs(_e); }); | |||
275 | ||||
276 | return fork_and_exec_process(name, argv, envp, fd_accepted); | |||
277 | } | |||
278 | ||||
279 | /* SIGCHLD handler. */ | |||
280 | static void sigchld_hdl(int sig) { | |||
281 | PROTECT_ERRNO__attribute__((cleanup(_reset_errno_))) __attribute__((unused )) int _saved_errno_ = (*__errno_location ()); | |||
282 | ||||
283 | for (;;) { | |||
284 | siginfo_t si; | |||
285 | int r; | |||
286 | ||||
287 | si.si_pid_sifields._kill.si_pid = 0; | |||
288 | r = waitid(P_ALL, 0, &si, WEXITED4|WNOHANG1); | |||
289 | if (r < 0) { | |||
290 | if (errno(*__errno_location ()) != ECHILD10) | |||
291 | log_error_errno(errno, "Failed to reap children: %m")({ 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/activate/activate.c", 291, __func__ , "Failed to reap children: %m") : -abs(_e); }); | |||
292 | return; | |||
293 | } | |||
294 | if (si.si_pid_sifields._kill.si_pid == 0) | |||
295 | return; | |||
296 | ||||
297 | log_info("Child %d died with code %d", si.si_pid, si.si_status)({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/activate/activate.c", 297, __func__, "Child %d died with code %d" , si._sifields._kill.si_pid, si._sifields._sigchld.si_status) : -abs(_e); }); | |||
298 | } | |||
299 | } | |||
300 | ||||
301 | static int install_chld_handler(void) { | |||
302 | static const struct sigaction act = { | |||
303 | .sa_flags = SA_NOCLDSTOP1|SA_RESTART0x10000000, | |||
304 | .sa_handler__sigaction_handler.sa_handler = sigchld_hdl, | |||
305 | }; | |||
306 | ||||
307 | if (sigaction(SIGCHLD17, &act, 0) < 0) | |||
308 | return log_error_errno(errno, "Failed to install SIGCHLD handler: %m")({ 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/activate/activate.c", 308, __func__ , "Failed to install SIGCHLD handler: %m") : -abs(_e); }); | |||
309 | ||||
310 | return 0; | |||
311 | } | |||
312 | ||||
313 | static void help(void) { | |||
314 | printf("%s [OPTIONS...]\n\n" | |||
315 | "Listen on sockets and launch child on connection.\n\n" | |||
316 | "Options:\n" | |||
317 | " -h --help Show this help and exit\n" | |||
318 | " --version Print version string and exit\n" | |||
319 | " -l --listen=ADDR Listen for raw connections at ADDR\n" | |||
320 | " -d --datagram Listen on datagram instead of stream socket\n" | |||
321 | " --seqpacket Listen on SOCK_SEQPACKET instead of stream socket\n" | |||
322 | " -a --accept Spawn separate child for each connection\n" | |||
323 | " -E --setenv=NAME[=VALUE] Pass an environment variable to children\n" | |||
324 | " --fdname=NAME[:NAME...] Specify names for file descriptors\n" | |||
325 | " --inetd Enable inetd file descriptor passing protocol\n" | |||
326 | "\n" | |||
327 | "Note: file descriptors from sd_listen_fds() will be passed through.\n" | |||
328 | , program_invocation_short_name); | |||
329 | } | |||
330 | ||||
331 | static int parse_argv(int argc, char *argv[]) { | |||
332 | enum { | |||
333 | ARG_VERSION = 0x100, | |||
334 | ARG_FDNAME, | |||
335 | ARG_SEQPACKET, | |||
336 | ARG_INETD, | |||
337 | }; | |||
338 | ||||
339 | static const struct option options[] = { | |||
340 | { "help", no_argument0, NULL((void*)0), 'h' }, | |||
341 | { "version", no_argument0, NULL((void*)0), ARG_VERSION }, | |||
342 | { "datagram", no_argument0, NULL((void*)0), 'd' }, | |||
343 | { "seqpacket", no_argument0, NULL((void*)0), ARG_SEQPACKET }, | |||
344 | { "listen", required_argument1, NULL((void*)0), 'l' }, | |||
345 | { "accept", no_argument0, NULL((void*)0), 'a' }, | |||
346 | { "setenv", required_argument1, NULL((void*)0), 'E' }, | |||
347 | { "environment", required_argument1, NULL((void*)0), 'E' }, /* legacy alias */ | |||
348 | { "fdname", required_argument1, NULL((void*)0), ARG_FDNAME }, | |||
349 | { "inetd", no_argument0, NULL((void*)0), ARG_INETD }, | |||
350 | {} | |||
351 | }; | |||
352 | ||||
353 | int c, r; | |||
354 | ||||
355 | assert(argc >= 0)do { if ((__builtin_expect(!!(!(argc >= 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("argc >= 0"), "../src/activate/activate.c" , 355, __PRETTY_FUNCTION__); } while (0); | |||
356 | assert(argv)do { if ((__builtin_expect(!!(!(argv)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("argv"), "../src/activate/activate.c", 356 , __PRETTY_FUNCTION__); } while (0); | |||
357 | ||||
358 | while ((c = getopt_long(argc, argv, "+hl:aE:d", options, NULL((void*)0))) >= 0) | |||
359 | switch(c) { | |||
360 | case 'h': | |||
361 | help(); | |||
362 | return 0; | |||
363 | ||||
364 | case ARG_VERSION: | |||
365 | return version(); | |||
366 | ||||
367 | case 'l': | |||
368 | r = strv_extend(&arg_listen, optarg); | |||
369 | if (r < 0) | |||
370 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/activate/activate.c" , 370, __func__); | |||
371 | ||||
372 | break; | |||
373 | ||||
374 | case 'd': | |||
375 | if (arg_socket_type == SOCK_SEQPACKETSOCK_SEQPACKET) { | |||
376 | log_error("--datagram may not be combined with --seqpacket.")({ 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/activate/activate.c", 376, __func__, "--datagram may not be combined with --seqpacket." ) : -abs(_e); }); | |||
377 | return -EINVAL22; | |||
378 | } | |||
379 | ||||
380 | arg_socket_type = SOCK_DGRAMSOCK_DGRAM; | |||
381 | break; | |||
382 | ||||
383 | case ARG_SEQPACKET: | |||
384 | if (arg_socket_type == SOCK_DGRAMSOCK_DGRAM) { | |||
385 | log_error("--seqpacket may not be combined with --datagram.")({ 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/activate/activate.c", 385, __func__, "--seqpacket may not be combined with --datagram." ) : -abs(_e); }); | |||
386 | return -EINVAL22; | |||
387 | } | |||
388 | ||||
389 | arg_socket_type = SOCK_SEQPACKETSOCK_SEQPACKET; | |||
390 | break; | |||
391 | ||||
392 | case 'a': | |||
393 | arg_accept = true1; | |||
394 | break; | |||
395 | ||||
396 | case 'E': | |||
397 | r = strv_extend(&arg_setenv, optarg); | |||
398 | if (r < 0) | |||
399 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/activate/activate.c" , 399, __func__); | |||
400 | ||||
401 | break; | |||
402 | ||||
403 | case ARG_FDNAME: { | |||
404 | _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **names; | |||
405 | char **s; | |||
406 | ||||
407 | names = strv_split(optarg, ":"); | |||
408 | if (!names) | |||
409 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/activate/activate.c" , 409, __func__); | |||
410 | ||||
411 | STRV_FOREACH(s, names)for ((s) = (names); (s) && *(s); (s)++) | |||
412 | if (!fdname_is_valid(*s)) { | |||
413 | _cleanup_free___attribute__((cleanup(freep))) char *esc; | |||
414 | ||||
415 | esc = cescape(*s); | |||
416 | log_warning("File descriptor name \"%s\" is not valid.", esc)({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/activate/activate.c", 416, __func__, "File descriptor name \"%s\" is not valid." , esc) : -abs(_e); }); | |||
417 | } | |||
418 | ||||
419 | /* Empty optargs means one empty name */ | |||
420 | r = strv_extend_strv(&arg_fdnames, | |||
421 | strv_isempty(names) ? STRV_MAKE("")((char**) ((const char*[]) { "", ((void*)0) })) : names, | |||
422 | false0); | |||
423 | if (r < 0) | |||
424 | return log_error_errno(r, "strv_extend_strv: %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/activate/activate.c", 424, __func__, "strv_extend_strv: %m" ) : -abs(_e); }); | |||
425 | break; | |||
426 | } | |||
427 | ||||
428 | case ARG_INETD: | |||
429 | arg_inetd = true1; | |||
430 | break; | |||
431 | ||||
432 | case '?': | |||
433 | return -EINVAL22; | |||
434 | ||||
435 | default: | |||
436 | assert_not_reached("Unhandled option")do { log_assert_failed_unreachable_realm(LOG_REALM_SYSTEMD, ( "Unhandled option"), "../src/activate/activate.c", 436, __PRETTY_FUNCTION__ ); } while (0); | |||
437 | } | |||
438 | ||||
439 | if (optind == argc) { | |||
440 | log_error("%s: command to execute is missing.",({ 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/activate/activate.c", 441, __func__, "%s: command to execute is missing." , program_invocation_short_name) : -abs(_e); }) | |||
441 | program_invocation_short_name)({ 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/activate/activate.c", 441, __func__, "%s: command to execute is missing." , program_invocation_short_name) : -abs(_e); }); | |||
442 | return -EINVAL22; | |||
443 | } | |||
444 | ||||
445 | if (arg_socket_type == SOCK_DGRAMSOCK_DGRAM && arg_accept) { | |||
446 | log_error("Datagram sockets do not accept connections. "({ 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/activate/activate.c", 447, __func__, "Datagram sockets do not accept connections. " "The --datagram and --accept options may not be combined.") : -abs(_e); }) | |||
447 | "The --datagram and --accept options may not be combined.")({ 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/activate/activate.c", 447, __func__, "Datagram sockets do not accept connections. " "The --datagram and --accept options may not be combined.") : -abs(_e); }); | |||
448 | return -EINVAL22; | |||
449 | } | |||
450 | ||||
451 | arg_args = argv + optind; | |||
452 | ||||
453 | return 1 /* work to do */; | |||
454 | } | |||
455 | ||||
456 | int main(int argc, char **argv, char **envp) { | |||
457 | int r, n; | |||
458 | int epoll_fd = -1; | |||
459 | ||||
460 | log_parse_environment()log_parse_environment_realm(LOG_REALM_SYSTEMD); | |||
461 | log_open(); | |||
462 | ||||
463 | r = parse_argv(argc, argv); | |||
464 | if (r
| |||
| ||||
465 | return r == 0 ? EXIT_SUCCESS0 : EXIT_FAILURE1; | |||
466 | ||||
467 | r = install_chld_handler(); | |||
468 | if (r
| |||
469 | return EXIT_FAILURE1; | |||
470 | ||||
471 | n = open_sockets(&epoll_fd, arg_accept); | |||
472 | if (n < 0) | |||
473 | return EXIT_FAILURE1; | |||
474 | if (n == 0) { | |||
475 | log_error("No sockets to listen on specified or passed in.")({ 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/activate/activate.c", 475, __func__, "No sockets to listen on specified or passed in." ) : -abs(_e); }); | |||
476 | return EXIT_FAILURE1; | |||
477 | } | |||
478 | ||||
479 | for (;;) { | |||
480 | struct epoll_event event; | |||
481 | ||||
482 | if (epoll_wait(epoll_fd, &event, 1, -1) < 0) { | |||
483 | if (errno(*__errno_location ()) == EINTR4) | |||
484 | continue; | |||
485 | ||||
486 | log_error_errno(errno, "epoll_wait() failed: %m")({ 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/activate/activate.c", 486, __func__ , "epoll_wait() failed: %m") : -abs(_e); }); | |||
487 | return EXIT_FAILURE1; | |||
488 | } | |||
489 | ||||
490 | log_info("Communication attempt on fd %i.", event.data.fd)({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/activate/activate.c", 490, __func__, "Communication attempt on fd %i." , event.data.fd) : -abs(_e); }); | |||
491 | if (arg_accept
| |||
492 | r = do_accept(argv[optind], argv + optind, envp, event.data.fd); | |||
493 | if (r < 0) | |||
494 | return EXIT_FAILURE1; | |||
495 | } else | |||
496 | break; | |||
497 | } | |||
498 | ||||
499 | exec_process(argv[optind], argv + optind, envp, SD_LISTEN_FDS_START3, (size_t) n); | |||
500 | ||||
501 | return EXIT_SUCCESS0; | |||
502 | } |