activate.c revision 7b7afdfc072b14a4fa4dc195f50becaa7cecc5e8
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2013 Zbigniew Jędrzejewski-Szmek
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <getopt.h>
#include <unistd.h>
#include "sd-daemon.h"
#include "alloc-util.h"
#include "fd-util.h"
#include "log.h"
#include "macro.h"
#include "signal-util.h"
#include "socket-util.h"
#include "string-util.h"
#include "strv.h"
static char** arg_listen = NULL;
static bool arg_accept = false;
static bool arg_datagram = false;
static char** arg_setenv = NULL;
static const char *arg_fdname = NULL;
struct epoll_event ev = {
};
int r;
if (r < 0)
return 0;
}
char **address;
int n, fd, r;
int count = 0;
n = sd_listen_fds(true);
if (n < 0)
return log_error_errno(n, "Failed to read listening file descriptors from environment: %m");
if (n > 0) {
log_info("Received %i descriptors via the environment.", n);
if (r < 0)
return r;
count ++;
}
}
/* Close logging and all other descriptors */
if (arg_listen) {
int except[3 + n];
log_close();
}
/** Note: we leak some fd's on error here. I doesn't matter
* much, since the program will exit immediately anyway, but
* would be a pain to fix.
*/
if (arg_datagram)
else
if (fd < 0) {
log_open();
}
count ++;
}
if (arg_listen)
log_open();
if (*epoll_fd < 0)
if (r < 0)
return r;
}
return count;
}
char **s;
unsigned i;
/* PATH, TERM, HOME, USER, LISTEN_FDS, LISTEN_PID, LISTEN_FDNAMES, NULL */
if (!envp)
return log_oom();
STRV_FOREACH(s, arg_setenv) {
if (strchr(*s, '='))
else {
_cleanup_free_ char *p;
p = strappend(*s, "=");
if (!p)
return log_oom();
n_env ++;
}
}
for (i = 0; i < ELEMENTSOF(tocopy); i++) {
n_env ++;
}
return log_oom();
if (arg_fdname) {
char *e;
if (!e)
return log_oom();
for (i = 1; i < (unsigned) fds; i++) {
char *c;
if (!c) {
free(e);
return log_oom();
}
free(e);
e = c;
}
}
if (!tmp)
return log_oom();
}
int r;
if (!tmp)
return log_oom();
parent_pid = getpid();
if (child_pid < 0)
/* In the child */
if (child_pid == 0) {
(void) reset_all_signal_handlers();
(void) reset_signal_mask();
if (r < 0) {
}
if (r < 0) {
}
if (r < 0) {
}
/* Make sure the child goes away when the parent dies */
/* Check whether our parent died before we were able
* to set the death signal */
if (getppid() != parent_pid)
}
return 0;
}
if (fd2 < 0) {
return fd2;
}
}
/* SIGCHLD handler. */
/* Wait for a dead child. */
}
static int install_chld_handler(void) {
int r;
.sa_flags = SA_SIGINFO,
};
if (r < 0)
return r;
}
static void help(void) {
printf("%s [OPTIONS...]\n\n"
"Listen on sockets and launch child on connection.\n\n"
"Options:\n"
" -d --datagram Datagram sockets\n"
" -l --listen=ADDR Listen for raw connections at ADDR\n"
" -a --accept Spawn separate child for each connection\n"
" -h --help Show this help and exit\n"
" -E --setenv=NAME[=VALUE] Pass an environment variable to children\n"
" --version Print version string and exit\n"
"\n"
"Note: file descriptors from sd_listen_fds() will be passed through.\n"
}
enum {
ARG_VERSION = 0x100,
};
{}
};
int c, r;
switch(c) {
case 'h':
help();
return 0;
case ARG_VERSION:
return version();
case 'l':
if (r < 0)
return log_oom();
break;
case 'd':
arg_datagram = true;
break;
case 'a':
arg_accept = true;
break;
case 'E':
if (r < 0)
return log_oom();
break;
case ARG_FDNAME:
if (!fdname_is_valid(optarg)) {
return -EINVAL;
}
arg_fdname = optarg;
break;
case '?':
return -EINVAL;
default:
assert_not_reached("Unhandled option");
}
log_error("%s: command to execute is missing.",
return -EINVAL;
}
if (arg_datagram && arg_accept) {
log_error("Datagram sockets do not accept connections. "
"The --datagram and --accept options may not be combined.");
return -EINVAL;
}
return 1 /* work to do */;
}
int r, n;
int epoll_fd = -1;
log_open();
if (r <= 0)
return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
r = install_chld_handler();
if (r < 0)
return EXIT_FAILURE;
if (n < 0)
return EXIT_FAILURE;
if (n == 0) {
log_error("No sockets to listen on specified or passed in.");
return EXIT_FAILURE;
}
for (;;) {
struct epoll_event event;
if (r < 0) {
continue;
return EXIT_FAILURE;
}
if (arg_accept) {
if (r < 0)
return EXIT_FAILURE;
} else
break;
}
return EXIT_SUCCESS;
}