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