From cf98937cc73201a71fabbd35fd9853cbe2790ed0 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Thu, 11 Feb 2016 23:33:09 -0500 Subject: activate: allow multiple, possibly invalid, fd names 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. --- src/activate/activate.c | 84 +++++++++++++++++++++++++++++++------------------ 1 file changed, 53 insertions(+), 31 deletions(-) (limited to 'src/activate') diff --git a/src/activate/activate.c b/src/activate/activate.c index 0db4967edb..23244fdc62 100644 --- a/src/activate/activate.c +++ b/src/activate/activate.c @@ -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; -- cgit v1.2.3-54-g00ecf