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