summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--man/systemd-activate.xml16
-rw-r--r--src/activate/activate.c84
2 files changed, 62 insertions, 38 deletions
diff --git a/man/systemd-activate.xml b/man/systemd-activate.xml
index 995e6eecce..a8e17f2a2a 100644
--- a/man/systemd-activate.xml
+++ b/man/systemd-activate.xml
@@ -136,13 +136,15 @@
</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" />
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;