| File: | build-scan/../src/activate/activate.c |
| Warning: | line 194, column 25 Value stored to 'start_fd' is never read |
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 && 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 *))); |
| 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; |
Value stored to 'start_fd' is never read | |
| 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 <= 0) |
| 465 | return r == 0 ? EXIT_SUCCESS0 : EXIT_FAILURE1; |
| 466 | |
| 467 | r = install_chld_handler(); |
| 468 | if (r < 0) |
| 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 | } |