LCOV - code coverage report
Current view: top level - activate - activate.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 23 262 8.8 %
Date: 2019-08-23 13:36:53 Functions: 3 10 30.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 7 246 2.8 %

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

Generated by: LCOV version 1.14