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 <namhyung@kernel.org>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
Arnaldo Carvalho de Melo 2026-10-06 16:57:22 +02:00
parent 5c52bb6584
commit f83fe2552e
3 changed files with 79 additions and 69 deletions

View File

@ -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(&section->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;

View File

@ -12,6 +12,7 @@
#include "config.h"
#include <errno.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
@ -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(&section->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);

View File

@ -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 *);