</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" />
#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;
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;
" --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,
ARG_GRACEFUL,
ARG_TIMEOUT,
ARG_EXEC,
+ ARG_PUSH_FD,
};
static const struct option options[] = {
{ "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 },
{},
};
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;
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;