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