activate.c revision eb56eb9b40950f1edcffdb7313f8de4f8572a6d5
813e3a6ffcd094696001716480bbd68008cc54c8Patrik Flykt/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
813e3a6ffcd094696001716480bbd68008cc54c8Patrik Flykt This file is part of systemd.
813e3a6ffcd094696001716480bbd68008cc54c8Patrik Flykt Copyright 2013 Zbigniew Jędrzejewski-Szmek
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 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 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 Flyktstatic bool arg_accept = false;
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 Flyktstatic int open_sockets(int *epoll_fd, bool accept) {
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 for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
f12ed3bf0b315fc88d5fbdf5bdca14b218c86e0cPatrik Flykt /* Close logging and all other descriptors */
f12ed3bf0b315fc88d5fbdf5bdca14b218c86e0cPatrik Flykt for (fd = 0; fd < SD_LISTEN_FDS_START + n; fd++)
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 fd = make_socket_fd(LOG_DEBUG, *address, SOCK_STREAM | (arg_accept*SOCK_CLOEXEC));
f12ed3bf0b315fc88d5fbdf5bdca14b218c86e0cPatrik Flykt log_error_errno(fd, "Failed to open '%s': %m", *address);
f12ed3bf0b315fc88d5fbdf5bdca14b218c86e0cPatrik Flykt log_error("Failed to create epoll object: %m");
f12ed3bf0b315fc88d5fbdf5bdca14b218c86e0cPatrik Flykt for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + count; fd++) {
f12ed3bf0b315fc88d5fbdf5bdca14b218c86e0cPatrik Flykt log_info("Listening on %s as %i.", strna(name), fd);
f12ed3bf0b315fc88d5fbdf5bdca14b218c86e0cPatrik Flyktstatic int launch(char* name, char **argv, char **env, int fds) {
f12ed3bf0b315fc88d5fbdf5bdca14b218c86e0cPatrik Flykt static const char* tocopy[] = {"TERM=", "PATH=", "USER=", "HOME="};
f12ed3bf0b315fc88d5fbdf5bdca14b218c86e0cPatrik Flykt /* PATH, TERM, HOME, USER, LISTEN_FDS, LISTEN_PID, NULL */
859cca44f834ab1cc3e41fa6b94744f1856ab027Patrik Flykt envp[n_env] = strv_find_prefix(env, tocopy[i]);
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 log_error("Failed to execp %s (%s): %m", name, tmp);
859cca44f834ab1cc3e41fa6b94744f1856ab027Patrik Flyktstatic int launch1(const char* child, char** argv, char **env, int fd) {
859cca44f834ab1cc3e41fa6b94744f1856ab027Patrik Flykt /* In the child */
859cca44f834ab1cc3e41fa6b94744f1856ab027Patrik Flykt if (r < 0) {
859cca44f834ab1cc3e41fa6b94744f1856ab027Patrik Flykt log_error("Failed to dup connection to stdin: %m");
859cca44f834ab1cc3e41fa6b94744f1856ab027Patrik Flykt if (r < 0) {
859cca44f834ab1cc3e41fa6b94744f1856ab027Patrik Flykt log_error("Failed to dup connection to stdout: %m");
859cca44f834ab1cc3e41fa6b94744f1856ab027Patrik Flykt if (r < 0) {
859cca44f834ab1cc3e41fa6b94744f1856ab027Patrik Flykt log_error("Failed to close dupped connection: %m");
859cca44f834ab1cc3e41fa6b94744f1856ab027Patrik Flykt /* Make sure the child goes away when the parent dies */
859cca44f834ab1cc3e41fa6b94744f1856ab027Patrik Flykt /* Check whether our parent died before we were able
859cca44f834ab1cc3e41fa6b94744f1856ab027Patrik Flykt * to set the death signal */
859cca44f834ab1cc3e41fa6b94744f1856ab027Patrik Flykt log_error("Failed to exec child %s: %m", child);
859cca44f834ab1cc3e41fa6b94744f1856ab027Patrik Flykt log_info("Spawned %s (%s) as PID %d", child, tmp, child_pid);
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 log_error("Failed to accept connection on fd:%d: %m", fd);
859cca44f834ab1cc3e41fa6b94744f1856ab027Patrik Flykt log_info("Connection from %s to %s", strna(peer), strna(local));
859cca44f834ab1cc3e41fa6b94744f1856ab027Patrik Flykt/* SIGCHLD handler. */
859cca44f834ab1cc3e41fa6b94744f1856ab027Patrik Flyktstatic void sigchld_hdl(int sig, siginfo_t *t, void *data) {
859cca44f834ab1cc3e41fa6b94744f1856ab027Patrik Flykt log_info("Child %d died with code %d", t->si_pid, t->si_status);
859cca44f834ab1cc3e41fa6b94744f1856ab027Patrik Flykt /* Wait for a dead child. */
859cca44f834ab1cc3e41fa6b94744f1856ab027Patrik Flyktstatic int install_chld_handler(void) {
859cca44f834ab1cc3e41fa6b94744f1856ab027Patrik Flykt log_error("Failed to install SIGCHLD handler: %m");
859cca44f834ab1cc3e41fa6b94744f1856ab027Patrik Flyktstatic void help(void) {
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 "Note: file descriptors from sd_listen_fds() will be passed through.\n"
2ea8857effb833615b16d10fc7a19a7104c19e13Patrik Flykt { "environment", required_argument, NULL, 'E' }, /* alias */
5e256ea7d3d556b3a1fb5c1faa94ec6a8833e53ePatrik Flykt while ((c = getopt_long(argc, argv, "+hl:aE:", options, NULL)) >= 0)
5e256ea7d3d556b3a1fb5c1faa94ec6a8833e53ePatrik Flykt return 0 /* done */;
5e256ea7d3d556b3a1fb5c1faa94ec6a8833e53ePatrik Flykt log_error("%s: command to execute is missing.",
5e256ea7d3d556b3a1fb5c1faa94ec6a8833e53ePatrik Flykt if (n == 0) {
5e256ea7d3d556b3a1fb5c1faa94ec6a8833e53ePatrik Flykt log_error("No sockets to listen on specified or passed in.");
5e256ea7d3d556b3a1fb5c1faa94ec6a8833e53ePatrik Flykt if (r < 0) {
5e256ea7d3d556b3a1fb5c1faa94ec6a8833e53ePatrik Flykt log_info("Communication attempt on fd %i.", event.data.fd);