]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core: add support for naming file descriptors passed using socket activation
authorLennart Poettering <lennart@poettering.net>
Sun, 4 Oct 2015 15:36:19 +0000 (17:36 +0200)
committerLennart Poettering <lennart@poettering.net>
Tue, 6 Oct 2015 09:52:48 +0000 (11:52 +0200)
This adds support for naming file descriptors passed using socket
activation. The names are passed in a new $LISTEN_FDNAMES= environment
variable, that matches the existign $LISTEN_FDS= one and contains a
colon-separated list of names.

This also adds support for naming fds submitted to the per-service fd
store using FDNAME= in the sd_notify() message.

This also adds a new FileDescriptorName= setting for socket unit files
to set the name for fds created by socket units.

This also adds a new call sd_listen_fds_with_names(), that is similar to
sd_listen_fds(), but also returns the names of the fds.

systemd-activate gained the new --fdname= switch to specify a name for
testing socket activation.

This is based on #1247 by Maciej Wereski.

Fixes #1247.

26 files changed:
Makefile-man.am
man/sd_listen_fds.xml
man/sd_notify.xml
man/systemd-activate.xml
man/systemd.socket.xml
man/systemd.xml
src/activate/activate.c
src/basic/strv.c
src/basic/strv.h
src/basic/util.c
src/basic/util.h
src/core/dbus-socket.c
src/core/execute.c
src/core/execute.h
src/core/load-fragment-gperf.gperf.m4
src/core/load-fragment.c
src/core/load-fragment.h
src/core/manager.c
src/core/service.c
src/core/service.h
src/core/socket.c
src/core/socket.h
src/libsystemd/sd-daemon/sd-daemon.c
src/systemd/sd-daemon.h
src/test/test-daemon.c
src/test/test-strv.c

index 14c2b7d57e4d249081ab0304177ca374dc5de654..1ff85d7d2cbb512d8384a36ea6952f4ae5dc8556 100644 (file)
@@ -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)
 
index 9b9705eb2ee5daaea1c3335a23a46d1b93275e04..ea55671e4fd5edb553c0e03b72606689feaf7eac 100644 (file)
@@ -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>
         <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
     <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
 
     <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>
       <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>
       <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>
index 14030f56b1015b55d0d7dfb078c0e7bc6e612409..2d73c27f62ccc9944aeb473ea33eb73aa80b6671 100644 (file)
@@ -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">
 
         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
       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", &amp;fd, 1);</programlisting>
+      <programlisting>sd_pid_notify_with_fds(0, 0, "FDSTORE=1\nFDNAME=foobar", &amp;fd, 1);</programlisting>
     </example>
   </refsect1>
 
     <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>
 
index 3b854fd8ecad8018b1cf82b2b116dc171a8c8360..90e974c991e7dd02bf2534fd6f75afe06d409103 100644 (file)
         </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>
       <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>
       <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>
index 212764075df26c04f32328b7f9baa93cd3f7bec7..46a47b2d9527edc4c6d187b23b0e2f12fcc6e827 100644 (file)
@@ -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">
 
         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
         <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>,
index 9e927c32044ba8dde8aad17f35e7fd0d58db0790..391333bfb4696810a4223e47ba99ed3377db3dc5 100644 (file)
       <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
index 2dfc4a0bc439684baed573b8c2b8b91ede47b86b..6a8432314ea868baa9596c214d2a3b5db6022c91 100644 (file)
@@ -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;
index 9524e80a6fbfbd6e99bacfb76f4b8ebac1c13870..90f0b8c741a93f8386519bfbed1ac9eabce06522 100644 (file)
@@ -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;
+}
index 4c4b6526de3bcdec3c0a3195a5fbafd7909a0a41..7c1f80230a7045e870767fef0b9d0e8c2f9400d4 100644 (file)
@@ -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);
index c63ec0ceb06179352c1f15007a331503faf81c42..054d45092e601d0381ede8b8b75fb12d06ec1dc5 100644 (file)
@@ -6842,3 +6842,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;
+}
index a4e367213088ad83892300589a7f89eb01ff2466..034410b8a8c05c82de8e1f4801d0b0dbd025d4df 100644 (file)
@@ -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);
index 4611ad5f8605edfcdb9288292b1189d9744b8214..7444649f8ba1022b581921b145f4a30cb63c0ed0 100644 (file)
@@ -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),
index 137a176c186c8e234bb357e568067397ec3ba29b..4664af873f1e16b2fdfd2ea39cff3c2e477186e0 100644 (file)
 
 #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>
 #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;
index 2c93044748d620a1c26d59b239d6a858b483c059..f1c37116fd19728035b277b8b6a903b137bcc79e 100644 (file)
@@ -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;
 };
index 2333926e7d1b8cb841c64136301860e1c7111a75..89e624b5579ab88ab30d7afa6035e7745e78a4b5 100644 (file)
@@ -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)
index fc2755cb92eec079cfe9eb95b0f0170112863d00..b1d4c6b57d3e79093638a1cd8534204b944b9e6d 100644 (file)
@@ -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,
index 6ee7c71bc49df78972fffe7acce7f2c517270bc0..8661cbfedcdc3ffd28ddad6b6bce461a4a3026f3 100644 (file)
@@ -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);
index 9de9691a47aef1cdbb50cbb50e0d1ef0e6245fe5..526d4d1cef0d9d93eeda8c204e8822ce7e35dd82 100644 (file)
@@ -495,6 +495,7 @@ static void manager_clean_environment(Manager *m) {
                         "MANAGERPID",
                         "LISTEN_PID",
                         "LISTEN_FDS",
+                        "LISTEN_FDNAMES",
                         "WATCHDOG_PID",
                         "WATCHDOG_USEC",
                         NULL);
