libsystemd,varlink: always return two fds in varlink upgrade API

This commit tweaks the API of sd_varlink_call_and_upgrade and
sd_varlink_reply_and_upgrade to return two independent fds even
if the internal {input,output}_fd are the same (e.g. a socket).

This makes the external API easier as there is no longer the risk
of double close. The sd_varlink_call_and_upgrade() is not in a
released version of systemd yet so I presume it is okay to update
it still.

This also allowed some simplifications in varlinkctl.c now that
the handling is easier.
This commit is contained in:
Michael Vogt
2026-04-09 13:02:11 +02:00
committed by Daan De Meyer
parent 34f29079fd
commit 0d21b105d2
4 changed files with 23 additions and 46 deletions
+10 -12
View File
@@ -2415,29 +2415,27 @@ static int varlink_handle_upgrade_fds(sd_varlink *v, int *ret_input_fd, int *ret
return varlink_log_errno(v, r, "Failed to set output fd to blocking mode: %m");
}
/* Hand out the fds to the caller. When the caller doesn't want one direction, shut it
* down: but avoid closing the underlying fd if the other direction still needs it
* (i.e. when input_fd == output_fd). */
bool same_fd = v->input_fd == v->output_fd;
/* For bidirectional sockets (input_fd == output_fd), dup the fd so that callers
* always get two independent fds they can close separately. */
if (v->input_fd == v->output_fd) {
v->output_fd = fcntl(v->input_fd, F_DUPFD_CLOEXEC, 3);
if (v->output_fd < 0)
return varlink_log_errno(v, errno, "Failed to dup upgraded connection fd: %m");
}
/* Hand out requested fds, shut down unwanted directions. */
if (ret_input_fd)
*ret_input_fd = TAKE_FD(v->input_fd);
else {
(void) shutdown(v->input_fd, SHUT_RD);
if (same_fd && ret_output_fd)
TAKE_FD(v->input_fd); /* don't close yet, output branch needs it */
else
v->input_fd = safe_close(v->input_fd);
v->input_fd = safe_close(v->input_fd);
}
if (ret_output_fd)
*ret_output_fd = TAKE_FD(v->output_fd);
else {
(void) shutdown(v->output_fd, SHUT_WR);
if (same_fd && ret_input_fd)
TAKE_FD(v->output_fd);
else
v->output_fd = safe_close(v->output_fd);
v->output_fd = safe_close(v->output_fd);
}
return 0;