]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-varlink: add sd_varlink_call_and_upgradeb() + sd_varlink_call_and_upgradebo() 42974/head
authorLennart Poettering <lennart@amutable.com>
Tue, 7 Jul 2026 10:45:31 +0000 (12:45 +0200)
committerLennart Poettering <lennart@amutable.com>
Sun, 12 Jul 2026 20:44:03 +0000 (22:44 +0200)
This are to the existing sd_varlink_call_and_upgrade() what
sd_varlink_callb() and sd_varlink_callbo() are to sd_varlink_call():
they put together an object on the fly, via the usual JSON builder
logic.

man/rules/meson.build
man/sd_varlink_call_and_upgrade.xml [new file with mode: 0644]
man/sd_varlink_reply_and_upgrade.xml
src/libsystemd/libsystemd.sym
src/libsystemd/sd-varlink/sd-varlink.c
src/systemd/sd-varlink.h

index 8c21e90090ed86b5922cac18b0229f76ed5ec316..486f565815f56e07cf95ace7aa435929941ea913 100644 (file)
@@ -968,6 +968,10 @@ manpages = [
    'sd_uid_get_sessions',
    'sd_uid_is_on_seat'],
   'HAVE_PAM'],
+ ['sd_varlink_call_and_upgrade',
+  '3',
+  ['sd_varlink_call_and_upgradeb', 'sd_varlink_call_and_upgradebo'],
+  ''],
  ['sd_varlink_connect_address',
   '3',
   ['sd_varlink_connect_exec',
diff --git a/man/sd_varlink_call_and_upgrade.xml b/man/sd_varlink_call_and_upgrade.xml
new file mode 100644 (file)
index 0000000..48eb9de
--- /dev/null
@@ -0,0 +1,177 @@
+<?xml version='1.0'?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
+
+<refentry id="sd_varlink_call_and_upgrade" xmlns:xi="http://www.w3.org/2001/XInclude">
+
+  <refentryinfo>
+    <title>sd_varlink_call_and_upgrade</title>
+    <productname>systemd</productname>
+  </refentryinfo>
+
+  <refmeta>
+    <refentrytitle>sd_varlink_call_and_upgrade</refentrytitle>
+    <manvolnum>3</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>sd_varlink_call_and_upgrade</refname>
+    <refname>sd_varlink_call_and_upgradeb</refname>
+    <refname>sd_varlink_call_and_upgradebo</refname>
+
+    <refpurpose>Invoke a Varlink method and take over the connection for a raw protocol</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcsynopsisinfo>#include &lt;systemd/sd-varlink.h&gt;</funcsynopsisinfo>
+
+      <funcprototype>
+        <funcdef>int <function>sd_varlink_call_and_upgrade</function></funcdef>
+        <paramdef>sd_varlink *<parameter>link</parameter></paramdef>
+        <paramdef>const char *<parameter>method</parameter></paramdef>
+        <paramdef>sd_json_variant *<parameter>parameters</parameter></paramdef>
+        <paramdef>sd_json_variant **<parameter>ret_parameters</parameter></paramdef>
+        <paramdef>const char **<parameter>ret_error_id</parameter></paramdef>
+        <paramdef>int *<parameter>ret_input_fd</parameter></paramdef>
+        <paramdef>int *<parameter>ret_output_fd</parameter></paramdef>
+      </funcprototype>
+
+      <funcprototype>
+        <funcdef>int <function>sd_varlink_call_and_upgradeb</function></funcdef>
+        <paramdef>sd_varlink *<parameter>link</parameter></paramdef>
+        <paramdef>const char *<parameter>method</parameter></paramdef>
+        <paramdef>sd_json_variant **<parameter>ret_parameters</parameter></paramdef>
+        <paramdef>const char **<parameter>ret_error_id</parameter></paramdef>
+        <paramdef>int *<parameter>ret_input_fd</parameter></paramdef>
+        <paramdef>int *<parameter>ret_output_fd</parameter></paramdef>
+        <paramdef>…</paramdef>
+      </funcprototype>
+
+      <funcprototype>
+        <funcdef>int <function>sd_varlink_call_and_upgradebo</function></funcdef>
+        <paramdef>sd_varlink *<parameter>link</parameter></paramdef>
+        <paramdef>const char *<parameter>method</parameter></paramdef>
+        <paramdef>sd_json_variant **<parameter>ret_parameters</parameter></paramdef>
+        <paramdef>const char **<parameter>ret_error_id</parameter></paramdef>
+        <paramdef>int *<parameter>ret_input_fd</parameter></paramdef>
+        <paramdef>int *<parameter>ret_output_fd</parameter></paramdef>
+        <paramdef>…</paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>These functions implement the client side of a Varlink <emphasis>protocol upgrade</emphasis>. They
+    are the counterpart of the server-side
+    <citerefentry><refentrytitle>sd_varlink_reply_and_upgrade</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+    family. If a method call is issued this way, the connection may switch, after the reply, from the Varlink
+    protocol to an arbitrary, non-Varlink ("raw") protocol spoken over the underlying socket or pipe file
+    descriptors, in a manner similar to the <literal>Upgrade:</literal> mechanism of HTTP.</para>
+
+    <para><function>sd_varlink_call_and_upgrade()</function> synchronously invokes the method
+    <parameter>method</parameter> on the connection <parameter>link</parameter>, requesting a protocol upgrade,
+    and waits for the reply. It takes the Varlink connection object, the method name, a JSON object with the
+    method call parameters (which may be <constant>NULL</constant>), two output pointers for the reply
+    parameters and a possible error identifier, and two output pointers for the file descriptors. The reply
+    parameters returned in <parameter>ret_parameters</parameter> and the error identifier returned in
+    <parameter>ret_error_id</parameter> are borrowed references that remain valid only until the connection is
+    closed or unreffed. Either of the two may be passed as <constant>NULL</constant> if the information is not
+    needed.</para>
+
+    <para>If the server replies with a regular reply (rather than a Varlink error) the connection is upgraded:
+    it is disconnected from the Varlink protocol, and ownership of the underlying file descriptors is
+    transferred to the caller via <parameter>ret_input_fd</parameter> and <parameter>ret_output_fd</parameter>,
+    which is responsible for eventually closing them with
+    <citerefentry project='man-pages'><refentrytitle>close</refentrytitle><manvolnum>2</manvolnum></citerefentry>.
+    If the server replies with a Varlink error instead, the connection is <emphasis>not</emphasis> upgraded and
+    no file descriptors are returned; the error identifier is reported in <parameter>ret_error_id</parameter>
+    (if non-<constant>NULL</constant>), otherwise a negative errno-style error derived from it is returned.</para>
+
+    <para>The returned file descriptors are switched to blocking mode. For bidirectional sockets a single
+    underlying file descriptor carries both directions; in this case <parameter>ret_input_fd</parameter> and
+    <parameter>ret_output_fd</parameter> are returned as two independent (duplicated) descriptors referring to
+    the same socket, so they may be closed separately. For transports backed by a pair of pipes the two
+    descriptors differ and refer to the distinct read and write ends. At least one of
+    <parameter>ret_input_fd</parameter> or <parameter>ret_output_fd</parameter> must be
+    non-<constant>NULL</constant>.</para>
+
+    <para><function>sd_varlink_call_and_upgradeb()</function> is similar to
+    <function>sd_varlink_call_and_upgrade()</function>, but instead of expecting a fully constructed
+    <type>sd_json_variant</type> object carrying the method call parameters, this object is constructed
+    on-the-fly from the variadic argument list, in a style identical to
+    <citerefentry><refentrytitle>sd_json_build</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
+    <function>sd_varlink_call_and_upgradebo()</function> is identical to
+    <function>sd_varlink_call_and_upgradeb()</function>, but an enclosing JSON object is added implicitly, so
+    that the argument list is expected to consist of object field pairs only, in a style identical to
+    <citerefentry><refentrytitle>sd_json_buildo</refentrytitle><manvolnum>3</manvolnum></citerefentry>. This
+    relationship mirrors that of
+    <citerefentry><refentrytitle>sd_varlink_call</refentrytitle><manvolnum>3</manvolnum></citerefentry> and its
+    <function>sd_varlink_callb()</function>/<function>sd_varlink_callbo()</function> variants.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>Return Value</title>
+
+    <para>On success, these functions return a positive integer if the connection was upgraded, or zero if the
+    server returned a Varlink error and <parameter>ret_error_id</parameter> was set to it. On failure, they
+    return a negative errno-style error code.</para>
+
+    <refsect2>
+      <title>Errors</title>
+
+      <para>Returned errors may indicate the following problems:</para>
+
+      <variablelist>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
+
+          <listitem><para>An argument is invalid.</para></listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><constant>-ENOTCONN</constant></term>
+
+          <listitem><para>The Varlink connection object is not connected.</para></listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><constant>-EPROTO</constant></term>
+
+          <listitem><para>A protocol error occurred, for example the server sent unexpected raw protocol data
+          before the upgrade completed.</para></listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><constant>-ENOMEM</constant></term>
+
+          <listitem><para>Memory allocation failed.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
+  </refsect1>
+
+  <xi:include href="libsystemd-pkgconfig.xml" />
+
+  <refsect1>
+    <title>History</title>
+    <para><function>sd_varlink_call_and_upgrade()</function> was added in version 261.</para>
+    <para><function>sd_varlink_call_and_upgradeb()</function> and
+    <function>sd_varlink_call_and_upgradebo()</function> were added in version 262.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>See Also</title>
+
+    <para><simplelist type="inline">
+      <member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
+      <member><citerefentry><refentrytitle>sd-varlink</refentrytitle><manvolnum>3</manvolnum></citerefentry></member>
+      <member><citerefentry><refentrytitle>sd_varlink_call</refentrytitle><manvolnum>3</manvolnum></citerefentry></member>
+      <member><citerefentry><refentrytitle>sd_varlink_reply_and_upgrade</refentrytitle><manvolnum>3</manvolnum></citerefentry></member>
+      <member><citerefentry><refentrytitle>sd_json_build</refentrytitle><manvolnum>3</manvolnum></citerefentry></member>
+    </simplelist></para>
+  </refsect1>
+</refentry>
index f51dee3779423bb7a677659f05c5d1f869533072..b2a8f6752f5617056c33eb7bbaa234fc817ba952 100644 (file)
       <member><citerefentry><refentrytitle>sd-varlink</refentrytitle><manvolnum>3</manvolnum></citerefentry></member>
       <member><citerefentry><refentrytitle>sd_varlink_reply</refentrytitle><manvolnum>3</manvolnum></citerefentry></member>
       <member><citerefentry><refentrytitle>sd_varlink_call</refentrytitle><manvolnum>3</manvolnum></citerefentry></member>
+      <member><citerefentry><refentrytitle>sd_varlink_call_and_upgrade</refentrytitle><manvolnum>3</manvolnum></citerefentry></member>
       <member><citerefentry><refentrytitle>sd_varlink_process</refentrytitle><manvolnum>3</manvolnum></citerefentry></member>
       <member><citerefentry><refentrytitle>sd_varlink_set_userdata</refentrytitle><manvolnum>3</manvolnum></citerefentry></member>
       <member><citerefentry><refentrytitle>sd_json_build</refentrytitle><manvolnum>3</manvolnum></citerefentry></member>
index 317c51b4c39ce83aca6f97245f218611c89e5b84..83fb8c92b35eaeca3f2b183a2909a35739dece51 100644 (file)
@@ -1108,6 +1108,7 @@ global:
 LIBSYSTEMD_262 {
 global:
         sd_varlink_bind_upgrade;
+        sd_varlink_call_and_upgradeb;
         sd_varlink_respond_and_upgrade;
         sd_varlink_respond_and_upgradeb;
 } LIBSYSTEMD_261;
index 198883d754c6956141a1562800837a5fa5d640dd..a86e523a47f40055cae2dbba5823a645bfe177ee 100644 (file)
@@ -2183,6 +2183,31 @@ finish:
         return r;
 }
 
+_public_ int sd_varlink_call_and_upgradeb(
+                sd_varlink *v,
+                const char *method,
+                sd_json_variant **ret_parameters,
+                const char **ret_error_id,
+                int *ret_input_fd,
+                int *ret_output_fd,
+                ...) {
+
+        _cleanup_(sd_json_variant_unrefp) sd_json_variant *parameters = NULL;
+        va_list ap;
+        int r;
+
+        assert_return(v, -EINVAL);
+        assert_return(method, -EINVAL);
+
+        va_start(ap, ret_output_fd);
+        r = sd_json_buildv(&parameters, ap);
+        va_end(ap);
+        if (r < 0)
+                return varlink_log_errno(v, r, "Failed to build json message: %m");
+
+        return sd_varlink_call_and_upgrade(v, method, parameters, ret_parameters, ret_error_id, ret_input_fd, ret_output_fd);
+}
+
 _public_ int sd_varlink_callb_ap(
                 sd_varlink *v,
                 const char *method,
index 7480594d74cfc1203db118cf7514434999864e27..3dbb443fa35068be1e78346671452c095d365305 100644 (file)
@@ -145,6 +145,9 @@ int sd_varlink_callb(sd_varlink *v, const char *method, sd_json_variant **ret_pa
  * Returns > 0 if the connection was upgraded, 0 if a Varlink error occurred (and ret_error_id was set),
  * or < 0 on local failure. */
 int sd_varlink_call_and_upgrade(sd_varlink *v, const char *method, sd_json_variant *parameters, sd_json_variant **ret_parameters, const char **ret_error_id, int *ret_input_fd, int *ret_output_fd);
+int sd_varlink_call_and_upgradeb(sd_varlink *v, const char *method, sd_json_variant **ret_parameters, const char **ret_error_id, int *ret_input_fd, int *ret_output_fd, ...);
+#define sd_varlink_call_and_upgradebo(v, method, ret_parameters, ret_error_id, ret_input_fd, ret_output_fd, ...) \
+        sd_varlink_call_and_upgradeb((v), (method), (ret_parameters), (ret_error_id), (ret_input_fd), (ret_output_fd), SD_JSON_BUILD_OBJECT(__VA_ARGS__))
 
 /* Send method call and begin collecting all 'more' replies into an array, finishing when a final reply is sent */
 int sd_varlink_collect_full(sd_varlink *v, const char *method, sd_json_variant *parameters, sd_json_variant **ret_parameters, const char **ret_error_id, sd_varlink_reply_flags_t *ret_flags);