]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
activate: allow multiple, possibly invalid, fd names
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Fri, 12 Feb 2016 04:33:09 +0000 (23:33 -0500)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Sat, 13 Feb 2016 16:54:39 +0000 (11:54 -0500)
Previous code only allowed a single name to be passed, and duplicated
it over all descriptors. For the sake of testing, allow different
names and in arbitrary number. If just one is given, duplicate it
to match the number of sockets. This matches previuos behaviour.

Since this is a testing tool, it seems useful to allow passing invalid
names to test application behaviour with invalid names. Hence, only
warn. When warning, escape the name.

man/systemd-activate.xml
src/activate/activate.c

index 995e6eecce6cf2535c8d51a9f018eecb296dff13..a8e17f2a2a0e677c2e3e61dc2e07a262f8ff63e2 100644 (file)
       </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>
+        <term><option>--fdname=</option><replaceable>NAME</replaceable><optional>:<replaceable>NAME</replaceable>...</optional></term>
+
+        <listitem><para>Specify names for the file descriptors passed. 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>.
+        Multiple entries may be specifies using separate options or by separating names with colons
+        (<literal>:</literal>) in one option. In case more names are given than descriptors, superflous ones willl be
+        ignored. In case less names are given than descriptors, the remaining file descriptors will be unnamed.
+        </para></listitem>
       </varlistentry>
 
       <xi:include href="standard-options.xml" xpointer="help" />
index 0db4967edba151cf26ee2671f4f6ee6cd5405f6a..23244fdc62a7bc0ccfca167fd9d885162b2a6ef3 100644 (file)
@@ -27,6 +27,7 @@
 #include "sd-daemon.h"
 
 #include "alloc-util.h"
+#include "escape.h"
 #include "fd-util.h"
 #include "log.h"
 #include "macro.h"
@@ -40,7 +41,7 @@ static bool arg_accept = false;
 static int arg_socket_type = SOCK_STREAM;
 static char** arg_args = NULL;
 static char** arg_setenv = NULL;
-static const char *arg_fdname = NULL;
+static char **arg_fdnames = NULL;
 static bool arg_inetd = false;
 
 static int add_epoll(int epoll_fd, int fd) {
@@ -134,7 +135,6 @@ static int exec_process(const char* name, char **argv, char **env, int start_fd,
         _cleanup_free_ char *joined = NULL;
         unsigned n_env = 0, length;
         const char *tocopy;
-        unsigned i;
         char **s;
         int r;
 
@@ -224,25 +224,30 @@ static int exec_process(const char* name, char **argv, char **env, int start_fd,
                 if (asprintf((char**)(envp + n_env++), "LISTEN_PID=" PID_FMT, getpid()) < 0)
                         return log_oom();
 
-                if (arg_fdname) {
+                if (arg_fdnames) {
+                        _cleanup_free_ char *names = NULL;
+                        size_t len;
                         char *e;
+                        int i;
+
+                        len = strv_length(arg_fdnames);
+                        if (len == 1)
+                                for (i = 1; i < n_fds; i++) {
+                                        r = strv_extend(&arg_fdnames, arg_fdnames[0]);
+                                        if (r < 0)
+                                                return log_error_errno(r, "Failed to extend strv: %m");
+                                }
+                        else if (len != (unsigned) n_fds)
+                                log_warning("The number of fd names is different than number of fds: %zu vs %d",
+                                            len, n_fds);
 
-                        e = strappend("LISTEN_FDNAMES=", arg_fdname);
-                        if (!e)
+                        names = strv_join(arg_fdnames, ":");
+                        if (!names)
                                 return log_oom();
 
-                        for (i = 1; i < (unsigned) n_fds; i++) {
-                                char *c;
-
-                                c = strjoin(e, ":", arg_fdname, NULL);
-                                if (!c) {
-                                        free(e);
-                                        return log_oom();
-                                }
-
-                                free(e);
-                                e = c;
-                        }
+                        e = strappend("LISTEN_FDNAMES=", names);
+                        if (!e)
+                                return log_oom();
 
                         envp[n_env++] = e;
                 }
@@ -339,14 +344,15 @@ static void help(void) {
         printf("%s [OPTIONS...]\n\n"
                "Listen on sockets and launch child on connection.\n\n"
                "Options:\n"
-               "  -h --help                Show this help and exit\n"
-               "     --version             Print version string and exit\n"
-               "  -l --listen=ADDR         Listen for raw connections at ADDR\n"
-               "  -d --datagram            Listen on datagram instead of stream socket\n"
-               "     --seqpacket           Listen on SOCK_SEQPACKET instead of stream socket\n"
-               "  -a --accept              Spawn separate child for each connection\n"
-               "  -E --setenv=NAME[=VALUE] Pass an environment variable to children\n"
-               "     --inetd               Enable inetd file descriptor passing protocol\n"
+               "  -h --help                  Show this help and exit\n"
+               "     --version               Print version string and exit\n"
+               "  -l --listen=ADDR           Listen for raw connections at ADDR\n"
+               "  -d --datagram              Listen on datagram instead of stream socket\n"
+               "     --seqpacket             Listen on SOCK_SEQPACKET instead of stream socket\n"
+               "  -a --accept                Spawn separate child for each connection\n"
+               "  -E --setenv=NAME[=VALUE]   Pass an environment variable to children\n"
+               "     --fdname=NAME[:NAME...] Specify names for file descriptors\n"
+               "     --inetd                 Enable inetd file descriptor passing protocol\n"
                "\n"
                "Note: file descriptors from sd_listen_fds() will be passed through.\n"
                , program_invocation_short_name);
@@ -424,14 +430,30 @@ static int parse_argv(int argc, char *argv[]) {
 
                         break;
 
-                case ARG_FDNAME:
-                        if (!fdname_is_valid(optarg)) {
-                                log_error("File descriptor name %s is not valid, refusing.", optarg);
-                                return -EINVAL;
-                        }
+                case ARG_FDNAME: {
+                        _cleanup_strv_free_ char **names;
+                        char **s;
+
+                        names = strv_split(optarg, ":");
+                        if (!names)
+                                return log_oom();
+
+                        STRV_FOREACH(s, names)
+                                if (!fdname_is_valid(*s)) {
+                                        _cleanup_free_ char *esc;
 
-                        arg_fdname = optarg;
+                                        esc = cescape(*s);
+                                        log_warning("File descriptor name \"%s\" is not valid.", esc);
+                                }
+
+                        /* Empty optargs means one empty name */
+                        r = strv_extend_strv(&arg_fdnames,
+                                             strv_isempty(names) ? STRV_MAKE("") : names,
+                                             false);
+                        if (r < 0)
+                                return log_error_errno(r, "strv_extend_strv: %m");
                         break;
+                }
 
                 case ARG_INETD:
                         arg_inetd = true;