X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Factivate%2Factivate.c;h=d73c16e8ab7aee220220b5efb57e538d9f80816c;hp=b3ef428cee16c88ec5f8af7df835db32da5a42d7;hb=c099716487df4a4f5394e57e7ca14da1d358166a;hpb=5b84559a76f30755019d6a0e6b2ccc9bbe0b3c56 diff --git a/src/activate/activate.c b/src/activate/activate.c index b3ef428ce..d73c16e8a 100644 --- a/src/activate/activate.c +++ b/src/activate/activate.c @@ -41,58 +41,23 @@ static char** arg_args = NULL; static char** arg_environ = NULL; static int add_epoll(int epoll_fd, int fd) { + struct epoll_event ev = { + .events = EPOLLIN + }; int r; - struct epoll_event ev = {EPOLLIN}; - ev.data.fd = fd; assert(epoll_fd >= 0); assert(fd >= 0); + ev.data.fd = fd; r = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev); if (r < 0) - log_error("Failed to add event on epoll fd:%d for fd:%d: %s", - epoll_fd, fd, strerror(-r)); - return r; -} - -static int print_socket(const char* desc, int fd) { - int r; - SocketAddress addr = { - .size = sizeof(union sockaddr_union), - .type = SOCK_STREAM, - }; - int family; - - r = getsockname(fd, &addr.sockaddr.sa, &addr.size); - if (r < 0) { - log_warning("Failed to query socket on fd:%d: %m", fd); - return 0; - } - - family = socket_address_family(&addr); - switch(family) { - case AF_INET: - case AF_INET6: { - char* _cleanup_free_ a = NULL; - r = socket_address_print(&addr, &a); - if (r < 0) - log_warning("socket_address_print(): %s", strerror(-r)); - else - log_info("%s %s address %s", - desc, - family == AF_INET ? "IP" : "IPv6", - a); - break; - } - default: - log_warning("Connection with unknown family %d", family); - } - - return 0; + log_error("Failed to add event on epoll fd:%d for fd:%d: %m", + epoll_fd, fd); + return -errno; } static int make_socket_fd(const char* address, int flags) { - _cleanup_free_ char *p = NULL; SocketAddress a; int fd, r; @@ -108,22 +73,13 @@ static int make_socket_fd(const char* address, int flags) { return fd; } - r = socket_address_print(&a, &p); - if (r < 0) { - log_error("socket_address_print(): %s", strerror(-r)); - close_nointr_nofail(fd); - return r; - } - - log_info("Listening on %s", p); - return fd; } static int open_sockets(int *epoll_fd, bool accept) { + char **address; int n, fd, r; int count = 0; - char **address; n = sd_listen_fds(true); if (n < 0) { @@ -131,17 +87,27 @@ static int open_sockets(int *epoll_fd, bool accept) { strerror(-n)); return n; } - log_info("Received %d descriptors", n); + if (n > 0) { + log_info("Received %i descriptors via the environment.", n); - for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) { - log_debug("Received descriptor fd:%d", fd); - print_socket("Listening on", fd); + for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) { + r = fd_cloexec(fd, arg_accept); + if (r < 0) + return r; - r = fd_cloexec(fd, arg_accept); - if (r < 0) - return r; + count ++; + } + } - count ++; + /* Close logging and all other descriptors */ + if (arg_listen) { + int except[3 + n]; + + for (fd = 0; fd < SD_LISTEN_FDS_START + n; fd++) + except[fd] = fd; + + log_close(); + close_all_fds(except, 3 + n); } /** Note: we leak some fd's on error here. I doesn't matter @@ -150,10 +116,10 @@ static int open_sockets(int *epoll_fd, bool accept) { */ STRV_FOREACH(address, arg_listen) { - log_info("Opening address %s", *address); fd = make_socket_fd(*address, SOCK_STREAM | (arg_accept*SOCK_CLOEXEC)); if (fd < 0) { + log_open(); log_error("Failed to open '%s': %s", *address, strerror(-fd)); return fd; } @@ -162,14 +128,21 @@ static int open_sockets(int *epoll_fd, bool accept) { count ++; } + if (arg_listen) + log_open(); + *epoll_fd = epoll_create1(EPOLL_CLOEXEC); if (*epoll_fd < 0) { log_error("Failed to create epoll object: %m"); return -errno; } - for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + count; fd++) { + _cleanup_free_ char *name = NULL; + + getsockname_pretty(fd, &name); + log_info("Listening on %s as %i.", strna(name), fd); + r = add_epoll(*epoll_fd, fd); if (r < 0) return r; @@ -179,16 +152,20 @@ static int open_sockets(int *epoll_fd, bool accept) { } static int launch(char* name, char **argv, char **env, int fds) { - unsigned n_env = 0, length; - _cleanup_strv_free_ char **envp = NULL; - char **s; + static const char* tocopy[] = {"TERM=", "PATH=", "USER=", "HOME="}; + _cleanup_strv_free_ char **envp = NULL; _cleanup_free_ char *tmp = NULL; + unsigned n_env = 0, length; + char **s; unsigned i; length = strv_length(arg_environ); + /* PATH, TERM, HOME, USER, LISTEN_FDS, LISTEN_PID, NULL */ envp = new0(char *, length + 7); + if (!envp) + return log_oom(); STRV_FOREACH(s, arg_environ) { if (strchr(*s, '=')) @@ -220,14 +197,15 @@ static int launch(char* name, char **argv, char **env, int fds) { log_info("Execing %s (%s)", name, tmp); execvpe(name, argv, envp); log_error("Failed to execp %s (%s): %m", name, tmp); + return -errno; } static int launch1(const char* child, char** argv, char **env, int fd) { + _cleanup_free_ char *tmp = NULL; pid_t parent_pid, child_pid; int r; - _cleanup_free_ char *tmp = NULL; tmp = strv_join(argv, " "); if (!tmp) return log_oom(); @@ -280,26 +258,26 @@ static int launch1(const char* child, char** argv, char **env, int fd) { } static int do_accept(const char* name, char **argv, char **envp, int fd) { - SocketAddress addr = { - .size = sizeof(union sockaddr_union), - .type = SOCK_STREAM, - }; - int fd2, r; + _cleanup_free_ char *local = NULL, *peer = NULL; + int fd2; - fd2 = accept(fd, &addr.sockaddr.sa, &addr.size); + fd2 = accept(fd, NULL, NULL); if (fd2 < 0) { log_error("Failed to accept connection on fd:%d: %m", fd); return fd2; } - print_socket("Connection from", fd2); + getsockname_pretty(fd2, &local); + getpeername_pretty(fd2, &peer); + log_info("Connection from %s to %s", strna(peer), strna(local)); - r = launch1(name, argv, envp, fd2); - return r; + return launch1(name, argv, envp, fd2); } /* SIGCHLD handler. */ static void sigchld_hdl(int sig, siginfo_t *t, void *data) { + PROTECT_ERRNO; + log_info("Child %d died with code %d", t->si_pid, t->si_status); /* Wait for a dead child. */ waitpid(t->si_pid, NULL, 0); @@ -307,10 +285,10 @@ static void sigchld_hdl(int sig, siginfo_t *t, void *data) { static int install_chld_handler(void) { int r; - struct sigaction act; - zero(act); - act.sa_flags = SA_SIGINFO; - act.sa_sigaction = sigchld_hdl; + struct sigaction act = { + .sa_flags = SA_SIGINFO, + .sa_sigaction = sigchld_hdl, + }; r = sigaction(SIGCHLD, &act, 0); if (r < 0) @@ -325,6 +303,8 @@ static int help(void) { " -l --listen=ADDR Listen for raw connections at ADDR\n" " -a --accept Spawn separate child for each connection\n" " -h --help Show this help and exit\n" + " -E --environment=NAME[=VALUE]\n" + " Pass an environment variable to children\n" " --version Print version string and exit\n" "\n" "Note: file descriptors from sd_listen_fds() will be passed through.\n" @@ -353,7 +333,7 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); - while ((c = getopt_long(argc, argv, "+hl:saE:", options, NULL)) >= 0) + while ((c = getopt_long(argc, argv, "+hl:aE:", options, NULL)) >= 0) switch(c) { case 'h': return help(); @@ -419,6 +399,10 @@ int main(int argc, char **argv, char **envp) { n = open_sockets(&epoll_fd, arg_accept); if (n < 0) return EXIT_FAILURE; + if (n == 0) { + log_error("No sockets to listen on specified or passed in."); + return EXIT_FAILURE; + } for (;;) { struct epoll_event event; @@ -432,7 +416,7 @@ int main(int argc, char **argv, char **envp) { return EXIT_FAILURE; } - log_info("Communication attempt on fd:%d", event.data.fd); + log_info("Communication attempt on fd %i.", event.data.fd); if (arg_accept) { r = do_accept(argv[optind], argv + optind, envp, event.data.fd);