]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
varlinkctl: optionally push fds to server
authorLennart Poettering <lennart@poettering.net>
Mon, 26 May 2025 11:19:14 +0000 (13:19 +0200)
committerLennart Poettering <lennart@poettering.net>
Tue, 27 May 2025 08:41:52 +0000 (10:41 +0200)
man/varlinkctl.xml
src/varlinkctl/varlinkctl.c

index 7ce622ad023ebbf97d073873e344d6fdc71c2e8c..556d2535f878b4d4c3e17d08211b48da9400ce46 100644 (file)
         </listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><option>--push-fd=</option></term>
+
+        <listitem>
+          <para>Takes a numeric file descriptor number as parameter. May be used to pass a file
+          descriptor along with the method call, if the underlying transport supports this. May be used
+          multiple times to pass multiple file descriptors, retaining the order in which they are
+          specified. The specified file descriptors must be passed to the <command>varlinkctl</command>
+          invocation. Optionally, in place of a numeric file descriptor number an absolute or relative file
+          system path (the latter must be prefixed with <literal>./</literal>) may be specified, which is
+          opened in read-only mode.</para>
+
+          <xi:include href="version-info.xml" xpointer="v258"/>
+        </listitem>
+      </varlistentry>
+
       <xi:include href="standard-options.xml" xpointer="no-pager" />
       <xi:include href="standard-options.xml" xpointer="help" />
       <xi:include href="standard-options.xml" xpointer="version" />
index 5bd091f20f5fccd2ff1a88e761bf207fd8440f59..e1d74709c30ea173e7b9a18a0e620b42dab3d49e 100644 (file)
@@ -18,6 +18,7 @@
 #include "memfd-util.h"
 #include "pager.h"
 #include "parse-argument.h"
+#include "parse-util.h"
 #include "pretty-print.h"
 #include "process-util.h"
 #include "string-util.h"
 #include "verbs.h"
 #include "version.h"
 
+typedef struct PushFds {
+        int *fds;
+        size_t n_fds;
+} PushFds;
+
 static sd_json_format_flags_t arg_json_format_flags = SD_JSON_FORMAT_OFF;
 static PagerFlags arg_pager_flags = 0;
 static sd_varlink_method_flags_t arg_method_flags = 0;
@@ -37,8 +43,17 @@ static bool arg_quiet = false;
 static char **arg_graceful = NULL;
 static usec_t arg_timeout = 0;
 static bool arg_exec = false;
+static PushFds arg_push_fds = {};
+
+static void push_fds_done(PushFds *p) {
+        assert(p);
+
+        close_many_and_free(p->fds, p->n_fds);
+        *p = (PushFds) {};
+}
 
 STATIC_DESTRUCTOR_REGISTER(arg_graceful, strv_freep);
+STATIC_DESTRUCTOR_REGISTER(arg_push_fds, push_fds_done);
 
 static int help(void) {
         _cleanup_free_ char *link = NULL;
@@ -80,6 +95,7 @@ static int help(void) {
                "     --graceful=ERROR    Treat specified Varlink error as success\n"
                "     --timeout=SECS      Maximum time to wait for method call completion\n"
                "  -E                     Short for --more --timeout=infinity\n"
+               "     --push-fd=FD        Pass the specified fd along with method call\n"
                "\nSee the %2$s for details.\n",
                program_invocation_short_name,
                link,
@@ -107,6 +123,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_GRACEFUL,
                 ARG_TIMEOUT,
                 ARG_EXEC,
+                ARG_PUSH_FD,
         };
 
         static const struct option options[] = {
@@ -121,6 +138,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "graceful", required_argument, NULL, ARG_GRACEFUL },
                 { "timeout",  required_argument, NULL, ARG_TIMEOUT  },
                 { "exec",     no_argument,       NULL, ARG_EXEC     },
+                { "push-fd",  required_argument, NULL, ARG_PUSH_FD  },
                 {},
         };
 
@@ -205,6 +223,34 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_exec = true;
                         break;
 
+                case ARG_PUSH_FD: {
+                        if (!GREEDY_REALLOC(arg_push_fds.fds, arg_push_fds.n_fds + 1))
+                                return log_oom();
+
+                        _cleanup_close_ int add_fd = -EBADF;
+                        if (STARTSWITH_SET(optarg, "/", "./")) {
+                                /* We usually expect a numeric fd spec, but as an extension let's treat this
+                                 * as a path to open in read-only mode in case this is clearly an absolute or
+                                 * relative path */
+                                add_fd = open(optarg, O_CLOEXEC|O_RDONLY|O_NOCTTY);
+                                if (add_fd < 0)
+                                        return log_error_errno(errno, "Failed to open '%s': %m", optarg);
+                        } else {
+                                int parsed_fd = parse_fd(optarg);
+                                if (parsed_fd < 0)
+                                        return log_error_errno(parsed_fd, "Failed to parse --push-fd= parameter: %s", optarg);
+
+                                /* Make a copy, so that the same fd could be used multiple times in a reasonable
+                                 * way. This also validates the fd early */
+                                add_fd = fcntl(parsed_fd, F_DUPFD_CLOEXEC, 3);
+                                if (add_fd < 0)
+                                        return log_error_errno(errno, "Failed to duplicate file descriptor %i: %m", parsed_fd);
+                        }
+
+                        arg_push_fds.fds[arg_push_fds.n_fds++] = TAKE_FD(add_fd);
+                        break;
+                }
+
                 case '?':
                         return -EINVAL;
 
@@ -616,6 +662,20 @@ static int verb_call(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return r;
 
+        if (arg_push_fds.n_fds > 0) {
+                r = sd_varlink_set_allow_fd_passing_output(vl, true);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to enable fd passing: %m");
+
+                FOREACH_ARRAY(f, arg_push_fds.fds, arg_push_fds.n_fds) {
+                        r = sd_varlink_push_fd(vl, *f);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to push file descriptor: %m");
+
+                        TAKE_FD(*f); /* we passed ownership away */
+                }
+        }
+
         if (arg_collect) {
                 sd_json_variant *reply = NULL;
                 const char *error = NULL;