From: Lennart Poettering Date: Wed, 18 Feb 2026 10:47:31 +0000 (+0100) Subject: report: split out service enumeration logic X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0e05a035779ca752590783cc2cc48c111775483e;p=thirdparty%2Fsystemd.git report: split out service enumeration logic We want to reuse it later to list all services, hence make it generic. (Also, allow symlinked services too) --- diff --git a/src/report/report.c b/src/report/report.c index d8e262049af..aea6d97a139 100644 --- a/src/report/report.c +++ b/src/report/report.c @@ -9,12 +9,12 @@ #include "ansi-color.h" #include "build.h" #include "dirent-util.h" -#include "fd-util.h" #include "log.h" #include "main-func.h" #include "parse-argument.h" #include "path-lookup.h" #include "pretty-print.h" +#include "recurse-dir.h" #include "runtime-scope.h" #include "set.h" #include "sort-util.h" @@ -191,7 +191,7 @@ finish: return 0; } -static int metrics_call(Context *context, const char *path) { +static int metrics_call(Context *context, const char *name, const char *path) { _cleanup_(sd_varlink_unrefp) sd_varlink *vl = NULL; int r; @@ -228,16 +228,17 @@ static int metrics_call(Context *context, const char *path) { *li = (LinkInfo) { .context = context, .link = sd_varlink_ref(vl), + .metric_prefix = strdup(name), }; - r = path_extract_filename(path, &li->metric_prefix); - if (r < 0) - return log_error_errno(r, "Failed to extract metric name from path %s: %m", path); + if (!li->metric_prefix) + return log_oom(); - (void) sd_varlink_set_userdata(vl, li); if (set_ensure_put(&context->link_infos, &link_info_hash_ops, li) < 0) return log_oom(); + (void) sd_varlink_set_userdata(vl, li); + TAKE_PTR(li); return 0; } @@ -265,6 +266,50 @@ static int metrics_output_sorted(Context *context) { return 0; } +static int readdir_sources(char **ret_directory, DirectoryEntries **ret) { + int r; + + assert(ret_directory); + assert(ret); + + _cleanup_free_ char *sources_path = NULL; + r = runtime_directory_generic(arg_runtime_scope, "systemd/report", &sources_path); + if (r < 0) + return log_error_errno(r, "Failed to determine sources directory path: %m"); + + log_debug("Looking for metrics in '%s'.", sources_path); + + size_t m = 0; + + _cleanup_free_ DirectoryEntries *de = NULL; + r = readdir_all_at( + AT_FDCWD, + sources_path, + RECURSE_DIR_IGNORE_DOT|RECURSE_DIR_ENSURE_TYPE, + &de); + if (r == -ENOENT) + *ret = NULL; + else if (r < 0) + return log_error_errno(r, "Failed to enumerate '%s': %m", sources_path); + else { + /* Filter out non-sockets/non-symlinks entries */ + FOREACH_ARRAY(i, de->entries, de->n_entries) { + struct dirent *d = *i; + + if (!IN_SET(d->d_type, DT_SOCK, DT_LNK)) + continue; + + de->entries[m++] = *i; + } + + de->n_entries = m; + *ret = TAKE_PTR(de); + } + + *ret_directory = TAKE_PTR(sources_path); + return m > 0; +} + static int verb_metrics(int argc, char *argv[], void *userdata) { Action action; int r; @@ -279,52 +324,46 @@ static int verb_metrics(int argc, char *argv[], void *userdata) { action = ACTION_DESCRIBE; } - _cleanup_free_ char *metrics_path = NULL; - r = runtime_directory_generic(arg_runtime_scope, "systemd/report", &metrics_path); - if (r < 0) - return log_error_errno(r, "Failed to determine metrics directory path: %m"); - - log_debug("Looking for metrics in %s/", metrics_path); - _cleanup_(context_done) Context context = { .action = action, }; + size_t n_skipped_sources = 0; - r = sd_event_default(&context.event); + _cleanup_free_ DirectoryEntries *de = NULL; + _cleanup_free_ char *sources_path = NULL; + r = readdir_sources(&sources_path, &de); if (r < 0) - return log_error_errno(r, "Failed to get event loop: %m"); + return r; + if (r > 0) { + r = sd_event_default(&context.event); + if (r < 0) + return log_error_errno(r, "Failed to get event loop: %m"); - r = sd_event_set_signal_exit(context.event, true); - if (r < 0) - return log_error_errno(r, "Failed to enable exit on SIGINT/SIGTERM: %m"); + r = sd_event_set_signal_exit(context.event, true); + if (r < 0) + return log_error_errno(r, "Failed to enable exit on SIGINT/SIGTERM: %m"); - size_t n_skipped_sources = 0; - _cleanup_closedir_ DIR *d = opendir(metrics_path); - if (!d) { - if (errno != ENOENT) - return log_error_errno(errno, "Failed to open metrics directory %s: %m", metrics_path); - } else - FOREACH_DIRENT(de, d, - return log_warning_errno(errno, "Failed to read %s: %m", metrics_path)) { - - if (!IN_SET(de->d_type, DT_SOCK, DT_UNKNOWN)) - continue; + FOREACH_ARRAY(i, de->entries, de->n_entries) { + struct dirent *d = *i; if (set_size(context.link_infos) >= METRICS_LINKS_MAX) { n_skipped_sources++; break; } - _cleanup_free_ char *p = path_join(metrics_path, de->d_name); + _cleanup_free_ char *p = path_join(sources_path, d->d_name); if (!p) return log_oom(); - (void) metrics_call(&context, p); + (void) metrics_call(&context, d->d_name, p); } + } if (set_isempty(context.link_infos)) log_info("No metrics sources found."); else { + assert(context.event); + r = sd_event_loop(context.event); if (r < 0) return log_error_errno(r, "Failed to run event loop: %m");