From 953d21846aad072103b5da00e2f67f7378335bb5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 7 Jul 2026 12:45:31 +0200 Subject: [PATCH] sd-varlink: add sd_varlink_call_and_upgradeb() + sd_varlink_call_and_upgradebo() 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 | 4 + man/sd_varlink_call_and_upgrade.xml | 177 +++++++++++++++++++++++++ man/sd_varlink_reply_and_upgrade.xml | 1 + src/libsystemd/libsystemd.sym | 1 + src/libsystemd/sd-varlink/sd-varlink.c | 25 ++++ src/systemd/sd-varlink.h | 3 + 6 files changed, 211 insertions(+) create mode 100644 man/sd_varlink_call_and_upgrade.xml diff --git a/man/rules/meson.build b/man/rules/meson.build index 8c21e90090e..486f565815f 100644 --- a/man/rules/meson.build +++ b/man/rules/meson.build @@ -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 index 00000000000..48eb9de93f7 --- /dev/null +++ b/man/sd_varlink_call_and_upgrade.xml @@ -0,0 +1,177 @@ + + + + + + + + sd_varlink_call_and_upgrade + systemd + + + + sd_varlink_call_and_upgrade + 3 + + + + sd_varlink_call_and_upgrade + sd_varlink_call_and_upgradeb + sd_varlink_call_and_upgradebo + + Invoke a Varlink method and take over the connection for a raw protocol + + + + + #include <systemd/sd-varlink.h> + + + int sd_varlink_call_and_upgrade + sd_varlink *link + 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 *link + const char *method + sd_json_variant **ret_parameters + const char **ret_error_id + int *ret_input_fd + int *ret_output_fd + … + + + + int sd_varlink_call_and_upgradebo + sd_varlink *link + const char *method + sd_json_variant **ret_parameters + const char **ret_error_id + int *ret_input_fd + int *ret_output_fd + … + + + + + + Description + + These functions implement the client side of a Varlink protocol upgrade. They + are the counterpart of the server-side + sd_varlink_reply_and_upgrade3 + 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 Upgrade: mechanism of HTTP. + + sd_varlink_call_and_upgrade() synchronously invokes the method + method on the connection link, 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 NULL), 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 ret_parameters and the error identifier returned in + ret_error_id are borrowed references that remain valid only until the connection is + closed or unreffed. Either of the two may be passed as NULL if the information is not + needed. + + 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 ret_input_fd and ret_output_fd, + which is responsible for eventually closing them with + close2. + If the server replies with a Varlink error instead, the connection is not upgraded and + no file descriptors are returned; the error identifier is reported in ret_error_id + (if non-NULL), otherwise a negative errno-style error derived from it is returned. + + The returned file descriptors are switched to blocking mode. For bidirectional sockets a single + underlying file descriptor carries both directions; in this case ret_input_fd and + ret_output_fd 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 + ret_input_fd or ret_output_fd must be + non-NULL. + + sd_varlink_call_and_upgradeb() is similar to + sd_varlink_call_and_upgrade(), but instead of expecting a fully constructed + sd_json_variant object carrying the method call parameters, this object is constructed + on-the-fly from the variadic argument list, in a style identical to + sd_json_build3. + sd_varlink_call_and_upgradebo() is identical to + sd_varlink_call_and_upgradeb(), 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 + sd_json_buildo3. This + relationship mirrors that of + sd_varlink_call3 and its + sd_varlink_callb()/sd_varlink_callbo() variants. + + + + Return Value + + On success, these functions return a positive integer if the connection was upgraded, or zero if the + server returned a Varlink error and ret_error_id was set to it. On failure, they + return a negative errno-style error code. + + + Errors + + Returned errors may indicate the following problems: + + + + -EINVAL + + An argument is invalid. + + + + -ENOTCONN + + The Varlink connection object is not connected. + + + + -EPROTO + + A protocol error occurred, for example the server sent unexpected raw protocol data + before the upgrade completed. + + + + -ENOMEM + + Memory allocation failed. + + + + + + + + + History + sd_varlink_call_and_upgrade() was added in version 261. + sd_varlink_call_and_upgradeb() and + sd_varlink_call_and_upgradebo() were added in version 262. + + + + See Also + + + systemd1 + sd-varlink3 + sd_varlink_call3 + sd_varlink_reply_and_upgrade3 + sd_json_build3 + + + diff --git a/man/sd_varlink_reply_and_upgrade.xml b/man/sd_varlink_reply_and_upgrade.xml index f51dee37794..b2a8f6752f5 100644 --- a/man/sd_varlink_reply_and_upgrade.xml +++ b/man/sd_varlink_reply_and_upgrade.xml @@ -219,6 +219,7 @@ sd-varlink3 sd_varlink_reply3 sd_varlink_call3 + sd_varlink_call_and_upgrade3 sd_varlink_process3 sd_varlink_set_userdata3 sd_json_build3 diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym index 317c51b4c39..83fb8c92b35 100644 --- a/src/libsystemd/libsystemd.sym +++ b/src/libsystemd/libsystemd.sym @@ -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; diff --git a/src/libsystemd/sd-varlink/sd-varlink.c b/src/libsystemd/sd-varlink/sd-varlink.c index 198883d754c..a86e523a47f 100644 --- a/src/libsystemd/sd-varlink/sd-varlink.c +++ b/src/libsystemd/sd-varlink/sd-varlink.c @@ -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(¶meters, 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, diff --git a/src/systemd/sd-varlink.h b/src/systemd/sd-varlink.h index 7480594d74c..3dbb443fa35 100644 --- a/src/systemd/sd-varlink.h +++ b/src/systemd/sd-varlink.h @@ -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); -- 2.47.3