Bug Summary

File:build-scan/../src/activate/activate.c
Warning:line 151, column 40
Potential leak of memory pointed to by 'envp'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name activate.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -relaxed-aliasing -menable-no-infs -menable-no-nans -menable-unsafe-fp-math -fno-signed-zeros -mreassociate -freciprocal-math -fdenormal-fp-math=preserve-sign,preserve-sign -ffp-contract=fast -fno-rounding-math -ffast-math -ffinite-math-only -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.0.0 -include config.h -I systemd-socket-activate.p -I . -I .. -I src/basic -I ../src/basic -I src/shared -I ../src/shared -I src/systemd -I ../src/systemd -I src/journal -I ../src/journal -I src/journal-remote -I ../src/journal-remote -I src/nspawn -I ../src/nspawn -I src/resolve -I ../src/resolve -I src/timesync -I ../src/timesync -I ../src/time-wait-sync -I src/login -I ../src/login -I src/udev -I ../src/udev -I src/libudev -I ../src/libudev -I src/core -I ../src/core -I ../src/libsystemd/sd-bus -I ../src/libsystemd/sd-device -I ../src/libsystemd/sd-hwdb -I ../src/libsystemd/sd-id128 -I ../src/libsystemd/sd-netlink -I ../src/libsystemd/sd-network -I src/libsystemd-network -I ../src/libsystemd-network -D _FILE_OFFSET_BITS=64 -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wwrite-strings -Wno-unused-parameter -Wno-missing-field-initializers -Wno-unused-result -Wno-format-signedness -Wno-error=nonnull -std=gnu99 -fconst-strings -fdebug-compilation-dir /home/mrc0mmand/repos/@redhat-plumbers/systemd-rhel8/build-scan -ferror-limit 19 -fvisibility hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -analyzer-output=html -faddrsig -o /tmp/scan-build-2021-07-16-221226-1465241-1 -x c ../src/activate/activate.c
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
23static char** arg_listen = NULL((void*)0);
24static bool_Bool arg_accept = false0;
25static int arg_socket_type = SOCK_STREAMSOCK_STREAM;
26static char** arg_args = NULL((void*)0);
27static char** arg_setenv = NULL((void*)0);
28static char **arg_fdnames = NULL((void*)0);
29static bool_Bool arg_inetd = false0;
30
31static 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
46static 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
114static 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
14.1
'arg_inetd' is false
&& n_fds != 1) {
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 *)));
15
Memory is allocated
132 if (!envp)
16
Assuming 'envp' is non-null
17
Taking false branch
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)++) {
18
Assuming 's' is non-null
19
Loop condition is true. Entering loop body
136
137 if (strchr(*s, '=')) {
20
Assuming the condition is false
21
Taking false branch
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)
22
Assuming 'p' is null
23
Taking true branch
151 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/activate/activate.c"
, 151, __func__)
;
24
Potential leak of memory pointed to by 'envp'
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
242static 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
264static 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. */
280static 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
301static 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
313static 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
331static 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
456int 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
0.1
'r' is > 0
<= 0)
1
Taking false branch
465 return r == 0 ? EXIT_SUCCESS0 : EXIT_FAILURE1;
466
467 r = install_chld_handler();
468 if (r
1.1
'r' is >= 0
< 0)
2
Taking false branch
469 return EXIT_FAILURE1;
470
471 n = open_sockets(&epoll_fd, arg_accept);
472 if (n < 0)
3
Assuming 'n' is >= 0
4
Taking false branch
473 return EXIT_FAILURE1;
474 if (n == 0) {
5
Assuming 'n' is not equal to 0
6
Taking false branch
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 (;;) {
7
Loop condition is true. Entering loop body
480 struct epoll_event event;
481
482 if (epoll_wait(epoll_fd, &event, 1, -1) < 0) {
8
Assuming the condition is false
9
Taking false branch
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); })
;
10
Assuming the condition is false
11
'?' condition is false
491 if (arg_accept
11.1
'arg_accept' is false
) {
12
Taking false branch
492 r = do_accept(argv[optind], argv + optind, envp, event.data.fd);
493 if (r < 0)
494 return EXIT_FAILURE1;
495 } else
496 break;
13
Execution continues on line 499
497 }
498
499 exec_process(argv[optind], argv + optind, envp, SD_LISTEN_FDS_START3, (size_t) n);
14
Calling 'exec_process'
500
501 return EXIT_SUCCESS0;
502}