Blame view

tools/perf/util/config.c 16.2 KB
078006012   Ingo Molnar   perf_counter tool...
1
  /*
5f9273d64   Namhyung Kim   perf tools: Remov...
2
3
4
5
   * config.c
   *
   * Helper functions for parsing config items.
   * Originally copied from GIT source.
078006012   Ingo Molnar   perf_counter tool...
6
7
8
9
10
   *
   * Copyright (C) Linus Torvalds, 2005
   * Copyright (C) Johannes Schindelin, 2005
   *
   */
a43783aee   Arnaldo Carvalho de Melo   perf tools: Inclu...
11
  #include <errno.h>
391e42060   Arnaldo Carvalho de Melo   perf tools: Inclu...
12
  #include <sys/param.h>
078006012   Ingo Molnar   perf_counter tool...
13
14
  #include "util.h"
  #include "cache.h"
4b6ab94ea   Josh Poimboeuf   perf subcmd: Crea...
15
  #include <subcmd/exec-cmd.h>
0b93da175   Namhyung Kim   perf tools: Add h...
16
  #include "util/hist.h"  /* perf_hist_config */
aa61fd05c   Wang Nan   perf tools: Intro...
17
  #include "util/llvm-utils.h"   /* perf_llvm_config */
20105ca12   Taeung Song   perf config: Intr...
18
  #include "config.h"
7a8ef4c4b   Arnaldo Carvalho de Melo   perf tools: Remov...
19
20
21
  #include <sys/types.h>
  #include <sys/stat.h>
  #include <unistd.h>
078006012   Ingo Molnar   perf_counter tool...
22

3d689ed60   Arnaldo Carvalho de Melo   perf tools: Move ...
23
  #include "sane_ctype.h"
078006012   Ingo Molnar   perf_counter tool...
24
  #define MAXNAME (256)
45de34bbe   Stephane Eranian   perf buildid: add...
25
26
27
28
  #define DEBUG_CACHE_DIR ".debug"
  
  
  char buildid_dir[MAXPATHLEN]; /* root dir for buildid, binary cache */
078006012   Ingo Molnar   perf_counter tool...
29
30
31
32
  static FILE *config_file;
  static const char *config_file_name;
  static int config_linenr;
  static int config_file_eof;
8a0a9c7e9   Taeung Song   perf config: Intr...
33
  static struct perf_config_set *config_set;
078006012   Ingo Molnar   perf_counter tool...
34

c7ac24178   Taeung Song   perf config: Add ...
35
  const char *config_exclusive_filename;
