162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * config.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Helper functions for parsing config items.
662306a36Sopenharmony_ci * Originally copied from GIT source.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Copyright (C) Linus Torvalds, 2005
962306a36Sopenharmony_ci * Copyright (C) Johannes Schindelin, 2005
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci#include <errno.h>
1362306a36Sopenharmony_ci#include <sys/param.h>
1462306a36Sopenharmony_ci#include "cache.h"
1562306a36Sopenharmony_ci#include "callchain.h"
1662306a36Sopenharmony_ci#include <subcmd/exec-cmd.h>
1762306a36Sopenharmony_ci#include "util/event.h"  /* proc_map_timeout */
1862306a36Sopenharmony_ci#include "util/hist.h"  /* perf_hist_config */
1962306a36Sopenharmony_ci#include "util/stat.h"  /* perf_stat__set_big_num */
2062306a36Sopenharmony_ci#include "util/evsel.h"  /* evsel__hw_names, evsel__use_bpf_counters */
2162306a36Sopenharmony_ci#include "util/srcline.h"  /* addr2line_timeout_ms */
2262306a36Sopenharmony_ci#include "build-id.h"
2362306a36Sopenharmony_ci#include "debug.h"
2462306a36Sopenharmony_ci#include "config.h"
2562306a36Sopenharmony_ci#include <sys/types.h>
2662306a36Sopenharmony_ci#include <sys/stat.h>
2762306a36Sopenharmony_ci#include <stdlib.h>
2862306a36Sopenharmony_ci#include <unistd.h>
2962306a36Sopenharmony_ci#include <linux/string.h>
3062306a36Sopenharmony_ci#include <linux/zalloc.h>
3162306a36Sopenharmony_ci#include <linux/ctype.h>
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#define MAXNAME (256)
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#define DEBUG_CACHE_DIR ".debug"
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cichar buildid_dir[MAXPATHLEN]; /* root dir for buildid, binary cache */
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cistatic FILE *config_file;
4162306a36Sopenharmony_cistatic const char *config_file_name;
4262306a36Sopenharmony_cistatic int config_linenr;
4362306a36Sopenharmony_cistatic int config_file_eof;
4462306a36Sopenharmony_cistatic struct perf_config_set *config_set;
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ciconst char *config_exclusive_filename;
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cistatic int get_next_char(void)
4962306a36Sopenharmony_ci{
5062306a36Sopenharmony_ci	int c;
5162306a36Sopenharmony_ci	FILE *f;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	c = '\n';
5462306a36Sopenharmony_ci	if ((f = config_file) != NULL) {
5562306a36Sopenharmony_ci		c = fgetc(f);
5662306a36Sopenharmony_ci		if (c == '\r') {
5762306a36Sopenharmony_ci			/* DOS like systems */
5862306a36Sopenharmony_ci			c = fgetc(f);
5962306a36Sopenharmony_ci			if (c != '\n') {
6062306a36Sopenharmony_ci				ungetc(c, f);
6162306a36Sopenharmony_ci				c = '\r';
6262306a36Sopenharmony_ci			}
6362306a36Sopenharmony_ci		}
6462306a36Sopenharmony_ci		if (c == '\n')
6562306a36Sopenharmony_ci			config_linenr++;
6662306a36Sopenharmony_ci		if (c == EOF) {
6762306a36Sopenharmony_ci			config_file_eof = 1;
6862306a36Sopenharmony_ci			c = '\n';
6962306a36Sopenharmony_ci		}
7062306a36Sopenharmony_ci	}
7162306a36Sopenharmony_ci	return c;
7262306a36Sopenharmony_ci}
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_cistatic char *parse_value(void)
7562306a36Sopenharmony_ci{
7662306a36Sopenharmony_ci	static char value[1024];
7762306a36Sopenharmony_ci	int quote = 0, comment = 0, space = 0;
7862306a36Sopenharmony_ci	size_t len = 0;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	for (;;) {
8162306a36Sopenharmony_ci		int c = get_next_char();
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci		if (len >= sizeof(value) - 1)
8462306a36Sopenharmony_ci			return NULL;
8562306a36Sopenharmony_ci		if (c == '\n') {
8662306a36Sopenharmony_ci			if (quote)
8762306a36Sopenharmony_ci				return NULL;
8862306a36Sopenharmony_ci			value[len] = 0;
8962306a36Sopenharmony_ci			return value;
9062306a36Sopenharmony_ci		}
9162306a36Sopenharmony_ci		if (comment)
9262306a36Sopenharmony_ci			continue;
9362306a36Sopenharmony_ci		if (isspace(c) && !quote) {
9462306a36Sopenharmony_ci			space = 1;
9562306a36Sopenharmony_ci			continue;
9662306a36Sopenharmony_ci		}
9762306a36Sopenharmony_ci		if (!quote) {
9862306a36Sopenharmony_ci			if (c == ';' || c == '#') {
9962306a36Sopenharmony_ci				comment = 1;
10062306a36Sopenharmony_ci				continue;
10162306a36Sopenharmony_ci			}
10262306a36Sopenharmony_ci		}
10362306a36Sopenharmony_ci		if (space) {
10462306a36Sopenharmony_ci			if (len)
10562306a36Sopenharmony_ci				value[len++] = ' ';
10662306a36Sopenharmony_ci			space = 0;
10762306a36Sopenharmony_ci		}
10862306a36Sopenharmony_ci		if (c == '\\') {
10962306a36Sopenharmony_ci			c = get_next_char();
11062306a36Sopenharmony_ci			switch (c) {
11162306a36Sopenharmony_ci			case '\n':
11262306a36Sopenharmony_ci				continue;
11362306a36Sopenharmony_ci			case 't':
11462306a36Sopenharmony_ci				c = '\t';
11562306a36Sopenharmony_ci				break;
11662306a36Sopenharmony_ci			case 'b':
11762306a36Sopenharmony_ci				c = '\b';
11862306a36Sopenharmony_ci				break;
11962306a36Sopenharmony_ci			case 'n':
12062306a36Sopenharmony_ci				c = '\n';
12162306a36Sopenharmony_ci				break;
12262306a36Sopenharmony_ci			/* Some characters escape as themselves */
12362306a36Sopenharmony_ci			case '\\': case '"':
12462306a36Sopenharmony_ci				break;
12562306a36Sopenharmony_ci			/* Reject unknown escape sequences */
12662306a36Sopenharmony_ci			default:
12762306a36Sopenharmony_ci				return NULL;
12862306a36Sopenharmony_ci			}
12962306a36Sopenharmony_ci			value[len++] = c;
13062306a36Sopenharmony_ci			continue;
13162306a36Sopenharmony_ci		}
13262306a36Sopenharmony_ci		if (c == '"') {
13362306a36Sopenharmony_ci			quote = 1-quote;
13462306a36Sopenharmony_ci			continue;
13562306a36Sopenharmony_ci		}
13662306a36Sopenharmony_ci		value[len++] = c;
13762306a36Sopenharmony_ci	}
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cistatic inline int iskeychar(int c)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	return isalnum(c) || c == '-' || c == '_';
14362306a36Sopenharmony_ci}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_cistatic int get_value(config_fn_t fn, void *data, char *name, unsigned int len)
14662306a36Sopenharmony_ci{
14762306a36Sopenharmony_ci	int c;
14862306a36Sopenharmony_ci	char *value;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	/* Get the full name */
15162306a36Sopenharmony_ci	for (;;) {
15262306a36Sopenharmony_ci		c = get_next_char();
15362306a36Sopenharmony_ci		if (config_file_eof)
15462306a36Sopenharmony_ci			break;
15562306a36Sopenharmony_ci		if (!iskeychar(c))
15662306a36Sopenharmony_ci			break;
15762306a36Sopenharmony_ci		name[len++] = c;
15862306a36Sopenharmony_ci		if (len >= MAXNAME)
15962306a36Sopenharmony_ci			return -1;
16062306a36Sopenharmony_ci	}
16162306a36Sopenharmony_ci	name[len] = 0;
16262306a36Sopenharmony_ci	while (c == ' ' || c == '\t')
16362306a36Sopenharmony_ci		c = get_next_char();
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	value = NULL;
16662306a36Sopenharmony_ci	if (c != '\n') {
16762306a36Sopenharmony_ci		if (c != '=')
16862306a36Sopenharmony_ci			return -1;
16962306a36Sopenharmony_ci		value = parse_value();
17062306a36Sopenharmony_ci		if (!value)
17162306a36Sopenharmony_ci			return -1;
17262306a36Sopenharmony_ci	}
17362306a36Sopenharmony_ci	return fn(name, value, data);
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_cistatic int get_extended_base_var(char *name, int baselen, int c)
17762306a36Sopenharmony_ci{
17862306a36Sopenharmony_ci	do {
17962306a36Sopenharmony_ci		if (c == '\n')
18062306a36Sopenharmony_ci			return -1;
18162306a36Sopenharmony_ci		c = get_next_char();
18262306a36Sopenharmony_ci	} while (isspace(c));
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	/* We require the format to be '[base "extension"]' */
18562306a36Sopenharmony_ci	if (c != '"')
18662306a36Sopenharmony_ci		return -1;
18762306a36Sopenharmony_ci	name[baselen++] = '.';
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	for (;;) {
19062306a36Sopenharmony_ci		int ch = get_next_char();
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci		if (ch == '\n')
19362306a36Sopenharmony_ci			return -1;
19462306a36Sopenharmony_ci		if (ch == '"')
19562306a36Sopenharmony_ci			break;
19662306a36Sopenharmony_ci		if (ch == '\\') {
19762306a36Sopenharmony_ci			ch = get_next_char();
19862306a36Sopenharmony_ci			if (ch == '\n')
19962306a36Sopenharmony_ci				return -1;
20062306a36Sopenharmony_ci		}
20162306a36Sopenharmony_ci		name[baselen++] = ch;
20262306a36Sopenharmony_ci		if (baselen > MAXNAME / 2)
20362306a36Sopenharmony_ci			return -1;
20462306a36Sopenharmony_ci	}
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	/* Final ']' */
20762306a36Sopenharmony_ci	if (get_next_char() != ']')
20862306a36Sopenharmony_ci		return -1;
20962306a36Sopenharmony_ci	return baselen;
21062306a36Sopenharmony_ci}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_cistatic int get_base_var(char *name)
21362306a36Sopenharmony_ci{
21462306a36Sopenharmony_ci	int baselen = 0;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	for (;;) {
21762306a36Sopenharmony_ci		int c = get_next_char();
21862306a36Sopenharmony_ci		if (config_file_eof)
21962306a36Sopenharmony_ci			return -1;
22062306a36Sopenharmony_ci		if (c == ']')
22162306a36Sopenharmony_ci			return baselen;
22262306a36Sopenharmony_ci		if (isspace(c))
22362306a36Sopenharmony_ci			return get_extended_base_var(name, baselen, c);
22462306a36Sopenharmony_ci		if (!iskeychar(c) && c != '.')
22562306a36Sopenharmony_ci			return -1;
22662306a36Sopenharmony_ci		if (baselen > MAXNAME / 2)
22762306a36Sopenharmony_ci			return -1;
22862306a36Sopenharmony_ci		name[baselen++] = tolower(c);
22962306a36Sopenharmony_ci	}
23062306a36Sopenharmony_ci}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_cistatic int perf_parse_file(config_fn_t fn, void *data)
23362306a36Sopenharmony_ci{
23462306a36Sopenharmony_ci	int comment = 0;
23562306a36Sopenharmony_ci	int baselen = 0;
23662306a36Sopenharmony_ci	static char var[MAXNAME];
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	/* U+FEFF Byte Order Mark in UTF8 */
23962306a36Sopenharmony_ci	static const unsigned char *utf8_bom = (unsigned char *) "\xef\xbb\xbf";
24062306a36Sopenharmony_ci	const unsigned char *bomptr = utf8_bom;
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	for (;;) {
24362306a36Sopenharmony_ci		int line, c = get_next_char();
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci		if (bomptr && *bomptr) {
24662306a36Sopenharmony_ci			/* We are at the file beginning; skip UTF8-encoded BOM
24762306a36Sopenharmony_ci			 * if present. Sane editors won't put this in on their
24862306a36Sopenharmony_ci			 * own, but e.g. Windows Notepad will do it happily. */
24962306a36Sopenharmony_ci			if ((unsigned char) c == *bomptr) {
25062306a36Sopenharmony_ci				bomptr++;
25162306a36Sopenharmony_ci				continue;
25262306a36Sopenharmony_ci			} else {
25362306a36Sopenharmony_ci				/* Do not tolerate partial BOM. */
25462306a36Sopenharmony_ci				if (bomptr != utf8_bom)
25562306a36Sopenharmony_ci					break;
25662306a36Sopenharmony_ci				/* No BOM at file beginning. Cool. */
25762306a36Sopenharmony_ci				bomptr = NULL;
25862306a36Sopenharmony_ci			}
25962306a36Sopenharmony_ci		}
26062306a36Sopenharmony_ci		if (c == '\n') {
26162306a36Sopenharmony_ci			if (config_file_eof)
26262306a36Sopenharmony_ci				return 0;
26362306a36Sopenharmony_ci			comment = 0;
26462306a36Sopenharmony_ci			continue;
26562306a36Sopenharmony_ci		}
26662306a36Sopenharmony_ci		if (comment || isspace(c))
26762306a36Sopenharmony_ci			continue;
26862306a36Sopenharmony_ci		if (c == '#' || c == ';') {
26962306a36Sopenharmony_ci			comment = 1;
27062306a36Sopenharmony_ci			continue;
27162306a36Sopenharmony_ci		}
27262306a36Sopenharmony_ci		if (c == '[') {
27362306a36Sopenharmony_ci			baselen = get_base_var(var);
27462306a36Sopenharmony_ci			if (baselen <= 0)
27562306a36Sopenharmony_ci				break;
27662306a36Sopenharmony_ci			var[baselen++] = '.';
27762306a36Sopenharmony_ci			var[baselen] = 0;
27862306a36Sopenharmony_ci			continue;
27962306a36Sopenharmony_ci		}
28062306a36Sopenharmony_ci		if (!isalpha(c))
28162306a36Sopenharmony_ci			break;
28262306a36Sopenharmony_ci		var[baselen] = tolower(c);
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci		/*
28562306a36Sopenharmony_ci		 * The get_value function might or might not reach the '\n',
28662306a36Sopenharmony_ci		 * so saving the current line number for error reporting.
28762306a36Sopenharmony_ci		 */
28862306a36Sopenharmony_ci		line = config_linenr;
28962306a36Sopenharmony_ci		if (get_value(fn, data, var, baselen+1) < 0) {
29062306a36Sopenharmony_ci			config_linenr = line;
29162306a36Sopenharmony_ci			break;
29262306a36Sopenharmony_ci		}
29362306a36Sopenharmony_ci	}
29462306a36Sopenharmony_ci	pr_err("bad config file line %d in %s\n", config_linenr, config_file_name);
29562306a36Sopenharmony_ci	return -1;
29662306a36Sopenharmony_ci}
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_cistatic int parse_unit_factor(const char *end, unsigned long *val)
29962306a36Sopenharmony_ci{
30062306a36Sopenharmony_ci	if (!*end)
30162306a36Sopenharmony_ci		return 1;
30262306a36Sopenharmony_ci	else if (!strcasecmp(end, "k")) {
30362306a36Sopenharmony_ci		*val *= 1024;
30462306a36Sopenharmony_ci		return 1;
30562306a36Sopenharmony_ci	}
30662306a36Sopenharmony_ci	else if (!strcasecmp(end, "m")) {
30762306a36Sopenharmony_ci		*val *= 1024 * 1024;
30862306a36Sopenharmony_ci		return 1;
30962306a36Sopenharmony_ci	}
31062306a36Sopenharmony_ci	else if (!strcasecmp(end, "g")) {
31162306a36Sopenharmony_ci		*val *= 1024 * 1024 * 1024;
31262306a36Sopenharmony_ci		return 1;
31362306a36Sopenharmony_ci	}
31462306a36Sopenharmony_ci	return 0;
31562306a36Sopenharmony_ci}
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_cistatic int perf_parse_llong(const char *value, long long *ret)
31862306a36Sopenharmony_ci{
31962306a36Sopenharmony_ci	if (value && *value) {
32062306a36Sopenharmony_ci		char *end;
32162306a36Sopenharmony_ci		long long val = strtoll(value, &end, 0);
32262306a36Sopenharmony_ci		unsigned long factor = 1;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci		if (!parse_unit_factor(end, &factor))
32562306a36Sopenharmony_ci			return 0;
32662306a36Sopenharmony_ci		*ret = val * factor;
32762306a36Sopenharmony_ci		return 1;
32862306a36Sopenharmony_ci	}
32962306a36Sopenharmony_ci	return 0;
33062306a36Sopenharmony_ci}
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_cistatic int perf_parse_long(const char *value, long *ret)
33362306a36Sopenharmony_ci{
33462306a36Sopenharmony_ci	if (value && *value) {
33562306a36Sopenharmony_ci		char *end;
33662306a36Sopenharmony_ci		long val = strtol(value, &end, 0);
33762306a36Sopenharmony_ci		unsigned long factor = 1;
33862306a36Sopenharmony_ci		if (!parse_unit_factor(end, &factor))
33962306a36Sopenharmony_ci			return 0;
34062306a36Sopenharmony_ci		*ret = val * factor;
34162306a36Sopenharmony_ci		return 1;
34262306a36Sopenharmony_ci	}
34362306a36Sopenharmony_ci	return 0;
34462306a36Sopenharmony_ci}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_cistatic void bad_config(const char *name)
34762306a36Sopenharmony_ci{
34862306a36Sopenharmony_ci	if (config_file_name)
34962306a36Sopenharmony_ci		pr_warning("bad config value for '%s' in %s, ignoring...\n", name, config_file_name);
35062306a36Sopenharmony_ci	else
35162306a36Sopenharmony_ci		pr_warning("bad config value for '%s', ignoring...\n", name);
35262306a36Sopenharmony_ci}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ciint perf_config_u64(u64 *dest, const char *name, const char *value)
35562306a36Sopenharmony_ci{
35662306a36Sopenharmony_ci	long long ret = 0;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	if (!perf_parse_llong(value, &ret)) {
35962306a36Sopenharmony_ci		bad_config(name);
36062306a36Sopenharmony_ci		return -1;
36162306a36Sopenharmony_ci	}
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	*dest = ret;
36462306a36Sopenharmony_ci	return 0;
36562306a36Sopenharmony_ci}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ciint perf_config_int(int *dest, const char *name, const char *value)
36862306a36Sopenharmony_ci{
36962306a36Sopenharmony_ci	long ret = 0;
37062306a36Sopenharmony_ci	if (!perf_parse_long(value, &ret)) {
37162306a36Sopenharmony_ci		bad_config(name);
37262306a36Sopenharmony_ci		return -1;
37362306a36Sopenharmony_ci	}
37462306a36Sopenharmony_ci	*dest = ret;
37562306a36Sopenharmony_ci	return 0;
37662306a36Sopenharmony_ci}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ciint perf_config_u8(u8 *dest, const char *name, const char *value)
37962306a36Sopenharmony_ci{
38062306a36Sopenharmony_ci	long ret = 0;
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	if (!perf_parse_long(value, &ret)) {
38362306a36Sopenharmony_ci		bad_config(name);
38462306a36Sopenharmony_ci		return -1;
38562306a36Sopenharmony_ci	}
38662306a36Sopenharmony_ci	*dest = ret;
38762306a36Sopenharmony_ci	return 0;
38862306a36Sopenharmony_ci}
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_cistatic int perf_config_bool_or_int(const char *name, const char *value, int *is_bool)
39162306a36Sopenharmony_ci{
39262306a36Sopenharmony_ci	int ret;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	*is_bool = 1;
39562306a36Sopenharmony_ci	if (!value)
39662306a36Sopenharmony_ci		return 1;
39762306a36Sopenharmony_ci	if (!*value)
39862306a36Sopenharmony_ci		return 0;
39962306a36Sopenharmony_ci	if (!strcasecmp(value, "true") || !strcasecmp(value, "yes") || !strcasecmp(value, "on"))
40062306a36Sopenharmony_ci		return 1;
40162306a36Sopenharmony_ci	if (!strcasecmp(value, "false") || !strcasecmp(value, "no") || !strcasecmp(value, "off"))
40262306a36Sopenharmony_ci		return 0;
40362306a36Sopenharmony_ci	*is_bool = 0;
40462306a36Sopenharmony_ci	return perf_config_int(&ret, name, value) < 0 ? -1 : ret;
40562306a36Sopenharmony_ci}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ciint perf_config_bool(const char *name, const char *value)
40862306a36Sopenharmony_ci{
40962306a36Sopenharmony_ci	int discard;
41062306a36Sopenharmony_ci	return !!perf_config_bool_or_int(name, value, &discard);
41162306a36Sopenharmony_ci}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_cistatic const char *perf_config_dirname(const char *name, const char *value)
41462306a36Sopenharmony_ci{
41562306a36Sopenharmony_ci	if (!name)
41662306a36Sopenharmony_ci		return NULL;
41762306a36Sopenharmony_ci	return value;
41862306a36Sopenharmony_ci}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_cistatic int perf_buildid_config(const char *var, const char *value)
42162306a36Sopenharmony_ci{
42262306a36Sopenharmony_ci	/* same dir for all commands */
42362306a36Sopenharmony_ci	if (!strcmp(var, "buildid.dir")) {
42462306a36Sopenharmony_ci		const char *dir = perf_config_dirname(var, value);
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci		if (!dir) {
42762306a36Sopenharmony_ci			pr_err("Invalid buildid directory!\n");
42862306a36Sopenharmony_ci			return -1;
42962306a36Sopenharmony_ci		}
43062306a36Sopenharmony_ci		strncpy(buildid_dir, dir, MAXPATHLEN-1);
43162306a36Sopenharmony_ci		buildid_dir[MAXPATHLEN-1] = '\0';
43262306a36Sopenharmony_ci	}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	return 0;
43562306a36Sopenharmony_ci}
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_cistatic int perf_default_core_config(const char *var, const char *value)
43862306a36Sopenharmony_ci{
43962306a36Sopenharmony_ci	if (!strcmp(var, "core.proc-map-timeout"))
44062306a36Sopenharmony_ci		proc_map_timeout = strtoul(value, NULL, 10);
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	if (!strcmp(var, "core.addr2line-timeout"))
44362306a36Sopenharmony_ci		addr2line_timeout_ms = strtoul(value, NULL, 10);
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	/* Add other config variables here. */
44662306a36Sopenharmony_ci	return 0;
44762306a36Sopenharmony_ci}
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_cistatic int perf_ui_config(const char *var, const char *value)
45062306a36Sopenharmony_ci{
45162306a36Sopenharmony_ci	/* Add other config variables here. */
45262306a36Sopenharmony_ci	if (!strcmp(var, "ui.show-headers"))
45362306a36Sopenharmony_ci		symbol_conf.show_hist_headers = perf_config_bool(var, value);
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	return 0;
45662306a36Sopenharmony_ci}
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_cistatic int perf_stat_config(const char *var, const char *value)
45962306a36Sopenharmony_ci{
46062306a36Sopenharmony_ci	if (!strcmp(var, "stat.big-num"))
46162306a36Sopenharmony_ci		perf_stat__set_big_num(perf_config_bool(var, value));
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	if (!strcmp(var, "stat.no-csv-summary"))
46462306a36Sopenharmony_ci		perf_stat__set_no_csv_summary(perf_config_bool(var, value));
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	if (!strcmp(var, "stat.bpf-counter-events"))
46762306a36Sopenharmony_ci		evsel__bpf_counter_events = strdup(value);
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	/* Add other config variables here. */
47062306a36Sopenharmony_ci	return 0;
47162306a36Sopenharmony_ci}
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ciint perf_default_config(const char *var, const char *value,
47462306a36Sopenharmony_ci			void *dummy __maybe_unused)
47562306a36Sopenharmony_ci{
47662306a36Sopenharmony_ci	if (strstarts(var, "core."))
47762306a36Sopenharmony_ci		return perf_default_core_config(var, value);
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	if (strstarts(var, "hist."))
48062306a36Sopenharmony_ci		return perf_hist_config(var, value);
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	if (strstarts(var, "ui."))
48362306a36Sopenharmony_ci		return perf_ui_config(var, value);
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	if (strstarts(var, "call-graph."))
48662306a36Sopenharmony_ci		return perf_callchain_config(var, value);
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	if (strstarts(var, "buildid."))
48962306a36Sopenharmony_ci		return perf_buildid_config(var, value);
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	if (strstarts(var, "stat."))
49262306a36Sopenharmony_ci		return perf_stat_config(var, value);
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	/* Add other config variables here. */
49562306a36Sopenharmony_ci	return 0;
49662306a36Sopenharmony_ci}
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_cistatic int perf_config_from_file(config_fn_t fn, const char *filename, void *data)
49962306a36Sopenharmony_ci{
50062306a36Sopenharmony_ci	int ret;
50162306a36Sopenharmony_ci	FILE *f = fopen(filename, "r");
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	ret = -1;
50462306a36Sopenharmony_ci	if (f) {
50562306a36Sopenharmony_ci		config_file = f;
50662306a36Sopenharmony_ci		config_file_name = filename;
50762306a36Sopenharmony_ci		config_linenr = 1;
50862306a36Sopenharmony_ci		config_file_eof = 0;
50962306a36Sopenharmony_ci		ret = perf_parse_file(fn, data);
51062306a36Sopenharmony_ci		fclose(f);
51162306a36Sopenharmony_ci		config_file_name = NULL;
51262306a36Sopenharmony_ci	}
51362306a36Sopenharmony_ci	return ret;
51462306a36Sopenharmony_ci}
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ciconst char *perf_etc_perfconfig(void)
51762306a36Sopenharmony_ci{
51862306a36Sopenharmony_ci	static const char *system_wide;
51962306a36Sopenharmony_ci	if (!system_wide)
52062306a36Sopenharmony_ci		system_wide = system_path(ETC_PERFCONFIG);
52162306a36Sopenharmony_ci	return system_wide;
52262306a36Sopenharmony_ci}
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_cistatic int perf_env_bool(const char *k, int def)
52562306a36Sopenharmony_ci{
52662306a36Sopenharmony_ci	const char *v = getenv(k);
52762306a36Sopenharmony_ci	return v ? perf_config_bool(k, v) : def;
52862306a36Sopenharmony_ci}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ciint perf_config_system(void)
53162306a36Sopenharmony_ci{
53262306a36Sopenharmony_ci	return !perf_env_bool("PERF_CONFIG_NOSYSTEM", 0);
53362306a36Sopenharmony_ci}
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ciint perf_config_global(void)
53662306a36Sopenharmony_ci{
53762306a36Sopenharmony_ci	return !perf_env_bool("PERF_CONFIG_NOGLOBAL", 0);
53862306a36Sopenharmony_ci}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_cistatic char *home_perfconfig(void)
54162306a36Sopenharmony_ci{
54262306a36Sopenharmony_ci	const char *home = NULL;
54362306a36Sopenharmony_ci	char *config;
54462306a36Sopenharmony_ci	struct stat st;
54562306a36Sopenharmony_ci	char path[PATH_MAX];
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	home = getenv("HOME");
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	/*
55062306a36Sopenharmony_ci	 * Skip reading user config if:
55162306a36Sopenharmony_ci	 *   - there is no place to read it from (HOME)
55262306a36Sopenharmony_ci	 *   - we are asked not to (PERF_CONFIG_NOGLOBAL=1)
55362306a36Sopenharmony_ci	 */
55462306a36Sopenharmony_ci	if (!home || !*home || !perf_config_global())
55562306a36Sopenharmony_ci		return NULL;
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	config = strdup(mkpath(path, sizeof(path), "%s/.perfconfig", home));
55862306a36Sopenharmony_ci	if (config == NULL) {
55962306a36Sopenharmony_ci		pr_warning("Not enough memory to process %s/.perfconfig, ignoring it.\n", home);
56062306a36Sopenharmony_ci		return NULL;
56162306a36Sopenharmony_ci	}
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	if (stat(config, &st) < 0)
56462306a36Sopenharmony_ci		goto out_free;
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	if (st.st_uid && (st.st_uid != geteuid())) {
56762306a36Sopenharmony_ci		pr_warning("File %s not owned by current user or root, ignoring it.\n", config);
56862306a36Sopenharmony_ci		goto out_free;
56962306a36Sopenharmony_ci	}
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	if (st.st_size)
57262306a36Sopenharmony_ci		return config;
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ciout_free:
57562306a36Sopenharmony_ci	free(config);
57662306a36Sopenharmony_ci	return NULL;
57762306a36Sopenharmony_ci}
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ciconst char *perf_home_perfconfig(void)
58062306a36Sopenharmony_ci{
58162306a36Sopenharmony_ci	static const char *config;
58262306a36Sopenharmony_ci	static bool failed;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	if (failed || config)
58562306a36Sopenharmony_ci		return config;
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	config = home_perfconfig();
58862306a36Sopenharmony_ci	if (!config)
58962306a36Sopenharmony_ci		failed = true;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	return config;
59262306a36Sopenharmony_ci}
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_cistatic struct perf_config_section *find_section(struct list_head *sections,
59562306a36Sopenharmony_ci						const char *section_name)
59662306a36Sopenharmony_ci{
59762306a36Sopenharmony_ci	struct perf_config_section *section;
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	list_for_each_entry(section, sections, node)
60062306a36Sopenharmony_ci		if (!strcmp(section->name, section_name))
60162306a36Sopenharmony_ci			return section;
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	return NULL;
60462306a36Sopenharmony_ci}
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_cistatic struct perf_config_item *find_config_item(const char *name,
60762306a36Sopenharmony_ci						 struct perf_config_section *section)
60862306a36Sopenharmony_ci{
60962306a36Sopenharmony_ci	struct perf_config_item *item;
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	list_for_each_entry(item, &section->items, node)
61262306a36Sopenharmony_ci		if (!strcmp(item->name, name))
61362306a36Sopenharmony_ci			return item;
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	return NULL;
61662306a36Sopenharmony_ci}
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_cistatic struct perf_config_section *add_section(struct list_head *sections,
61962306a36Sopenharmony_ci					       const char *section_name)
62062306a36Sopenharmony_ci{
62162306a36Sopenharmony_ci	struct perf_config_section *section = zalloc(sizeof(*section));
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	if (!section)
62462306a36Sopenharmony_ci		return NULL;
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	INIT_LIST_HEAD(&section->items);
62762306a36Sopenharmony_ci	section->name = strdup(section_name);
62862306a36Sopenharmony_ci	if (!section->name) {
62962306a36Sopenharmony_ci		pr_debug("%s: strdup failed\n", __func__);
63062306a36Sopenharmony_ci		free(section);
63162306a36Sopenharmony_ci		return NULL;
63262306a36Sopenharmony_ci	}
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	list_add_tail(&section->node, sections);
63562306a36Sopenharmony_ci	return section;
63662306a36Sopenharmony_ci}
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_cistatic struct perf_config_item *add_config_item(struct perf_config_section *section,
63962306a36Sopenharmony_ci						const char *name)
64062306a36Sopenharmony_ci{
64162306a36Sopenharmony_ci	struct perf_config_item *item = zalloc(sizeof(*item));
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	if (!item)
64462306a36Sopenharmony_ci		return NULL;
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	item->name = strdup(name);
64762306a36Sopenharmony_ci	if (!item->name) {
64862306a36Sopenharmony_ci		pr_debug("%s: strdup failed\n", __func__);
64962306a36Sopenharmony_ci		free(item);
65062306a36Sopenharmony_ci		return NULL;
65162306a36Sopenharmony_ci	}
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	list_add_tail(&item->node, &section->items);
65462306a36Sopenharmony_ci	return item;
65562306a36Sopenharmony_ci}
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_cistatic int set_value(struct perf_config_item *item, const char *value)
65862306a36Sopenharmony_ci{
65962306a36Sopenharmony_ci	char *val = strdup(value);
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	if (!val)
66262306a36Sopenharmony_ci		return -1;
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	zfree(&item->value);
66562306a36Sopenharmony_ci	item->value = val;
66662306a36Sopenharmony_ci	return 0;
66762306a36Sopenharmony_ci}
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_cistatic int collect_config(const char *var, const char *value,
67062306a36Sopenharmony_ci			  void *perf_config_set)
67162306a36Sopenharmony_ci{
67262306a36Sopenharmony_ci	int ret = -1;
67362306a36Sopenharmony_ci	char *ptr, *key;
67462306a36Sopenharmony_ci	char *section_name, *name;
67562306a36Sopenharmony_ci	struct perf_config_section *section = NULL;
67662306a36Sopenharmony_ci	struct perf_config_item *item = NULL;
67762306a36Sopenharmony_ci	struct perf_config_set *set = perf_config_set;
67862306a36Sopenharmony_ci	struct list_head *sections;
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	if (set == NULL)
68162306a36Sopenharmony_ci		return -1;
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	sections = &set->sections;
68462306a36Sopenharmony_ci	key = ptr = strdup(var);
68562306a36Sopenharmony_ci	if (!key) {
68662306a36Sopenharmony_ci		pr_debug("%s: strdup failed\n", __func__);
68762306a36Sopenharmony_ci		return -1;
68862306a36Sopenharmony_ci	}
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	section_name = strsep(&ptr, ".");
69162306a36Sopenharmony_ci	name = ptr;
69262306a36Sopenharmony_ci	if (name == NULL || value == NULL)
69362306a36Sopenharmony_ci		goto out_free;
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	section = find_section(sections, section_name);
69662306a36Sopenharmony_ci	if (!section) {
69762306a36Sopenharmony_ci		section = add_section(sections, section_name);
69862306a36Sopenharmony_ci		if (!section)
69962306a36Sopenharmony_ci			goto out_free;
70062306a36Sopenharmony_ci	}
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	item = find_config_item(name, section);
70362306a36Sopenharmony_ci	if (!item) {
70462306a36Sopenharmony_ci		item = add_config_item(section, name);
70562306a36Sopenharmony_ci		if (!item)
70662306a36Sopenharmony_ci			goto out_free;
70762306a36Sopenharmony_ci	}
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	/* perf_config_set can contain both user and system config items.
71062306a36Sopenharmony_ci	 * So we should know where each value is from.
71162306a36Sopenharmony_ci	 * The classification would be needed when a particular config file
71262306a36Sopenharmony_ci	 * is overwritten by setting feature i.e. set_config().
71362306a36Sopenharmony_ci	 */
71462306a36Sopenharmony_ci	if (strcmp(config_file_name, perf_etc_perfconfig()) == 0) {
71562306a36Sopenharmony_ci		section->from_system_config = true;
71662306a36Sopenharmony_ci		item->from_system_config = true;
71762306a36Sopenharmony_ci	} else {
71862306a36Sopenharmony_ci		section->from_system_config = false;
71962306a36Sopenharmony_ci		item->from_system_config = false;
72062306a36Sopenharmony_ci	}
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci	ret = set_value(item, value);
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ciout_free:
72562306a36Sopenharmony_ci	free(key);
72662306a36Sopenharmony_ci	return ret;
72762306a36Sopenharmony_ci}
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ciint perf_config_set__collect(struct perf_config_set *set, const char *file_name,
73062306a36Sopenharmony_ci			     const char *var, const char *value)
73162306a36Sopenharmony_ci{
73262306a36Sopenharmony_ci	config_file_name = file_name;
73362306a36Sopenharmony_ci	return collect_config(var, value, set);
73462306a36Sopenharmony_ci}
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_cistatic int perf_config_set__init(struct perf_config_set *set)
73762306a36Sopenharmony_ci{
73862306a36Sopenharmony_ci	int ret = -1;
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci	/* Setting $PERF_CONFIG makes perf read _only_ the given config file. */
74162306a36Sopenharmony_ci	if (config_exclusive_filename)
74262306a36Sopenharmony_ci		return perf_config_from_file(collect_config, config_exclusive_filename, set);
74362306a36Sopenharmony_ci	if (perf_config_system() && !access(perf_etc_perfconfig(), R_OK)) {
74462306a36Sopenharmony_ci		if (perf_config_from_file(collect_config, perf_etc_perfconfig(), set) < 0)
74562306a36Sopenharmony_ci			goto out;
74662306a36Sopenharmony_ci	}
74762306a36Sopenharmony_ci	if (perf_config_global() && perf_home_perfconfig()) {
74862306a36Sopenharmony_ci		if (perf_config_from_file(collect_config, perf_home_perfconfig(), set) < 0)
74962306a36Sopenharmony_ci			goto out;
75062306a36Sopenharmony_ci	}
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ciout:
75362306a36Sopenharmony_ci	return ret;
75462306a36Sopenharmony_ci}
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_cistruct perf_config_set *perf_config_set__new(void)
75762306a36Sopenharmony_ci{
75862306a36Sopenharmony_ci	struct perf_config_set *set = zalloc(sizeof(*set));
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	if (set) {
76162306a36Sopenharmony_ci		INIT_LIST_HEAD(&set->sections);
76262306a36Sopenharmony_ci		perf_config_set__init(set);
76362306a36Sopenharmony_ci	}
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	return set;
76662306a36Sopenharmony_ci}
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_cistruct perf_config_set *perf_config_set__load_file(const char *file)
76962306a36Sopenharmony_ci{
77062306a36Sopenharmony_ci	struct perf_config_set *set = zalloc(sizeof(*set));
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	if (set) {
77362306a36Sopenharmony_ci		INIT_LIST_HEAD(&set->sections);
77462306a36Sopenharmony_ci		perf_config_from_file(collect_config, file, set);
77562306a36Sopenharmony_ci	}
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	return set;
77862306a36Sopenharmony_ci}
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_cistatic int perf_config__init(void)
78162306a36Sopenharmony_ci{
78262306a36Sopenharmony_ci	if (config_set == NULL)
78362306a36Sopenharmony_ci		config_set = perf_config_set__new();
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	return config_set == NULL;
78662306a36Sopenharmony_ci}
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ciint perf_config_set(struct perf_config_set *set,
78962306a36Sopenharmony_ci		    config_fn_t fn, void *data)
79062306a36Sopenharmony_ci{
79162306a36Sopenharmony_ci	int ret = 0;
79262306a36Sopenharmony_ci	char key[BUFSIZ];
79362306a36Sopenharmony_ci	struct perf_config_section *section;
79462306a36Sopenharmony_ci	struct perf_config_item *item;
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci	perf_config_set__for_each_entry(set, section, item) {
79762306a36Sopenharmony_ci		char *value = item->value;
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci		if (value) {
80062306a36Sopenharmony_ci			scnprintf(key, sizeof(key), "%s.%s",
80162306a36Sopenharmony_ci				  section->name, item->name);
80262306a36Sopenharmony_ci			ret = fn(key, value, data);
80362306a36Sopenharmony_ci			if (ret < 0) {
80462306a36Sopenharmony_ci				pr_err("Error in the given config file: wrong config key-value pair %s=%s\n",
80562306a36Sopenharmony_ci				       key, value);
80662306a36Sopenharmony_ci				/*
80762306a36Sopenharmony_ci				 * Can't be just a 'break', as perf_config_set__for_each_entry()
80862306a36Sopenharmony_ci				 * expands to two nested for() loops.
80962306a36Sopenharmony_ci				 */
81062306a36Sopenharmony_ci				goto out;
81162306a36Sopenharmony_ci			}
81262306a36Sopenharmony_ci		}
81362306a36Sopenharmony_ci	}
81462306a36Sopenharmony_ciout:
81562306a36Sopenharmony_ci	return ret;
81662306a36Sopenharmony_ci}
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ciint perf_config(config_fn_t fn, void *data)
81962306a36Sopenharmony_ci{
82062306a36Sopenharmony_ci	if (config_set == NULL && perf_config__init())
82162306a36Sopenharmony_ci		return -1;
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	return perf_config_set(config_set, fn, data);
82462306a36Sopenharmony_ci}
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_civoid perf_config__exit(void)
82762306a36Sopenharmony_ci{
82862306a36Sopenharmony_ci	perf_config_set__delete(config_set);
82962306a36Sopenharmony_ci	config_set = NULL;
83062306a36Sopenharmony_ci}
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_civoid perf_config__refresh(void)
83362306a36Sopenharmony_ci{
83462306a36Sopenharmony_ci	perf_config__exit();
83562306a36Sopenharmony_ci	perf_config__init();
83662306a36Sopenharmony_ci}
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_cistatic void perf_config_item__delete(struct perf_config_item *item)
83962306a36Sopenharmony_ci{
84062306a36Sopenharmony_ci	zfree(&item->name);
84162306a36Sopenharmony_ci	zfree(&item->value);
84262306a36Sopenharmony_ci	free(item);
84362306a36Sopenharmony_ci}
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_cistatic void perf_config_section__purge(struct perf_config_section *section)
84662306a36Sopenharmony_ci{
84762306a36Sopenharmony_ci	struct perf_config_item *item, *tmp;
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	list_for_each_entry_safe(item, tmp, &section->items, node) {
85062306a36Sopenharmony_ci		list_del_init(&item->node);
85162306a36Sopenharmony_ci		perf_config_item__delete(item);
85262306a36Sopenharmony_ci	}
85362306a36Sopenharmony_ci}
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_cistatic void perf_config_section__delete(struct perf_config_section *section)
85662306a36Sopenharmony_ci{
85762306a36Sopenharmony_ci	perf_config_section__purge(section);
85862306a36Sopenharmony_ci	zfree(&section->name);
85962306a36Sopenharmony_ci	free(section);
86062306a36Sopenharmony_ci}
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_cistatic void perf_config_set__purge(struct perf_config_set *set)
86362306a36Sopenharmony_ci{
86462306a36Sopenharmony_ci	struct perf_config_section *section, *tmp;
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci	list_for_each_entry_safe(section, tmp, &set->sections, node) {
86762306a36Sopenharmony_ci		list_del_init(&section->node);
86862306a36Sopenharmony_ci		perf_config_section__delete(section);
86962306a36Sopenharmony_ci	}
87062306a36Sopenharmony_ci}
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_civoid perf_config_set__delete(struct perf_config_set *set)
87362306a36Sopenharmony_ci{
87462306a36Sopenharmony_ci	if (set == NULL)
87562306a36Sopenharmony_ci		return;
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	perf_config_set__purge(set);
87862306a36Sopenharmony_ci	free(set);
87962306a36Sopenharmony_ci}
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci/*
88262306a36Sopenharmony_ci * Call this to report error for your variable that should not
88362306a36Sopenharmony_ci * get a boolean value (i.e. "[my] var" means "true").
88462306a36Sopenharmony_ci */
88562306a36Sopenharmony_ciint config_error_nonbool(const char *var)
88662306a36Sopenharmony_ci{
88762306a36Sopenharmony_ci	pr_err("Missing value for '%s'", var);
88862306a36Sopenharmony_ci	return -1;
88962306a36Sopenharmony_ci}
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_civoid set_buildid_dir(const char *dir)
89262306a36Sopenharmony_ci{
89362306a36Sopenharmony_ci	if (dir)
89462306a36Sopenharmony_ci		scnprintf(buildid_dir, MAXPATHLEN, "%s", dir);
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci	/* default to $HOME/.debug */
89762306a36Sopenharmony_ci	if (buildid_dir[0] == '\0') {
89862306a36Sopenharmony_ci		char *home = getenv("HOME");
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci		if (home) {
90162306a36Sopenharmony_ci			snprintf(buildid_dir, MAXPATHLEN, "%s/%s",
90262306a36Sopenharmony_ci				 home, DEBUG_CACHE_DIR);
90362306a36Sopenharmony_ci		} else {
90462306a36Sopenharmony_ci			strncpy(buildid_dir, DEBUG_CACHE_DIR, MAXPATHLEN-1);
90562306a36Sopenharmony_ci		}
90662306a36Sopenharmony_ci		buildid_dir[MAXPATHLEN-1] = '\0';
90762306a36Sopenharmony_ci	}
90862306a36Sopenharmony_ci	/* for communicating with external commands */
90962306a36Sopenharmony_ci	setenv("PERF_BUILDID_DIR", buildid_dir, 1);
91062306a36Sopenharmony_ci}
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_cistruct perf_config_scan_data {
91362306a36Sopenharmony_ci	const char *name;
91462306a36Sopenharmony_ci	const char *fmt;
91562306a36Sopenharmony_ci	va_list args;
91662306a36Sopenharmony_ci	int ret;
91762306a36Sopenharmony_ci};
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_cistatic int perf_config_scan_cb(const char *var, const char *value, void *data)
92062306a36Sopenharmony_ci{
92162306a36Sopenharmony_ci	struct perf_config_scan_data *d = data;
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	if (!strcmp(var, d->name))
92462306a36Sopenharmony_ci		d->ret = vsscanf(value, d->fmt, d->args);
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci	return 0;
92762306a36Sopenharmony_ci}
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ciint perf_config_scan(const char *name, const char *fmt, ...)
93062306a36Sopenharmony_ci{
93162306a36Sopenharmony_ci	struct perf_config_scan_data d = {
93262306a36Sopenharmony_ci		.name = name,
93362306a36Sopenharmony_ci		.fmt = fmt,
93462306a36Sopenharmony_ci	};
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci	va_start(d.args, fmt);
93762306a36Sopenharmony_ci	perf_config(perf_config_scan_cb, &d);
93862306a36Sopenharmony_ci	va_end(d.args);
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci	return d.ret;
94162306a36Sopenharmony_ci}
942