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, §ion->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(§ion->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(§ion->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, §ion->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, §ion->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(§ion->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(§ion->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