xref: /linux/tools/perf/util/config.c (revision c7decec2f2d2ab0366567f9e30c0e1418cece43f)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * config.c
4  *
5  * Helper functions for parsing config items.
6  * Originally copied from GIT source.
7  *
8  * Copyright (C) Linus Torvalds, 2005
9  * Copyright (C) Johannes Schindelin, 2005
10  *
11  */
12 #include <errno.h>
13 #include <sys/param.h>
14 #include "cache.h"
15 #include "callchain.h"
16 #include "header.h"
17 #include <subcmd/exec-cmd.h>
18 #include "util/event.h"  /* proc_map_timeout */
19 #include "util/hist.h"  /* perf_hist_config */
20 #include "util/stat.h"  /* perf_stat__set_big_num */
21 #include "util/evsel.h"  /* evsel__hw_names, evsel__use_bpf_counters */
22 #include "util/addr2line.h"  /* addr2line_timeout_ms */
23 #include "srcline.h"
24 #include "build-id.h"
25 #include "debug.h"
26 #include "config.h"
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <linux/string.h>
32 #include <linux/zalloc.h>
33 #include <linux/ctype.h>
34 
35 #define MAXNAME (256)
36 
37 #define DEBUG_CACHE_DIR ".debug"
38 
39 #define METRIC_ONLY_LEN 20
40 
41 static struct stats walltime_nsecs_stats;
42 
43 struct perf_stat_config stat_config = {
44 	.aggr_mode		= AGGR_GLOBAL,
45 	.aggr_level		= MAX_CACHE_LVL + 1,
46 	.scale			= true,
47 	.unit_width		= 4, /* strlen("unit") */
48 	.run_count		= 1,
49 	.metric_only_len	= METRIC_ONLY_LEN,
50 	.walltime_nsecs_stats	= &walltime_nsecs_stats,
51 	.big_num		= true,
52 	.ctl_fd			= -1,
53 	.ctl_fd_ack		= -1,
54 	.iostat_run		= false,
55 };
56 
57 char buildid_dir[MAXPATHLEN]; /* root dir for buildid, binary cache */
58 
59 static FILE *config_file;
60 static const char *config_file_name;
61 static int config_linenr;
62 static int config_file_eof;
63 static struct perf_config_set *config_set;
64 
65 const char *config_exclusive_filename;
66 
get_next_char(void)67 static int get_next_char(void)
68 {
69 	int c;
70 	FILE *f;
71 
72 	c = '\n';
73 	if ((f = config_file) != NULL) {
74 		c = fgetc(f);
75 		if (c == '\r') {
76 			/* DOS like systems */
77 			c = fgetc(f);
78 			if (c != '\n') {
79 				ungetc(c, f);
80 				c = '\r';
81 			}
82 		}
83 		if (c == '\n')
84 			config_linenr++;
85 		if (c == EOF) {
86 			config_file_eof = 1;
87 			c = '\n';
88 		}
89 	}
90 	return c;
91 }
92 
parse_value(void)93 static char *parse_value(void)
94 {
95 	static char value[1024];
96 	int quote = 0, comment = 0, space = 0;
97 	size_t len = 0;
98 
99 	for (;;) {
100 		int c = get_next_char();
101 
102 		if (len >= sizeof(value) - 1)
103 			return NULL;
104 		if (c == '\n') {
105 			if (quote)
106 				return NULL;
107 			value[len] = 0;
108 			return value;
109 		}
110 		if (comment)
111 			continue;
112 		if (isspace(c) && !quote) {
113 			space = 1;
114 			continue;
115 		}
116 		if (!quote) {
117 			if (c == ';' || c == '#') {
118 				comment = 1;
119 				continue;
120 			}
121 		}
122 		if (space) {
123 			if (len)
124 				value[len++] = ' ';
125 			space = 0;
126 		}
127 		if (c == '\\') {
128 			c = get_next_char();
129 			switch (c) {
130 			case '\n':
131 				continue;
132 			case 't':
133 				c = '\t';
134 				break;
135 			case 'b':
136 				c = '\b';
137 				break;
138 			case 'n':
139 				c = '\n';
140 				break;
141 			/* Some characters escape as themselves */
142 			case '\\': case '"':
143 				break;
144 			/* Reject unknown escape sequences */
145 			default:
146 				return NULL;
147 			}
148 			value[len++] = c;
149 			continue;
150 		}
151 		if (c == '"') {
152 			quote = 1-quote;
153 			continue;
154 		}
155 		value[len++] = c;
156 	}
157 }
158 
iskeychar(int c)159 static inline int iskeychar(int c)
160 {
161 	return isalnum(c) || c == '-' || c == '_';
162 }
163 
get_value(config_fn_t fn,void * data,char * name,unsigned int len)164 static int get_value(config_fn_t fn, void *data, char *name, unsigned int len)
165 {
166 	int c;
167 	char *value;
168 
169 	/* Get the full name */
170 	for (;;) {
171 		c = get_next_char();
172 		if (config_file_eof)
173 			break;
174 		if (!iskeychar(c))
175 			break;
176 		name[len++] = c;
177 		if (len >= MAXNAME)
178 			return -1;
179 	}
180 	name[len] = 0;
181 	while (c == ' ' || c == '\t')
182 		c = get_next_char();
183 
184 	value = NULL;
185 	if (c != '\n') {
186 		if (c != '=')
187 			return -1;
188 		value = parse_value();
189 		if (!value)
190 			return -1;
191 	}
192 	return fn(name, value, data);
193 }
194 
get_extended_base_var(char * name,int baselen,int c)195 static int get_extended_base_var(char *name, int baselen, int c)
196 {
197 	do {
198 		if (c == '\n')
199 			return -1;
200 		c = get_next_char();
201 	} while (isspace(c));
202 
203 	/* We require the format to be '[base "extension"]' */
204 	if (c != '"')
205 		return -1;
206 	name[baselen++] = '.';
207 
208 	for (;;) {
209 		int ch = get_next_char();
210 
211 		if (ch == '\n')
212 			return -1;
213 		if (ch == '"')
214 			break;
215 		if (ch == '\\') {
216 			ch = get_next_char();
217 			if (ch == '\n')
218 				return -1;
219 		}
220 		name[baselen++] = ch;
221 		if (baselen > MAXNAME / 2)
222 			return -1;
223 	}
224 
225 	/* Final ']' */
226 	if (get_next_char() != ']')
227 		return -1;
228 	return baselen;
229 }
230 
get_base_var(char * name)231 static int get_base_var(char *name)
232 {
233 	int baselen = 0;
234 
235 	for (;;) {
236 		int c = get_next_char();
237 		if (config_file_eof)
238 			return -1;
239 		if (c == ']')
240 			return baselen;
241 		if (isspace(c))
242 			return get_extended_base_var(name, baselen, c);
243 		if (!iskeychar(c) && c != '.')
244 			return -1;
245 		if (baselen > MAXNAME / 2)
246 			return -1;
247 		name[baselen++] = tolower(c);
248 	}
249 }
250 
perf_parse_file(config_fn_t fn,void * data)251 static int perf_parse_file(config_fn_t fn, void *data)
252 {
253 	int comment = 0;
254 	int baselen = 0;
255 	static char var[MAXNAME];
256 
257 	/* U+FEFF Byte Order Mark in UTF8 */
258 	static const unsigned char *utf8_bom = (unsigned char *) "\xef\xbb\xbf";
259 	const unsigned char *bomptr = utf8_bom;
260 
261 	for (;;) {
262 		int line, c = get_next_char();
263 
264 		if (bomptr && *bomptr) {
265 			/* We are at the file beginning; skip UTF8-encoded BOM
266 			 * if present. Sane editors won't put this in on their
267 			 * own, but e.g. Windows Notepad will do it happily. */
268 			if ((unsigned char) c == *bomptr) {
269 				bomptr++;
270 				continue;
271 			} else {
272 				/* Do not tolerate partial BOM. */
273 				if (bomptr != utf8_bom)
274 					break;
275 				/* No BOM at file beginning. Cool. */
276 				bomptr = NULL;
277 			}
278 		}
279 		if (c == '\n') {
280 			if (config_file_eof)
281 				return 0;
282 			comment = 0;
283 			continue;
284 		}
285 		if (comment || isspace(c))
286 			continue;
287 		if (c == '#' || c == ';') {
288 			comment = 1;
289 			continue;
290 		}
291 		if (c == '[') {
292 			baselen = get_base_var(var);
293 			if (baselen <= 0)
294 				break;
295 			var[baselen++] = '.';
296 			var[baselen] = 0;
297 			continue;
298 		}
299 		if (!isalpha(c))
300 			break;
301 		var[baselen] = tolower(c);
302 
303 		/*
304 		 * The get_value function might or might not reach the '\n',
305 		 * so saving the current line number for error reporting.
306 		 */
307 		line = config_linenr;
308 		if (get_value(fn, data, var, baselen+1) < 0) {
309 			config_linenr = line;
310 			break;
311 		}
312 	}
313 	pr_err("bad config file line %d in %s\n", config_linenr, config_file_name);
314 	return -1;
315 }
316 
parse_unit_factor(const char * end,unsigned long * val)317 static int parse_unit_factor(const char *end, unsigned long *val)
318 {
319 	if (!*end)
320 		return 1;
321 	else if (!strcasecmp(end, "k")) {
322 		*val *= 1024;
323 		return 1;
324 	}
325 	else if (!strcasecmp(end, "m")) {
326 		*val *= 1024 * 1024;
327 		return 1;
328 	}
329 	else if (!strcasecmp(end, "g")) {
330 		*val *= 1024 * 1024 * 1024;
331 		return 1;
332 	}
333 	return 0;
334 }
335 
perf_parse_llong(const char * value,long long * ret)336 static int perf_parse_llong(const char *value, long long *ret)
337 {
338 	if (value && *value) {
339 		char *end;
340 		long long val = strtoll(value, &end, 0);
341 		unsigned long factor = 1;
342 
343 		if (!parse_unit_factor(end, &factor))
344 			return 0;
345 		*ret = val * factor;
346 		return 1;
347 	}
348 	return 0;
349 }
350 
perf_parse_long(const char * value,long * ret)351 static int perf_parse_long(const char *value, long *ret)
352 {
353 	if (value && *value) {
354 		char *end;
355 		long val = strtol(value, &end, 0);
356 		unsigned long factor = 1;
357 		if (!parse_unit_factor(end, &factor))
358 			return 0;
359 		*ret = val * factor;
360 		return 1;
361 	}
362 	return 0;
363 }
364 
bad_config(const char * name)365 static void bad_config(const char *name)
366 {
367 	if (config_file_name)
368 		pr_warning("bad config value for '%s' in %s, ignoring...\n", name, config_file_name);
369 	else
370 		pr_warning("bad config value for '%s', ignoring...\n", name);
371 }
372 
perf_config_u64(u64 * dest,const char * name,const char * value)373 int perf_config_u64(u64 *dest, const char *name, const char *value)
374 {
375 	long long ret = 0;
376 
377 	if (!perf_parse_llong(value, &ret)) {
378 		bad_config(name);
379 		return -1;
380 	}
381 
382 	*dest = ret;
383 	return 0;
384 }
385 
perf_config_int(int * dest,const char * name,const char * value)386 int perf_config_int(int *dest, const char *name, const char *value)
387 {
388 	long ret = 0;
389 	if (!perf_parse_long(value, &ret)) {
390 		bad_config(name);
391 		return -1;
392 	}
393 	*dest = ret;
394 	return 0;
395 }
396 
perf_config_u8(u8 * dest,const char * name,const char * value)397 int perf_config_u8(u8 *dest, const char *name, const char *value)
398 {
399 	long ret = 0;
400 
401 	if (!perf_parse_long(value, &ret)) {
402 		bad_config(name);
403 		return -1;
404 	}
405 	*dest = ret;
406 	return 0;
407 }
408 
perf_config_bool_or_int(const char * name,const char * value,int * is_bool)409 static int perf_config_bool_or_int(const char *name, const char *value, int *is_bool)
410 {
411 	int ret;
412 
413 	*is_bool = 1;
414 	if (!value)
415 		return 1;
416 	if (!*value)
417 		return 0;
418 	if (!strcasecmp(value, "true") || !strcasecmp(value, "yes") || !strcasecmp(value, "on"))
419 		return 1;
420 	if (!strcasecmp(value, "false") || !strcasecmp(value, "no") || !strcasecmp(value, "off"))
421 		return 0;
422 	*is_bool = 0;
423 	return perf_config_int(&ret, name, value) < 0 ? -1 : ret;
424 }
425 
perf_config_bool(const char * name,const char * value)426 int perf_config_bool(const char *name, const char *value)
427 {
428 	int discard;
429 	return !!perf_config_bool_or_int(name, value, &discard);
430 }
431 
perf_config_dirname(const char * name,const char * value)432 static const char *perf_config_dirname(const char *name, const char *value)
433 {
434 	if (!name)
435 		return NULL;
436 	return value;
437 }
438 
perf_buildid_config(const char * var,const char * value)439 static int perf_buildid_config(const char *var, const char *value)
440 {
441 	/* same dir for all commands */
442 	if (!strcmp(var, "buildid.dir")) {
443 		const char *dir = perf_config_dirname(var, value);
444 
445 		if (!dir) {
446 			pr_err("Invalid buildid directory!\n");
447 			return -1;
448 		}
449 		strncpy(buildid_dir, dir, MAXPATHLEN-1);
450 		buildid_dir[MAXPATHLEN-1] = '\0';
451 	}
452 
453 	return 0;
454 }
455 
perf_default_core_config(const char * var,const char * value)456 static int perf_default_core_config(const char *var, const char *value)
457 {
458 	if (!strcmp(var, "core.proc-map-timeout"))
459 		proc_map_timeout = strtoul(value, NULL, 10);
460 
461 	if (!strcmp(var, "core.addr2line-timeout"))
462 		addr2line_timeout_ms = strtoul(value, NULL, 10);
463 
464 	/* Add other config variables here. */
465 	return 0;
466 }
467 
perf_ui_config(const char * var,const char * value)468 static int perf_ui_config(const char *var, const char *value)
469 {
470 	/* Add other config variables here. */
471 	if (!strcmp(var, "ui.show-headers"))
472 		symbol_conf.show_hist_headers = perf_config_bool(var, value);
473 
474 	return 0;
475 }
476 
perf_stat__set_big_num(int set)477 void perf_stat__set_big_num(int set)
478 {
479 	stat_config.big_num = (set != 0);
480 }
481 
perf_stat__set_no_csv_summary(int set)482 static void perf_stat__set_no_csv_summary(int set)
483 {
484 	stat_config.no_csv_summary = (set != 0);
485 }
486 
perf_stat_config(const char * var,const char * value)487 static int perf_stat_config(const char *var, const char *value)
488 {
489 	if (!strcmp(var, "stat.big-num"))
490 		perf_stat__set_big_num(perf_config_bool(var, value));
491 
492 	if (!strcmp(var, "stat.no-csv-summary"))
493 		perf_stat__set_no_csv_summary(perf_config_bool(var, value));
494 
495 	if (!strcmp(var, "stat.bpf-counter-events"))
496 		evsel__bpf_counter_events = strdup(value);
497 
498 	/* Add other config variables here. */
499 	return 0;
500 }
501 
perf_default_config(const char * var,const char * value,void * dummy __maybe_unused)502 int perf_default_config(const char *var, const char *value,
503 			void *dummy __maybe_unused)
504 {
505 	if (strstarts(var, "core."))
506 		return perf_default_core_config(var, value);
507 
508 	if (strstarts(var, "hist."))
509 		return perf_hist_config(var, value);
510 
511 	if (strstarts(var, "ui."))
512 		return perf_ui_config(var, value);
513 
514 	if (strstarts(var, "call-graph."))
515 		return perf_callchain_config(var, value);
516 
517 	if (strstarts(var, "buildid."))
518 		return perf_buildid_config(var, value);
519 
520 	if (strstarts(var, "stat."))
521 		return perf_stat_config(var, value);
522 
523 	if (strstarts(var, "addr2line."))
524 		return addr2line_configure(var, value, dummy);
525 
526 	/* Add other config variables here. */
527 	return 0;
528 }
529 
perf_config_from_file(config_fn_t fn,const char * filename,void * data)530 static int perf_config_from_file(config_fn_t fn, const char *filename, void *data)
531 {
532 	int ret;
533 	FILE *f = fopen(filename, "r");
534 
535 	ret = -1;
536 	if (f) {
537 		config_file = f;
538 		config_file_name = filename;
539 		config_linenr = 1;
540 		config_file_eof = 0;
541 		ret = perf_parse_file(fn, data);
542 		fclose(f);
543 		config_file_name = NULL;
544 	}
545 	return ret;
546 }
547 
perf_etc_perfconfig(void)548 const char *perf_etc_perfconfig(void)
549 {
550 	static const char *system_wide;
551 	if (!system_wide)
552 		system_wide = system_path(ETC_PERFCONFIG);
553 	return system_wide;
554 }
555 
perf_env_bool(const char * k,int def)556 static int perf_env_bool(const char *k, int def)
557 {
558 	const char *v = getenv(k);
559 	return v ? perf_config_bool(k, v) : def;
560 }
561 
perf_config_system(void)562 int perf_config_system(void)
563 {
564 	return !perf_env_bool("PERF_CONFIG_NOSYSTEM", 0);
565 }
566 
perf_config_global(void)567 int perf_config_global(void)
568 {
569 	return !perf_env_bool("PERF_CONFIG_NOGLOBAL", 0);
570 }
571 
home_perfconfig(void)572 static char *home_perfconfig(void)
573 {
574 	const char *home = NULL;
575 	char *config;
576 	struct stat st;
577 	char path[PATH_MAX];
578 
579 	home = getenv("HOME");
580 
581 	/*
582 	 * Skip reading user config if:
583 	 *   - there is no place to read it from (HOME)
584 	 *   - we are asked not to (PERF_CONFIG_NOGLOBAL=1)
585 	 */
586 	if (!home || !*home || !perf_config_global())
587 		return NULL;
588 
589 	config = strdup(mkpath(path, sizeof(path), "%s/.perfconfig", home));
590 	if (config == NULL) {
591 		pr_warning("Not enough memory to process %s/.perfconfig, ignoring it.\n", home);
592 		return NULL;
593 	}
594 
595 	if (stat(config, &st) < 0)
596 		goto out_free;
597 
598 	if (st.st_uid && (st.st_uid != geteuid())) {
599 		pr_warning("File %s not owned by current user or root, ignoring it.\n", config);
600 		goto out_free;
601 	}
602 
603 	if (st.st_size)
604 		return config;
605 
606 out_free:
607 	free(config);
608 	return NULL;
609 }
610 
perf_home_perfconfig(void)611 const char *perf_home_perfconfig(void)
612 {
613 	static const char *config;
614 	static bool failed;
615 
616 	if (failed || config)
617 		return config;
618 
619 	config = home_perfconfig();
620 	if (!config)
621 		failed = true;
622 
623 	return config;
624 }
625 
find_section(struct list_head * sections,const char * section_name)626 static struct perf_config_section *find_section(struct list_head *sections,
627 						const char *section_name)
628 {
629 	struct perf_config_section *section;
630 
631 	list_for_each_entry(section, sections, node)
632 		if (!strcmp(section->name, section_name))
633 			return section;
634 
635 	return NULL;
636 }
637 
find_config_item(const char * name,struct perf_config_section * section)638 static struct perf_config_item *find_config_item(const char *name,
639 						 struct perf_config_section *section)
640 {
641 	struct perf_config_item *item;
642 
643 	list_for_each_entry(item, &section->items, node)
644 		if (!strcmp(item->name, name))
645 			return item;
646 
647 	return NULL;
648 }
649 
add_section(struct list_head * sections,const char * section_name)650 static struct perf_config_section *add_section(struct list_head *sections,
651 					       const char *section_name)
652 {
653 	struct perf_config_section *section = zalloc(sizeof(*section));
654 
655 	if (!section)
656 		return NULL;
657 
658 	INIT_LIST_HEAD(&section->items);
659 	section->name = strdup(section_name);
660 	if (!section->name) {
661 		pr_debug("%s: strdup failed\n", __func__);
662 		free(section);
663 		return NULL;
664 	}
665 
666 	list_add_tail(&section->node, sections);
667 	return section;
668 }
669 
add_config_item(struct perf_config_section * section,const char * name)670 static struct perf_config_item *add_config_item(struct perf_config_section *section,
671 						const char *name)
672 {
673 	struct perf_config_item *item = zalloc(sizeof(*item));
674 
675 	if (!item)
676 		return NULL;
677 
678 	item->name = strdup(name);
679 	if (!item->name) {
680 		pr_debug("%s: strdup failed\n", __func__);
681 		free(item);
682 		return NULL;
683 	}
684 
685 	list_add_tail(&item->node, &section->items);
686 	return item;
687 }
688 
set_value(struct perf_config_item * item,const char * value)689 static int set_value(struct perf_config_item *item, const char *value)
690 {
691 	char *val = strdup(value);
692 
693 	if (!val)
694 		return -1;
695 
696 	zfree(&item->value);
697 	item->value = val;
698 	return 0;
699 }
700 
collect_config(const char * var,const char * value,void * perf_config_set)701 static int collect_config(const char *var, const char *value,
702 			  void *perf_config_set)
703 {
704 	int ret = -1;
705 	char *ptr, *key;
706 	char *section_name, *name;
707 	struct perf_config_section *section = NULL;
708 	struct perf_config_item *item = NULL;
709 	struct perf_config_set *set = perf_config_set;
710 	struct list_head *sections;
711 
712 	if (set == NULL)
713 		return -1;
714 
715 	sections = &set->sections;
716 	key = ptr = strdup(var);
717 	if (!key) {
718 		pr_debug("%s: strdup failed\n", __func__);
719 		return -1;
720 	}
721 
722 	section_name = strsep(&ptr, ".");
723 	name = ptr;
724 	if (name == NULL || value == NULL)
725 		goto out_free;
726 
727 	section = find_section(sections, section_name);
728 	if (!section) {
729 		section = add_section(sections, section_name);
730 		if (!section)
731 			goto out_free;
732 	}
733 
734 	item = find_config_item(name, section);
735 	if (!item) {
736 		item = add_config_item(section, name);
737 		if (!item)
738 			goto out_free;
739 	}
740 
741 	/* perf_config_set can contain both user and system config items.
742 	 * So we should know where each value is from.
743 	 * The classification would be needed when a particular config file
744 	 * is overwritten by setting feature i.e. set_config().
745 	 */
746 	if (strcmp(config_file_name, perf_etc_perfconfig()) == 0) {
747 		section->from_system_config = true;
748 		item->from_system_config = true;
749 	} else {
750 		section->from_system_config = false;
751 		item->from_system_config = false;
752 	}
753 
754 	ret = set_value(item, value);
755 
756 out_free:
757 	free(key);
758 	return ret;
759 }
760 
perf_config_set__collect(struct perf_config_set * set,const char * file_name,const char * var,const char * value)761 int perf_config_set__collect(struct perf_config_set *set, const char *file_name,
762 			     const char *var, const char *value)
763 {
764 	config_file_name = file_name;
765 	return collect_config(var, value, set);
766 }
767 
perf_config_set__init(struct perf_config_set * set)768 static int perf_config_set__init(struct perf_config_set *set)
769 {
770 	int ret = -1;
771 
772 	/* Setting $PERF_CONFIG makes perf read _only_ the given config file. */
773 	if (config_exclusive_filename)
774 		return perf_config_from_file(collect_config, config_exclusive_filename, set);
775 	if (perf_config_system() && !access(perf_etc_perfconfig(), R_OK)) {
776 		if (perf_config_from_file(collect_config, perf_etc_perfconfig(), set) < 0)
777 			goto out;
778 	}
779 	if (perf_config_global() && perf_home_perfconfig()) {
780 		if (perf_config_from_file(collect_config, perf_home_perfconfig(), set) < 0)
781 			goto out;
782 	}
783 
784 out:
785 	return ret;
786 }
787 
perf_config_set__new(void)788 struct perf_config_set *perf_config_set__new(void)
789 {
790 	struct perf_config_set *set = zalloc(sizeof(*set));
791 
792 	if (set) {
793 		INIT_LIST_HEAD(&set->sections);
794 		perf_config_set__init(set);
795 	}
796 
797 	return set;
798 }
799 
perf_config_set__load_file(const char * file)800 struct perf_config_set *perf_config_set__load_file(const char *file)
801 {
802 	struct perf_config_set *set = zalloc(sizeof(*set));
803 
804 	if (set) {
805 		INIT_LIST_HEAD(&set->sections);
806 		perf_config_from_file(collect_config, file, set);
807 	}
808 
809 	return set;
810 }
811 
perf_config__init(void)812 static int perf_config__init(void)
813 {
814 	if (config_set == NULL)
815 		config_set = perf_config_set__new();
816 
817 	return config_set == NULL;
818 }
819 
perf_config_set(struct perf_config_set * set,config_fn_t fn,void * data)820 int perf_config_set(struct perf_config_set *set,
821 		    config_fn_t fn, void *data)
822 {
823 	int ret = 0;
824 	char key[BUFSIZ];
825 	struct perf_config_section *section;
826 	struct perf_config_item *item;
827 
828 	perf_config_set__for_each_entry(set, section, item) {
829 		char *value = item->value;
830 
831 		if (value) {
832 			scnprintf(key, sizeof(key), "%s.%s",
833 				  section->name, item->name);
834 			ret = fn(key, value, data);
835 			if (ret < 0) {
836 				pr_err("Error in the given config file: wrong config key-value pair %s=%s\n",
837 				       key, value);
838 				/*
839 				 * Can't be just a 'break', as perf_config_set__for_each_entry()
840 				 * expands to two nested for() loops.
841 				 */
842 				goto out;
843 			}
844 		}
845 	}
846 out:
847 	return ret;
848 }
849 
perf_config(config_fn_t fn,void * data)850 int perf_config(config_fn_t fn, void *data)
851 {
852 	if (config_set == NULL && perf_config__init())
853 		return -1;
854 
855 	return perf_config_set(config_set, fn, data);
856 }
857 
perf_config__exit(void)858 void perf_config__exit(void)
859 {
860 	perf_config_set__delete(config_set);
861 	config_set = NULL;
862 }
863 
perf_config_item__delete(struct perf_config_item * item)864 static void perf_config_item__delete(struct perf_config_item *item)
865 {
866 	zfree(&item->name);
867 	zfree(&item->value);
868 	free(item);
869 }
870 
perf_config_section__purge(struct perf_config_section * section)871 static void perf_config_section__purge(struct perf_config_section *section)
872 {
873 	struct perf_config_item *item, *tmp;
874 
875 	list_for_each_entry_safe(item, tmp, &section->items, node) {
876 		list_del_init(&item->node);
877 		perf_config_item__delete(item);
878 	}
879 }
880 
perf_config_section__delete(struct perf_config_section * section)881 static void perf_config_section__delete(struct perf_config_section *section)
882 {
883 	perf_config_section__purge(section);
884 	zfree(&section->name);
885 	free(section);
886 }
887 
perf_config_set__purge(struct perf_config_set * set)888 static void perf_config_set__purge(struct perf_config_set *set)
889 {
890 	struct perf_config_section *section, *tmp;
891 
892 	list_for_each_entry_safe(section, tmp, &set->sections, node) {
893 		list_del_init(&section->node);
894 		perf_config_section__delete(section);
895 	}
896 }
897 
perf_config_set__delete(struct perf_config_set * set)898 void perf_config_set__delete(struct perf_config_set *set)
899 {
900 	if (set == NULL)
901 		return;
902 
903 	perf_config_set__purge(set);
904 	free(set);
905 }
906 
907 /*
908  * Call this to report error for your variable that should not
909  * get a boolean value (i.e. "[my] var" means "true").
910  */
config_error_nonbool(const char * var)911 int config_error_nonbool(const char *var)
912 {
913 	pr_err("Missing value for '%s'", var);
914 	return -1;
915 }
916 
set_buildid_dir(const char * dir)917 void set_buildid_dir(const char *dir)
918 {
919 	if (dir)
920 		scnprintf(buildid_dir, MAXPATHLEN, "%s", dir);
921 
922 	/* default to $HOME/.debug */
923 	if (buildid_dir[0] == '\0') {
924 		char *home = getenv("HOME");
925 
926 		if (home) {
927 			snprintf(buildid_dir, MAXPATHLEN, "%s/%s",
928 				 home, DEBUG_CACHE_DIR);
929 		} else {
930 			strncpy(buildid_dir, DEBUG_CACHE_DIR, MAXPATHLEN-1);
931 		}
932 		buildid_dir[MAXPATHLEN-1] = '\0';
933 	}
934 	/* for communicating with external commands */
935 	setenv("PERF_BUILDID_DIR", buildid_dir, 1);
936 }
937 
938 struct perf_config_scan_data {
939 	const char *name;
940 	const char *fmt;
941 	const char *value;
942 	va_list args;
943 	int ret;
944 };
945 
perf_config_scan_cb(const char * var,const char * value,void * data)946 static int perf_config_scan_cb(const char *var, const char *value, void *data)
947 {
948 	struct perf_config_scan_data *d = data;
949 
950 	if (!strcmp(var, d->name))
951 		d->ret = vsscanf(value, d->fmt, d->args);
952 
953 	return 0;
954 }
955 
perf_config_scan(const char * name,const char * fmt,...)956 int perf_config_scan(const char *name, const char *fmt, ...)
957 {
958 	struct perf_config_scan_data d = {
959 		.name = name,
960 		.fmt = fmt,
961 	};
962 
963 	va_start(d.args, fmt);
964 	perf_config(perf_config_scan_cb, &d);
965 	va_end(d.args);
966 
967 	return d.ret;
968 }
969 
perf_config_get_cb(const char * var,const char * value,void * data)970 static int perf_config_get_cb(const char *var, const char *value, void *data)
971 {
972 	struct perf_config_scan_data *d = data;
973 
974 	if (!strcmp(var, d->name))
975 		d->value = value;
976 
977 	return 0;
978 }
979 
perf_config_get(const char * name)980 const char *perf_config_get(const char *name)
981 {
982 	struct perf_config_scan_data d = {
983 		.name = name,
984 		.value = NULL,
985 	};
986 
987 	perf_config(perf_config_get_cb, &d);
988 	return d.value;
989 }
990