diff options
| author | Tom Gundersen <teg@jklm.no> | 2015-10-06 12:06:56 +0200 | 
|---|---|---|
| committer | Tom Gundersen <teg@jklm.no> | 2015-10-06 12:06:56 +0200 | 
| commit | e1719ef19d542c88e319e77aaf970dc36c2269f4 (patch) | |
| tree | 674f2f4b65756cb993709a8c75b82c082fb68a36 | |
| parent | f0990739fc24e60facb7ef0c3e97a046bd1d9d17 (diff) | |
| parent | df9d6993b677c05c7f502acafc5c8efa642792fe (diff) | |
Merge pull request #1468 from poettering/fdnames
Add support for naming fds for socket activation and more
| -rw-r--r-- | Makefile-man.am | 5 | ||||
| -rw-r--r-- | man/sd_listen_fds.xml | 133 | ||||
| -rw-r--r-- | man/sd_notify.xml | 31 | ||||
| -rw-r--r-- | man/systemd-activate.xml | 13 | ||||
| -rw-r--r-- | man/systemd-analyze.xml | 6 | ||||
| -rw-r--r-- | man/systemd.socket.xml | 23 | ||||
| -rw-r--r-- | man/systemd.xml | 1 | ||||
| -rw-r--r-- | src/activate/activate.c | 61 | ||||
| -rw-r--r-- | src/basic/strv.c | 47 | ||||
| -rw-r--r-- | src/basic/strv.h | 2 | ||||
| -rw-r--r-- | src/basic/util.c | 25 | ||||
| -rw-r--r-- | src/basic/util.h | 2 | ||||
| -rw-r--r-- | src/core/dbus-socket.c | 20 | ||||
| -rw-r--r-- | src/core/execute.c | 81 | ||||
| -rw-r--r-- | src/core/execute.h | 13 | ||||
| -rw-r--r-- | src/core/load-fragment-gperf.gperf.m4 | 1 | ||||
| -rw-r--r-- | src/core/load-fragment.c | 48 | ||||
| -rw-r--r-- | src/core/load-fragment.h | 1 | ||||
| -rw-r--r-- | src/core/manager.c | 1 | ||||
| -rw-r--r-- | src/core/service.c | 189 | ||||
| -rw-r--r-- | src/core/service.h | 1 | ||||
| -rw-r--r-- | src/core/socket.c | 43 | ||||
| -rw-r--r-- | src/core/socket.h | 10 | ||||
| -rw-r--r-- | src/gpt-auto-generator/gpt-auto-generator.c | 1 | ||||
| -rw-r--r-- | src/libsystemd/sd-daemon/sd-daemon.c | 79 | ||||
| -rw-r--r-- | src/systemd/sd-daemon.h | 2 | ||||
| -rw-r--r-- | src/test/test-daemon.c | 17 | ||||
| -rw-r--r-- | src/test/test-strv.c | 36 | ||||
| -rw-r--r-- | units/systemd-networkd.socket | 2 | 
29 files changed, 696 insertions, 198 deletions
| diff --git a/Makefile-man.am b/Makefile-man.am index 14c2b7d57e..1ff85d7d2c 100644 --- a/Makefile-man.am +++ b/Makefile-man.am @@ -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) diff --git a/man/sd_listen_fds.xml b/man/sd_listen_fds.xml index 9b9705eb2e..ea55671e4f 100644 --- a/man/sd_listen_fds.xml +++ b/man/sd_listen_fds.xml @@ -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> diff --git a/man/sd_notify.xml b/man/sd_notify.xml index 14030f56b1..2d73c27f62 100644 --- a/man/sd_notify.xml +++ b/man/sd_notify.xml @@ -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> diff --git a/man/systemd-activate.xml b/man/systemd-activate.xml index 3b854fd8ec..90e974c991 100644 --- a/man/systemd-activate.xml +++ b/man/systemd-activate.xml @@ -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> diff --git a/man/systemd-analyze.xml b/man/systemd-analyze.xml index 632e6363f6..d2db265f58 100644 --- a/man/systemd-analyze.xml +++ b/man/systemd-analyze.xml @@ -98,6 +98,12 @@      <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>        <arg choice="plain">verify</arg>        <arg choice="opt" rep="repeat"><replaceable>FILES</replaceable></arg>      </cmdsynopsis> diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml index 212764075d..46a47b2d95 100644 --- a/man/systemd.socket.xml +++ b/man/systemd.socket.xml @@ -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>, diff --git a/man/systemd.xml b/man/systemd.xml index 9e927c3204..391333bfb4 100644 --- a/man/systemd.xml +++ b/man/systemd.xml @@ -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 diff --git a/src/activate/activate.c b/src/activate/activate.c index 2dfc4a0bc4..6a8432314e 100644 --- a/src/activate/activate.c +++ b/src/activate/activate.c @@ -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; diff --git a/src/basic/strv.c b/src/basic/strv.c index 9524e80a6f..90f0b8c741 100644 --- a/src/basic/strv.c +++ b/src/basic/strv.c @@ -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; +} diff --git a/src/basic/strv.h b/src/basic/strv.h index 4c4b6526de..7c1f80230a 100644 --- a/src/basic/strv.h +++ b/src/basic/strv.h @@ -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); diff --git a/src/basic/util.c b/src/basic/util.c index 9f520462cf..630c7ea9ff 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -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; +} diff --git a/src/basic/util.h b/src/basic/util.h index a4e3672130..034410b8a8 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -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); diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c index 4611ad5f86..7444649f8b 100644 --- a/src/core/dbus-socket.c +++ b/src/core/dbus-socket.c @@ -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), diff --git a/src/core/execute.c b/src/core/execute.c index 137a176c18..4664af873f 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -21,18 +21,18 @@  #include <errno.h>  #include <fcntl.h> -#include <unistd.h> -#include <string.h> +#include <glob.h> +#include <grp.h> +#include <poll.h>  #include <signal.h> -#include <sys/socket.h> -#include <sys/un.h> +#include <string.h> +#include <sys/personality.h>  #include <sys/prctl.h> +#include <sys/socket.h>  #include <sys/stat.h> -#include <grp.h> -#include <poll.h> -#include <glob.h> +#include <sys/un.h> +#include <unistd.h>  #include <utmpx.h> -#include <sys/personality.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 "af-list.h" +#include "async.h" +#include "barrier.h" +#include "bus-endpoint.h" +#include "cap-list.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 "bus-endpoint.h" -#include "cap-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; diff --git a/src/core/execute.h b/src/core/execute.h index 2c93044748..f1c37116fd 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -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;  }; diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 2333926e7d..89e624b557 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -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) diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index fc2755cb92..b1d4c6b57d 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -1475,10 +1475,10 @@ int config_parse_socket_service(                  void *userdata) {          _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; +        _cleanup_free_ char *p = NULL;          Socket *s = data; -        int r;          Unit *x; -        _cleanup_free_ char *p = NULL; +        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, diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h index 6ee7c71bc4..8661cbfedc 100644 --- a/src/core/load-fragment.h +++ b/src/core/load-fragment.h @@ -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); diff --git a/src/core/manager.c b/src/core/manager.c index 9de9691a47..526d4d1cef 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -495,6 +495,7 @@ static void manager_clean_environment(Manager *m) {                          "MANAGERPID",                          "LISTEN_PID",                          "LISTEN_FDS", +                        "LISTEN_FDNAMES",                          "WATCHDOG_PID",                          "WATCHDOG_USEC",                          NULL); diff --git a/src/core/service.c b/src/core/service.c index 3bb0d913b4..8c339765a4 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -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; -                        memcpy(t + rn_fds, cfds, cn_fds * sizeof(int)); -                        rfds = t; -                        rn_fds += cn_fds; +                        if (!rfds) { +                                rfds = cfds; +                                rn_fds = cn_fds; -                        free(cfds); +                                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; +                        } + +                        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) diff --git a/src/core/service.h b/src/core/service.h index a8d42706bd..61bb44fbcf 100644 --- a/src/core/service.h +++ b/src/core/service.h @@ -97,6 +97,7 @@ struct ServiceFDStore {          Service *service;          int fd; +        char *fdname;          sd_event_source *event_source;          LIST_FIELDS(ServiceFDStore, fd_store); diff --git a/src/core/socket.c b/src/core/socket.c index 3250e7efc6..6300b20f3e 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -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", diff --git a/src/core/socket.h b/src/core/socket.h index d20dc8d81a..94cda8a90d 100644 --- a/src/core/socket.h +++ b/src/core/socket.h @@ -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); diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c index dbb6648daa..96425c5b07 100644 --- a/src/gpt-auto-generator/gpt-auto-generator.c +++ b/src/gpt-auto-generator/gpt-auto-generator.c @@ -871,7 +871,6 @@ static int get_block_device_harder(const char *path, dev_t *dev) {                          goto fallback;                  found = de; -                break;          }          if (!found) diff --git a/src/libsystemd/sd-daemon/sd-daemon.c b/src/libsystemd/sd-daemon/sd-daemon.c index 5fb0b73d02..437518119b 100644 --- a/src/libsystemd/sd-daemon/sd-daemon.c +++ b/src/libsystemd/sd-daemon/sd-daemon.c @@ -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) { diff --git a/src/systemd/sd-daemon.h b/src/systemd/sd-daemon.h index 861dc8f1f4..214e77cab1 100644 --- a/src/systemd/sd-daemon.h +++ b/src/systemd/sd-daemon.h @@ -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 diff --git a/src/test/test-daemon.c b/src/test/test-daemon.c index 7e0ac754d1..45fb554445 100644 --- a/src/test/test-daemon.c +++ b/src/test/test-daemon.c @@ -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;  } diff --git a/src/test/test-strv.c b/src/test/test-strv.c index cc47fd4d34..64801f8e01 100644 --- a/src/test/test-strv.c +++ b/src/test/test-strv.c @@ -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;  } diff --git a/units/systemd-networkd.socket b/units/systemd-networkd.socket index 8cd7bab67a..2c20935d83 100644 --- a/units/systemd-networkd.socket +++ b/units/systemd-networkd.socket @@ -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 | 
