mirror of
https://github.com/systemd/systemd.git
synced 2025-03-22 06:50:18 +03:00
Merge pull request #1468 from poettering/fdnames
Add support for naming fds for socket activation and more
This commit is contained in:
commit
e1719ef19d
@ -355,6 +355,7 @@ MANPAGES_ALIAS += \
|
||||
man/sd_journal_set_data_threshold.3 \
|
||||
man/sd_journal_test_cursor.3 \
|
||||
man/sd_journal_wait.3 \
|
||||
man/sd_listen_fds_with_names.3 \
|
||||
man/sd_machine_get_ifindices.3 \
|
||||
man/sd_notifyf.3 \
|
||||
man/sd_pid_notify.3 \
|
||||
@ -643,6 +644,7 @@ man/sd_journal_sendv.3: man/sd_journal_print.3
|
||||
man/sd_journal_set_data_threshold.3: man/sd_journal_get_data.3
|
||||
man/sd_journal_test_cursor.3: man/sd_journal_get_cursor.3
|
||||
man/sd_journal_wait.3: man/sd_journal_get_fd.3
|
||||
man/sd_listen_fds_with_names.3: man/sd_listen_fds.3
|
||||
man/sd_machine_get_ifindices.3: man/sd_machine_get_class.3
|
||||
man/sd_notifyf.3: man/sd_notify.3
|
||||
man/sd_pid_notify.3: man/sd_notify.3
|
||||
@ -1319,6 +1321,9 @@ man/sd_journal_test_cursor.html: man/sd_journal_get_cursor.html
|
||||
man/sd_journal_wait.html: man/sd_journal_get_fd.html
|
||||
$(html-alias)
|
||||
|
||||
man/sd_listen_fds_with_names.html: man/sd_listen_fds.html
|
||||
$(html-alias)
|
||||
|
||||
man/sd_machine_get_ifindices.html: man/sd_machine_get_class.html
|
||||
$(html-alias)
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?xml version='1.0'?> <!--*-nxml-*-->
|
||||
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||
|
||||
@ -45,6 +45,7 @@
|
||||
|
||||
<refnamediv>
|
||||
<refname>sd_listen_fds</refname>
|
||||
<refname>sd_listen_fds_with_names</refname>
|
||||
<refname>SD_LISTEN_FDS_START</refname>
|
||||
<refpurpose>Check for file descriptors passed by the system manager</refpurpose>
|
||||
</refnamediv>
|
||||
@ -59,23 +60,26 @@
|
||||
<funcdef>int <function>sd_listen_fds</function></funcdef>
|
||||
<paramdef>int <parameter>unset_environment</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>int <function>sd_listen_fds_with_names</function></funcdef>
|
||||
<paramdef>int <parameter>unset_environment</parameter></paramdef>
|
||||
<paramdef>char*** <parameter>names</parameter></paramdef>
|
||||
</funcprototype>
|
||||
</funcsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para><function>sd_listen_fds()</function> shall be called by a
|
||||
daemon to check for file descriptors passed by the init system as
|
||||
part of the socket-based activation logic.</para>
|
||||
|
||||
<para>If the <parameter>unset_environment</parameter> parameter is
|
||||
non-zero, <function>sd_listen_fds()</function> will unset the
|
||||
<varname>$LISTEN_FDS</varname> and <varname>$LISTEN_PID</varname>
|
||||
environment variables before returning (regardless of whether the
|
||||
function call itself succeeded or not). Further calls to
|
||||
<function>sd_listen_fds()</function> will then fail, but the
|
||||
variables are no longer inherited by child processes.</para>
|
||||
<para><function>sd_listen_fds()</function> may be invoked by a
|
||||
daemon to check for file descriptors passed by the service manager as
|
||||
part of the socket-based activation logic. It returns the number
|
||||
of received file descriptors. If no file descriptors have been
|
||||
received zero is returned. The first file descriptor may be found
|
||||
at file descriptor number 3
|
||||
(i.e. <constant>SD_LISTEN_FDS_START</constant>), the remaining
|
||||
descriptors follow at 4, 5, 6, ..., if any.</para>
|
||||
|
||||
<para>If a daemon receives more than one file descriptor, they
|
||||
will be passed in the same order as configured in the systemd
|
||||
@ -108,12 +112,86 @@
|
||||
<literal>FDSTORE=1</literal> messages, these file descriptors are
|
||||
passed last, in arbitrary order, and with duplicates
|
||||
removed.</para>
|
||||
|
||||
<para>If the <parameter>unset_environment</parameter> parameter is
|
||||
non-zero, <function>sd_listen_fds()</function> will unset the
|
||||
<varname>$LISTEN_FDS</varname>, <varname>$LISTEN_PID</varname> and
|
||||
<varname>$LISTEN_FDNAMES</varname> environment variables before
|
||||
returning (regardless of whether the function call itself
|
||||
succeeded or not). Further calls to
|
||||
<function>sd_listen_fds()</function> will then return zero, but the
|
||||
variables are no longer inherited by child processes.</para>
|
||||
|
||||
<para><function>sd_listen_fds_with_names()</function> is like
|
||||
<function>sd_listen_fds()</function> but optionally also returns
|
||||
an array of strings with identification names for the passed file
|
||||
descriptors, if that is available, and the
|
||||
<parameter>names</parameter> parameter is non-NULL. This
|
||||
information is read from the <varname>$LISTEN_FDNAMES</varname>
|
||||
variable, which may contain a colon-separated list of names. For
|
||||
socket-activated services, these names may be configured with the
|
||||
<varname>FileDescriptorName=</varname> setting in socket unit
|
||||
files, see
|
||||
<citerefentry><refentrytitle>systemd.socket</refentrytitle><manvolnum>5</manvolnum></citerefentry>
|
||||
for details. For file descriptors pushed into the file descriptor
|
||||
store (see above) the name is set via the
|
||||
<varname>FDNAME=</varname> field transmitted via
|
||||
<function>sd_pid_notify_with_fds()</function>. The primary usecase
|
||||
for these names are services which accept a variety of file
|
||||
descriptors which are not recognizable with functions like
|
||||
<function>sd_is_socket()</function> alone, and thus require
|
||||
identification via a name. It is recommended to rely on named file
|
||||
descriptors only if identification via
|
||||
<function>sd_is_socket()</function> and related calls is not
|
||||
sufficient. Note that the names used are not unique in any
|
||||
way. The returned array of strings has as many entries as file
|
||||
descriptors has been received, plus a final NULL pointer
|
||||
terminating the array. The caller needs to free the array itself
|
||||
and each of its elements with libc's <varname>free()</varname>
|
||||
call after use. If the <parameter>names</parameter> parameter is
|
||||
NULL the call is entirely equivalent to
|
||||
<function>sd_listen_fds()</function>.</para>
|
||||
|
||||
<para>Under specific conditions the following automatic file
|
||||
descriptor names are returned:
|
||||
|
||||
<table>
|
||||
<title>
|
||||
<command>Special names</command>
|
||||
</title>
|
||||
|
||||
<tgroup cols='2'>
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Name</entry>
|
||||
<entry>Description</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><literal>unknown</literal></entry>
|
||||
<entry>The process received no name for the specific file descriptor from the service manager.</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><literal>stored</literal></entry>
|
||||
<entry>The file descriptor originates in the service manager's per-service file descriptor store, and the <varname>FDNAME=</varname> field was absent when the file descriptor was submitted to the service manager.</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><literal>connection</literal></entry>
|
||||
<entry>The service was activated in per-connection style using <varname>Accept=yes</varname> in the socket unit file, and the file descriptor is the connection socket.</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Return Value</title>
|
||||
|
||||
<para>On failure, this call returns a negative errno-style error
|
||||
<para>On failure, these calls returns a negative errno-style error
|
||||
code. If
|
||||
<varname>$LISTEN_FDS</varname>/<varname>$LISTEN_PID</varname> was
|
||||
not set or was not correctly set for this daemon and hence no file
|
||||
@ -128,13 +206,16 @@
|
||||
|
||||
<xi:include href="libsystemd-pkgconfig.xml" xpointer="pkgconfig-text"/>
|
||||
|
||||
<para>Internally, this function checks whether the
|
||||
<varname>$LISTEN_PID</varname> environment variable equals the
|
||||
daemon PID. If not, it returns immediately. Otherwise, it parses
|
||||
the number passed in the <varname>$LISTEN_FDS</varname>
|
||||
<para>Internally, <function>sd_listen_fds()</function> checks
|
||||
whether the <varname>$LISTEN_PID</varname> environment variable
|
||||
equals the daemon PID. If not, it returns immediately. Otherwise,
|
||||
it parses the number passed in the <varname>$LISTEN_FDS</varname>
|
||||
environment variable, then sets the FD_CLOEXEC flag for the parsed
|
||||
number of file descriptors starting from SD_LISTEN_FDS_START.
|
||||
Finally, it returns the parsed number.</para>
|
||||
Finally, it returns the parsed
|
||||
number. <function>sd_listen_fds_with_names()</function> does the
|
||||
same but also parses <varname>$LISTEN_FDNAMES</varname> if
|
||||
set.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
@ -144,15 +225,14 @@
|
||||
<varlistentry>
|
||||
<term><varname>$LISTEN_PID</varname></term>
|
||||
<term><varname>$LISTEN_FDS</varname></term>
|
||||
<term><varname>$LISTEN_FDNAMES</varname></term>
|
||||
|
||||
<listitem><para>Set by the init system
|
||||
for supervised processes that use
|
||||
socket-based activation. This
|
||||
environment variable specifies the
|
||||
data
|
||||
<function>sd_listen_fds()</function>
|
||||
parses. See above for
|
||||
details.</para></listitem>
|
||||
<listitem><para>Set by the service manager for supervised
|
||||
processes that use socket-based activation. This environment
|
||||
variable specifies the data
|
||||
<function>sd_listen_fds()</function> and
|
||||
<function>sd_listen_fds_with_names()</function> parses. See
|
||||
above for details.</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
@ -167,6 +247,7 @@
|
||||
<citerefentry><refentrytitle>sd_is_socket</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_is_socket_inet</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_is_socket_unix</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_pid_notify_with_fds</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>daemon</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd.socket</refentrytitle><manvolnum>5</manvolnum></citerefentry>
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?xml version='1.0'?> <!--*-nxml-*-->
|
||||
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||
|
||||
@ -229,6 +229,27 @@
|
||||
below.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>FDNAME=...</term>
|
||||
|
||||
<listitem><para>When used in combination with
|
||||
<varname>FDSTORE=1</varname> specifies a name for the
|
||||
submitted file descriptors. This name is passed to the service
|
||||
during activation, and may be queried using
|
||||
<citerefentry><refentrytitle>sd_listen_fds_with_names</refentrytitle><manvolnum>3</manvolnum></citerefentry>. File
|
||||
descriptors submitted without this field set, will implicitly
|
||||
get the name <literal>stored</literal> assigned. Note that if
|
||||
multiple file descriptors are submitted at once the specified
|
||||
name will be assigned to all of them. In order to assign
|
||||
different names to submitted file descriptors, submit them in
|
||||
seperate invocations of
|
||||
<function>sd_pid_notify_with_fds()</function>. The name may
|
||||
consist of any ASCII characters, but must not contain control
|
||||
characters or <literal>:</literal>. It may not be longer than
|
||||
255 characters. If a submitted name does not follow these
|
||||
restrictions it is ignored.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
|
||||
<para>It is recommended to prefix variable names that are not
|
||||
@ -358,7 +379,7 @@
|
||||
in order to continue operation after a service restart without
|
||||
losing state use <literal>FDSTORE=1</literal>:</para>
|
||||
|
||||
<programlisting>sd_pid_notify_with_fds(0, 0, "FDSTORE=1", &fd, 1);</programlisting>
|
||||
<programlisting>sd_pid_notify_with_fds(0, 0, "FDSTORE=1\nFDNAME=foobar", &fd, 1);</programlisting>
|
||||
</example>
|
||||
</refsect1>
|
||||
|
||||
@ -367,9 +388,11 @@
|
||||
<para>
|
||||
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd-daemon</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_listen_fds</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_listen_fds_with_names</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_watchdog_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>daemon</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_watchdog_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry>
|
||||
<citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
|
@ -115,6 +115,16 @@
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--fdname=</option><replaceable>NAME</replaceable></term>
|
||||
|
||||
<listitem><para>Specify a name for the activation file
|
||||
descriptors. This is equivalent to setting
|
||||
<varname>FileDescriptorName=</varname> in socket unit files, and
|
||||
enables use of
|
||||
<citerefentry><refentrytitle>sd_listen_fds_with_names</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<xi:include href="standard-options.xml" xpointer="help" />
|
||||
<xi:include href="standard-options.xml" xpointer="version" />
|
||||
</variablelist>
|
||||
@ -126,6 +136,7 @@
|
||||
<varlistentry>
|
||||
<term><varname>$LISTEN_FDS</varname></term>
|
||||
<term><varname>$LISTEN_PID</varname></term>
|
||||
<term><varname>$LISTEN_FDNAMES</varname></term>
|
||||
|
||||
<listitem><para>See
|
||||
<citerefentry><refentrytitle>sd_listen_fds</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para></listitem>
|
||||
@ -165,6 +176,8 @@
|
||||
<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>sd_listen_fds</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_listen_fds_with_names</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry project='man-pages'><refentrytitle>cat</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
@ -95,6 +95,12 @@
|
||||
<arg choice="plain">set-log-level</arg>
|
||||
<arg choice="plain"><replaceable>LEVEL</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
<cmdsynopsis>
|
||||
<command>systemd-analyze</command>
|
||||
<arg choice="opt" rep="repeat">OPTIONS</arg>
|
||||
<arg choice="plain">set-log-target</arg>
|
||||
<arg choice="plain"><replaceable>TARGET</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
<cmdsynopsis>
|
||||
<command>systemd-analyze</command>
|
||||
<arg choice="opt" rep="repeat">OPTIONS</arg>
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?xml version='1.0'?> <!--*-nxml-*-->
|
||||
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||
|
||||
@ -748,6 +748,22 @@
|
||||
list.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>FileDescriptorName=</varname></term>
|
||||
<listitem><para>Assigns a name to all file descriptors this
|
||||
socket unit encapsulates. This is useful to help activated
|
||||
services to identify specific file descriptors, if multiple
|
||||
are passed. Services may use the
|
||||
<citerefentry><refentrytitle>sd_listen_fds_with_names</refentrytitle><manvolnum>3</manvolnum></citerefentry>
|
||||
call to acquire the names configured for the received file
|
||||
descriptors. Names may contain any ASCII character, but must
|
||||
exclude control characters or <literal>:</literal>, and must
|
||||
be at most 255 characters in length. If this setting is not
|
||||
used the file descriptor name defaults to the name of the
|
||||
socket unit, including its <filename>.socket</filename>
|
||||
suffix.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
|
||||
<para>Check
|
||||
@ -768,9 +784,10 @@
|
||||
<citerefentry><refentrytitle>systemd.kill</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd.directives</refentrytitle><manvolnum>7</manvolnum></citerefentry>
|
||||
<citerefentry><refentrytitle>systemd.directives</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_listen_fds</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_listen_fds_with_names</refentrytitle><manvolnum>3</manvolnum></citerefentry>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
For more extensive descriptions see the "systemd for Developers" series:
|
||||
<ulink url="http://0pointer.de/blog/projects/socket-activation.html">Socket Activation</ulink>,
|
||||
|
@ -835,6 +835,7 @@
|
||||
<varlistentry>
|
||||
<term><varname>$LISTEN_PID</varname></term>
|
||||
<term><varname>$LISTEN_FDS</varname></term>
|
||||
<term><varname>$LISTEN_FDNAMES</varname></term>
|
||||
|
||||
<listitem><para>Set by systemd for supervised processes during
|
||||
socket-based activation. See
|
||||
|
@ -26,7 +26,7 @@
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "systemd/sd-daemon.h"
|
||||
#include "sd-daemon.h"
|
||||
|
||||
#include "log.h"
|
||||
#include "macro.h"
|
||||
@ -38,6 +38,7 @@ static char** arg_listen = NULL;
|
||||
static bool arg_accept = false;
|
||||
static char** arg_args = NULL;
|
||||
static char** arg_setenv = NULL;
|
||||
static const char *arg_fdname = NULL;
|
||||
|
||||
static int add_epoll(int epoll_fd, int fd) {
|
||||
struct epoll_event ev = {
|
||||
@ -136,8 +137,8 @@ static int launch(char* name, char **argv, char **env, int fds) {
|
||||
|
||||
length = strv_length(arg_setenv);
|
||||
|
||||
/* PATH, TERM, HOME, USER, LISTEN_FDS, LISTEN_PID, NULL */
|
||||
envp = new0(char *, length + 7);
|
||||
/* PATH, TERM, HOME, USER, LISTEN_FDS, LISTEN_PID, LISTEN_FDNAMES, NULL */
|
||||
envp = new0(char *, length + 8);
|
||||
if (!envp)
|
||||
return log_oom();
|
||||
|
||||
@ -145,7 +146,9 @@ static int launch(char* name, char **argv, char **env, int fds) {
|
||||
if (strchr(*s, '='))
|
||||
envp[n_env++] = *s;
|
||||
else {
|
||||
_cleanup_free_ char *p = strappend(*s, "=");
|
||||
_cleanup_free_ char *p;
|
||||
|
||||
p = strappend(*s, "=");
|
||||
if (!p)
|
||||
return log_oom();
|
||||
envp[n_env] = strv_find_prefix(env, p);
|
||||
@ -164,15 +167,37 @@ static int launch(char* name, char **argv, char **env, int fds) {
|
||||
(asprintf((char**)(envp + n_env++), "LISTEN_PID=%d", getpid()) < 0))
|
||||
return log_oom();
|
||||
|
||||
if (arg_fdname) {
|
||||
char *e;
|
||||
|
||||
e = strappend("LISTEN_FDNAMES=", arg_fdname);
|
||||
if (!e)
|
||||
return log_oom();
|
||||
|
||||
for (i = 1; i < (unsigned) fds; i++) {
|
||||
char *c;
|
||||
|
||||
c = strjoin(e, ":", arg_fdname, NULL);
|
||||
if (!c) {
|
||||
free(e);
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
free(e);
|
||||
e = c;
|
||||
}
|
||||
|
||||
envp[n_env++] = e;
|
||||
}
|
||||
|
||||
tmp = strv_join(argv, " ");
|
||||
if (!tmp)
|
||||
return log_oom();
|
||||
|
||||
log_info("Execing %s (%s)", name, tmp);
|
||||
execvpe(name, argv, envp);
|
||||
log_error_errno(errno, "Failed to execp %s (%s): %m", name, tmp);
|
||||
|
||||
return -errno;
|
||||
return log_error_errno(errno, "Failed to execp %s (%s): %m", name, tmp);
|
||||
}
|
||||
|
||||
static int launch1(const char* child, char** argv, char **env, int fd) {
|
||||
@ -289,6 +314,7 @@ static void help(void) {
|
||||
static int parse_argv(int argc, char *argv[]) {
|
||||
enum {
|
||||
ARG_VERSION = 0x100,
|
||||
ARG_FDNAME,
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
@ -297,11 +323,12 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
{ "listen", required_argument, NULL, 'l' },
|
||||
{ "accept", no_argument, NULL, 'a' },
|
||||
{ "setenv", required_argument, NULL, 'E' },
|
||||
{ "environment", required_argument, NULL, 'E' }, /* alias */
|
||||
{ "environment", required_argument, NULL, 'E' }, /* legacy alias */
|
||||
{ "fdname", required_argument, NULL, ARG_FDNAME },
|
||||
{}
|
||||
};
|
||||
|
||||
int c;
|
||||
int c, r;
|
||||
|
||||
assert(argc >= 0);
|
||||
assert(argv);
|
||||
@ -315,25 +342,27 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
case ARG_VERSION:
|
||||
return version();
|
||||
|
||||
case 'l': {
|
||||
int r = strv_extend(&arg_listen, optarg);
|
||||
case 'l':
|
||||
r = strv_extend(&arg_listen, optarg);
|
||||
if (r < 0)
|
||||
return r;
|
||||
return log_oom();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'a':
|
||||
arg_accept = true;
|
||||
break;
|
||||
|
||||
case 'E': {
|
||||
int r = strv_extend(&arg_setenv, optarg);
|
||||
case 'E':
|
||||
r = strv_extend(&arg_setenv, optarg);
|
||||
if (r < 0)
|
||||
return r;
|
||||
return log_oom();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ARG_FDNAME:
|
||||
arg_fdname = optarg;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
|
@ -277,8 +277,8 @@ char **strv_split_newlines(const char *s) {
|
||||
}
|
||||
|
||||
int strv_split_extract(char ***t, const char *s, const char *separators, ExtractFlags flags) {
|
||||
size_t n = 0, allocated = 0;
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
size_t n = 0, allocated = 0;
|
||||
int r;
|
||||
|
||||
assert(t);
|
||||
@ -302,13 +302,16 @@ int strv_split_extract(char ***t, const char *s, const char *separators, Extract
|
||||
l[n] = NULL;
|
||||
}
|
||||
|
||||
if (!l)
|
||||
if (!l) {
|
||||
l = new0(char*, 1);
|
||||
if (!l)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
*t = l;
|
||||
l = NULL;
|
||||
|
||||
return 0;
|
||||
return (int) n;
|
||||
}
|
||||
|
||||
char *strv_join(char **l, const char *separator) {
|
||||
@ -745,3 +748,41 @@ char **strv_skip(char **l, size_t n) {
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
int strv_extend_n(char ***l, const char *value, size_t n) {
|
||||
size_t i, j, k;
|
||||
char **nl;
|
||||
|
||||
assert(l);
|
||||
|
||||
if (!value)
|
||||
return 0;
|
||||
if (n == 0)
|
||||
return 0;
|
||||
|
||||
/* Adds the value value n times to l */
|
||||
|
||||
k = strv_length(*l);
|
||||
|
||||
nl = realloc(*l, sizeof(char*) * (k + n + 1));
|
||||
if (!nl)
|
||||
return -ENOMEM;
|
||||
|
||||
*l = nl;
|
||||
|
||||
for (i = k; i < k + n; i++) {
|
||||
nl[i] = strdup(value);
|
||||
if (!nl[i])
|
||||
goto rollback;
|
||||
}
|
||||
|
||||
nl[i] = NULL;
|
||||
return 0;
|
||||
|
||||
rollback:
|
||||
for (j = k; j < i; i++)
|
||||
free(nl[j]);
|
||||
|
||||
nl[k] = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
@ -158,3 +158,5 @@ static inline bool strv_fnmatch_or_empty(char* const* patterns, const char *s, i
|
||||
char ***strv_free_free(char ***l);
|
||||
|
||||
char **strv_skip(char **l, size_t n);
|
||||
|
||||
int strv_extend_n(char ***l, const char *value, size_t n);
|
||||
|
@ -6845,3 +6845,28 @@ int version(void) {
|
||||
SYSTEMD_FEATURES);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool fdname_is_valid(const char *s) {
|
||||
const char *p;
|
||||
|
||||
/* Validates a name for $LISTEN_NAMES. We basically allow
|
||||
* everything ASCII that's not a control character. Also, as
|
||||
* special exception the ":" character is not allowed, as we
|
||||
* use that as field separator in $LISTEN_NAMES.
|
||||
*
|
||||
* Note that the empty string is explicitly allowed here.*/
|
||||
|
||||
if (!s)
|
||||
return false;
|
||||
|
||||
for (p = s; *p; p++) {
|
||||
if (*p < ' ')
|
||||
return false;
|
||||
if (*p >= 127)
|
||||
return false;
|
||||
if (*p == ':')
|
||||
return false;
|
||||
}
|
||||
|
||||
return p - s < 256;
|
||||
}
|
||||
|
@ -941,3 +941,5 @@ int receive_one_fd(int transport_fd, int flags);
|
||||
void nop_signal_handler(int sig);
|
||||
|
||||
int version(void);
|
||||
|
||||
bool fdname_is_valid(const char *s);
|
||||
|
@ -84,6 +84,25 @@ static int property_get_listen(
|
||||
return sd_bus_message_close_container(reply);
|
||||
}
|
||||
|
||||
|
||||
static int property_get_fdname(
|
||||
sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *userdata,
|
||||
sd_bus_error *error) {
|
||||
|
||||
Socket *s = SOCKET(userdata);
|
||||
|
||||
assert(bus);
|
||||
assert(reply);
|
||||
assert(s);
|
||||
|
||||
return sd_bus_message_append(reply, "s", socket_fdname(s));
|
||||
}
|
||||
|
||||
const sd_bus_vtable bus_socket_vtable[] = {
|
||||
SD_BUS_VTABLE_START(0),
|
||||
SD_BUS_PROPERTY("BindIPv6Only", "s", property_get_bind_ipv6_only, offsetof(Socket, bind_ipv6_only), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
@ -128,6 +147,7 @@ const sd_bus_vtable bus_socket_vtable[] = {
|
||||
SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Socket, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
SD_BUS_PROPERTY("NConnections", "u", bus_property_get_unsigned, offsetof(Socket, n_connections), 0),
|
||||
SD_BUS_PROPERTY("NAccepted", "u", bus_property_get_unsigned, offsetof(Socket, n_accepted), 0),
|
||||
SD_BUS_PROPERTY("FileDescriptorName", "s", property_get_fdname, 0, 0),
|
||||
BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPre", offsetof(Socket, exec_command[SOCKET_EXEC_START_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
|
||||
BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPost", offsetof(Socket, exec_command[SOCKET_EXEC_START_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
|
||||
BUS_EXEC_COMMAND_LIST_VTABLE("ExecStopPre", offsetof(Socket, exec_command[SOCKET_EXEC_STOP_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
|
||||
|
@ -21,18 +21,18 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <glob.h>
|
||||
#include <grp.h>
|
||||
#include <poll.h>
|
||||
#include <glob.h>
|
||||
#include <utmpx.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <sys/personality.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
#include <utmpx.h>
|
||||
|
||||
#ifdef HAVE_PAM
|
||||
#include <security/pam_appl.h>
|
||||
@ -50,37 +50,38 @@
|
||||
#include <sys/apparmor.h>
|
||||
#endif
|
||||
|
||||
#include "barrier.h"
|
||||
#include "sd-messages.h"
|
||||
#include "rm-rf.h"
|
||||
#include "strv.h"
|
||||
#include "macro.h"
|
||||
#include "capability.h"
|
||||
#include "util.h"
|
||||
#include "log.h"
|
||||
#include "ioprio.h"
|
||||
#include "securebits.h"
|
||||
#include "namespace.h"
|
||||
#include "exit-status.h"
|
||||
#include "missing.h"
|
||||
#include "utmp-wtmp.h"
|
||||
#include "def.h"
|
||||
#include "path-util.h"
|
||||
#include "env-util.h"
|
||||
#include "fileio.h"
|
||||
#include "unit.h"
|
||||
#include "async.h"
|
||||
#include "selinux-util.h"
|
||||
#include "errno-list.h"
|
||||
|
||||
#include "af-list.h"
|
||||
#include "mkdir.h"
|
||||
#include "smack-util.h"
|
||||
#include "async.h"
|
||||
#include "barrier.h"
|
||||
#include "bus-endpoint.h"
|
||||
#include "cap-list.h"
|
||||
#include "capability.h"
|
||||
#include "def.h"
|
||||
#include "env-util.h"
|
||||
#include "errno-list.h"
|
||||
#include "exit-status.h"
|
||||
#include "fileio.h"
|
||||
#include "formats-util.h"
|
||||
#include "ioprio.h"
|
||||
#include "log.h"
|
||||
#include "macro.h"
|
||||
#include "missing.h"
|
||||
#include "mkdir.h"
|
||||
#include "namespace.h"
|
||||
#include "path-util.h"
|
||||
#include "process-util.h"
|
||||
#include "terminal-util.h"
|
||||
#include "rm-rf.h"
|
||||
#include "securebits.h"
|
||||
#include "selinux-util.h"
|
||||
#include "signal-util.h"
|
||||
#include "smack-util.h"
|
||||
#include "strv.h"
|
||||
#include "terminal-util.h"
|
||||
#include "unit.h"
|
||||
#include "util.h"
|
||||
#include "utmp-wtmp.h"
|
||||
|
||||
#ifdef HAVE_APPARMOR
|
||||
#include "apparmor-util.h"
|
||||
@ -1198,6 +1199,7 @@ static void do_idle_pipe_dance(int idle_pipe[4]) {
|
||||
static int build_environment(
|
||||
const ExecContext *c,
|
||||
unsigned n_fds,
|
||||
char ** fd_names,
|
||||
usec_t watchdog_usec,
|
||||
const char *home,
|
||||
const char *username,
|
||||
@ -1211,11 +1213,13 @@ static int build_environment(
|
||||
assert(c);
|
||||
assert(ret);
|
||||
|
||||
our_env = new0(char*, 10);
|
||||
our_env = new0(char*, 11);
|
||||
if (!our_env)
|
||||
return -ENOMEM;
|
||||
|
||||
if (n_fds > 0) {
|
||||
_cleanup_free_ char *joined = NULL;
|
||||
|
||||
if (asprintf(&x, "LISTEN_PID="PID_FMT, getpid()) < 0)
|
||||
return -ENOMEM;
|
||||
our_env[n_env++] = x;
|
||||
@ -1223,6 +1227,15 @@ static int build_environment(
|
||||
if (asprintf(&x, "LISTEN_FDS=%u", n_fds) < 0)
|
||||
return -ENOMEM;
|
||||
our_env[n_env++] = x;
|
||||
|
||||
joined = strv_join(fd_names, ":");
|
||||
if (!joined)
|
||||
return -ENOMEM;
|
||||
|
||||
x = strjoin("LISTEN_FDNAMES=", joined, NULL);
|
||||
if (!x)
|
||||
return -ENOMEM;
|
||||
our_env[n_env++] = x;
|
||||
}
|
||||
|
||||
if (watchdog_usec > 0) {
|
||||
@ -1273,7 +1286,7 @@ static int build_environment(
|
||||
}
|
||||
|
||||
our_env[n_env++] = NULL;
|
||||
assert(n_env <= 10);
|
||||
assert(n_env <= 11);
|
||||
|
||||
*ret = our_env;
|
||||
our_env = NULL;
|
||||
@ -1850,7 +1863,7 @@ static int exec_child(
|
||||
#endif
|
||||
}
|
||||
|
||||
r = build_environment(context, n_fds, params->watchdog_usec, home, username, shell, &our_env);
|
||||
r = build_environment(context, n_fds, params->fd_names, params->watchdog_usec, home, username, shell, &our_env);
|
||||
if (r < 0) {
|
||||
*exit_status = EXIT_MEMORY;
|
||||
return r;
|
||||
|
@ -208,19 +208,30 @@ struct ExecContext {
|
||||
|
||||
struct ExecParameters {
|
||||
char **argv;
|
||||
int *fds; unsigned n_fds;
|
||||
|
||||
int *fds;
|
||||
char **fd_names;
|
||||
unsigned n_fds;
|
||||
|
||||
char **environment;
|
||||
|
||||
bool apply_permissions;
|
||||
bool apply_chroot;
|
||||
bool apply_tty_stdin;
|
||||
|
||||
bool confirm_spawn;
|
||||
bool selinux_context_net;
|
||||
|
||||
CGroupMask cgroup_supported;
|
||||
const char *cgroup_path;
|
||||
bool cgroup_delegate;
|
||||
|
||||
const char *runtime_prefix;
|
||||
|
||||
usec_t watchdog_usec;
|
||||
|
||||
int *idle_pipe;
|
||||
|
||||
char *bus_endpoint_path;
|
||||
int bus_endpoint_fd;
|
||||
};
|
||||
|
@ -287,6 +287,7 @@ Socket.MessageQueueMaxMessages, config_parse_long, 0,
|
||||
Socket.MessageQueueMessageSize, config_parse_long, 0, offsetof(Socket, mq_msgsize)
|
||||
Socket.RemoveOnStop, config_parse_bool, 0, offsetof(Socket, remove_on_stop)
|
||||
Socket.Symlinks, config_parse_unit_path_strv_printf, 0, offsetof(Socket, symlinks)
|
||||
Socket.FileDescriptorName, config_parse_fdname, 0, 0
|
||||
Socket.Service, config_parse_socket_service, 0, 0
|
||||
m4_ifdef(`HAVE_SMACK',
|
||||
`Socket.SmackLabel, config_parse_string, 0, offsetof(Socket, smack)
|
||||
|
@ -1475,10 +1475,10 @@ int config_parse_socket_service(
|
||||
void *userdata) {
|
||||
|
||||
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
Socket *s = data;
|
||||
int r;
|
||||
Unit *x;
|
||||
_cleanup_free_ char *p = NULL;
|
||||
Socket *s = data;
|
||||
Unit *x;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
@ -1507,6 +1507,50 @@ int config_parse_socket_service(
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_fdname(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
_cleanup_free_ char *p = NULL;
|
||||
Socket *s = data;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
s->fdname = mfree(s->fdname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = unit_name_printf(UNIT(s), rvalue, &p);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!fdname_is_valid(p)) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid file descriptor name, ignoring: %s", p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
free(s->fdname);
|
||||
s->fdname = p;
|
||||
p = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_service_sockets(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
|
@ -107,6 +107,7 @@ int config_parse_protect_system(const char* unit, const char *filename, unsigned
|
||||
int config_parse_bus_name(const char* unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
||||
int config_parse_exec_utmp_mode(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
||||
int config_parse_working_directory(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
||||
int config_parse_fdname(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
||||
|
||||
/* gperf prototypes */
|
||||
const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, unsigned length);
|
||||
|
@ -495,6 +495,7 @@ static void manager_clean_environment(Manager *m) {
|
||||
"MANAGERPID",
|
||||
"LISTEN_PID",
|
||||
"LISTEN_FDS",
|
||||
"LISTEN_FDNAMES",
|
||||
"WATCHDOG_PID",
|
||||
"WATCHDOG_USEC",
|
||||
NULL);
|
||||
|
@ -261,6 +261,7 @@ static void service_fd_store_unlink(ServiceFDStore *fs) {
|
||||
sd_event_source_unref(fs->event_source);
|
||||
}
|
||||
|
||||
free(fs->fdname);
|
||||
safe_close(fs->fd);
|
||||
free(fs);
|
||||
}
|
||||
@ -334,7 +335,7 @@ static int on_fd_store_io(sd_event_source *e, int fd, uint32_t revents, void *us
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int service_add_fd_store(Service *s, int fd) {
|
||||
static int service_add_fd_store(Service *s, int fd, const char *name) {
|
||||
ServiceFDStore *fs;
|
||||
int r;
|
||||
|
||||
@ -361,9 +362,13 @@ static int service_add_fd_store(Service *s, int fd) {
|
||||
|
||||
fs->fd = fd;
|
||||
fs->service = s;
|
||||
fs->fdname = strdup(name ?: "stored");
|
||||
if (!fs->fdname)
|
||||
return -ENOMEM;
|
||||
|
||||
r = sd_event_add_io(UNIT(s)->manager->event, &fs->event_source, fd, 0, on_fd_store_io, fs);
|
||||
if (r < 0) {
|
||||
free(fs->fdname);
|
||||
free(fs);
|
||||
return r;
|
||||
}
|
||||
@ -376,7 +381,7 @@ static int service_add_fd_store(Service *s, int fd) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int service_add_fd_store_set(Service *s, FDSet *fds) {
|
||||
static int service_add_fd_store_set(Service *s, FDSet *fds, const char *name) {
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
@ -391,7 +396,7 @@ static int service_add_fd_store_set(Service *s, FDSet *fds) {
|
||||
if (fd < 0)
|
||||
break;
|
||||
|
||||
r = service_add_fd_store(s, fd);
|
||||
r = service_add_fd_store(s, fd, name);
|
||||
if (r < 0)
|
||||
return log_unit_error_errno(UNIT(s), r, "Couldn't add fd to fd store: %m");
|
||||
if (r > 0) {
|
||||
@ -956,62 +961,79 @@ static int service_coldplug(Unit *u) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int service_collect_fds(Service *s, int **fds, unsigned *n_fds) {
|
||||
static int service_collect_fds(Service *s, int **fds, char ***fd_names) {
|
||||
_cleanup_strv_free_ char **rfd_names = NULL;
|
||||
_cleanup_free_ int *rfds = NULL;
|
||||
unsigned rn_fds = 0;
|
||||
Iterator i;
|
||||
int r;
|
||||
Unit *u;
|
||||
int rn_fds = 0, r;
|
||||
|
||||
assert(s);
|
||||
assert(fds);
|
||||
assert(n_fds);
|
||||
assert(fd_names);
|
||||
|
||||
if (s->socket_fd >= 0)
|
||||
return 0;
|
||||
if (s->socket_fd >= 0) {
|
||||
|
||||
SET_FOREACH(u, UNIT(s)->dependencies[UNIT_TRIGGERED_BY], i) {
|
||||
int *cfds;
|
||||
unsigned cn_fds;
|
||||
Socket *sock;
|
||||
/* Pass the per-connection socket */
|
||||
|
||||
if (u->type != UNIT_SOCKET)
|
||||
continue;
|
||||
rfds = new(int, 1);
|
||||
if (!rfds)
|
||||
return -ENOMEM;
|
||||
rfds[0] = s->socket_fd;
|
||||
|
||||
sock = SOCKET(u);
|
||||
rfd_names = strv_new("connection", NULL);
|
||||
if (!rfd_names)
|
||||
return -ENOMEM;
|
||||
|
||||
r = socket_collect_fds(sock, &cfds, &cn_fds);
|
||||
if (r < 0)
|
||||
return r;
|
||||
rn_fds = 1;
|
||||
} else {
|
||||
Iterator i;
|
||||
Unit *u;
|
||||
|
||||
if (cn_fds <= 0) {
|
||||
free(cfds);
|
||||
continue;
|
||||
}
|
||||
/* Pass all our configured sockets for singleton services */
|
||||
|
||||
if (!rfds) {
|
||||
rfds = cfds;
|
||||
rn_fds = cn_fds;
|
||||
} else {
|
||||
int *t;
|
||||
SET_FOREACH(u, UNIT(s)->dependencies[UNIT_TRIGGERED_BY], i) {
|
||||
_cleanup_free_ int *cfds = NULL;
|
||||
Socket *sock;
|
||||
int cn_fds;
|
||||
|
||||
t = realloc(rfds, (rn_fds + cn_fds) * sizeof(int));
|
||||
if (!t) {
|
||||
free(cfds);
|
||||
return -ENOMEM;
|
||||
if (u->type != UNIT_SOCKET)
|
||||
continue;
|
||||
|
||||
sock = SOCKET(u);
|
||||
|
||||
cn_fds = socket_collect_fds(sock, &cfds);
|
||||
if (cn_fds < 0)
|
||||
return cn_fds;
|
||||
|
||||
if (cn_fds <= 0)
|
||||
continue;
|
||||
|
||||
if (!rfds) {
|
||||
rfds = cfds;
|
||||
rn_fds = cn_fds;
|
||||
|
||||
cfds = NULL;
|
||||
} else {
|
||||
int *t;
|
||||
|
||||
t = realloc(rfds, (rn_fds + cn_fds) * sizeof(int));
|
||||
if (!t)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(t + rn_fds, cfds, cn_fds * sizeof(int));
|
||||
|
||||
rfds = t;
|
||||
rn_fds += cn_fds;
|
||||
}
|
||||
|
||||
memcpy(t + rn_fds, cfds, cn_fds * sizeof(int));
|
||||
rfds = t;
|
||||
rn_fds += cn_fds;
|
||||
|
||||
free(cfds);
|
||||
|
||||
r = strv_extend_n(&rfd_names, socket_fdname(sock), cn_fds);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
if (s->n_fd_store > 0) {
|
||||
ServiceFDStore *fs;
|
||||
char **nl;
|
||||
int *t;
|
||||
|
||||
t = realloc(rfds, (rn_fds + s->n_fd_store) * sizeof(int));
|
||||
@ -1019,15 +1041,32 @@ static int service_collect_fds(Service *s, int **fds, unsigned *n_fds) {
|
||||
return -ENOMEM;
|
||||
|
||||
rfds = t;
|
||||
LIST_FOREACH(fd_store, fs, s->fd_store)
|
||||
rfds[rn_fds++] = fs->fd;
|
||||
|
||||
nl = realloc(rfd_names, (rn_fds + s->n_fd_store + 1) * sizeof(char*));
|
||||
if (!nl)
|
||||
return -ENOMEM;
|
||||
|
||||
rfd_names = nl;
|
||||
|
||||
LIST_FOREACH(fd_store, fs, s->fd_store) {
|
||||
rfds[rn_fds] = fs->fd;
|
||||
rfd_names[rn_fds] = strdup(strempty(fs->fdname));
|
||||
if (!rfd_names[rn_fds])
|
||||
return -ENOMEM;
|
||||
|
||||
rn_fds++;
|
||||
}
|
||||
|
||||
rfd_names[rn_fds] = NULL;
|
||||
}
|
||||
|
||||
*fds = rfds;
|
||||
*n_fds = rn_fds;
|
||||
*fd_names = rfd_names;
|
||||
|
||||
rfds = NULL;
|
||||
return 0;
|
||||
rfd_names = NULL;
|
||||
|
||||
return rn_fds;
|
||||
}
|
||||
|
||||
static int service_spawn(
|
||||
@ -1041,15 +1080,13 @@ static int service_spawn(
|
||||
bool is_control,
|
||||
pid_t *_pid) {
|
||||
|
||||
pid_t pid;
|
||||
int r;
|
||||
int *fds = NULL;
|
||||
_cleanup_free_ int *fdsbuf = NULL;
|
||||
unsigned n_fds = 0, n_env = 0;
|
||||
_cleanup_strv_free_ char **argv = NULL, **final_env = NULL, **our_env = NULL, **fd_names = NULL;
|
||||
_cleanup_free_ char *bus_endpoint_path = NULL;
|
||||
_cleanup_strv_free_ char
|
||||
**argv = NULL, **final_env = NULL, **our_env = NULL;
|
||||
_cleanup_free_ int *fds = NULL;
|
||||
unsigned n_fds = 0, n_env = 0;
|
||||
const char *path;
|
||||
pid_t pid;
|
||||
|
||||
ExecParameters exec_params = {
|
||||
.apply_permissions = apply_permissions,
|
||||
.apply_chroot = apply_chroot,
|
||||
@ -1058,6 +1095,8 @@ static int service_spawn(
|
||||
.selinux_context_net = s->socket_fd_selinux_context_net
|
||||
};
|
||||
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
assert(c);
|
||||
assert(_pid);
|
||||
@ -1077,16 +1116,11 @@ static int service_spawn(
|
||||
s->exec_context.std_output == EXEC_OUTPUT_SOCKET ||
|
||||
s->exec_context.std_error == EXEC_OUTPUT_SOCKET) {
|
||||
|
||||
if (s->socket_fd >= 0) {
|
||||
fds = &s->socket_fd;
|
||||
n_fds = 1;
|
||||
} else {
|
||||
r = service_collect_fds(s, &fdsbuf, &n_fds);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
r = service_collect_fds(s, &fds, &fd_names);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
fds = fdsbuf;
|
||||
}
|
||||
n_fds = r;
|
||||
}
|
||||
|
||||
if (timeout > 0) {
|
||||
@ -1124,7 +1158,7 @@ static int service_spawn(
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (UNIT_DEREF(s->accept_socket)) {
|
||||
if (s->socket_fd >= 0) {
|
||||
union sockaddr_union sa;
|
||||
socklen_t salen = sizeof(sa);
|
||||
|
||||
@ -1190,6 +1224,7 @@ static int service_spawn(
|
||||
|
||||
exec_params.argv = argv;
|
||||
exec_params.fds = fds;
|
||||
exec_params.fd_names = fd_names;
|
||||
exec_params.n_fds = n_fds;
|
||||
exec_params.environment = final_env;
|
||||
exec_params.confirm_spawn = UNIT(s)->manager->confirm_spawn;
|
||||
@ -2053,13 +2088,16 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
|
||||
}
|
||||
|
||||
LIST_FOREACH(fd_store, fs, s->fd_store) {
|
||||
_cleanup_free_ char *c = NULL;
|
||||
int copy;
|
||||
|
||||
copy = fdset_put_dup(fds, fs->fd);
|
||||
if (copy < 0)
|
||||
return copy;
|
||||
|
||||
unit_serialize_item_format(u, f, "fd-store-fd", "%i", copy);
|
||||
c = cescape(fs->fdname);
|
||||
|
||||
unit_serialize_item_format(u, f, "fd-store-fd", "%i %s", copy, strempty(c));
|
||||
}
|
||||
|
||||
if (s->main_exec_status.pid > 0) {
|
||||
@ -2189,12 +2227,24 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
|
||||
s->bus_endpoint_fd = fdset_remove(fds, fd);
|
||||
}
|
||||
} else if (streq(key, "fd-store-fd")) {
|
||||
const char *fdv;
|
||||
size_t pf;
|
||||
int fd;
|
||||
|
||||
if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
|
||||
pf = strcspn(value, WHITESPACE);
|
||||
fdv = strndupa(value, pf);
|
||||
|
||||
if (safe_atoi(fdv, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
|
||||
log_unit_debug(u, "Failed to parse fd-store-fd value: %s", value);
|
||||
else {
|
||||
r = service_add_fd_store(s, fd);
|
||||
_cleanup_free_ char *t = NULL;
|
||||
const char *fdn;
|
||||
|
||||
fdn = value + pf;
|
||||
fdn += strspn(fdn, WHITESPACE);
|
||||
(void) cunescape(fdn, 0, &t);
|
||||
|
||||
r = service_add_fd_store(s, fd, t);
|
||||
if (r < 0)
|
||||
log_unit_error_errno(u, r, "Failed to add fd to store: %m");
|
||||
else if (r > 0)
|
||||
@ -2948,8 +2998,17 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags, FDSet *fds)
|
||||
if (strv_find(tags, "WATCHDOG=1"))
|
||||
service_reset_watchdog(s);
|
||||
|
||||
if (strv_find(tags, "FDSTORE=1"))
|
||||
service_add_fd_store_set(s, fds);
|
||||
if (strv_find(tags, "FDSTORE=1")) {
|
||||
const char *name;
|
||||
|
||||
name = strv_find_startswith(tags, "FDNAME=");
|
||||
if (name && !fdname_is_valid(name)) {
|
||||
log_unit_warning(u, "Passed FDNAME= name is invalid, ignoring.");
|
||||
name = NULL;
|
||||
}
|
||||
|
||||
service_add_fd_store_set(s, fds, name);
|
||||
}
|
||||
|
||||
/* Notify clients about changed status or main pid */
|
||||
if (notify_dbus)
|
||||
|
@ -97,6 +97,7 @@ struct ServiceFDStore {
|
||||
Service *service;
|
||||
|
||||
int fd;
|
||||
char *fdname;
|
||||
sd_event_source *event_source;
|
||||
|
||||
LIST_FIELDS(ServiceFDStore, fd_store);
|
||||
|
@ -508,6 +508,7 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
|
||||
"%sTCPCongestion: %s\n"
|
||||
"%sRemoveOnStop: %s\n"
|
||||
"%sWritable: %s\n"
|
||||
"%sFDName: %s\n"
|
||||
"%sSELinuxContextFromNet: %s\n",
|
||||
prefix, socket_state_to_string(s->state),
|
||||
prefix, socket_result_to_string(s->result),
|
||||
@ -525,6 +526,7 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
|
||||
prefix, strna(s->tcp_congestion),
|
||||
prefix, yes_no(s->remove_on_stop),
|
||||
prefix, yes_no(s->writable),
|
||||
prefix, socket_fdname(s),
|
||||
prefix, yes_no(s->selinux_context_from_net));
|
||||
|
||||
if (s->control_pid > 0)
|
||||
@ -1028,8 +1030,6 @@ static int fifo_address_create(
|
||||
|
||||
fail:
|
||||
mac_selinux_create_file_clear();
|
||||
safe_close(fd);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -2630,49 +2630,43 @@ static int socket_dispatch_timer(sd_event_source *source, usec_t usec, void *use
|
||||
return 0;
|
||||
}
|
||||
|
||||
int socket_collect_fds(Socket *s, int **fds, unsigned *n_fds) {
|
||||
int *rfds;
|
||||
unsigned rn_fds, k;
|
||||
int i;
|
||||
int socket_collect_fds(Socket *s, int **fds) {
|
||||
int *rfds, k = 0, n = 0;
|
||||
SocketPort *p;
|
||||
|
||||
assert(s);
|
||||
assert(fds);
|
||||
assert(n_fds);
|
||||
|
||||
/* Called from the service code for requesting our fds */
|
||||
|
||||
rn_fds = 0;
|
||||
LIST_FOREACH(port, p, s->ports) {
|
||||
if (p->fd >= 0)
|
||||
rn_fds++;
|
||||
rn_fds += p->n_auxiliary_fds;
|
||||
n++;
|
||||
n += p->n_auxiliary_fds;
|
||||
}
|
||||
|
||||
if (rn_fds <= 0) {
|
||||
if (n <= 0) {
|
||||
*fds = NULL;
|
||||
*n_fds = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
rfds = new(int, rn_fds);
|
||||
rfds = new(int, n);
|
||||
if (!rfds)
|
||||
return -ENOMEM;
|
||||
|
||||
k = 0;
|
||||
LIST_FOREACH(port, p, s->ports) {
|
||||
int i;
|
||||
|
||||
if (p->fd >= 0)
|
||||
rfds[k++] = p->fd;
|
||||
for (i = 0; i < p->n_auxiliary_fds; ++i)
|
||||
rfds[k++] = p->auxiliary_fds[i];
|
||||
}
|
||||
|
||||
assert(k == rn_fds);
|
||||
assert(k == n);
|
||||
|
||||
*fds = rfds;
|
||||
*n_fds = rn_fds;
|
||||
|
||||
return 0;
|
||||
return n;
|
||||
}
|
||||
|
||||
static void socket_reset_failed(Unit *u) {
|
||||
@ -2768,6 +2762,19 @@ static int socket_get_timeout(Unit *u, uint64_t *timeout) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *socket_fdname(Socket *s) {
|
||||
assert(s);
|
||||
|
||||
/* Returns the name to use for $LISTEN_NAMES. If the user
|
||||
* didn't specify anything specifically, use the socket unit's
|
||||
* name as fallback. */
|
||||
|
||||
if (s->fdname)
|
||||
return s->fdname;
|
||||
|
||||
return UNIT(s)->id;
|
||||
}
|
||||
|
||||
static const char* const socket_exec_command_table[_SOCKET_EXEC_COMMAND_MAX] = {
|
||||
[SOCKET_EXEC_START_PRE] = "StartPre",
|
||||
[SOCKET_EXEC_START_CHOWN] = "StartChown",
|
||||
|
@ -154,16 +154,22 @@ struct Socket {
|
||||
char *user, *group;
|
||||
|
||||
bool reset_cpu_usage:1;
|
||||
|
||||
char *fdname;
|
||||
};
|
||||
|
||||
/* Called from the service code when collecting fds */
|
||||
int socket_collect_fds(Socket *s, int **fds, unsigned *n_fds);
|
||||
int socket_collect_fds(Socket *s, int **fds);
|
||||
|
||||
/* Called from the service code when a per-connection service ended */
|
||||
void socket_connection_unref(Socket *s);
|
||||
|
||||
void socket_free_ports(Socket *s);
|
||||
|
||||
int socket_instantiate_service(Socket *s);
|
||||
|
||||
char *socket_fdname(Socket *s);
|
||||
|
||||
extern const UnitVTable socket_vtable;
|
||||
|
||||
const char* socket_exec_command_to_string(SocketExecCommand i) _const_;
|
||||
@ -173,5 +179,3 @@ const char* socket_result_to_string(SocketResult i) _const_;
|
||||
SocketResult socket_result_from_string(const char *s) _pure_;
|
||||
|
||||
const char* socket_port_type_to_string(SocketPort *p) _pure_;
|
||||
|
||||
int socket_instantiate_service(Socket *s);
|
||||
|
@ -871,7 +871,6 @@ static int get_block_device_harder(const char *path, dev_t *dev) {
|
||||
goto fallback;
|
||||
|
||||
found = de;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
|
@ -19,25 +19,37 @@
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include <limits.h>
|
||||
#include <mqueue.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "path-util.h"
|
||||
#include "socket-util.h"
|
||||
#include "strv.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "sd-daemon.h"
|
||||
|
||||
static void unsetenv_all(bool unset_environment) {
|
||||
|
||||
if (!unset_environment)
|
||||
return;
|
||||
|
||||
unsetenv("LISTEN_PID");
|
||||
unsetenv("LISTEN_FDS");
|
||||
unsetenv("LISTEN_FDNAMES");
|
||||
}
|
||||
|
||||
_public_ int sd_listen_fds(int unset_environment) {
|
||||
const char *e;
|
||||
unsigned n;
|
||||
@ -79,12 +91,49 @@ _public_ int sd_listen_fds(int unset_environment) {
|
||||
r = (int) n;
|
||||
|
||||
finish:
|
||||
if (unset_environment) {
|
||||
unsetenv("LISTEN_PID");
|
||||
unsetenv("LISTEN_FDS");
|
||||
unsetenv_all(unset_environment);
|
||||
return r;
|
||||
}
|
||||
|
||||
_public_ int sd_listen_fds_with_names(int unset_environment, char ***names) {
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
bool have_names;
|
||||
int n_names = 0, n_fds;
|
||||
const char *e;
|
||||
int r;
|
||||
|
||||
if (!names)
|
||||
return sd_listen_fds(unset_environment);
|
||||
|
||||
e = getenv("LISTEN_FDNAMES");
|
||||
if (e) {
|
||||
n_names = strv_split_extract(&l, e, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
|
||||
if (n_names < 0) {
|
||||
unsetenv_all(unset_environment);
|
||||
return n_names;
|
||||
}
|
||||
|
||||
have_names = true;
|
||||
} else
|
||||
have_names = false;
|
||||
|
||||
n_fds = sd_listen_fds(unset_environment);
|
||||
if (n_fds <= 0)
|
||||
return n_fds;
|
||||
|
||||
if (have_names) {
|
||||
if (n_names != n_fds)
|
||||
return -EINVAL;
|
||||
} else {
|
||||
r = strv_extend_n(&l, "unknown", n_fds);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return r;
|
||||
*names = l;
|
||||
l = NULL;
|
||||
|
||||
return n_fds;
|
||||
}
|
||||
|
||||
_public_ int sd_is_fifo(int fd, const char *path) {
|
||||
|
@ -76,6 +76,8 @@ _SD_BEGIN_DECLARATIONS;
|
||||
*/
|
||||
int sd_listen_fds(int unset_environment);
|
||||
|
||||
int sd_listen_fds_with_names(int unset_environment, char ***names);
|
||||
|
||||
/*
|
||||
Helper call for identifying a passed file descriptor. Returns 1 if
|
||||
the file descriptor is a FIFO in the file system stored under the
|
||||
|
@ -21,9 +21,22 @@
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "systemd/sd-daemon.h"
|
||||
#include "sd-daemon.h"
|
||||
|
||||
#include "strv.h"
|
||||
|
||||
int main(int argc, char*argv[]) {
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
int n, i;
|
||||
|
||||
n = sd_listen_fds_with_names(false, &l);
|
||||
if (n < 0) {
|
||||
log_error_errno(n, "Failed to get listening fds: %m");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
log_info("fd=%i name=%s\n", SD_LISTEN_FDS_START + i, l[i]);
|
||||
|
||||
sd_notify(0,
|
||||
"STATUS=Starting up");
|
||||
@ -49,5 +62,5 @@ int main(int argc, char*argv[]) {
|
||||
"STOPPING=1");
|
||||
sleep(5);
|
||||
|
||||
return 0;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
@ -155,7 +155,7 @@ static void test_strv_join(void) {
|
||||
|
||||
static void test_strv_quote_unquote(const char* const *split, const char *quoted) {
|
||||
_cleanup_free_ char *p;
|
||||
_cleanup_strv_free_ char **s;
|
||||
_cleanup_strv_free_ char **s = NULL;
|
||||
char **t;
|
||||
int r;
|
||||
|
||||
@ -166,7 +166,7 @@ static void test_strv_quote_unquote(const char* const *split, const char *quoted
|
||||
assert_se(streq(p, quoted));
|
||||
|
||||
r = strv_split_extract(&s, quoted, WHITESPACE, EXTRACT_QUOTES);
|
||||
assert_se(r == 0);
|
||||
assert_se(r == (int) strv_length(s));
|
||||
assert_se(s);
|
||||
STRV_FOREACH(t, s) {
|
||||
assert_se(*t);
|
||||
@ -183,7 +183,7 @@ static void test_strv_unquote(const char *quoted, char **list) {
|
||||
int r;
|
||||
|
||||
r = strv_split_extract(&s, quoted, WHITESPACE, EXTRACT_QUOTES);
|
||||
assert_se(r == 0);
|
||||
assert_se(r == (int) strv_length(list));
|
||||
assert_se(s);
|
||||
j = strv_join(s, " | ");
|
||||
assert_se(j);
|
||||
@ -225,7 +225,7 @@ static void test_strv_split_extract(void) {
|
||||
int r;
|
||||
|
||||
r = strv_split_extract(&l, str, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
|
||||
assert_se(r == 0);
|
||||
assert_se(r == (int) strv_length(l));
|
||||
assert_se(streq_ptr(l[0], ""));
|
||||
assert_se(streq_ptr(l[1], "foo:bar"));
|
||||
assert_se(streq_ptr(l[2], ""));
|
||||
@ -591,6 +591,33 @@ static void test_strv_skip(void) {
|
||||
test_strv_skip_one(STRV_MAKE(NULL), 55, STRV_MAKE(NULL));
|
||||
}
|
||||
|
||||
static void test_strv_extend_n(void) {
|
||||
_cleanup_strv_free_ char **v = NULL;
|
||||
|
||||
v = strv_new("foo", "bar", NULL);
|
||||
assert_se(v);
|
||||
|
||||
assert_se(strv_extend_n(&v, "waldo", 3) >= 0);
|
||||
assert_se(strv_extend_n(&v, "piep", 2) >= 0);
|
||||
|
||||
assert_se(streq(v[0], "foo"));
|
||||
assert_se(streq(v[1], "bar"));
|
||||
assert_se(streq(v[2], "waldo"));
|
||||
assert_se(streq(v[3], "waldo"));
|
||||
assert_se(streq(v[4], "waldo"));
|
||||
assert_se(streq(v[5], "piep"));
|
||||
assert_se(streq(v[6], "piep"));
|
||||
assert_se(v[7] == NULL);
|
||||
|
||||
v = strv_free(v);
|
||||
|
||||
assert_se(strv_extend_n(&v, "foo", 1) >= 0);
|
||||
assert_se(strv_extend_n(&v, "bar", 0) >= 0);
|
||||
|
||||
assert_se(streq(v[0], "foo"));
|
||||
assert_se(v[1] == NULL);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
test_specifier_printf();
|
||||
test_strv_foreach();
|
||||
@ -650,6 +677,7 @@ int main(int argc, char *argv[]) {
|
||||
test_strv_reverse();
|
||||
test_strv_shell_escape();
|
||||
test_strv_skip();
|
||||
test_strv_extend_n();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
# (at your option) any later version.
|
||||
|
||||
[Unit]
|
||||
Description=networkd rtnetlink socket
|
||||
Description=Network Service Netlink Socket
|
||||
Documentation=man:systemd-networkd.service(8) man:rtnetlink(7)
|
||||
ConditionCapability=CAP_NET_ADMIN
|
||||
DefaultDependencies=no
|
||||
|
Loading…
x
Reference in New Issue
Block a user