index 2c78cb96c2f5036dac22221070072deb49633c5e..c941689dd7c1b4f0832ef02673e1163025ecf014 100644 (file)
@@ -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) {
@@ -957,56 +962,79 @@ static int service_coldplug(Unit *u) {
         return 0;
 }
 
-static int service_collect_fds(Service *s, int **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;
-        int rn_fds = 0;
-        Iterator i;
-        Unit *u;
+        int rn_fds = 0, r;
 
         assert(s);
         assert(fds);
+        assert(fd_names);
 
-        if (s->socket_fd >= 0)
-                return -EINVAL;
+        if (s->socket_fd >= 0) {
 
-        SET_FOREACH(u, UNIT(s)->dependencies[UNIT_TRIGGERED_BY], i) {
-                _cleanup_free_ int *cfds = NULL;
-                Socket *sock;
-                int cn_fds;
+                /* Pass the per-connection socket */
 
-                if (u->type != UNIT_SOCKET)
-                        continue;
+                rfds = new(int, 1);
+                if (!rfds)
+                        return -ENOMEM;
+                rfds[0] = s->socket_fd;
+
+                rfd_names = strv_new("connection", NULL);
+                if (!rfd_names)
+                        return -ENOMEM;
 
-                sock = SOCKET(u);
+                rn_fds = 1;
+        } else {
+                Iterator i;
+                Unit *u;
 
-                cn_fds = socket_collect_fds(sock, &cfds);
-                if (cn_fds < 0)
-                        return cn_fds;
+                /* Pass all our configured sockets for singleton services */
 
-                if (cn_fds <= 0)
-                        continue;
+                SET_FOREACH(u, UNIT(s)->dependencies[UNIT_TRIGGERED_BY], i) {
+                        _cleanup_free_ int *cfds = NULL;
+                        Socket *sock;
+                        int cn_fds;
 
-                if (!rfds) {
-                        rfds = cfds;
-                        rn_fds = cn_fds;
+                        if (u->type != UNIT_SOCKET)
+                                continue;
 
-                        cfds = NULL;
-                } else {
-                        int *t;
+                        sock = SOCKET(u);
 
-                        t = realloc(rfds, (rn_fds + cn_fds) * sizeof(int));
-                        if (!t)
-                                return -ENOMEM;
+                        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;
 
-                        memcpy(t + rn_fds, cfds, cn_fds * sizeof(int));
+                                cfds = NULL;
+                        } else {
+                                int *t;
 
-                        rfds = t;
-                        rn_fds += cn_fds;
+                                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));
@@ -1014,12 +1042,30 @@ static int service_collect_fds(Service *s, int **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;
+        *fd_names = rfd_names;
+
         rfds = NULL;
+        rfd_names = NULL;
 
         return rn_fds;
 }
@@ -1035,15 +1081,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,
@@ -1052,6 +1096,8 @@ static int service_spawn(
                 .selinux_context_net = s->socket_fd_selinux_context_net
         };
 
+        int r;
+
         assert(s);
         assert(c);
         assert(_pid);
@@ -1071,17 +1117,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);
-                        if (r < 0)
-                                goto fail;
+                r = service_collect_fds(s, &fds, &fd_names);
+                if (r < 0)
+                        goto fail;
 
-                        fds = fdsbuf;
-                        n_fds = r;
-                }
+                n_fds = r;
         }
 
         if (timeout > 0) {
@@ -1119,7 +1159,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);
 
@@ -1185,6 +1225,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;
@@ -2047,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) {
@@ -2183,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)
@@ -2942,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)
index a8d42706bdcaa334b13cc5fc59a5ee3b3aa18bba..61bb44fbcf206760748d54a018986d4cd46c550c 100644 (file)
@@ -97,6 +97,7 @@ struct ServiceFDStore {
         Service *service;
 
         int fd;
+        char *fdname;
         sd_event_source *event_source;
 
         LIST_FIELDS(ServiceFDStore, fd_store);
index 4462fbd72d4c0902583f6b6b1cb8389fe606a328..6300b20f3e99b9d4f06071dc870fa58f87d8daa8 100644 (file)
@@ -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)
@@ -2760,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",
index 96091b0609952016768ca68f5dbe0a6ddaf079f2..94cda8a90d1536638ab853fcf7c4f6f4730a8dd7 100644 (file)
@@ -154,6 +154,8 @@ struct Socket {
         char *user, *group;
 
         bool reset_cpu_usage:1;
+
+        char *fdname;
 };
 
 /* Called from the service code when collecting fds */
@@ -164,6 +166,10 @@ 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);
index 5fb0b73d02ca3f5f79b414a59faadce6167d23dc..437518119bd07ef807f58dad5dcce7c2958c3403 100644 (file)
   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) {
index 861dc8f1f4fc6f1e5f046245ec74937c059a9df2..214e77cab14e95c43c12b0485b66bc8302f6c054 100644 (file)
@@ -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
index 7e0ac754d160a65798ba4eb01fb971ef125ed0f0..45fb554445eae2778579bfbc09a67c9691e1b974 100644 (file)
 
 #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;
 }
index cc47fd4d349ea7807baf5ed387d4333810fbf6e3..64801f8e01c62e7ca76ec1ccccfe2884427d4ef6 100644 (file)
@@ -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;
 }