activate.c revision 29a5ca9baa58e55c4d9e1d008cdd014aa9c3c3e1
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen/***
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen This file is part of systemd.
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen Copyright 2013 Zbigniew Jędrzejewski-Szmek
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen systemd is free software; you can redistribute it and/or modify it
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen under the terms of the GNU Lesser General Public License as published by
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen the Free Software Foundation; either version 2.1 of the License, or
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen (at your option) any later version.
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen systemd is distributed in the hope that it will be useful, but
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen WITHOUT ANY WARRANTY; without even the implied warranty of
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen Lesser General Public License for more details.
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen You should have received a copy of the GNU Lesser General Public License
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen along with systemd; If not, see <http://www.gnu.org/licenses/>.
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen***/
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen#include <unistd.h>
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen#include <fcntl.h>
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen#include <sys/epoll.h>
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen#include <sys/prctl.h>
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen#include <sys/socket.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include <sys/wait.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include <getopt.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen#include <systemd/sd-daemon.h>
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen#include "socket-util.h"
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen#include "build.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "log.h"
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen#include "strv.h"
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen#include "macro.h"
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersenstatic char** arg_listen = NULL;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersenstatic bool arg_accept = false;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersenstatic char** arg_args = NULL;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersenstatic char** arg_environ = NULL;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersenstatic int add_epoll(int epoll_fd, int fd) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen int r;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen struct epoll_event ev = {EPOLLIN};
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen ev.data.fd = fd;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen assert(epoll_fd >= 0);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen assert(fd >= 0);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (r < 0)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_error("Failed to add event on epoll fd:%d for fd:%d: %s",
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen epoll_fd, fd, strerror(-r));
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return r;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen}
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersenstatic int print_socket(const char* desc, int fd) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen int r;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen SocketAddress addr = {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen .size = sizeof(union sockaddr_union),
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen .type = SOCK_STREAM,
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen };
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen int family;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = getsockname(fd, &addr.sockaddr.sa, &addr.size);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (r < 0) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_warning("Failed to query socket on fd:%d: %m", fd);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return 0;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen family = socket_address_family(&addr);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen switch(family) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen case AF_INET:
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen case AF_INET6: {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen char* _cleanup_free_ a = NULL;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = socket_address_print(&addr, &a);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (r < 0)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_warning("socket_address_print(): %s", strerror(-r));
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen else
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_info("%s %s address %s",
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen desc,
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen family == AF_INET ? "IP" : "IPv6",
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen a);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen break;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen default:
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_warning("Connection with unknown family %d", family);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return 0;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen}
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersenstatic int open_sockets(int *epoll_fd, bool accept) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen int n, fd, r;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen int count = 0;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen char **address;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen n = sd_listen_fds(true);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (n < 0) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_error("Failed to read listening file descriptors from environment: %s",
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen strerror(-n));
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return n;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_info("Received %d descriptors", n);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_debug("Received descriptor fd:%d", fd);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen print_socket("Listening on", fd);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = fd_cloexec(fd, arg_accept);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (r < 0)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return r;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen count ++;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen /** Note: we leak some fd's on error here. I doesn't matter
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen * much, since the program will exit immediately anyway, but
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen * would be a pain to fix.
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen */
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen STRV_FOREACH(address, arg_listen) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_info("Opening address %s", *address);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen fd = make_socket_fd(*address, SOCK_STREAM | (arg_accept*SOCK_CLOEXEC));
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (fd < 0) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_error("Failed to open '%s': %s", *address, strerror(-fd));
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return fd;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen count ++;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen *epoll_fd = epoll_create1(EPOLL_CLOEXEC);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (*epoll_fd < 0) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_error("Failed to create epoll object: %m");
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return -errno;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + count; fd++) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = add_epoll(*epoll_fd, fd);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (r < 0)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return r;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return count;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen}
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersenstatic int launch(char* name, char **argv, char **env, int fds) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen unsigned n_env = 0, length;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen _cleanup_strv_free_ char **envp = NULL;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen char **s;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen static const char* tocopy[] = {"TERM=", "PATH=", "USER=", "HOME="};
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen _cleanup_free_ char *tmp = NULL;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen unsigned i;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen length = strv_length(arg_environ);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen /* PATH, TERM, HOME, USER, LISTEN_FDS, LISTEN_PID, NULL */
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen envp = new(char *, length + 7);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen STRV_FOREACH(s, arg_environ) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (strchr(*s, '='))
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen envp[n_env++] = *s;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen else {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen _cleanup_free_ char *p = strappend(*s, "=");
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (!p)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return log_oom();
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen envp[n_env] = strv_find_prefix(env, p);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (envp[n_env])
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen n_env ++;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen for (i = 0; i < ELEMENTSOF(tocopy); i++) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen envp[n_env] = strv_find_prefix(env, tocopy[i]);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (envp[n_env])
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen n_env ++;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
2237aa02f3e2739a1ebe9c0bc224b5125f5eb292David Herrmann if ((asprintf((char**)(envp + n_env++), "LISTEN_FDS=%d", fds) < 0) ||
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen (asprintf((char**)(envp + n_env++), "LISTEN_PID=%d", getpid()) < 0))
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return log_oom();
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen tmp = strv_join(argv, " ");
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (!tmp)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return log_oom();
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_info("Execing %s (%s)", name, tmp);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen execvpe(name, argv, envp);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_error("Failed to execp %s (%s): %m", name, tmp);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return -errno;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen}
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersenstatic int launch1(const char* child, char** argv, char **env, int fd) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen pid_t parent_pid, child_pid;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen int r;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen _cleanup_free_ char *tmp = NULL;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen tmp = strv_join(argv, " ");
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (!tmp)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return log_oom();
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen parent_pid = getpid();
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen child_pid = fork();
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (child_pid < 0) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_error("Failed to fork: %m");
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return -errno;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen /* In the child */
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (child_pid == 0) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = dup2(fd, STDIN_FILENO);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (r < 0) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_error("Failed to dup connection to stdin: %m");
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen _exit(EXIT_FAILURE);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = dup2(fd, STDOUT_FILENO);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (r < 0) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_error("Failed to dup connection to stdout: %m");
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen _exit(EXIT_FAILURE);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = close(fd);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (r < 0) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_error("Failed to close dupped connection: %m");
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen _exit(EXIT_FAILURE);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen /* Make sure the child goes away when the parent dies */
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen _exit(EXIT_FAILURE);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen /* Check whether our parent died before we were able
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen * to set the death signal */
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (getppid() != parent_pid)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen _exit(EXIT_SUCCESS);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen execvp(child, argv);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_error("Failed to exec child %s: %m", child);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen _exit(EXIT_FAILURE);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_info("Spawned %s (%s) as PID %d", child, tmp, child_pid);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return 0;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen}
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersenstatic int do_accept(const char* name, char **argv, char **envp, int fd) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen SocketAddress addr = {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen .size = sizeof(union sockaddr_union),
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen .type = SOCK_STREAM,
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen };
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen int fd2, r;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen fd2 = accept(fd, &addr.sockaddr.sa, &addr.size);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (fd2 < 0) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_error("Failed to accept connection on fd:%d: %m", fd);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return fd2;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen print_socket("Connection from", fd2);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = launch1(name, argv, envp, fd2);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return r;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen}
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen/* SIGCHLD handler. */
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersenstatic void sigchld_hdl(int sig, siginfo_t *t, void *data) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_info("Child %d died with code %d", t->si_pid, t->si_status);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen /* Wait for a dead child. */
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen waitpid(t->si_pid, NULL, 0);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen}
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersenstatic int install_chld_handler(void) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen int r;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen struct sigaction act;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen zero(act);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen act.sa_flags = SA_SIGINFO;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen act.sa_sigaction = sigchld_hdl;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = sigaction(SIGCHLD, &act, 0);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (r < 0)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_error("Failed to install SIGCHLD handler: %m");
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return r;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen}
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersenstatic int help(void) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen printf("%s [OPTIONS...]\n\n"
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen "Listen on sockets and launch child on connection.\n\n"
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen "Options:\n"
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen " -l --listen=ADDR Listen for raw connections at ADDR\n"
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen " -a --accept Spawn separate child for each connection\n"
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen " -h --help Show this help and exit\n"
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen " --version Print version string and exit\n"
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen "\n"
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen "Note: file descriptors from sd_listen_fds() will be passed through.\n"
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen , program_invocation_short_name
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen );
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return 0;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen}
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersenstatic int parse_argv(int argc, char *argv[]) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen enum {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen ARG_VERSION = 0x100,
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen };
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen static const struct option options[] = {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen { "help", no_argument, NULL, 'h' },
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen { "version", no_argument, NULL, ARG_VERSION },
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen { "listen", required_argument, NULL, 'l' },
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen { "accept", no_argument, NULL, 'a' },
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen { "environment", required_argument, NULL, 'E' },
2237aa02f3e2739a1ebe9c0bc224b5125f5eb292David Herrmann {}
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen };
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen int c;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen assert(argc >= 0);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen assert(argv);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen while ((c = getopt_long(argc, argv, "+hl:saE:", options, NULL)) >= 0)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen switch(c) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen case 'h':
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return help();
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen case ARG_VERSION:
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen puts(PACKAGE_STRING);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen puts(SYSTEMD_FEATURES);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return 0 /* done */;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen case 'l': {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen int r = strv_extend(&arg_listen, optarg);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (r < 0)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return r;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen break;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen case 'a':
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen arg_accept = true;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen break;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
2237aa02f3e2739a1ebe9c0bc224b5125f5eb292David Herrmann case 'E': {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen int r = strv_extend(&arg_environ, optarg);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (r < 0)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return r;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen break;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen case '?':
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return -EINVAL;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen default:
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen assert_not_reached("Unhandled option");
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (optind == argc) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_error("Usage: %s [OPTION...] PROGRAM [OPTION...]",
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen program_invocation_short_name);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return -EINVAL;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen arg_args = argv + optind;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return 1 /* work to do */;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen}
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersenint main(int argc, char **argv, char **envp) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen int r, n;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen int epoll_fd = -1;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_set_max_level(LOG_DEBUG);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_show_color(true);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_parse_environment();
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = parse_argv(argc, argv);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (r <= 0)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = install_chld_handler();
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (r < 0)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return EXIT_FAILURE;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen n = open_sockets(&epoll_fd, arg_accept);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (n < 0)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return EXIT_FAILURE;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen while (true) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen struct epoll_event event;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = epoll_wait(epoll_fd, &event, 1, -1);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (r < 0) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (errno == EINTR)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen continue;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_error("epoll_wait() failed: %m");
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return EXIT_FAILURE;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_info("Communication attempt on fd:%d", event.data.fd);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (arg_accept) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = do_accept(argv[optind], argv + optind, envp,
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen event.data.fd);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (r < 0)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return EXIT_FAILURE;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen } else
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen break;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen }
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen launch(argv[optind], argv + optind, envp, n);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return EXIT_SUCCESS;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen}
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen