From: Lennart Poettering Date: Mon, 26 May 2025 11:19:14 +0000 (+0200) Subject: varlinkctl: optionally push fds to server X-Git-Tag: v258-rc1~480^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b4c2e2b9702dbaaeedd4ec8f67e5f29b92f6fc92;p=thirdparty%2Fsystemd.git varlinkctl: optionally push fds to server --- diff --git a/man/varlinkctl.xml b/man/varlinkctl.xml index 7ce622ad023..556d2535f87 100644 --- a/man/varlinkctl.xml +++ b/man/varlinkctl.xml @@ -338,6 +338,22 @@ + + + + + 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 varlinkctl + invocation. Optionally, in place of a numeric file descriptor number an absolute or relative file + system path (the latter must be prefixed with ./) may be specified, which is + opened in read-only mode. + + + + + diff --git a/src/varlinkctl/varlinkctl.c b/src/varlinkctl/varlinkctl.c index 5bd091f20f5..e1d74709c30 100644 --- a/src/varlinkctl/varlinkctl.c +++ b/src/varlinkctl/varlinkctl.c @@ -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" @@ -29,6 +30,11 @@ #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;