activate.c revision e9c1ea9de87d4d508ac38ce87a2fa56e7529a91a
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering This file is part of systemd.
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering Copyright 2013 Zbigniew Jędrzejewski-Szmek
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering systemd is free software; you can redistribute it and/or modify it
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering under the terms of the GNU Lesser General Public License as published by
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering (at your option) any later version.
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering systemd is distributed in the hope that it will be useful, but
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering Lesser General Public License for more details.
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering You should have received a copy of the GNU Lesser General Public License
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringstatic bool arg_accept = false;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringstatic int add_epoll(int epoll_fd, int fd) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering r = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_error("Failed to add event on epoll fd:%d for fd:%d: %s",
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering log_error("Querying flags for fd:%d: %m", fd);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (fcntl(fd, F_SETFD, flags & ~FD_CLOEXEC) < 0) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering log_error("Settings flags for fd:%d: %m", fd);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poetteringstatic int print_socket(const char* desc, int fd) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering r = getsockname(fd, &addr.sockaddr.sa, &addr.size);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering log_warning("Failed to query socket on fd:%d: %m", fd);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering log_warning("socket_address_print(): %s", strerror(-r));
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering log_warning("Connection with unknown family %d", family);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poetteringstatic int open_sockets(int *epoll_fd, bool accept) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering log_error("Failed to read listening file descriptors from environment: %s",
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering log_debug("Received descriptor fd:%d", fd);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /** Note: we leak some fd's on error here. I doesn't matter
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering * much, since the program will exit immediately anyway, but
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering * would be a pain to fix.
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_info("Opening address %s", *address);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering fd = make_socket_fd(*address, SOCK_STREAM | (arg_accept*SOCK_CLOEXEC));
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_error("Failed to open '%s': %s", *address, strerror(-fd));
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering *epoll_fd = epoll_create1(EPOLL_CLOEXEC);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_error("Failed to create epoll object: %m");
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + count; fd++) {
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mackstatic int launch(char* name, char **argv, char **env, int fds) {
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack static const char* tocopy[] = {"TERM=", "PATH=", "USER=", "HOME="};
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack /* PATH, TERM, HOME, USER, LISTEN_FDS, LISTEN_PID, NULL */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering _cleanup_free_ char *p = strappend(*s, "=");
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering for (i = 0; i < ELEMENTSOF(tocopy); i++) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering envp[n_env] = strv_find_prefix(env, tocopy[i]);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if ((asprintf((char**)(envp + n_env++), "LISTEN_FDS=%d", fds) < 0) ||
79008bddf679a5e0900369950eb346c9fa687107Lennart Poettering (asprintf((char**)(envp + n_env++), "LISTEN_PID=%d", getpid()) < 0))
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_error("Failed to execp %s (%s): %m", name, tmp);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringstatic int launch1(const char* child, char** argv, char **env, int fd) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* In the child */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_error("Failed to dup connection to stdin: %m");
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_error("Failed to dup connection to stdout: %m");
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_error("Failed to close dupped connection: %m");
3f9da416457c4265b8f1179516a32ad1a987ff7dLennart Poettering /* Make sure the child goes away when the parent dies */
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering /* Check whether our parent died before we were able
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering * to set the death signal */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_error("Failed to exec child %s: %m", child);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_info("Spawned %s (%s) as PID %d", child, tmp, child_pid);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringstatic int do_accept(const char* name, char **argv, char **envp, int fd) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering fd2 = accept(fd, &addr.sockaddr.sa, &addr.size);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_error("Failed to accept connection on fd:%d: %m", fd);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering/* SIGCHLD handler. */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringstatic void sigchld_hdl(int sig, siginfo_t *t, void *data) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_info("Child %d died with code %d", t->si_pid, t->si_status);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* Wait for a dead child. */
8f077bf94e129fa1b6f0159e3140c4326f1066cfZbigniew Jędrzejewski-Szmekstatic int install_chld_handler(void) {
8f077bf94e129fa1b6f0159e3140c4326f1066cfZbigniew Jędrzejewski-Szmek r = sigaction(SIGCHLD, &act, 0);
23bbb0de4e3f85d9704a5c12a5afa2dfa0159e41Michal Schmidt log_error("Failed to install SIGCHLD handler: %m");
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringstatic int help(void) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering "Listen on sockets and launch child on connection.\n\n"
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering " -l --listen=ADDR Listen for raw connections at ADDR\n"
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering " -a --accept Spawn separate child for each connection\n"
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering " -h --help Show this help and exit\n"
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering " --version Print version string and exit\n"
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering "Note: file descriptors from sd_listen_fds() will be passed through.\n"
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poetteringstatic int parse_argv(int argc, char *argv[]) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering { "version", no_argument, NULL, ARG_VERSION },
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering { "listen", required_argument, NULL, 'l' },
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering { "environment", required_argument, NULL, 'E' },
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering while ((c = getopt_long(argc, argv, "+hl:saE:", options, NULL)) >= 0)
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return 0 /* done */;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return 0 /* done */;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering int r = strv_extend(&arg_listen, optarg);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering int r = strv_extend(&arg_environ, optarg);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering log_error("Usage: %s [OPTION...] PROGRAM [OPTION...]",
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poetteringint main(int argc, char **argv, char **envp) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering while (true) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_info("Communication attempt on fd:%d", event.data.fd);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering r = do_accept(argv[optind], argv + optind, envp,