| 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 | } |