blob: f5604039cbe49ae6e37797053ccbf7c5520f6c4d [file] [log] [blame]
Ingo Molnar07800602009-04-20 15:00:56 +02001/*
Namhyung Kim5f9273d2011-12-13 22:52:03 +09002 * config.c
3 *
4 * Helper functions for parsing config items.
5 * Originally copied from GIT source.
Ingo Molnar07800602009-04-20 15:00:56 +02006 *
7 * Copyright (C) Linus Torvalds, 2005
8 * Copyright (C) Johannes Schindelin, 2005
9 *
10 */
Arnaldo Carvalho de Meloa43783a2017-04-18 10:46:11 -030011#include <errno.h>
Ingo Molnar07800602009-04-20 15:00:56 +020012#include "util.h"
13#include "cache.h"
Josh Poimboeuf4b6ab942015-12-15 09:39:39 -060014#include <subcmd/exec-cmd.h>
Namhyung Kim0b93da12014-01-14 12:02:15 +090015#include "util/hist.h" /* perf_hist_config */
Wang Nanaa61fd02015-07-21 11:13:34 +000016#include "util/llvm-utils.h" /* perf_llvm_config */
Taeung Song20105ca2016-04-14 16:53:18 +090017#include "config.h"
Ingo Molnar07800602009-04-20 15:00:56 +020018
Arnaldo Carvalho de Melo3d689ed2017-04-17 16:10:49 -030019#include "sane_ctype.h"
20
Ingo Molnar07800602009-04-20 15:00:56 +020021#define MAXNAME (256)
22
Stephane Eranian45de34b2010-06-01 21:25:01 +020023#define DEBUG_CACHE_DIR ".debug"
24
25
26char buildid_dir[MAXPATHLEN]; /* root dir for buildid, binary cache */
27
Ingo Molnar07800602009-04-20 15:00:56 +020028static FILE *config_file;
29static const char *config_file_name;
30static int config_linenr;
31static int config_file_eof;
Taeung Song8a0a9c72016-06-23 23:14:31 +090032static struct perf_config_set *config_set;
Ingo Molnar07800602009-04-20 15:00:56 +020033
Taeung Songc7ac2412016-02-11 02:51:17 +090034const char *config_exclusive_filename;
Ingo Molnar07800602009-04-20 15:00:56 +020035
36static int get_next_char(void)
37{
38 int c;
39 FILE *f;
40
41 c = '\n';
42 if ((f = config_file) != NULL) {
43 c = fgetc(f);
44 if (c == '\r') {
45 /* DOS like systems */
46 c = fgetc(f);
47 if (c != '\n') {
48 ungetc(c, f);
49 c = '\r';
50 }
51 }
52 if (c == '\n')
53 config_linenr++;
54 if (c == EOF) {
55 config_file_eof = 1;
56 c = '\n';
57 }
58 }
59 return c;
60}
61
62static char *parse_value(void)
63{
64 static char value[1024];
Ingo Molnarf37a2912009-07-01 12:37:06 +020065 int quote = 0, comment = 0, space = 0;
66 size_t len = 0;
Ingo Molnar07800602009-04-20 15:00:56 +020067
68 for (;;) {
69 int c = get_next_char();
Ingo Molnarf37a2912009-07-01 12:37:06 +020070
Ingo Molnar07800602009-04-20 15:00:56 +020071 if (len >= sizeof(value) - 1)
72 return NULL;
73 if (c == '\n') {
74 if (quote)
75 return NULL;
76 value[len] = 0;
77 return value;
78 }
79 if (comment)
80 continue;
81 if (isspace(c) && !quote) {
82 space = 1;
83 continue;
84 }
85 if (!quote) {
86 if (c == ';' || c == '#') {
87 comment = 1;
88 continue;
89 }
90 }
91 if (space) {
92 if (len)
93 value[len++] = ' ';
94 space = 0;
95 }
96 if (c == '\\') {
97 c = get_next_char();
98 switch (c) {
99 case '\n':
100 continue;
101 case 't':
102 c = '\t';
103 break;
104 case 'b':
105 c = '\b';
106 break;
107 case 'n':
108 c = '\n';
109 break;
110 /* Some characters escape as themselves */
111 case '\\': case '"':
112 break;
113 /* Reject unknown escape sequences */
114 default:
115 return NULL;
116 }
117 value[len++] = c;
118 continue;
119 }
120 if (c == '"') {
121 quote = 1-quote;
122 continue;
123 }
124 value[len++] = c;
125 }
126}
127
128static inline int iskeychar(int c)
129{
Arnaldo Carvalho de Melo8dc7c652012-05-29 21:59:02 -0300130 return isalnum(c) || c == '-' || c == '_';
Ingo Molnar07800602009-04-20 15:00:56 +0200131}
132
133static int get_value(config_fn_t fn, void *data, char *name, unsigned int len)
134{
135 int c;
136 char *value;
137
138 /* Get the full name */
139 for (;;) {
140 c = get_next_char();
141 if (config_file_eof)
142 break;
143 if (!iskeychar(c))
144 break;
Stephane Eranian45de34b2010-06-01 21:25:01 +0200145 name[len++] = c;
Ingo Molnar07800602009-04-20 15:00:56 +0200146 if (len >= MAXNAME)
147 return -1;
148 }
149 name[len] = 0;
150 while (c == ' ' || c == '\t')
151 c = get_next_char();
152
153 value = NULL;
154 if (c != '\n') {
155 if (c != '=')
156 return -1;
157 value = parse_value();
158 if (!value)
159 return -1;
160 }
161 return fn(name, value, data);
162}
163
164static int get_extended_base_var(char *name, int baselen, int c)
165{
166 do {
167 if (c == '\n')
168 return -1;
169 c = get_next_char();
170 } while (isspace(c));
171
172 /* We require the format to be '[base "extension"]' */
173 if (c != '"')
174 return -1;
175 name[baselen++] = '.';
176
177 for (;;) {
Ingo Molnar83a09442009-08-15 12:26:57 +0200178 int ch = get_next_char();
179
180 if (ch == '\n')
Ingo Molnar07800602009-04-20 15:00:56 +0200181 return -1;
Ingo Molnar83a09442009-08-15 12:26:57 +0200182 if (ch == '"')
Ingo Molnar07800602009-04-20 15:00:56 +0200183 break;
Ingo Molnar83a09442009-08-15 12:26:57 +0200184 if (ch == '\\') {
185 ch = get_next_char();
186 if (ch == '\n')
Ingo Molnar07800602009-04-20 15:00:56 +0200187 return -1;
188 }
Ingo Molnar83a09442009-08-15 12:26:57 +0200189 name[baselen++] = ch;
Ingo Molnar07800602009-04-20 15:00:56 +0200190 if (baselen > MAXNAME / 2)
191 return -1;
192 }
193
194 /* Final ']' */
195 if (get_next_char() != ']')
196 return -1;
197 return baselen;
198}
199
200static int get_base_var(char *name)
201{
202 int baselen = 0;
203
204 for (;;) {
205 int c = get_next_char();
206 if (config_file_eof)
207 return -1;
208 if (c == ']')
209 return baselen;
210 if (isspace(c))
211 return get_extended_base_var(name, baselen, c);
212 if (!iskeychar(c) && c != '.')
213 return -1;
214 if (baselen > MAXNAME / 2)
215 return -1;
216 name[baselen++] = tolower(c);
217 }
218}
219
220static int perf_parse_file(config_fn_t fn, void *data)
221{
222 int comment = 0;
223 int baselen = 0;
224 static char var[MAXNAME];
225
226 /* U+FEFF Byte Order Mark in UTF8 */
227 static const unsigned char *utf8_bom = (unsigned char *) "\xef\xbb\xbf";
228 const unsigned char *bomptr = utf8_bom;
229
230 for (;;) {
Jiri Olsa49757c92014-09-23 13:56:56 +0200231 int line, c = get_next_char();
232
Ingo Molnar07800602009-04-20 15:00:56 +0200233 if (bomptr && *bomptr) {
234 /* We are at the file beginning; skip UTF8-encoded BOM
235 * if present. Sane editors won't put this in on their
236 * own, but e.g. Windows Notepad will do it happily. */
237 if ((unsigned char) c == *bomptr) {
238 bomptr++;
239 continue;
240 } else {
241 /* Do not tolerate partial BOM. */
242 if (bomptr != utf8_bom)
243 break;
244 /* No BOM at file beginning. Cool. */
245 bomptr = NULL;
246 }
247 }
248 if (c == '\n') {
249 if (config_file_eof)
250 return 0;
251 comment = 0;
252 continue;
253 }
254 if (comment || isspace(c))
255 continue;
256 if (c == '#' || c == ';') {
257 comment = 1;
258 continue;
259 }
260 if (c == '[') {
261 baselen = get_base_var(var);
262 if (baselen <= 0)
263 break;
264 var[baselen++] = '.';
265 var[baselen] = 0;
266 continue;
267 }
268 if (!isalpha(c))
269 break;
270 var[baselen] = tolower(c);
Jiri Olsa49757c92014-09-23 13:56:56 +0200271
272 /*
273 * The get_value function might or might not reach the '\n',
274 * so saving the current line number for error reporting.
275 */
276 line = config_linenr;
277 if (get_value(fn, data, var, baselen+1) < 0) {
278 config_linenr = line;
Ingo Molnar07800602009-04-20 15:00:56 +0200279 break;
Jiri Olsa49757c92014-09-23 13:56:56 +0200280 }
Ingo Molnar07800602009-04-20 15:00:56 +0200281 }
Taeung Song78f71c92016-06-06 19:52:52 +0900282 pr_err("bad config file line %d in %s\n", config_linenr, config_file_name);
283 return -1;
Ingo Molnar07800602009-04-20 15:00:56 +0200284}
285
286static int parse_unit_factor(const char *end, unsigned long *val)
287{
288 if (!*end)
289 return 1;
290 else if (!strcasecmp(end, "k")) {
291 *val *= 1024;
292 return 1;
293 }
294 else if (!strcasecmp(end, "m")) {
295 *val *= 1024 * 1024;
296 return 1;
297 }
298 else if (!strcasecmp(end, "g")) {
299 *val *= 1024 * 1024 * 1024;
300 return 1;
301 }
302 return 0;
303}
304
Jiri Olsa94c06552014-06-06 05:27:28 -0400305static int perf_parse_llong(const char *value, long long *ret)
306{
307 if (value && *value) {
308 char *end;
309 long long val = strtoll(value, &end, 0);
310 unsigned long factor = 1;
311
312 if (!parse_unit_factor(end, &factor))
313 return 0;
314 *ret = val * factor;
315 return 1;
316 }
317 return 0;
318}
319
Ingo Molnar07800602009-04-20 15:00:56 +0200320static int perf_parse_long(const char *value, long *ret)
321{
322 if (value && *value) {
323 char *end;
324 long val = strtol(value, &end, 0);
325 unsigned long factor = 1;
326 if (!parse_unit_factor(end, &factor))
327 return 0;
328 *ret = val * factor;
329 return 1;
330 }
331 return 0;
332}
333
Ingo Molnar07800602009-04-20 15:00:56 +0200334static void die_bad_config(const char *name)
335{
336 if (config_file_name)
337 die("bad config value for '%s' in %s", name, config_file_name);
338 die("bad config value for '%s'", name);
339}
340
Jiri Olsa94c06552014-06-06 05:27:28 -0400341u64 perf_config_u64(const char *name, const char *value)
342{
343 long long ret = 0;
344
345 if (!perf_parse_llong(value, &ret))
346 die_bad_config(name);
347 return (u64) ret;
348}
349
Ingo Molnar07800602009-04-20 15:00:56 +0200350int perf_config_int(const char *name, const char *value)
351{
352 long ret = 0;
353 if (!perf_parse_long(value, &ret))
354 die_bad_config(name);
355 return ret;
356}
357
Arnaldo Carvalho de Meloa41794c2010-05-18 18:29:23 -0300358static int perf_config_bool_or_int(const char *name, const char *value, int *is_bool)
Ingo Molnar07800602009-04-20 15:00:56 +0200359{
360 *is_bool = 1;
361 if (!value)
362 return 1;
363 if (!*value)
364 return 0;
365 if (!strcasecmp(value, "true") || !strcasecmp(value, "yes") || !strcasecmp(value, "on"))
366 return 1;
367 if (!strcasecmp(value, "false") || !strcasecmp(value, "no") || !strcasecmp(value, "off"))
368 return 0;
369 *is_bool = 0;
370 return perf_config_int(name, value);
371}
372
373int perf_config_bool(const char *name, const char *value)
374{
375 int discard;
376 return !!perf_config_bool_or_int(name, value, &discard);
377}
378
Arnaldo Carvalho de Melo814b3f52016-06-16 17:10:46 -0300379static const char *perf_config_dirname(const char *name, const char *value)
Stephane Eranian45de34b2010-06-01 21:25:01 +0200380{
381 if (!name)
382 return NULL;
383 return value;
384}
385
Taeung Song9cb59872016-03-28 02:22:19 +0900386static int perf_buildid_config(const char *var, const char *value)
387{
388 /* same dir for all commands */
389 if (!strcmp(var, "buildid.dir")) {
Vinson Leed8e28652016-04-04 22:07:39 +0000390 const char *dir = perf_config_dirname(var, value);
Taeung Song9cb59872016-03-28 02:22:19 +0900391
Arnaldo Carvalho de Meloecc4c562017-01-24 13:44:10 -0300392 if (!dir) {
393 pr_err("Invalid buildid directory!\n");
Taeung Song9cb59872016-03-28 02:22:19 +0900394 return -1;
Arnaldo Carvalho de Meloecc4c562017-01-24 13:44:10 -0300395 }
Vinson Leed8e28652016-04-04 22:07:39 +0000396 strncpy(buildid_dir, dir, MAXPATHLEN-1);
Taeung Song9cb59872016-03-28 02:22:19 +0900397 buildid_dir[MAXPATHLEN-1] = '\0';
398 }
399
400 return 0;
401}
402
Irina Tirdea1d037ca2012-09-11 01:15:03 +0300403static int perf_default_core_config(const char *var __maybe_unused,
404 const char *value __maybe_unused)
Ingo Molnar07800602009-04-20 15:00:56 +0200405{
Paul Bolle395cf962011-08-15 02:02:26 +0200406 /* Add other config variables here. */
Ingo Molnar07800602009-04-20 15:00:56 +0200407 return 0;
408}
409
Jiri Olsac8302362014-06-27 18:26:58 +0200410static int perf_ui_config(const char *var, const char *value)
411{
412 /* Add other config variables here. */
Arnaldo Carvalho de Meloecc4c562017-01-24 13:44:10 -0300413 if (!strcmp(var, "ui.show-headers"))
Jiri Olsac8302362014-06-27 18:26:58 +0200414 symbol_conf.show_hist_headers = perf_config_bool(var, value);
Arnaldo Carvalho de Meloecc4c562017-01-24 13:44:10 -0300415
Jiri Olsac8302362014-06-27 18:26:58 +0200416 return 0;
417}
418
Irina Tirdea1d037ca2012-09-11 01:15:03 +0300419int perf_default_config(const char *var, const char *value,
420 void *dummy __maybe_unused)
Ingo Molnar07800602009-04-20 15:00:56 +0200421{
422 if (!prefixcmp(var, "core."))
423 return perf_default_core_config(var, value);
424
Namhyung Kim0b93da12014-01-14 12:02:15 +0900425 if (!prefixcmp(var, "hist."))
426 return perf_hist_config(var, value);
427
Jiri Olsac8302362014-06-27 18:26:58 +0200428 if (!prefixcmp(var, "ui."))
429 return perf_ui_config(var, value);
430
Namhyung Kim2b9240c2014-09-23 10:01:43 +0900431 if (!prefixcmp(var, "call-graph."))
432 return perf_callchain_config(var, value);
433
Wang Nanaa61fd02015-07-21 11:13:34 +0000434 if (!prefixcmp(var, "llvm."))
435 return perf_llvm_config(var, value);
436
Taeung Song9cb59872016-03-28 02:22:19 +0900437 if (!prefixcmp(var, "buildid."))
438 return perf_buildid_config(var, value);
439
Paul Bolle395cf962011-08-15 02:02:26 +0200440 /* Add other config variables here. */
Ingo Molnar07800602009-04-20 15:00:56 +0200441 return 0;
442}
443
Arnaldo Carvalho de Meloa41794c2010-05-18 18:29:23 -0300444static int perf_config_from_file(config_fn_t fn, const char *filename, void *data)
Ingo Molnar07800602009-04-20 15:00:56 +0200445{
446 int ret;
447 FILE *f = fopen(filename, "r");
448
449 ret = -1;
450 if (f) {
451 config_file = f;
452 config_file_name = filename;
453 config_linenr = 1;
454 config_file_eof = 0;
455 ret = perf_parse_file(fn, data);
456 fclose(f);
457 config_file_name = NULL;
458 }
459 return ret;
460}
461
Taeung Songc7ac2412016-02-11 02:51:17 +0900462const char *perf_etc_perfconfig(void)
Ingo Molnar07800602009-04-20 15:00:56 +0200463{
464 static const char *system_wide;
465 if (!system_wide)
466 system_wide = system_path(ETC_PERFCONFIG);
467 return system_wide;
468}
469
470static int perf_env_bool(const char *k, int def)
471{
472 const char *v = getenv(k);
473 return v ? perf_config_bool(k, v) : def;
474}
475
Arnaldo Carvalho de Meloa41794c2010-05-18 18:29:23 -0300476static int perf_config_system(void)
Ingo Molnar07800602009-04-20 15:00:56 +0200477{
478 return !perf_env_bool("PERF_CONFIG_NOSYSTEM", 0);
479}
480
Arnaldo Carvalho de Meloa41794c2010-05-18 18:29:23 -0300481static int perf_config_global(void)
Ingo Molnar07800602009-04-20 15:00:56 +0200482{
483 return !perf_env_bool("PERF_CONFIG_NOGLOBAL", 0);
484}
485
Taeung Song20105ca2016-04-14 16:53:18 +0900486static struct perf_config_section *find_section(struct list_head *sections,
487 const char *section_name)
488{
489 struct perf_config_section *section;
490
491 list_for_each_entry(section, sections, node)
492 if (!strcmp(section->name, section_name))
493 return section;
494
495 return NULL;
496}
497
498static struct perf_config_item *find_config_item(const char *name,
499 struct perf_config_section *section)
500{
501 struct perf_config_item *item;
502
503 list_for_each_entry(item, &section->items, node)
504 if (!strcmp(item->name, name))
505 return item;
506
507 return NULL;
508}
509
510static struct perf_config_section *add_section(struct list_head *sections,
511 const char *section_name)
512{
513 struct perf_config_section *section = zalloc(sizeof(*section));
514
515 if (!section)
516 return NULL;
517
518 INIT_LIST_HEAD(&section->items);
519 section->name = strdup(section_name);
520 if (!section->name) {
521 pr_debug("%s: strdup failed\n", __func__);
522 free(section);
523 return NULL;
524 }
525
526 list_add_tail(&section->node, sections);
527 return section;
528}
529
530static struct perf_config_item *add_config_item(struct perf_config_section *section,
531 const char *name)
532{
533 struct perf_config_item *item = zalloc(sizeof(*item));
534
535 if (!item)
536 return NULL;
537
538 item->name = strdup(name);
539 if (!item->name) {
540 pr_debug("%s: strdup failed\n", __func__);
541 free(item);
542 return NULL;
543 }
544
545 list_add_tail(&item->node, &section->items);
546 return item;
547}
548
549static int set_value(struct perf_config_item *item, const char *value)
550{
551 char *val = strdup(value);
552
553 if (!val)
554 return -1;
555
556 zfree(&item->value);
557 item->value = val;
558 return 0;
559}
560
561static int collect_config(const char *var, const char *value,
562 void *perf_config_set)
563{
564 int ret = -1;
565 char *ptr, *key;
566 char *section_name, *name;
567 struct perf_config_section *section = NULL;
568 struct perf_config_item *item = NULL;
569 struct perf_config_set *set = perf_config_set;
Taeung Song7db91f22016-06-06 19:52:54 +0900570 struct list_head *sections;
Taeung Song20105ca2016-04-14 16:53:18 +0900571
Taeung Song7db91f22016-06-06 19:52:54 +0900572 if (set == NULL)
573 return -1;
574
575 sections = &set->sections;
Taeung Song20105ca2016-04-14 16:53:18 +0900576 key = ptr = strdup(var);
577 if (!key) {
578 pr_debug("%s: strdup failed\n", __func__);
579 return -1;
580 }
581
582 section_name = strsep(&ptr, ".");
583 name = ptr;
584 if (name == NULL || value == NULL)
585 goto out_free;
586
587 section = find_section(sections, section_name);
588 if (!section) {
589 section = add_section(sections, section_name);
590 if (!section)
591 goto out_free;
592 }
593
594 item = find_config_item(name, section);
595 if (!item) {
596 item = add_config_item(section, name);
597 if (!item)
598 goto out_free;
599 }
600
Taeung Song08d090c2016-11-04 15:44:22 +0900601 /* perf_config_set can contain both user and system config items.
602 * So we should know where each value is from.
603 * The classification would be needed when a particular config file
604 * is overwrited by setting feature i.e. set_config().
605 */
606 if (strcmp(config_file_name, perf_etc_perfconfig()) == 0) {
607 section->from_system_config = true;
608 item->from_system_config = true;
609 } else {
610 section->from_system_config = false;
611 item->from_system_config = false;
612 }
613
Taeung Song20105ca2016-04-14 16:53:18 +0900614 ret = set_value(item, value);
615 return ret;
616
617out_free:
618 free(key);
Taeung Song20105ca2016-04-14 16:53:18 +0900619 return -1;
620}
621
Taeung Song08d090c2016-11-04 15:44:22 +0900622int perf_config_set__collect(struct perf_config_set *set, const char *file_name,
Taeung Songc6fc0182016-11-04 15:44:20 +0900623 const char *var, const char *value)
624{
Taeung Song08d090c2016-11-04 15:44:22 +0900625 config_file_name = file_name;
Taeung Songc6fc0182016-11-04 15:44:20 +0900626 return collect_config(var, value, set);
627}
628
Taeung Song8beeb002016-06-07 18:26:12 +0900629static int perf_config_set__init(struct perf_config_set *set)
630{
631 int ret = -1;
632 const char *home = NULL;
Jiri Olsa3e00cbe2017-03-30 16:46:37 +0200633 char *user_config;
634 struct stat st;
Taeung Song8beeb002016-06-07 18:26:12 +0900635
636 /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */
637 if (config_exclusive_filename)
638 return perf_config_from_file(collect_config, config_exclusive_filename, set);
639 if (perf_config_system() && !access(perf_etc_perfconfig(), R_OK)) {
640 if (perf_config_from_file(collect_config, perf_etc_perfconfig(), set) < 0)
641 goto out;
642 }
643
644 home = getenv("HOME");
Taeung Song8beeb002016-06-07 18:26:12 +0900645
Jiri Olsa3e00cbe2017-03-30 16:46:37 +0200646 /*
647 * Skip reading user config if:
648 * - there is no place to read it from (HOME)
649 * - we are asked not to (PERF_CONFIG_NOGLOBAL=1)
650 */
651 if (!home || !*home || !perf_config_global())
652 return 0;
Taeung Song8beeb002016-06-07 18:26:12 +0900653
Jiri Olsa3e00cbe2017-03-30 16:46:37 +0200654 user_config = strdup(mkpath("%s/.perfconfig", home));
655 if (user_config == NULL) {
656 warning("Not enough memory to process %s/.perfconfig, "
657 "ignoring it.", home);
658 goto out;
Taeung Song8beeb002016-06-07 18:26:12 +0900659 }
Jiri Olsa3e00cbe2017-03-30 16:46:37 +0200660
661 if (stat(user_config, &st) < 0) {
662 if (errno == ENOENT)
663 ret = 0;
664 goto out_free;
665 }
666
667 ret = 0;
668
669 if (st.st_uid && (st.st_uid != geteuid())) {
670 warning("File %s not owned by current user or root, "
671 "ignoring it.", user_config);
672 goto out_free;
673 }
674
675 if (st.st_size)
676 ret = perf_config_from_file(collect_config, user_config, set);
677
678out_free:
679 free(user_config);
Taeung Song8beeb002016-06-07 18:26:12 +0900680out:
681 return ret;
682}
683
Taeung Song20105ca2016-04-14 16:53:18 +0900684struct perf_config_set *perf_config_set__new(void)
685{
686 struct perf_config_set *set = zalloc(sizeof(*set));
687
688 if (set) {
689 INIT_LIST_HEAD(&set->sections);
Taeung Song8beeb002016-06-07 18:26:12 +0900690 if (perf_config_set__init(set) < 0) {
Taeung Song25d8f482016-06-07 18:26:11 +0900691 perf_config_set__delete(set);
692 set = NULL;
693 }
Taeung Song20105ca2016-04-14 16:53:18 +0900694 }
695
696 return set;
697}
698
Taeung Song8a0a9c72016-06-23 23:14:31 +0900699int perf_config(config_fn_t fn, void *data)
700{
701 int ret = 0;
702 char key[BUFSIZ];
703 struct perf_config_section *section;
704 struct perf_config_item *item;
705
706 if (config_set == NULL)
707 return -1;
708
709 perf_config_set__for_each_entry(config_set, section, item) {
710 char *value = item->value;
711
712 if (value) {
713 scnprintf(key, sizeof(key), "%s.%s",
714 section->name, item->name);
715 ret = fn(key, value, data);
716 if (ret < 0) {
717 pr_err("Error: wrong config key-value pair %s=%s\n",
718 key, value);
719 break;
720 }
721 }
722 }
723
724 return ret;
725}
726
727void perf_config__init(void)
728{
729 if (config_set == NULL)
730 config_set = perf_config_set__new();
731}
732
733void perf_config__exit(void)
734{
735 perf_config_set__delete(config_set);
736 config_set = NULL;
737}
738
739void perf_config__refresh(void)
740{
741 perf_config__exit();
742 perf_config__init();
743}
744
Taeung Song20105ca2016-04-14 16:53:18 +0900745static void perf_config_item__delete(struct perf_config_item *item)
746{
747 zfree(&item->name);
748 zfree(&item->value);
749 free(item);
750}
751
752static void perf_config_section__purge(struct perf_config_section *section)
753{
754 struct perf_config_item *item, *tmp;
755
756 list_for_each_entry_safe(item, tmp, &section->items, node) {
757 list_del_init(&item->node);
758 perf_config_item__delete(item);
759 }
760}
761
762static void perf_config_section__delete(struct perf_config_section *section)
763{
764 perf_config_section__purge(section);
765 zfree(&section->name);
766 free(section);
767}
768
769static void perf_config_set__purge(struct perf_config_set *set)
770{
771 struct perf_config_section *section, *tmp;
772
773 list_for_each_entry_safe(section, tmp, &set->sections, node) {
774 list_del_init(&section->node);
775 perf_config_section__delete(section);
776 }
777}
778
779void perf_config_set__delete(struct perf_config_set *set)
780{
Taeung Song826424c2016-06-08 21:36:49 +0900781 if (set == NULL)
782 return;
783
Taeung Song20105ca2016-04-14 16:53:18 +0900784 perf_config_set__purge(set);
785 free(set);
786}
787
Ingo Molnar07800602009-04-20 15:00:56 +0200788/*
Ingo Molnar07800602009-04-20 15:00:56 +0200789 * Call this to report error for your variable that should not
790 * get a boolean value (i.e. "[my] var" means "true").
791 */
792int config_error_nonbool(const char *var)
793{
794 return error("Missing value for '%s'", var);
795}
Stephane Eranian45de34b2010-06-01 21:25:01 +0200796
Jiri Olsa99ce8e92014-12-01 20:06:24 +0100797void set_buildid_dir(const char *dir)
Stephane Eranian45de34b2010-06-01 21:25:01 +0200798{
Jiri Olsa99ce8e92014-12-01 20:06:24 +0100799 if (dir)
800 scnprintf(buildid_dir, MAXPATHLEN-1, "%s", dir);
Stephane Eranian45de34b2010-06-01 21:25:01 +0200801
Stephane Eranian45de34b2010-06-01 21:25:01 +0200802 /* default to $HOME/.debug */
803 if (buildid_dir[0] == '\0') {
Taeung Song37194f42016-03-28 02:22:20 +0900804 char *home = getenv("HOME");
805
806 if (home) {
Stephane Eranian45de34b2010-06-01 21:25:01 +0200807 snprintf(buildid_dir, MAXPATHLEN-1, "%s/%s",
Taeung Song37194f42016-03-28 02:22:20 +0900808 home, DEBUG_CACHE_DIR);
Stephane Eranian45de34b2010-06-01 21:25:01 +0200809 } else {
810 strncpy(buildid_dir, DEBUG_CACHE_DIR, MAXPATHLEN-1);
811 }
812 buildid_dir[MAXPATHLEN-1] = '\0';
813 }
814 /* for communicating with external commands */
815 setenv("PERF_BUILDID_DIR", buildid_dir, 1);
816}