078006012   Ingo Molnar   perf_counter tool...
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
  
  static int get_next_char(void)
  {
  	int c;
  	FILE *f;
  
  	c = '
  ';
  	if ((f = config_file) != NULL) {
  		c = fgetc(f);
  		if (c == '\r') {
  			/* DOS like systems */
  			c = fgetc(f);
  			if (c != '
  ') {
  				ungetc(c, f);
  				c = '\r';
  			}
  		}
  		if (c == '
  ')
  			config_linenr++;
  		if (c == EOF) {
  			config_file_eof = 1;
  			c = '
  ';
  		}
  	}
  	return c;
  }
  
  static char *parse_value(void)
  {
  	static char value[1024];
f37a291c5   Ingo Molnar   perf_counter tool...
70
71
  	int quote = 0, comment = 0, space = 0;
  	size_t len = 0;
078006012   Ingo Molnar   perf_counter tool...
72
73
74
  
  	for (;;) {
  		int c = get_next_char();
f37a291c5   Ingo Molnar   perf_counter tool...
75

078006012   Ingo Molnar   perf_counter tool...
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
  		if (len >= sizeof(value) - 1)
  			return NULL;
  		if (c == '
  ') {
  			if (quote)
  				return NULL;
  			value[len] = 0;
  			return value;
  		}
  		if (comment)
  			continue;
  		if (isspace(c) && !quote) {
  			space = 1;
  			continue;
  		}
  		if (!quote) {
  			if (c == ';' || c == '#') {
  				comment = 1;
  				continue;
  			}
  		}
  		if (space) {
  			if (len)
  				value[len++] = ' ';
  			space = 0;
  		}
  		if (c == '\\') {
  			c = get_next_char();
  			switch (c) {
  			case '
  ':
  				continue;
  			case 't':
  				c = '\t';
  				break;
  			case 'b':
  				c = '\b';
  				break;
  			case 'n':
  				c = '
  ';
  				break;
  			/* Some characters escape as themselves */
  			case '\\': case '"':
  				break;
  			/* Reject unknown escape sequences */
  			default:
  				return NULL;
  			}
  			value[len++] = c;
  			continue;
  		}
  		if (c == '"') {
  			quote = 1-quote;
  			continue;
  		}
  		value[len++] = c;
  	}
  }
  
  static inline int iskeychar(int c)
  {
8dc7c651d   Arnaldo Carvalho de Melo   perf config: Allo...
138
  	return isalnum(c) || c == '-' || c == '_';
078006012   Ingo Molnar   perf_counter tool...
139
140
141
142
143
144
145
146
147
148
149
150
151
152
  }
  
  static int get_value(config_fn_t fn, void *data, char *name, unsigned int len)
  {
  	int c;
  	char *value;
  
  	/* Get the full name */
  	for (;;) {
  		c = get_next_char();
  		if (config_file_eof)
  			break;
  		if (!iskeychar(c))
  			break;
45de34bbe   Stephane Eranian   perf buildid: add...
153
  		name[len++] = c;
078006012   Ingo Molnar   perf_counter tool...
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
  		if (len >= MAXNAME)
  			return -1;
  	}
  	name[len] = 0;
  	while (c == ' ' || c == '\t')
  		c = get_next_char();
  
  	value = NULL;
  	if (c != '
  ') {
  		if (c != '=')
  			return -1;
  		value = parse_value();
  		if (!value)
  			return -1;
  	}
  	return fn(name, value, data);
  }
  
  static int get_extended_base_var(char *name, int baselen, int c)
  {
  	do {
  		if (c == '
  ')
  			return -1;
  		c = get_next_char();
  	} while (isspace(c));
  
  	/* We require the format to be '[base "extension"]' */
  	if (c != '"')
  		return -1;
  	name[baselen++] = '.';
  
  	for (;;) {
83a0944fa   Ingo Molnar   perf: Enable more...
188
189
190
191
  		int ch = get_next_char();
  
  		if (ch == '
  ')
078006012   Ingo Molnar   perf_counter tool...
192
  			return -1;
83a0944fa   Ingo Molnar   perf: Enable more...
193
  		if (ch == '"')
078006012   Ingo Molnar   perf_counter tool...
194
  			break;
83a0944fa   Ingo Molnar   perf: Enable more...
195
196
197
198
  		if (ch == '\\') {
  			ch = get_next_char();
  			if (ch == '
  ')
078006012   Ingo Molnar   perf_counter tool...
199
200
  				return -1;
  		}
83a0944fa   Ingo Molnar   perf: Enable more...
201
  		name[baselen++] = ch;
078006012   Ingo Molnar   perf_counter tool...
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
  		if (baselen > MAXNAME / 2)
  			return -1;
  	}
  
  	/* Final ']' */
  	if (get_next_char() != ']')
  		return -1;
  	return baselen;
  }
  
  static int get_base_var(char *name)
  {
  	int baselen = 0;
  
  	for (;;) {
  		int c = get_next_char();
  		if (config_file_eof)
  			return -1;
  		if (c == ']')
  			return baselen;
  		if (isspace(c))
  			return get_extended_base_var(name, baselen, c);
  		if (!iskeychar(c) && c != '.')
  			return -1;
  		if (baselen > MAXNAME / 2)
  			return -1;
  		name[baselen++] = tolower(c);
  	}
  }
  
  static int perf_parse_file(config_fn_t fn, void *data)
  {
  	int comment = 0;
  	int baselen = 0;
  	static char var[MAXNAME];
  
  	/* U+FEFF Byte Order Mark in UTF8 */
  	static const unsigned char *utf8_bom = (unsigned char *) "\xef\xbb\xbf";
  	const unsigned char *bomptr = utf8_bom;
  
  	for (;;) {
49757c9cc   Jiri Olsa   perf tools: Fix l...
243
  		int line, c = get_next_char();
078006012   Ingo Molnar   perf_counter tool...
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
  		if (bomptr && *bomptr) {
  			/* We are at the file beginning; skip UTF8-encoded BOM
  			 * if present. Sane editors won't put this in on their
  			 * own, but e.g. Windows Notepad will do it happily. */
  			if ((unsigned char) c == *bomptr) {
  				bomptr++;
  				continue;
  			} else {
  				/* Do not tolerate partial BOM. */
  				if (bomptr != utf8_bom)
  					break;
  				/* No BOM at file beginning. Cool. */
  				bomptr = NULL;
  			}
  		}
  		if (c == '
  ') {
  			if (config_file_eof)
  				return 0;
  			comment = 0;
  			continue;
  		}
  		if (comment || isspace(c))
  			continue;
  		if (c == '#' || c == ';') {
  			comment = 1;
  			continue;
  		}
  		if (c == '[') {
  			baselen = get_base_var(var);
  			if (baselen <= 0)
  				break;
  			var[baselen++] = '.';
  			var[baselen] = 0;
  			continue;
  		}
  		if (!isalpha(c))
  			break;
  		var[baselen] = tolower(c);
49757c9cc   Jiri Olsa   perf tools: Fix l...
283
284
285
286
287
288
289
290
291
  
  		/*
  		 * The get_value function might or might not reach the '
  ',
  		 * so saving the current line number for error reporting.
  		 */
  		line = config_linenr;
  		if (get_value(fn, data, var, baselen+1) < 0) {
  			config_linenr = line;
078006012   Ingo Molnar   perf_counter tool...
292
  			break;
49757c9cc   Jiri Olsa   perf tools: Fix l...
293
  		}
078006012   Ingo Molnar   perf_counter tool...
294
  	}
78f71c996   Taeung Song   perf config: Fix ...
295
296
297
  	pr_err("bad config file line %d in %s
  ", config_linenr, config_file_name);
  	return -1;
078006012   Ingo Molnar   perf_counter tool...
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
  }
  
  static int parse_unit_factor(const char *end, unsigned long *val)
  {
  	if (!*end)
  		return 1;
  	else if (!strcasecmp(end, "k")) {
  		*val *= 1024;
  		return 1;
  	}
  	else if (!strcasecmp(end, "m")) {
  		*val *= 1024 * 1024;
  		return 1;
  	}
  	else if (!strcasecmp(end, "g")) {
  		*val *= 1024 * 1024 * 1024;
  		return 1;
  	}
  	return 0;
  }
94c0655fc   Jiri Olsa   perf tools: Add p...
318
319
320
321
322
323
324
325
326
327
328
329
330
331
  static int perf_parse_llong(const char *value, long long *ret)
  {
  	if (value && *value) {
  		char *end;
  		long long val = strtoll(value, &end, 0);
  		unsigned long factor = 1;
  
  		if (!parse_unit_factor(end, &factor))
  			return 0;
  		*ret = val * factor;
  		return 1;
  	}
  	return 0;
  }
078006012   Ingo Molnar   perf_counter tool...
332
333
334
335
336
337
338
339
340
341
342
343
344
  static int perf_parse_long(const char *value, long *ret)
  {
  	if (value && *value) {
  		char *end;
  		long val = strtol(value, &end, 0);
  		unsigned long factor = 1;
  		if (!parse_unit_factor(end, &factor))
  			return 0;
  		*ret = val * factor;
  		return 1;
  	}
  	return 0;
  }
078006012   Ingo Molnar   perf_counter tool...
345
346
347
348
349
350
  static void die_bad_config(const char *name)
  {
  	if (config_file_name)
  		die("bad config value for '%s' in %s", name, config_file_name);
  	die("bad config value for '%s'", name);
  }
94c0655fc   Jiri Olsa   perf tools: Add p...
351
352
353
354
355
356
357
358
  u64 perf_config_u64(const char *name, const char *value)
  {
  	long long ret = 0;
  
  	if (!perf_parse_llong(value, &ret))
  		die_bad_config(name);
  	return (u64) ret;
  }
078006012   Ingo Molnar   perf_counter tool...
359
360
361
362
363
364
365
  int perf_config_int(const char *name, const char *value)
  {
  	long ret = 0;
  	if (!perf_parse_long(value, &ret))
  		die_bad_config(name);
  	return ret;
  }
a41794cdd   Arnaldo Carvalho de Melo   perf tools: Remov...
366
  static int perf_config_bool_or_int(const char *name, const char *value, int *is_bool)
078006012   Ingo Molnar   perf_counter tool...
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
  {
  	*is_bool = 1;
  	if (!value)
  		return 1;
  	if (!*value)
  		return 0;
  	if (!strcasecmp(value, "true") || !strcasecmp(value, "yes") || !strcasecmp(value, "on"))
  		return 1;
  	if (!strcasecmp(value, "false") || !strcasecmp(value, "no") || !strcasecmp(value, "off"))
  		return 0;
  	*is_bool = 0;
  	return perf_config_int(name, value);
  }
  
  int perf_config_bool(const char *name, const char *value)
  {
  	int discard;
  	return !!perf_config_bool_or_int(name, value, &discard);
  }
814b3f512   Arnaldo Carvalho de Melo   perf tools: Remov...
386
  static const char *perf_config_dirname(const char *name, const char *value)
45de34bbe   Stephane Eranian   perf buildid: add...
387
388
389
390
391
  {
  	if (!name)
  		return NULL;
  	return value;
  }
9cb5987c8   Taeung Song   perf config: Rewo...
392
393
394
395
  static int perf_buildid_config(const char *var, const char *value)
  {
  	/* same dir for all commands */
  	if (!strcmp(var, "buildid.dir")) {
d8e28654f   Vinson Lee   perf config: Fix ...
396
  		const char *dir = perf_config_dirname(var, value);
9cb5987c8   Taeung Song   perf config: Rewo...
397

ecc4c5614   Arnaldo Carvalho de Melo   perf tools: Propa...
398
399
400
  		if (!dir) {
  			pr_err("Invalid buildid directory!
  ");
9cb5987c8   Taeung Song   perf config: Rewo...
401
  			return -1;
ecc4c5614   Arnaldo Carvalho de Melo   perf tools: Propa...
402
  		}
d8e28654f   Vinson Lee   perf config: Fix ...
403
  		strncpy(buildid_dir, dir, MAXPATHLEN-1);
9cb5987c8   Taeung Song   perf config: Rewo...
404
405
406
407
408
  		buildid_dir[MAXPATHLEN-1] = '\0';
  	}
  
  	return 0;
  }
1d037ca16   Irina Tirdea   perf tools: Use _...
409
410
  static int perf_default_core_config(const char *var __maybe_unused,
  				    const char *value __maybe_unused)
078006012   Ingo Molnar   perf_counter tool...
411
  {
395cf9691   Paul Bolle   doc: fix broken r...
412
  	/* Add other config variables here. */
078006012   Ingo Molnar   perf_counter tool...
413
414
  	return 0;
  }
c83023676   Jiri Olsa   perf hists browse...
415
416
417
  static int perf_ui_config(const char *var, const char *value)
  {
  	/* Add other config variables here. */
ecc4c5614   Arnaldo Carvalho de Melo   perf tools: Propa...
418
  	if (!strcmp(var, "ui.show-headers"))
c83023676   Jiri Olsa   perf hists browse...
419
  		symbol_conf.show_hist_headers = perf_config_bool(var, value);
ecc4c5614   Arnaldo Carvalho de Melo   perf tools: Propa...
420

c83023676   Jiri Olsa   perf hists browse...
421
422
  	return 0;
  }
1d037ca16   Irina Tirdea   perf tools: Use _...
423
424
  int perf_default_config(const char *var, const char *value,
  			void *dummy __maybe_unused)
078006012   Ingo Molnar   perf_counter tool...
425
426
427
  {
  	if (!prefixcmp(var, "core."))
  		return perf_default_core_config(var, value);
0b93da175   Namhyung Kim   perf tools: Add h...
428
429
  	if (!prefixcmp(var, "hist."))
  		return perf_hist_config(var, value);
c83023676   Jiri Olsa   perf hists browse...
430
431
  	if (!prefixcmp(var, "ui."))
  		return perf_ui_config(var, value);
2b9240caf   Namhyung Kim   perf tools: Intro...
432
433
  	if (!prefixcmp(var, "call-graph."))
  		return perf_callchain_config(var, value);
aa61fd05c   Wang Nan   perf tools: Intro...
434
435
  	if (!prefixcmp(var, "llvm."))
  		return perf_llvm_config(var, value);
9cb5987c8   Taeung Song   perf config: Rewo...
436
437
  	if (!prefixcmp(var, "buildid."))
  		return perf_buildid_config(var, value);
395cf9691   Paul Bolle   doc: fix broken r...
438
  	/* Add other config variables here. */
078006012   Ingo Molnar   perf_counter tool...
439
440
  	return 0;
  }
a41794cdd   Arnaldo Carvalho de Melo   perf tools: Remov...
441
  static int perf_config_from_file(config_fn_t fn, const char *filename, void *data)
078006012   Ingo Molnar   perf_counter tool...
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
  {
  	int ret;
  	FILE *f = fopen(filename, "r");
  
  	ret = -1;
  	if (f) {
  		config_file = f;
  		config_file_name = filename;
  		config_linenr = 1;
  		config_file_eof = 0;
  		ret = perf_parse_file(fn, data);
  		fclose(f);
  		config_file_name = NULL;
  	}
  	return ret;
  }
c7ac24178   Taeung Song   perf config: Add ...
458
  const char *perf_etc_perfconfig(void)
078006012   Ingo Molnar   perf_counter tool...
459
460
461
462
463
464
465
466
467
468
469
470
  {
  	static const char *system_wide;
  	if (!system_wide)
  		system_wide = system_path(ETC_PERFCONFIG);
  	return system_wide;
  }
  
  static int perf_env_bool(const char *k, int def)
  {
  	const char *v = getenv(k);
  	return v ? perf_config_bool(k, v) : def;
  }
a41794cdd   Arnaldo Carvalho de Melo   perf tools: Remov...
471
  static int perf_config_system(void)
078006012   Ingo Molnar   perf_counter tool...
472
473
474
  {
  	return !perf_env_bool("PERF_CONFIG_NOSYSTEM", 0);
  }
a41794cdd   Arnaldo Carvalho de Melo   perf tools: Remov...
475
  static int perf_config_global(void)
078006012   Ingo Molnar   perf_counter tool...
476
477
478
  {
  	return !perf_env_bool("PERF_CONFIG_NOGLOBAL", 0);
  }
20105ca12   Taeung Song   perf config: Intr...
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
  static struct perf_config_section *find_section(struct list_head *sections,
  						const char *section_name)
  {
  	struct perf_config_section *section;
  
  	list_for_each_entry(section, sections, node)
  		if (!strcmp(section->name, section_name))
  			return section;
  
  	return NULL;
  }
  
  static struct perf_config_item *find_config_item(const char *name,
  						 struct perf_config_section *section)
  {
  	struct perf_config_item *item;
  
  	list_for_each_entry(item, &section->items, node)
  		if (!strcmp(item->name, name))
  			return item;
  
  	return NULL;
  }
  
  static struct perf_config_section *add_section(struct list_head *sections,
  					       const char *section_name)
  {
  	struct perf_config_section *section = zalloc(sizeof(*section));
  
  	if (!section)
  		return NULL;
  
  	INIT_LIST_HEAD(&section->items);
  	section->name = strdup(section_name);
  	if (!section->name) {
  		pr_debug("%s: strdup failed
  ", __func__);
  		free(section);
  		return NULL;
  	}
  
  	list_add_tail(&section->node, sections);
  	return section;
  }
  
  static struct perf_config_item *add_config_item(struct perf_config_section *section,
  						const char *name)
  {
  	struct perf_config_item *item = zalloc(sizeof(*item));
  
  	if (!item)
  		return NULL;
  
  	item->name = strdup(name);
  	if (!item->name) {
  		pr_debug("%s: strdup failed
  ", __func__);
  		free(item);
  		return NULL;
  	}
  
  	list_add_tail(&item->node, &section->items);
  	return item;
  }
  
  static int set_value(struct perf_config_item *item, const char *value)
  {
  	char *val = strdup(value);
  
  	if (!val)
  		return -1;
  
  	zfree(&item->value);
  	item->value = val;
  	return 0;
  }
  
  static int collect_config(const char *var, const char *value,
  			  void *perf_config_set)
  {
  	int ret = -1;
  	char *ptr, *key;
  	char *section_name, *name;
  	struct perf_config_section *section = NULL;
  	struct perf_config_item *item = NULL;
  	struct perf_config_set *set = perf_config_set;
7db91f251   Taeung Song   perf config: Hand...
565
  	struct list_head *sections;
20105ca12   Taeung Song   perf config: Intr...
566

7db91f251   Taeung Song   perf config: Hand...
567
568
569
570
  	if (set == NULL)
  		return -1;
  
  	sections = &set->sections;
20105ca12   Taeung Song   perf config: Intr...
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
  	key = ptr = strdup(var);
  	if (!key) {
  		pr_debug("%s: strdup failed
  ", __func__);
  		return -1;
  	}
  
  	section_name = strsep(&ptr, ".");
  	name = ptr;
  	if (name == NULL || value == NULL)
  		goto out_free;
  
  	section = find_section(sections, section_name);
  	if (!section) {
  		section = add_section(sections, section_name);
  		if (!section)
  			goto out_free;
  	}
  
  	item = find_config_item(name, section);
  	if (!item) {
  		item = add_config_item(section, name);
  		if (!item)
  			goto out_free;
  	}
08d090cfe   Taeung Song   perf config: Mark...
596
597
598
599
600
601
602
603
604
605
606
607
  	/* perf_config_set can contain both user and system config items.
  	 * So we should know where each value is from.
  	 * The classification would be needed when a particular config file
  	 * is overwrited by setting feature i.e. set_config().
  	 */
  	if (strcmp(config_file_name, perf_etc_perfconfig()) == 0) {
  		section->from_system_config = true;
  		item->from_system_config = true;
  	} else {
  		section->from_system_config = false;
  		item->from_system_config = false;
  	}
20105ca12   Taeung Song   perf config: Intr...
608
609
610
611
612
  	ret = set_value(item, value);
  	return ret;
  
  out_free:
  	free(key);
20105ca12   Taeung Song   perf config: Intr...
613
614
  	return -1;
  }
08d090cfe   Taeung Song   perf config: Mark...
615
  int perf_config_set__collect(struct perf_config_set *set, const char *file_name,
c6fc018a7   Taeung Song   perf config: Add ...
616
617
  			     const char *var, const char *value)
  {
08d090cfe   Taeung Song   perf config: Mark...
618
  	config_file_name = file_name;
c6fc018a7   Taeung Song   perf config: Add ...
619
620
  	return collect_config(var, value, set);
  }
8beeb00f2   Taeung Song   perf config: Use ...
621
622
623
624
  static int perf_config_set__init(struct perf_config_set *set)
  {
  	int ret = -1;
  	const char *home = NULL;
3e00cbe88   Jiri Olsa   perf tools: Do no...
625
626
  	char *user_config;
  	struct stat st;
8beeb00f2   Taeung Song   perf config: Use ...
627
628
629
630
631
632
633
634
635
636
  
  	/* Setting $PERF_CONFIG makes perf read _only_ the given config file. */
  	if (config_exclusive_filename)
  		return perf_config_from_file(collect_config, config_exclusive_filename, set);
  	if (perf_config_system() && !access(perf_etc_perfconfig(), R_OK)) {
  		if (perf_config_from_file(collect_config, perf_etc_perfconfig(), set) < 0)
  			goto out;
  	}
  
  	home = getenv("HOME");
8beeb00f2   Taeung Song   perf config: Use ...
637

3e00cbe88   Jiri Olsa   perf tools: Do no...
638
639
640
641
642
643
644
  	/*
  	 * Skip reading user config if:
  	 *   - there is no place to read it from (HOME)
  	 *   - we are asked not to (PERF_CONFIG_NOGLOBAL=1)
  	 */
  	if (!home || !*home || !perf_config_global())
  		return 0;
8beeb00f2   Taeung Song   perf config: Use ...
645

3e00cbe88   Jiri Olsa   perf tools: Do no...
646
647
648
649
650
651
652
653
654
655
656
657
  	user_config = strdup(mkpath("%s/.perfconfig", home));
  	if (user_config == NULL) {
  		warning("Not enough memory to process %s/.perfconfig, "
  			"ignoring it.", home);
  		goto out;
  	}
  
  	if (stat(user_config, &st) < 0) {
  		if (errno == ENOENT)
  			ret = 0;
  		goto out_free;
  	}
afc45cf52   Arnaldo Carvalho de Melo   perf config: Do n...
658

3e00cbe88   Jiri Olsa   perf tools: Do no...
659
  	ret = 0;
8beeb00f2   Taeung Song   perf config: Use ...
660

3e00cbe88   Jiri Olsa   perf tools: Do no...
661
662
663
664
665
666
667
668
  	if (st.st_uid && (st.st_uid != geteuid())) {
  		warning("File %s not owned by current user or root, "
  			"ignoring it.", user_config);
  		goto out_free;
  	}
  
  	if (st.st_size)
  		ret = perf_config_from_file(collect_config, user_config, set);
8beeb00f2   Taeung Song   perf config: Use ...
669

8beeb00f2   Taeung Song   perf config: Use ...
670
  out_free:
3e00cbe88   Jiri Olsa   perf tools: Do no...
671
  	free(user_config);
8beeb00f2   Taeung Song   perf config: Use ...
672
673
674
  out:
  	return ret;
  }
20105ca12   Taeung Song   perf config: Intr...
675
676
677
678
679
680
  struct perf_config_set *perf_config_set__new(void)
  {
  	struct perf_config_set *set = zalloc(sizeof(*set));
  
  	if (set) {
  		INIT_LIST_HEAD(&set->sections);
8beeb00f2   Taeung Song   perf config: Use ...
681
  		if (perf_config_set__init(set) < 0) {
25d8f48f7   Taeung Song   perf config: Cons...
682
683
684
  			perf_config_set__delete(set);
  			set = NULL;
  		}
20105ca12   Taeung Song   perf config: Intr...
685
686
687
688
  	}
  
  	return set;
  }
8a0a9c7e9   Taeung Song   perf config: Intr...
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
  int perf_config(config_fn_t fn, void *data)
  {
  	int ret = 0;
  	char key[BUFSIZ];
  	struct perf_config_section *section;
  	struct perf_config_item *item;
  
  	if (config_set == NULL)
  		return -1;
  
  	perf_config_set__for_each_entry(config_set, section, item) {
  		char *value = item->value;
  
  		if (value) {
  			scnprintf(key, sizeof(key), "%s.%s",
  				  section->name, item->name);
  			ret = fn(key, value, data);
  			if (ret < 0) {
  				pr_err("Error: wrong config key-value pair %s=%s
  ",
  				       key, value);
  				break;
  			}
  		}
  	}
  
  	return ret;
  }
  
  void perf_config__init(void)
  {
  	if (config_set == NULL)
  		config_set = perf_config_set__new();
  }
  
  void perf_config__exit(void)
  {
  	perf_config_set__delete(config_set);
  	config_set = NULL;
  }
  
  void perf_config__refresh(void)
  {
  	perf_config__exit();
  	perf_config__init();
  }
20105ca12   Taeung Song   perf config: Intr...
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
  static void perf_config_item__delete(struct perf_config_item *item)
  {
  	zfree(&item->name);
  	zfree(&item->value);
  	free(item);
  }
  
  static void perf_config_section__purge(struct perf_config_section *section)
  {
  	struct perf_config_item *item, *tmp;
  
  	list_for_each_entry_safe(item, tmp, &section->items, node) {
  		list_del_init(&item->node);
  		perf_config_item__delete(item);
  	}
  }
  
  static void perf_config_section__delete(struct perf_config_section *section)
  {
  	perf_config_section__purge(section);
  	zfree(&section->name);
  	free(section);
  }
  
  static void perf_config_set__purge(struct perf_config_set *set)
  {
  	struct perf_config_section *section, *tmp;
  
  	list_for_each_entry_safe(section, tmp, &set->sections, node) {
  		list_del_init(&section->node);
  		perf_config_section__delete(section);
  	}
  }
  
  void perf_config_set__delete(struct perf_config_set *set)
  {
826424cc9   Taeung Song   perf config: Hand...
771
772
  	if (set == NULL)
  		return;
20105ca12   Taeung Song   perf config: Intr...
773
774
775
  	perf_config_set__purge(set);
  	free(set);
  }
078006012   Ingo Molnar   perf_counter tool...
776
  /*
078006012   Ingo Molnar   perf_counter tool...
777
778
779
780
781
782
783
   * Call this to report error for your variable that should not
   * get a boolean value (i.e. "[my] var" means "true").
   */
  int config_error_nonbool(const char *var)
  {
  	return error("Missing value for '%s'", var);
  }
45de34bbe   Stephane Eranian   perf buildid: add...
784

99ce8e9fc   Jiri Olsa   perf tools: Add -...
785
  void set_buildid_dir(const char *dir)
45de34bbe   Stephane Eranian   perf buildid: add...
786
  {
99ce8e9fc   Jiri Olsa   perf tools: Add -...
787
788
  	if (dir)
  		scnprintf(buildid_dir, MAXPATHLEN-1, "%s", dir);
45de34bbe   Stephane Eranian   perf buildid: add...
789

45de34bbe   Stephane Eranian   perf buildid: add...
790
791
  	/* default to $HOME/.debug */
  	if (buildid_dir[0] == '\0') {
37194f443   Taeung Song   perf config: Rena...
792
793
794
  		char *home = getenv("HOME");
  
  		if (home) {
45de34bbe   Stephane Eranian   perf buildid: add...
795
  			snprintf(buildid_dir, MAXPATHLEN-1, "%s/%s",
37194f443   Taeung Song   perf config: Rena...
796
  				 home, DEBUG_CACHE_DIR);
45de34bbe   Stephane Eranian   perf buildid: add...
797
798
799
800
801
802
803
804
  		} else {
  			strncpy(buildid_dir, DEBUG_CACHE_DIR, MAXPATHLEN-1);
  		}
  		buildid_dir[MAXPATHLEN-1] = '\0';
  	}
  	/* for communicating with external commands */
  	setenv("PERF_BUILDID_DIR", buildid_dir, 1);
  }