From f83fe2552ef28e4d94c438873b7ce09eb35c671d Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 6 Oct 2026 16:57:22 +0200 Subject: [PATCH] perf config: Move perf_config__set_variable() to util/config.c Move perf_config__set_variable() out of the 'perf config' builtin so that opt-in features can persist their choice from outside it, e.g. util/debuginfo.c writing core.debuginfod=false when the user disables debuginfod for the rest of the session. The set_config() body becomes perf_config_set__write(), with the system_config choice as an argument, as the builtin's use_system_config/use_user_config statics are not available outside it. perf_config_set__write() checked fopen() but none of the fprintf()s or fclose(), so a write failure after truncating the file was reported as success. Harmless for the interactive 'perf config' this came from, but this makes it an entry point a background feature can call with no other feedback, so propagate those errors too. Assisted-by: LLM Reviewed-by: Namhyung Kim Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-config.c | 70 +--------------------------------- tools/perf/util/config.c | 76 +++++++++++++++++++++++++++++++++++++ tools/perf/util/config.h | 2 + 3 files changed, 79 insertions(+), 69 deletions(-) diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c index cefd042e4f85..3b074aca8d34 100644 --- a/tools/perf/builtin-config.c +++ b/tools/perf/builtin-config.c @@ -41,37 +41,7 @@ static struct option config_options[] = { static int set_config(struct perf_config_set *set, const char *file_name) { - struct perf_config_section *section = NULL; - struct perf_config_item *item = NULL; - const char *first_line = "# this file is auto-generated."; - FILE *fp; - - if (set == NULL) - return -1; - - fp = fopen(file_name, "w"); - if (!fp) - return -1; - - fprintf(fp, "%s\n", first_line); - - /* overwrite configvariables */ - perf_config_items__for_each_entry(&set->sections, section) { - if (!use_system_config && section->from_system_config) - continue; - fprintf(fp, "[%s]\n", section->name); - - perf_config_items__for_each_entry(§ion->items, item) { - if (!use_system_config && item->from_system_config) - continue; - if (item->value) - fprintf(fp, "\t%s = %s\n", - item->name, item->value); - } - } - fclose(fp); - - return 0; + return perf_config_set__write(set, file_name, use_system_config); } static int show_spec_config(struct perf_config_set *set, const char *var) @@ -158,44 +128,6 @@ static int parse_config_arg(char *arg, char **var, char **value) return 0; } -int perf_config__set_variable(const char *var, const char *value) -{ - char path[PATH_MAX]; - char *user_config = mkpath(path, sizeof(path), "%s/.perfconfig", getenv("HOME")); - const char *config_filename; - struct perf_config_set *set; - int ret = -1; - - if (use_system_config) - config_exclusive_filename = perf_etc_perfconfig(); - else if (use_user_config) - config_exclusive_filename = user_config; - - if (!config_exclusive_filename) - config_filename = user_config; - else - config_filename = config_exclusive_filename; - - set = perf_config_set__new(); - if (!set) - goto out_err; - - if (perf_config_set__collect(set, config_filename, var, value) < 0) { - pr_err("Failed to add '%s=%s'\n", var, value); - goto out_err; - } - - if (set_config(set, config_filename) < 0) { - pr_err("Failed to set the configs on %s\n", config_filename); - goto out_err; - } - - ret = 0; -out_err: - perf_config_set__delete(set); - return ret; -} - int cmd_config(int argc, const char **argv) { int i, ret = -1; diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index 8fe43b032e9a..85e50d0a2558 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c @@ -12,6 +12,7 @@ #include "config.h" #include +#include #include #include #include @@ -883,6 +884,81 @@ void perf_config__exit(void) config_set = NULL; } +int perf_config_set__write(struct perf_config_set *set, + const char *file_name, bool system_config) +{ + struct perf_config_section *section = NULL; + struct perf_config_item *item = NULL; + int ret = 0; + FILE *fp; + + fp = fopen(file_name, "w"); + if (!fp) + return -1; + + if (fprintf(fp, "# this file is auto-generated.\n") < 0) + ret = -1; + + /* overwrite configvariables */ + perf_config_sections__for_each_entry(&set->sections, section) { + if (!system_config && section->from_system_config) + continue; + if (fprintf(fp, "[%s]\n", section->name) < 0) + ret = -1; + + perf_config_items__for_each_entry(§ion->items, item) { + if (!system_config && item->from_system_config) + continue; + if (item->value && + fprintf(fp, "\t%s = %s\n", item->name, item->value) < 0) + ret = -1; + } + } + if (fclose(fp) != 0) + ret = -1; + + return ret; +} + +/* + * Set @var=@value in the config file perf is using: ~/.perfconfig or the + * file named by PERF_CONFIG. Same rewrite 'perf config' does, comments + * are not preserved. + */ +int perf_config__set_variable(const char *var, const char *value) +{ + char path[PATH_MAX]; + char *user_config = mkpath(path, sizeof(path), "%s/.perfconfig", getenv("HOME")); + const char *config_filename; + bool system_config; + struct perf_config_set *set; + int ret = -1; + + config_filename = config_exclusive_filename ?: user_config; + + /* Rewriting the system wide file keeps its entries, or it is truncated. */ + system_config = strcmp(config_filename, perf_etc_perfconfig()) == 0; + + set = perf_config_set__new(); + if (!set) + goto out_err; + + if (perf_config_set__collect(set, config_filename, var, value) < 0) { + pr_err("Failed to add '%s=%s'\n", var, value); + goto out_err; + } + + if (perf_config_set__write(set, config_filename, system_config) < 0) { + pr_err("Failed to set the configs on %s\n", config_filename); + goto out_err; + } + + ret = 0; +out_err: + perf_config_set__delete(set); + return ret; +} + static void perf_config_item__delete(struct perf_config_item *item) { zfree(&item->name); diff --git a/tools/perf/util/config.h b/tools/perf/util/config.h index 987b47cf54c3..9098f8a04585 100644 --- a/tools/perf/util/config.h +++ b/tools/perf/util/config.h @@ -33,6 +33,8 @@ int perf_config_scan(const char *name, const char *fmt, ...) __scanf(2, 3); const char *perf_config_get(const char *name); int perf_config_set(struct perf_config_set *set, config_fn_t fn, void *data); +int perf_config_set__write(struct perf_config_set *set, + const char *file_name, bool system_config); int perf_config_int(int *dest, const char *, const char *); int perf_config_u8(u8 *dest, const char *name, const char *value); int perf_config_u64(u64 *dest, const char *, const char *);