activate.c revision 29a5ca9baa58e55c4d9e1d008cdd014aa9c3c3e1
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen This file is part of systemd.
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen Copyright 2013 Zbigniew Jędrzejewski-Szmek
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 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 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 Gundersenstatic bool arg_accept = false;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_error("Failed to add event on epoll fd:%d for fd:%d: %s",
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersenstatic int print_socket(const char* desc, int fd) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = getsockname(fd, &addr.sockaddr.sa, &addr.size);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_warning("Failed to query socket on fd:%d: %m", fd);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_warning("socket_address_print(): %s", strerror(-r));
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_warning("Connection with unknown family %d", family);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersenstatic int open_sockets(int *epoll_fd, bool accept) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_error("Failed to read listening file descriptors from environment: %s",
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
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 fd = make_socket_fd(*address, SOCK_STREAM | (arg_accept*SOCK_CLOEXEC));
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_error("Failed to open '%s': %s", *address, strerror(-fd));
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_error("Failed to create epoll object: %m");
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + count; fd++) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersenstatic int launch(char* name, char **argv, char **env, int fds) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen static const char* tocopy[] = {"TERM=", "PATH=", "USER=", "HOME="};
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen /* PATH, TERM, HOME, USER, LISTEN_FDS, LISTEN_PID, NULL */
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen envp[n_env] = strv_find_prefix(env, tocopy[i]);
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 log_error("Failed to execp %s (%s): %m", name, tmp);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersenstatic int launch1(const char* child, char** argv, char **env, int fd) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen /* In the child */
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_error("Failed to dup connection to stdin: %m");
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_error("Failed to dup connection to stdout: %m");
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_error("Failed to close dupped connection: %m");
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen /* Make sure the child goes away when the parent dies */
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen /* Check whether our parent died before we were able
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen * to set the death signal */
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_error("Failed to exec child %s: %m", child);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_info("Spawned %s (%s) as PID %d", child, tmp, child_pid);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersenstatic int do_accept(const char* name, char **argv, char **envp, int fd) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen fd2 = accept(fd, &addr.sockaddr.sa, &addr.size);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_error("Failed to accept connection on fd:%d: %m", fd);
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 Gundersenstatic int install_chld_handler(void) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_error("Failed to install SIGCHLD handler: %m");
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersenstatic int help(void) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen "Listen on sockets and launch child on connection.\n\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 "Note: file descriptors from sd_listen_fds() will be passed through.\n"
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersenstatic int parse_argv(int argc, char *argv[]) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen { "version", no_argument, NULL, ARG_VERSION },
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen { "environment", required_argument, NULL, 'E' },
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen while ((c = getopt_long(argc, argv, "+hl:saE:", options, NULL)) >= 0)
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen return 0 /* done */;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_error("Usage: %s [OPTION...] PROGRAM [OPTION...]",
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen while (true) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_info("Communication attempt on fd:%d", event.data.fd);