varlinkctl: optionally push fds to server

This commit is contained in:
Lennart Poettering
2025-05-27 10:41:52 +02:00
parent 0261fe571b
commit b4c2e2b970
2 changed files with 76 additions and 0 deletions
+60
View 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"
@@ -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;