varlink-util: add varlink_execute_directory() flavour that returns unconnectable sockets

This commit is contained in:
Lennart Poettering committed 2026-10-17 18:02:40 +02:00
1 parent 8948eb15d9
commit e878354562
3 files changed
+62 -4

No files matched your search

+42
View File
@@ -21,6 +21,7 @@
#include "rm-rf.h"
#include "socket-util.h"
#include "string-util.h"
#include "strv.h"
#include "tests.h"
#include "time-util.h"
#include "tmpfile-util.h"
@@ -1515,6 +1516,20 @@ static int execute_dir_client_fiber(void *arg) {
a->reply_count), (ssize_t) a->n_servers);
ASSERT_EQ(*a->reply_count, a->n_servers);
/* Sockets that have a live listener must be counted as contacted, not as offline. */
_cleanup_strv_free_ char **offline = NULL;
ASSERT_OK_EQ(varlink_execute_directory_full(
a->tmpdir,
"io.test.ExecDirPing",
/* parameters= */ NULL,
/* more= */ false,
/* timeout_usec= */ USEC_INFINITY,
execute_dir_reply,
a->reply_count,
&offline), (ssize_t) a->n_servers);
ASSERT_TRUE(strv_isempty(offline));
ASSERT_EQ(*a->reply_count, 2 * a->n_servers);
/* Calling the helper against a non-existent directory must fail. */
_cleanup_free_ char *nope = NULL;
ASSERT_OK(asprintf(&nope, "%s/does-not-exist", a->tmpdir));
@@ -1542,6 +1557,33 @@ static int execute_dir_client_fiber(void *arg) {
a->reply_count));
ASSERT_EQ(*a->reply_count, count_before);
ASSERT_OK_ZERO(varlink_execute_directory_full(
empty,
"io.test.ExecDirPing",
/* parameters= */ NULL,
/* more= */ false,
/* timeout_usec= */ USEC_INFINITY,
execute_dir_reply,
a->reply_count,
&offline));
ASSERT_TRUE(strv_isempty(offline));
/* A socket inode nobody listens on must not be counted as contacted, but as offline. */
_cleanup_free_ char *dead = ASSERT_PTR(path_join(empty, "dead"));
ASSERT_OK_ERRNO(mknod(dead, S_IFSOCK|0600, 0));
ASSERT_OK_ZERO(varlink_execute_directory_full(
empty,
"io.test.ExecDirPing",
/* parameters= */ NULL,
/* more= */ false,
/* timeout_usec= */ USEC_INFINITY,
execute_dir_reply,
a->reply_count,
&offline));
ASSERT_TRUE(strv_equal(offline, STRV_MAKE("dead")));
ASSERT_EQ(*a->reply_count, count_before);
ASSERT_OK(sd_event_exit(sd_fiber_get_event(), EXIT_SUCCESS));
return 0;
}
+16 -3
View File
@@ -13,6 +13,7 @@
#include "set.h"
#include "socket-util.h"
#include "string-util.h"
#include "strv.h"
#include "varlink-internal.h"
#include "varlink-util.h"
#include "version.h"
@@ -245,14 +246,15 @@ static int varlink_finish_idle(Set *s) {
#define VARLINK_EXECUTE_SOCKETS_MAX 255
ssize_t varlink_execute_directory(
ssize_t varlink_execute_directory_full(
const char *path,
const char *method,
sd_json_variant *parameters,
bool more,
usec_t timeout_usec,
sd_varlink_reply_t reply,
void *userdata) {
void *userdata,
char ***ret_offline_sockets) {
int r;
@@ -262,7 +264,10 @@ ssize_t varlink_execute_directory(
/* Invokes the specified method on all Varlink sockets in the specified directory. Any reply
* will be dispatched to the reply callback. Blocks until the last reply has come in.
*
* Returns how many sockets were contacted.
* Returns how many sockets were contacted. If ret_offline_sockets is non-NULL it is set to the
* names of the sockets that exist in the directory but could not be contacted (because nobody
* listens on them, or because there are too many of them). This allows callers to distinguish
* "nobody there" from "somebody there, but not reachable".
*
* Usecase for all of this: hook directories, where components can link their sockets into to get
* notified about certain system events. */
@@ -278,6 +283,7 @@ ssize_t varlink_execute_directory(
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
_cleanup_(set_freep) Set *links = NULL;
_cleanup_strv_free_ char **offline = NULL;
size_t t = 0;
FOREACH_ARRAY(dp, dentries->entries, dentries->n_entries) {
struct dirent *de = *dp;
@@ -290,6 +296,8 @@ ssize_t varlink_execute_directory(
if (set_size(links) >= VARLINK_EXECUTE_SOCKETS_MAX) {
log_debug("Too many sockets (%zu) in directory, skipping '%s'.", t, j);
if (ret_offline_sockets && strv_extend(&offline, de->d_name) < 0)
return log_oom_debug();
continue;
}
@@ -300,6 +308,8 @@ ssize_t varlink_execute_directory(
r = connect_unix_path(socket_fd, fd, de->d_name);
if (r < 0) {
log_debug_errno(r, "Failed to connect to '%s', ignoring: %m", j);
if (ret_offline_sockets && strv_extend(&offline, de->d_name) < 0)
return log_oom_debug();
continue;
}
@@ -377,5 +387,8 @@ ssize_t varlink_execute_directory(
return r;
}
if (ret_offline_sockets)
*ret_offline_sockets = TAKE_PTR(offline);
return (ssize_t) c;
}
+4 -1
View File
@@ -34,4 +34,7 @@ int varlink_check_privileged_peer(sd_varlink *vl);
extern const struct hash_ops varlink_hash_ops;
ssize_t varlink_execute_directory(const char *path, const char *method, sd_json_variant *parameters, bool more, usec_t timeout_usec, sd_varlink_reply_t reply, void *userdata);
ssize_t varlink_execute_directory_full(const char *path, const char *method, sd_json_variant *parameters, bool more, usec_t timeout_usec, sd_varlink_reply_t reply, void *userdata, char ***ret_offline_sockets);
static inline ssize_t varlink_execute_directory(const char *path, const char *method, sd_json_variant *parameters, bool more, usec_t timeout_usec, sd_varlink_reply_t reply, void *userdata) {
return varlink_execute_directory_full(path, method, parameters, more, timeout_usec, reply, userdata, /* ret_offline_sockets= */ NULL);
}