activate.c revision 603938e0a9b5379984d7397e3cf81683c0037a53
/*-*- 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 <unistd.h>
#include <fcntl.h>
#include <getopt.h>
#include <systemd/sd-daemon.h>
#include "socket-util.h"
#include "build.h"
#include "log.h"
#include "strv.h"
#include "macro.h"
static char** arg_listen = NULL;
static bool arg_accept = false;
static char** arg_environ = NULL;
struct epoll_event ev = {
};
int r;
if (r < 0) {
return -errno;
}
return 0;
}
int fd, r;
r = socket_address_parse(&a, address);
if (r < 0) {
return r;
}
fd = socket_address_listen(&a, flags, SOMAXCONN, SOCKET_ADDRESS_DEFAULT, NULL, false, false, 0755, 0644, NULL);
if (fd < 0) {
return fd;
}
return fd;
}
char **address;
int n, fd, r;
int count = 0;
n = sd_listen_fds(true);
if (n < 0) {
log_error("Failed to read listening file descriptors from environment: %s",
strerror(-n));
return n;
}
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 (fd < 0) {
log_open();
return fd;
}
count ++;
}
if (arg_listen)
log_open();
if (*epoll_fd < 0) {
log_error("Failed to create epoll object: %m");
return -errno;
}
if (r < 0)
return r;
}
return count;
}
char **s;
unsigned i;
/* PATH, TERM, HOME, USER, LISTEN_FDS, LISTEN_PID, NULL */
if (!envp)
return log_oom();
STRV_FOREACH(s, arg_environ) {
if (strchr(*s, '='))
else {
if (!p)
return log_oom();
n_env ++;
}
}
for (i = 0; i < ELEMENTSOF(tocopy); i++) {
n_env ++;
}
return log_oom();
if (!tmp)
return log_oom();
return -errno;
}
int r;
if (!tmp)
return log_oom();
parent_pid = getpid();
if (child_pid < 0) {
log_error("Failed to fork: %m");
return -errno;
}
/* In the child */
if (child_pid == 0) {
if (r < 0) {
log_error("Failed to dup connection to stdin: %m");
}
if (r < 0) {
log_error("Failed to dup connection to stdout: %m");
}
if (r < 0) {
log_error("Failed to close dupped connection: %m");
}
/* 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;
}
int fd2;
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)
log_error("Failed to install SIGCHLD handler: %m");
return r;
}
static int help(void) {
printf("%s [OPTIONS...]\n\n"
"Listen on sockets and launch child on connection.\n\n"
"Options:\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 --environment=NAME[=VALUE]\n"
" 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"
);
return 0;
}
enum {
ARG_VERSION = 0x100,
};
{}
};
int c;
switch(c) {
case 'h':
return help();
case ARG_VERSION:
return 0 /* done */;
case 'l': {
if (r < 0)
return r;
break;
}
case 'a':
arg_accept = true;
break;
case 'E': {
if (r < 0)
return r;
break;
}
case '?':
return -EINVAL;
default:
assert_not_reached("Unhandled option");
}
log_error("Usage: %s [OPTION...] PROGRAM [OPTION...]",
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;
log_error("epoll_wait() failed: %m");
return EXIT_FAILURE;
}
if (arg_accept) {
if (r < 0)
return EXIT_FAILURE;
} else
break;
}
return EXIT_SUCCESS;
}