mirror of
https://github.com/systemd/systemd.git
synced 2025-01-11 09:18:07 +03:00
systemd-activate: add a socket-activation test tool
This commit is contained in:
parent
5674767ec2
commit
2ca0435be9
@ -44,6 +44,7 @@ MANPAGES += \
|
||||
man/shutdown.8 \
|
||||
man/sysctl.d.5 \
|
||||
man/systemctl.1 \
|
||||
man/systemd-activate.8 \
|
||||
man/systemd-analyze.1 \
|
||||
man/systemd-ask-password-console.service.8 \
|
||||
man/systemd-ask-password.1 \
|
||||
|
14
Makefile.am
14
Makefile.am
@ -2313,6 +2313,18 @@ EXTRA_DIST += \
|
||||
src/libsystemd-id128/libsystemd-id128.pc.in \
|
||||
src/libsystemd-id128/libsystemd-id128.sym
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
rootlibexec_PROGRAMS += \
|
||||
systemd-activate
|
||||
|
||||
systemd_activate_SOURCES = \
|
||||
src/activate/activate.c
|
||||
|
||||
systemd_activate_LDADD = \
|
||||
libsystemd-shared.la \
|
||||
libsystemd-daemon.la
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
systemd_journald_SOURCES = \
|
||||
src/journal/journald.c \
|
||||
@ -2559,6 +2571,8 @@ libsystemd-journal-uninstall-hook:
|
||||
INSTALL_EXEC_HOOKS += libsystemd-journal-install-hook
|
||||
UNINSTALL_EXEC_HOOKS += libsystemd-journal-uninstall-hook
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# Update catalog on installation. Do not bother if installing
|
||||
# in DESTDIR, since this is likely for packaging purposes.
|
||||
catalog-update-hook:
|
||||
|
2
TODO
2
TODO
@ -350,8 +350,6 @@ Features:
|
||||
|
||||
* explore multiple service instances per listening socket idea
|
||||
|
||||
* testing tool for socket activation: some binary that listens on a socket and passes it on using the usual socket activation protocol to some server.
|
||||
|
||||
* shutdown: don't read-only mount anything when running in container
|
||||
|
||||
* MountFlags=shared acts as MountFlags=slave right now.
|
||||
|
171
man/systemd-activate.xml
Normal file
171
man/systemd-activate.xml
Normal file
@ -0,0 +1,171 @@
|
||||
<?xml version='1.0'?> <!--*-nxml-*-->
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||
|
||||
<!--
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2013 Zbigniew Jędrzejewski-Szmek
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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/>.
|
||||
-->
|
||||
|
||||
<refentry id="systemd-journal-gatewayd.service">
|
||||
|
||||
<refentryinfo>
|
||||
<title>systemd-activate</title>
|
||||
<productname>systemd</productname>
|
||||
|
||||
<authorgroup>
|
||||
<author>
|
||||
<contrib>Developer</contrib>
|
||||
<firstname>Zbigniew</firstname>
|
||||
<surname>Jędrzejewski-Szmek</surname>
|
||||
<email>zbyszek@in.waw.pl</email>
|
||||
</author>
|
||||
</authorgroup>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>systemd-activate</refentrytitle>
|
||||
<manvolnum>8</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>systemd-activate</refname>
|
||||
<refpurpose>Test socket activation of daemons</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>/usr/lib/systemd/systemd-activate</command>
|
||||
<arg choice="opt" rep="repeat">OPTIONS</arg>
|
||||
<arg choice="plain"><replaceable>daemon</replaceable></arg>
|
||||
<arg choice="opt" rep="repeat">OPTIONS</arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para><command>systemd-activate</command> can be used to
|
||||
launch a socket activated daemon from the command-line for
|
||||
testing purposes. It can also be used to launch single instances
|
||||
of the daemon per connection (inetd-style).
|
||||
</para>
|
||||
|
||||
<para>The daemon to launch and its options should be specifed
|
||||
after options intended for <command>systemd-activate</command>.
|
||||
</para>
|
||||
|
||||
<para>If the <option>-a</option> option is given, file descriptor
|
||||
of the connection will be used as the standard input and output of
|
||||
the launched process. Otherwise, standard input and output will be
|
||||
inherited, and sockets will be passed through file descriptors 3
|
||||
and higher. Sockets passed through <varname>$LISTEN_FDS</varname>
|
||||
to <command>systemd-activate</command> will be passed through to
|
||||
the dameon, in the original positions. Other sockets specified
|
||||
with <option>--listen</option> will use consecutive descriptors.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Options</title>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>--help</option></term>
|
||||
<term><option>-h</option></term>
|
||||
|
||||
<listitem><para>Prints a short help
|
||||
text and exits.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--version</option></term>
|
||||
|
||||
<listitem><para>Prints a short version
|
||||
string and exits.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-l</option></term>
|
||||
<term><option>--listen=<replaceable>address</replaceable></option></term>
|
||||
|
||||
<listitem><para>Listen on this <replaceable>address</replaceable>.
|
||||
Takes a string like <literal>2000</literal> or
|
||||
<literal>127.0.0.1:2001</literal>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-a</option></term>
|
||||
<term><option>--accept</option></term>
|
||||
|
||||
<listitem><para>Launch a separate instance of daemon per
|
||||
connection and pass the connection socket as standard input
|
||||
and standard output.</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Environment variables</title>
|
||||
<variablelist class='environment-variables'>
|
||||
<varlistentry>
|
||||
<term><varname>$LISTEN_FDS</varname></term>
|
||||
<term><varname>$LISTEN_PID</varname></term>
|
||||
|
||||
<para>See
|
||||
<citerefentry><refentrytitle>sd_listen_fds</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>$SYSTEMD_LOG_TARGET</varname></term>
|
||||
<term><varname>$SYSTEMD_LOG_LEVEL</varname></term>
|
||||
<term><varname>$SYSTEMD_LOG_COLOR</varname></term>
|
||||
<term><varname>$SYSTEMD_LOG_LOCATION</varname></term>
|
||||
|
||||
<para>Same as in
|
||||
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Example 1</title>
|
||||
|
||||
<programlisting>$ /usr/lib/systemd/systemd-activate -l 2000 -a cat</programlisting>
|
||||
|
||||
<para>This runs an echo server on port 2000.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Example 2</title>
|
||||
|
||||
<programlisting>$ /usr/lib/systemd/systemd-activate -l 19531 /usr/lib/systemd/systemd-journal-gatewayd</programlisting>
|
||||
|
||||
<para>This runs a socket activated instance of
|
||||
<citerefentry><refentrytitle>systemd-journal-gatewayd</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See Also</title>
|
||||
<para>
|
||||
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd.socket</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>cat</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||
</para>
|
||||
</refsect1>
|
||||
</refentry>
|
410
src/activate/activate.c
Normal file
410
src/activate/activate.c
Normal file
@ -0,0 +1,410 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2013 Zbigniew Jędrzejewski-Szmek
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
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 <sys/epoll.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/wait.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_args = NULL;
|
||||
|
||||
static int add_epoll(int epoll_fd, int fd) {
|
||||
int r;
|
||||
struct epoll_event ev = {EPOLLIN};
|
||||
ev.data.fd = fd;
|
||||
|
||||
assert(epoll_fd >= 0);
|
||||
assert(fd >= 0);
|
||||
|
||||
r = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
|
||||
if (r < 0)
|
||||
log_error("Failed to add event on epoll fd:%d for fd:%d: %s",
|
||||
epoll_fd, fd, strerror(-r));
|
||||
return r;
|
||||
}
|
||||
|
||||
static int set_nocloexec(int fd) {
|
||||
int flags;
|
||||
|
||||
flags = fcntl(fd, F_GETFD);
|
||||
if (flags < 0) {
|
||||
log_error("Querying flags for fd:%d: %m", fd);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (!(flags & FD_CLOEXEC))
|
||||
return 0;
|
||||
|
||||
if (fcntl(fd, F_SETFD, flags & ~FD_CLOEXEC) < 0) {
|
||||
log_error("Settings flags for fd:%d: %m", fd);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int print_socket(const char* desc, int fd) {
|
||||
int r;
|
||||
SocketAddress addr = {
|
||||
.size = sizeof(union sockaddr_union),
|
||||
.type = SOCK_STREAM,
|
||||
};
|
||||
int family;
|
||||
|
||||
r = getsockname(fd, &addr.sockaddr.sa, &addr.size);
|
||||
if (r < 0) {
|
||||
log_warning("Failed to query socket on fd:%d: %m", fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
family = socket_address_family(&addr);
|
||||
switch(family) {
|
||||
case AF_INET:
|
||||
case AF_INET6: {
|
||||
char* _cleanup_free_ a = NULL;
|
||||
r = socket_address_print(&addr, &a);
|
||||
if (r < 0)
|
||||
log_warning("socket_address_print(): %s", strerror(-r));
|
||||
else
|
||||
log_info("%s %s address %s",
|
||||
desc,
|
||||
family == AF_INET ? "IP" : "IPv6",
|
||||
a);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
log_warning("Connection with unknown family %d", family);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int open_sockets(int *epoll_fd, bool accept) {
|
||||
int n, fd;
|
||||
int count = 0;
|
||||
char **address;
|
||||
|
||||
n = sd_listen_fds(true);
|
||||
if (n < 0) {
|
||||
log_error("Failed to read listening file descriptors from environment: %s",
|
||||
strerror(-n));
|
||||
return n;
|
||||
}
|
||||
log_info("Received %d descriptors", n);
|
||||
|
||||
for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
|
||||
log_debug("Received descriptor fd:%d", fd);
|
||||
print_socket("Listening on", fd);
|
||||
|
||||
if (!arg_accept) {
|
||||
int r = set_nocloexec(fd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
count ++;
|
||||
}
|
||||
|
||||
STRV_FOREACH(address, arg_listen) {
|
||||
log_info("Opening address %s", *address);
|
||||
|
||||
fd = make_socket_fd(*address, SOCK_STREAM | (arg_accept*SOCK_CLOEXEC));
|
||||
if (fd < 0) {
|
||||
log_error("Failed to open '%s': %s", *address, strerror(-fd));
|
||||
return fd;
|
||||
}
|
||||
|
||||
count ++;
|
||||
}
|
||||
|
||||
*epoll_fd = epoll_create1(EPOLL_CLOEXEC);
|
||||
if (*epoll_fd < 0) {
|
||||
log_error("Failed to create epoll object: %m");
|
||||
return -errno;
|
||||
}
|
||||
|
||||
for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + count; fd++) {
|
||||
int r = add_epoll(*epoll_fd, fd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int launch(char* name, char **argv, char **environ, int fds) {
|
||||
unsigned n_env = 0;
|
||||
char* envp[7] = {NULL}; /* PATH, TERM, HOME, USER, LISTEN_FDS, LISTEN_PID */
|
||||
static const char* tocopy[] = {"TERM=", "PATH=", "USER=", "HOME="};
|
||||
char _cleanup_free_ *tmp = NULL;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < ELEMENTSOF(tocopy); i++) {
|
||||
envp[n_env] = strv_find_prefix(environ, tocopy[i]);
|
||||
if (envp[n_env])
|
||||
n_env ++;
|
||||
}
|
||||
|
||||
if ((asprintf((char**)(envp + n_env++), "LISTEN_FDS=%d", fds) < 0) ||
|
||||
(asprintf((char**)(envp + n_env++), "LISTEN_PID=%d", getpid()) < 0))
|
||||
return log_oom();
|
||||
|
||||
tmp = strv_join(argv, " ");
|
||||
if (!tmp)
|
||||
return log_oom();
|
||||
|
||||
log_info("Execing %s (%s)", name, tmp);
|
||||
execvpe(name, argv, envp);
|
||||
log_error("Failed to execp %s (%s): %m", name, tmp);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
static int launch1(const char* child, char** argv, char **environ, int fd) {
|
||||
pid_t parent_pid, child_pid;
|
||||
int r;
|
||||
|
||||
char _cleanup_free_ *tmp = NULL;
|
||||
tmp = strv_join(argv, " ");
|
||||
if (!tmp)
|
||||
return log_oom();
|
||||
|
||||
parent_pid = getpid();
|
||||
|
||||
child_pid = fork();
|
||||
if (child_pid < 0) {
|
||||
log_error("Failed to fork: %m");
|
||||
return -errno;
|
||||
}
|
||||
|
||||
/* In the child */
|
||||
if (child_pid == 0) {
|
||||
r = dup2(fd, STDIN_FILENO);
|
||||
if (r < 0) {
|
||||
log_error("Failed to dup connection to stdin: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
r = dup2(fd, STDOUT_FILENO);
|
||||
if (r < 0) {
|
||||
log_error("Failed to dup connection to stdout: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
r = close(fd);
|
||||
if (r < 0) {
|
||||
log_error("Failed to close dupped connection: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Make sure the child goes away when the parent dies */
|
||||
if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
|
||||
_exit(EXIT_FAILURE);
|
||||
|
||||
/* Check whether our parent died before we were able
|
||||
* to set the death signal */
|
||||
if (getppid() != parent_pid)
|
||||
_exit(EXIT_SUCCESS);
|
||||
|
||||
execvp(child, argv);
|
||||
log_error("Failed to exec child %s: %m", child);
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
log_info("Spawned %s (%s) as PID %d", child, tmp, child_pid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_accept(const char* name, char **argv, char **envp, int fd) {
|
||||
SocketAddress addr = {
|
||||
.size = sizeof(union sockaddr_union),
|
||||
.type = SOCK_STREAM,
|
||||
};
|
||||
int fd2, r;
|
||||
|
||||
fd2 = accept(fd, &addr.sockaddr.sa, &addr.size);
|
||||
if (fd2 < 0) {
|
||||
log_error("Failed to accept connection on fd:%d: %m", fd);
|
||||
return fd2;
|
||||
}
|
||||
|
||||
print_socket("Connection from", fd2);
|
||||
|
||||
r = launch1(name, argv, envp, fd2);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* SIGCHLD handler. */
|
||||
static void sigchld_hdl(int sig, siginfo_t *t, void *data)
|
||||
{
|
||||
log_info("Child %d died with code %d", t->si_pid, t->si_status);
|
||||
/* Wait for a dead child. */
|
||||
waitpid(t->si_pid, NULL, 0);
|
||||
}
|
||||
|
||||
static int install_chld_handler(void) {
|
||||
int r;
|
||||
struct sigaction act;
|
||||
zero(act);
|
||||
act.sa_flags = SA_SIGINFO;
|
||||
act.sa_sigaction = sigchld_hdl;
|
||||
|
||||
r = sigaction(SIGCHLD, &act, 0);
|
||||
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"
|
||||
" --version Print version string and exit\n"
|
||||
"\n"
|
||||
"Note: file descriptors from sd_listen_fds() will be passed through.\n"
|
||||
, program_invocation_short_name
|
||||
);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_argv(int argc, char *argv[]) {
|
||||
enum {
|
||||
ARG_VERSION = 0x100,
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, ARG_VERSION },
|
||||
{ "listen", required_argument, NULL, 'l' },
|
||||
{ "accept", no_argument, NULL, 'a' },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
int c;
|
||||
|
||||
assert(argc >= 0);
|
||||
assert(argv);
|
||||
|
||||
while ((c = getopt_long(argc, argv, "+hl:sa", options, NULL)) >= 0)
|
||||
switch(c) {
|
||||
case 'h':
|
||||
help();
|
||||
return 0 /* done */;
|
||||
|
||||
case ARG_VERSION:
|
||||
puts(PACKAGE_STRING);
|
||||
puts(SYSTEMD_FEATURES);
|
||||
return 0 /* done */;
|
||||
|
||||
case 'l': {
|
||||
int r = strv_extend(&arg_listen, optarg);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'a':
|
||||
arg_accept = true;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
|
||||
default:
|
||||
log_error("Unknown option code %c", c);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (optind == argc) {
|
||||
log_error("Usage: %s [OPTION...] PROGRAM [OPTION...]",
|
||||
program_invocation_short_name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
arg_args = argv + optind;
|
||||
|
||||
return 1 /* work to do */;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv, char **envp) {
|
||||
int r, n;
|
||||
int epoll_fd = -1;
|
||||
|
||||
log_set_max_level(LOG_DEBUG);
|
||||
log_show_color(true);
|
||||
log_parse_environment();
|
||||
|
||||
r = parse_argv(argc, argv);
|
||||
if (r <= 0)
|
||||
return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
|
||||
r = install_chld_handler();
|
||||
if (r < 0)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
n = open_sockets(&epoll_fd, arg_accept);
|
||||
if (n < 0)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
while (true) {
|
||||
struct epoll_event event;
|
||||
|
||||
r = epoll_wait(epoll_fd, &event, 1, -1);
|
||||
if (r < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
|
||||
log_error("epoll_wait() failed: %m");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
log_info("Communication attempt on fd:%d", event.data.fd);
|
||||
if (arg_accept) {
|
||||
r = do_accept(argv[optind], argv + optind, envp,
|
||||
event.data.fd);
|
||||
if (r < 0)
|
||||
return EXIT_FAILURE;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
launch(argv[optind], argv + optind, envp, n);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
@ -565,6 +565,45 @@ bool socket_address_matches_fd(const SocketAddress *a, int fd) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int make_socket_fd(const char* address, int flags) {
|
||||
SocketAddress a;
|
||||
int fd, r;
|
||||
char _cleanup_free_ *p = NULL;
|
||||
|
||||
r = socket_address_parse(&a, address);
|
||||
if (r < 0) {
|
||||
log_error("failed to parse socket: %s", strerror(-r));
|
||||
return r;
|
||||
}
|
||||
|
||||
fd = socket(socket_address_family(&a), flags, 0);
|
||||
if (fd < 0) {
|
||||
log_error("socket(): %m");
|
||||
return -errno;
|
||||
}
|
||||
|
||||
r = socket_address_print(&a, &p);
|
||||
if (r < 0) {
|
||||
log_error("socket_address_print(): %s", strerror(-r));
|
||||
return r;
|
||||
}
|
||||
log_info("Listening on %s", p);
|
||||
|
||||
r = bind(fd, &a.sockaddr.sa, a.size);
|
||||
if (r < 0) {
|
||||
log_error("bind to %s: %m", address);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
r = listen(fd, SOMAXCONN);
|
||||
if (r < 0) {
|
||||
log_error("listen on %s: %m", address);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static const char* const netlink_family_table[] = {
|
||||
[NETLINK_ROUTE] = "route",
|
||||
[NETLINK_FIREWALL] = "firewall",
|
||||
|
@ -88,6 +88,8 @@ bool socket_address_is_netlink(const SocketAddress *a, const char *s);
|
||||
|
||||
bool socket_address_matches_fd(const SocketAddress *a, int fd);
|
||||
|
||||
int make_socket_fd(const char* address, int flags);
|
||||
|
||||
bool socket_address_equal(const SocketAddress *a, const SocketAddress *b);
|
||||
|
||||
bool socket_address_needs_mount(const SocketAddress *a, const char *prefix);
|
||||
|
Loading…
Reference in New Issue
Block a user