186470930SIngo Molnar /* 25f9273d6SNamhyung Kim * config.c 35f9273d6SNamhyung Kim * 45f9273d6SNamhyung Kim * Helper functions for parsing config items. 55f9273d6SNamhyung Kim * Originally copied from GIT source. 686470930SIngo Molnar * 786470930SIngo Molnar * Copyright (C) Linus Torvalds, 2005 886470930SIngo Molnar * Copyright (C) Johannes Schindelin, 2005 986470930SIngo Molnar * 1086470930SIngo Molnar */ 11a43783aeSArnaldo Carvalho de Melo #include <errno.h> 12391e4206SArnaldo Carvalho de Melo #include <sys/param.h> 1386470930SIngo Molnar #include "util.h" 1486470930SIngo Molnar #include "cache.h" 154b6ab94eSJosh Poimboeuf #include <subcmd/exec-cmd.h> 160b93da17SNamhyung Kim #include "util/hist.h" /* perf_hist_config */ 17aa61fd05SWang Nan #include "util/llvm-utils.h" /* perf_llvm_config */ 1820105ca1STaeung Song #include "config.h" 197a8ef4c4SArnaldo Carvalho de Melo #include <sys/types.h> 207a8ef4c4SArnaldo Carvalho de Melo #include <sys/stat.h> 217a8ef4c4SArnaldo Carvalho de Melo #include <unistd.h> 2286470930SIngo Molnar 233d689ed6SArnaldo Carvalho de Melo #include "sane_ctype.h" 243d689ed6SArnaldo Carvalho de Melo 2586470930SIngo Molnar #define MAXNAME (256) 2686470930SIngo Molnar 2745de34bbSStephane Eranian #define DEBUG_CACHE_DIR ".debug" 2845de34bbSStephane Eranian 2945de34bbSStephane Eranian 3045de34bbSStephane Eranian char buildid_dir[MAXPATHLEN]; /* root dir for buildid, binary cache */ 3145de34bbSStephane Eranian 3286470930SIngo Molnar static FILE *config_file; 3386470930SIngo Molnar static const char *config_file_name; 3486470930SIngo Molnar static int config_linenr; 3586470930SIngo Molnar static int config_file_eof; 368a0a9c7eSTaeung Song static struct perf_config_set *config_set; 3786470930SIngo Molnar 38c7ac2417STaeung Song const char *config_exclusive_filename; 3986470930SIngo Molnar 4086470930SIngo Molnar static int get_next_char(void) 4186470930SIngo Molnar { 4286470930SIngo Molnar int c; 4386470930SIngo Molnar FILE *f; 4486470930SIngo Molnar 4586470930SIngo Molnar c = '\n'; 4686470930SIngo Molnar if ((f = config_file) != NULL) { 4786470930SIngo Molnar c = fgetc(f); 4886470930SIngo Molnar if (c == '\r') { 4986470930SIngo Molnar /* DOS like systems */ 5086470930SIngo Molnar c = fgetc(f); 5186470930SIngo Molnar if (c != '\n') { 5286470930SIngo Molnar ungetc(c, f); 5386470930SIngo Molnar c = '\r'; 5486470930SIngo Molnar } 5586470930SIngo Molnar } 5686470930SIngo Molnar if (c == '\n') 5786470930SIngo Molnar config_linenr++; 5886470930SIngo Molnar if (c == EOF) { 5986470930SIngo Molnar config_file_eof = 1; 6086470930SIngo Molnar c = '\n'; 6186470930SIngo Molnar } 6286470930SIngo Molnar } 6386470930SIngo Molnar return c; 6486470930SIngo Molnar } 6586470930SIngo Molnar 6686470930SIngo Molnar static char *parse_value(void) 6786470930SIngo Molnar { 6886470930SIngo Molnar static char value[1024]; 69f37a291cSIngo Molnar int quote = 0, comment = 0, space = 0; 70f37a291cSIngo Molnar size_t len = 0; 7186470930SIngo Molnar 7286470930SIngo Molnar for (;;) { 7386470930SIngo Molnar int c = get_next_char(); 74f37a291cSIngo Molnar 7586470930SIngo Molnar if (len >= sizeof(value) - 1) 7686470930SIngo Molnar return NULL; 7786470930SIngo Molnar if (c == '\n') { 7886470930SIngo Molnar if (quote) 7986470930SIngo Molnar return NULL; 8086470930SIngo Molnar value[len] = 0; 8186470930SIngo Molnar return value; 8286470930SIngo Molnar } 8386470930SIngo Molnar if (comment) 8486470930SIngo Molnar continue; 8586470930SIngo Molnar if (isspace(c) && !quote) { 8686470930SIngo Molnar space = 1; 8786470930SIngo Molnar continue; 8886470930SIngo Molnar } 8986470930SIngo Molnar if (!quote) { 9086470930SIngo Molnar if (c == ';' || c == '#') { 9186470930SIngo Molnar comment = 1; 9286470930SIngo Molnar continue; 9386470930SIngo Molnar } 9486470930SIngo Molnar } 9586470930SIngo Molnar if (space) { 9686470930SIngo Molnar if (len) 9786470930SIngo Molnar value[len++] = ' '; 9886470930SIngo Molnar space = 0; 9986470930SIngo Molnar } 10086470930SIngo Molnar if (c == '\\') { 10186470930SIngo Molnar c = get_next_char(); 10286470930SIngo Molnar switch (c) { 10386470930SIngo Molnar case '\n': 10486470930SIngo Molnar continue; 10586470930SIngo Molnar case 't': 10686470930SIngo Molnar c = '\t'; 10786470930SIngo Molnar break; 10886470930SIngo Molnar case 'b': 10986470930SIngo Molnar c = '\b'; 11086470930SIngo Molnar break; 11186470930SIngo Molnar case 'n': 11286470930SIngo Molnar c = '\n'; 11386470930SIngo Molnar break; 11486470930SIngo Molnar /* Some characters escape as themselves */ 11586470930SIngo Molnar case '\\': case '"': 11686470930SIngo Molnar break; 11786470930SIngo Molnar /* Reject unknown escape sequences */ 11886470930SIngo Molnar default: 11986470930SIngo Molnar return NULL; 12086470930SIngo Molnar } 12186470930SIngo Molnar value[len++] = c; 12286470930SIngo Molnar continue; 12386470930SIngo Molnar } 12486470930SIngo Molnar if (c == '"') { 12586470930SIngo Molnar quote = 1-quote; 12686470930SIngo Molnar continue; 12786470930SIngo Molnar } 12886470930SIngo Molnar value[len++] = c; 12986470930SIngo Molnar } 13086470930SIngo Molnar } 13186470930SIngo Molnar 13286470930SIngo Molnar static inline int iskeychar(int c) 13386470930SIngo Molnar { 1348dc7c651SArnaldo Carvalho de Melo return isalnum(c) || c == '-' || c == '_'; 13586470930SIngo Molnar } 13686470930SIngo Molnar 13786470930SIngo Molnar static int get_value(config_fn_t fn, void *data, char *name, unsigned int len) 13886470930SIngo Molnar { 13986470930SIngo Molnar int c; 14086470930SIngo Molnar char *value; 14186470930SIngo Molnar 14286470930SIngo Molnar /* Get the full name */ 14386470930SIngo Molnar for (;;) { 14486470930SIngo Molnar c = get_next_char(); 14586470930SIngo Molnar if (config_file_eof) 14686470930SIngo Molnar break; 14786470930SIngo Molnar if (!iskeychar(c)) 14886470930SIngo Molnar break; 14945de34bbSStephane Eranian name[len++] = c; 15086470930SIngo Molnar if (len >= MAXNAME) 15186470930SIngo Molnar return -1; 15286470930SIngo Molnar } 15386470930SIngo Molnar name[len] = 0; 15486470930SIngo Molnar while (c == ' ' || c == '\t') 15586470930SIngo Molnar c = get_next_char(); 15686470930SIngo Molnar 15786470930SIngo Molnar value = NULL; 15886470930SIngo Molnar if (c != '\n') { 15986470930SIngo Molnar if (c != '=') 16086470930SIngo Molnar return -1; 16186470930SIngo Molnar value = parse_value(); 16286470930SIngo Molnar if (!value) 16386470930SIngo Molnar return -1; 16486470930SIngo Molnar } 16586470930SIngo Molnar return fn(name, value, data); 16686470930SIngo Molnar } 16786470930SIngo Molnar 16886470930SIngo Molnar static int get_extended_base_var(char *name, int baselen, int c) 16986470930SIngo Molnar { 17086470930SIngo Molnar do { 17186470930SIngo Molnar if (c == '\n') 17286470930SIngo Molnar return -1; 17386470930SIngo Molnar c = get_next_char(); 17486470930SIngo Molnar } while (isspace(c)); 17586470930SIngo Molnar 17686470930SIngo Molnar /* We require the format to be '[base "extension"]' */ 17786470930SIngo Molnar if (c != '"') 17886470930SIngo Molnar return -1; 17986470930SIngo Molnar name[baselen++] = '.'; 18086470930SIngo Molnar 18186470930SIngo Molnar for (;;) { 18283a0944fSIngo Molnar int ch = get_next_char(); 18383a0944fSIngo Molnar 18483a0944fSIngo Molnar if (ch == '\n') 18586470930SIngo Molnar return -1; 18683a0944fSIngo Molnar if (ch == '"') 18786470930SIngo Molnar break; 18883a0944fSIngo Molnar if (ch == '\\') { 18983a0944fSIngo Molnar ch = get_next_char(); 19083a0944fSIngo Molnar if (ch == '\n') 19186470930SIngo Molnar return -1; 19286470930SIngo Molnar } 19383a0944fSIngo Molnar name[baselen++] = ch; 19486470930SIngo Molnar if (baselen > MAXNAME / 2) 19586470930SIngo Molnar return -1; 19686470930SIngo Molnar } 19786470930SIngo Molnar 19886470930SIngo Molnar /* Final ']' */ 19986470930SIngo Molnar if (get_next_char() != ']') 20086470930SIngo Molnar return -1; 20186470930SIngo Molnar return baselen; 20286470930SIngo Molnar } 20386470930SIngo Molnar 20486470930SIngo Molnar static int get_base_var(char *name) 20586470930SIngo Molnar { 20686470930SIngo Molnar int baselen = 0; 20786470930SIngo Molnar 20886470930SIngo Molnar for (;;) { 20986470930SIngo Molnar int c = get_next_char(); 21086470930SIngo Molnar if (config_file_eof) 21186470930SIngo Molnar return -1; 21286470930SIngo Molnar if (c == ']') 21386470930SIngo Molnar return baselen; 21486470930SIngo Molnar if (isspace(c)) 21586470930SIngo Molnar return get_extended_base_var(name, baselen, c); 21686470930SIngo Molnar if (!iskeychar(c) && c != '.') 21786470930SIngo Molnar return -1; 21886470930SIngo Molnar if (baselen > MAXNAME / 2) 21986470930SIngo Molnar return -1; 22086470930SIngo Molnar name[baselen++] = tolower(c); 22186470930SIngo Molnar } 22286470930SIngo Molnar } 22386470930SIngo Molnar 22486470930SIngo Molnar static int perf_parse_file(config_fn_t fn, void *data) 22586470930SIngo Molnar { 22686470930SIngo Molnar int comment = 0; 22786470930SIngo Molnar int baselen = 0; 22886470930SIngo Molnar static char var[MAXNAME]; 22986470930SIngo Molnar 23086470930SIngo Molnar /* U+FEFF Byte Order Mark in UTF8 */ 23186470930SIngo Molnar static const unsigned char *utf8_bom = (unsigned char *) "\xef\xbb\xbf"; 23286470930SIngo Molnar const unsigned char *bomptr = utf8_bom; 23386470930SIngo Molnar 23486470930SIngo Molnar for (;;) { 23549757c9cSJiri Olsa int line, c = get_next_char(); 23649757c9cSJiri Olsa 23786470930SIngo Molnar if (bomptr && *bomptr) { 23886470930SIngo Molnar /* We are at the file beginning; skip UTF8-encoded BOM 23986470930SIngo Molnar * if present. Sane editors won't put this in on their 24086470930SIngo Molnar * own, but e.g. Windows Notepad will do it happily. */ 24186470930SIngo Molnar if ((unsigned char) c == *bomptr) { 24286470930SIngo Molnar bomptr++; 24386470930SIngo Molnar continue; 24486470930SIngo Molnar } else { 24586470930SIngo Molnar /* Do not tolerate partial BOM. */ 24686470930SIngo Molnar if (bomptr != utf8_bom) 24786470930SIngo Molnar break; 24886470930SIngo Molnar /* No BOM at file beginning. Cool. */ 24986470930SIngo Molnar bomptr = NULL; 25086470930SIngo Molnar } 25186470930SIngo Molnar } 25286470930SIngo Molnar if (c == '\n') { 25386470930SIngo Molnar if (config_file_eof) 25486470930SIngo Molnar return 0; 25586470930SIngo Molnar comment = 0; 25686470930SIngo Molnar continue; 25786470930SIngo Molnar } 25886470930SIngo Molnar if (comment || isspace(c)) 25986470930SIngo Molnar continue; 26086470930SIngo Molnar if (c == '#' || c == ';') { 26186470930SIngo Molnar comment = 1; 26286470930SIngo Molnar continue; 26386470930SIngo Molnar } 26486470930SIngo Molnar if (c == '[') { 26586470930SIngo Molnar baselen = get_base_var(var); 26686470930SIngo Molnar if (baselen <= 0) 26786470930SIngo Molnar break; 26886470930SIngo Molnar var[baselen++] = '.'; 26986470930SIngo Molnar var[baselen] = 0; 27086470930SIngo Molnar continue; 27186470930SIngo Molnar } 27286470930SIngo Molnar if (!isalpha(c)) 27386470930SIngo Molnar break; 27486470930SIngo Molnar var[baselen] = tolower(c); 27549757c9cSJiri Olsa 27649757c9cSJiri Olsa /* 27749757c9cSJiri Olsa * The get_value function might or might not reach the '\n', 27849757c9cSJiri Olsa * so saving the current line number for error reporting. 27949757c9cSJiri Olsa */ 28049757c9cSJiri Olsa line = config_linenr; 28149757c9cSJiri Olsa if (get_value(fn, data, var, baselen+1) < 0) { 28249757c9cSJiri Olsa config_linenr = line; 28386470930SIngo Molnar break; 28486470930SIngo Molnar } 28549757c9cSJiri Olsa } 28678f71c99STaeung Song pr_err("bad config file line %d in %s\n", config_linenr, config_file_name); 28778f71c99STaeung Song return -1; 28886470930SIngo Molnar } 28986470930SIngo Molnar 29086470930SIngo Molnar static int parse_unit_factor(const char *end, unsigned long *val) 29186470930SIngo Molnar { 29286470930SIngo Molnar if (!*end) 29386470930SIngo Molnar return 1; 29486470930SIngo Molnar else if (!strcasecmp(end, "k")) { 29586470930SIngo Molnar *val *= 1024; 29686470930SIngo Molnar return 1; 29786470930SIngo Molnar } 29886470930SIngo Molnar else if (!strcasecmp(end, "m")) { 29986470930SIngo Molnar *val *= 1024 * 1024; 30086470930SIngo Molnar return 1; 30186470930SIngo Molnar } 30286470930SIngo Molnar else if (!strcasecmp(end, "g")) { 30386470930SIngo Molnar *val *= 1024 * 1024 * 1024; 30486470930SIngo Molnar return 1; 30586470930SIngo Molnar } 30686470930SIngo Molnar return 0; 30786470930SIngo Molnar } 30886470930SIngo Molnar 30994c0655fSJiri Olsa static int perf_parse_llong(const char *value, long long *ret) 31094c0655fSJiri Olsa { 31194c0655fSJiri Olsa if (value && *value) { 31294c0655fSJiri Olsa char *end; 31394c0655fSJiri Olsa long long val = strtoll(value, &end, 0); 31494c0655fSJiri Olsa unsigned long factor = 1; 31594c0655fSJiri Olsa 31694c0655fSJiri Olsa if (!parse_unit_factor(end, &factor)) 31794c0655fSJiri Olsa return 0; 31894c0655fSJiri Olsa *ret = val * factor; 31994c0655fSJiri Olsa return 1; 32094c0655fSJiri Olsa } 32194c0655fSJiri Olsa return 0; 32294c0655fSJiri Olsa } 32394c0655fSJiri Olsa 32486470930SIngo Molnar static int perf_parse_long(const char *value, long *ret) 32586470930SIngo Molnar { 32686470930SIngo Molnar if (value && *value) { 32786470930SIngo Molnar char *end; 32886470930SIngo Molnar long val = strtol(value, &end, 0); 32986470930SIngo Molnar unsigned long factor = 1; 33086470930SIngo Molnar if (!parse_unit_factor(end, &factor)) 33186470930SIngo Molnar return 0; 33286470930SIngo Molnar *ret = val * factor; 33386470930SIngo Molnar return 1; 33486470930SIngo Molnar } 33586470930SIngo Molnar return 0; 33686470930SIngo Molnar } 33786470930SIngo Molnar 338*25ce4bb8SArnaldo Carvalho de Melo static void bad_config(const char *name) 33986470930SIngo Molnar { 34086470930SIngo Molnar if (config_file_name) 341*25ce4bb8SArnaldo Carvalho de Melo pr_warning("bad config value for '%s' in %s, ignoring...\n", name, config_file_name); 342*25ce4bb8SArnaldo Carvalho de Melo else 343*25ce4bb8SArnaldo Carvalho de Melo pr_warning("bad config value for '%s', ignoring...\n", name); 34486470930SIngo Molnar } 34586470930SIngo Molnar 346*25ce4bb8SArnaldo Carvalho de Melo int perf_config_u64(u64 *dest, const char *name, const char *value) 34794c0655fSJiri Olsa { 34894c0655fSJiri Olsa long long ret = 0; 34994c0655fSJiri Olsa 350*25ce4bb8SArnaldo Carvalho de Melo if (!perf_parse_llong(value, &ret)) { 351*25ce4bb8SArnaldo Carvalho de Melo bad_config(name); 352*25ce4bb8SArnaldo Carvalho de Melo return -1; 35394c0655fSJiri Olsa } 35494c0655fSJiri Olsa 355*25ce4bb8SArnaldo Carvalho de Melo *dest = ret; 356*25ce4bb8SArnaldo Carvalho de Melo return 0; 357*25ce4bb8SArnaldo Carvalho de Melo } 358*25ce4bb8SArnaldo Carvalho de Melo 359*25ce4bb8SArnaldo Carvalho de Melo int perf_config_int(int *dest, const char *name, const char *value) 36086470930SIngo Molnar { 36186470930SIngo Molnar long ret = 0; 362*25ce4bb8SArnaldo Carvalho de Melo if (!perf_parse_long(value, &ret)) { 363*25ce4bb8SArnaldo Carvalho de Melo bad_config(name); 364*25ce4bb8SArnaldo Carvalho de Melo return -1; 365*25ce4bb8SArnaldo Carvalho de Melo } 366*25ce4bb8SArnaldo Carvalho de Melo *dest = ret; 367*25ce4bb8SArnaldo Carvalho de Melo return 0; 36886470930SIngo Molnar } 36986470930SIngo Molnar 370a41794cdSArnaldo Carvalho de Melo static int perf_config_bool_or_int(const char *name, const char *value, int *is_bool) 37186470930SIngo Molnar { 372*25ce4bb8SArnaldo Carvalho de Melo int ret; 373*25ce4bb8SArnaldo Carvalho de Melo 37486470930SIngo Molnar *is_bool = 1; 37586470930SIngo Molnar if (!value) 37686470930SIngo Molnar return 1; 37786470930SIngo Molnar if (!*value) 37886470930SIngo Molnar return 0; 37986470930SIngo Molnar if (!strcasecmp(value, "true") || !strcasecmp(value, "yes") || !strcasecmp(value, "on")) 38086470930SIngo Molnar return 1; 38186470930SIngo Molnar if (!strcasecmp(value, "false") || !strcasecmp(value, "no") || !strcasecmp(value, "off")) 38286470930SIngo Molnar return 0; 38386470930SIngo Molnar *is_bool = 0; 384*25ce4bb8SArnaldo Carvalho de Melo return perf_config_int(&ret, name, value) < 0 ? -1 : ret; 38586470930SIngo Molnar } 38686470930SIngo Molnar 38786470930SIngo Molnar int perf_config_bool(const char *name, const char *value) 38886470930SIngo Molnar { 38986470930SIngo Molnar int discard; 39086470930SIngo Molnar return !!perf_config_bool_or_int(name, value, &discard); 39186470930SIngo Molnar } 39286470930SIngo Molnar 393814b3f51SArnaldo Carvalho de Melo static const char *perf_config_dirname(const char *name, const char *value) 39445de34bbSStephane Eranian { 39545de34bbSStephane Eranian if (!name) 39645de34bbSStephane Eranian return NULL; 39745de34bbSStephane Eranian return value; 39845de34bbSStephane Eranian } 39945de34bbSStephane Eranian 4009cb5987cSTaeung Song static int perf_buildid_config(const char *var, const char *value) 4019cb5987cSTaeung Song { 4029cb5987cSTaeung Song /* same dir for all commands */ 4039cb5987cSTaeung Song if (!strcmp(var, "buildid.dir")) { 404d8e28654SVinson Lee const char *dir = perf_config_dirname(var, value); 4059cb5987cSTaeung Song 406ecc4c561SArnaldo Carvalho de Melo if (!dir) { 407ecc4c561SArnaldo Carvalho de Melo pr_err("Invalid buildid directory!\n"); 4089cb5987cSTaeung Song return -1; 409ecc4c561SArnaldo Carvalho de Melo } 410d8e28654SVinson Lee strncpy(buildid_dir, dir, MAXPATHLEN-1); 4119cb5987cSTaeung Song buildid_dir[MAXPATHLEN-1] = '\0'; 4129cb5987cSTaeung Song } 4139cb5987cSTaeung Song 4149cb5987cSTaeung Song return 0; 4159cb5987cSTaeung Song } 4169cb5987cSTaeung Song 4171d037ca1SIrina Tirdea static int perf_default_core_config(const char *var __maybe_unused, 4181d037ca1SIrina Tirdea const char *value __maybe_unused) 41986470930SIngo Molnar { 420395cf969SPaul Bolle /* Add other config variables here. */ 42186470930SIngo Molnar return 0; 42286470930SIngo Molnar } 42386470930SIngo Molnar 424c8302367SJiri Olsa static int perf_ui_config(const char *var, const char *value) 425c8302367SJiri Olsa { 426c8302367SJiri Olsa /* Add other config variables here. */ 427ecc4c561SArnaldo Carvalho de Melo if (!strcmp(var, "ui.show-headers")) 428c8302367SJiri Olsa symbol_conf.show_hist_headers = perf_config_bool(var, value); 429ecc4c561SArnaldo Carvalho de Melo 430c8302367SJiri Olsa return 0; 431c8302367SJiri Olsa } 432c8302367SJiri Olsa 4331d037ca1SIrina Tirdea int perf_default_config(const char *var, const char *value, 4341d037ca1SIrina Tirdea void *dummy __maybe_unused) 43586470930SIngo Molnar { 43686470930SIngo Molnar if (!prefixcmp(var, "core.")) 43786470930SIngo Molnar return perf_default_core_config(var, value); 43886470930SIngo Molnar 4390b93da17SNamhyung Kim if (!prefixcmp(var, "hist.")) 4400b93da17SNamhyung Kim return perf_hist_config(var, value); 4410b93da17SNamhyung Kim 442c8302367SJiri Olsa if (!prefixcmp(var, "ui.")) 443c8302367SJiri Olsa return perf_ui_config(var, value); 444c8302367SJiri Olsa 4452b9240caSNamhyung Kim if (!prefixcmp(var, "call-graph.")) 4462b9240caSNamhyung Kim return perf_callchain_config(var, value); 4472b9240caSNamhyung Kim 448aa61fd05SWang Nan if (!prefixcmp(var, "llvm.")) 449aa61fd05SWang Nan return perf_llvm_config(var, value); 450aa61fd05SWang Nan 4519cb5987cSTaeung Song if (!prefixcmp(var, "buildid.")) 4529cb5987cSTaeung Song return perf_buildid_config(var, value); 4539cb5987cSTaeung Song 454395cf969SPaul Bolle /* Add other config variables here. */ 45586470930SIngo Molnar return 0; 45686470930SIngo Molnar } 45786470930SIngo Molnar 458a41794cdSArnaldo Carvalho de Melo static int perf_config_from_file(config_fn_t fn, const char *filename, void *data) 45986470930SIngo Molnar { 46086470930SIngo Molnar int ret; 46186470930SIngo Molnar FILE *f = fopen(filename, "r"); 46286470930SIngo Molnar 46386470930SIngo Molnar ret = -1; 46486470930SIngo Molnar if (f) { 46586470930SIngo Molnar config_file = f; 46686470930SIngo Molnar config_file_name = filename; 46786470930SIngo Molnar config_linenr = 1; 46886470930SIngo Molnar config_file_eof = 0; 46986470930SIngo Molnar ret = perf_parse_file(fn, data); 47086470930SIngo Molnar fclose(f); 47186470930SIngo Molnar config_file_name = NULL; 47286470930SIngo Molnar } 47386470930SIngo Molnar return ret; 47486470930SIngo Molnar } 47586470930SIngo Molnar 476c7ac2417STaeung Song const char *perf_etc_perfconfig(void) 47786470930SIngo Molnar { 47886470930SIngo Molnar static const char *system_wide; 47986470930SIngo Molnar if (!system_wide) 48086470930SIngo Molnar system_wide = system_path(ETC_PERFCONFIG); 48186470930SIngo Molnar return system_wide; 48286470930SIngo Molnar } 48386470930SIngo Molnar 48486470930SIngo Molnar static int perf_env_bool(const char *k, int def) 48586470930SIngo Molnar { 48686470930SIngo Molnar const char *v = getenv(k); 48786470930SIngo Molnar return v ? perf_config_bool(k, v) : def; 48886470930SIngo Molnar } 48986470930SIngo Molnar 490a41794cdSArnaldo Carvalho de Melo static int perf_config_system(void) 49186470930SIngo Molnar { 49286470930SIngo Molnar return !perf_env_bool("PERF_CONFIG_NOSYSTEM", 0); 49386470930SIngo Molnar } 49486470930SIngo Molnar 495a41794cdSArnaldo Carvalho de Melo static int perf_config_global(void) 49686470930SIngo Molnar { 49786470930SIngo Molnar return !perf_env_bool("PERF_CONFIG_NOGLOBAL", 0); 49886470930SIngo Molnar } 49986470930SIngo Molnar 50020105ca1STaeung Song static struct perf_config_section *find_section(struct list_head *sections, 50120105ca1STaeung Song const char *section_name) 50220105ca1STaeung Song { 50320105ca1STaeung Song struct perf_config_section *section; 50420105ca1STaeung Song 50520105ca1STaeung Song list_for_each_entry(section, sections, node) 50620105ca1STaeung Song if (!strcmp(section->name, section_name)) 50720105ca1STaeung Song return section; 50820105ca1STaeung Song 50920105ca1STaeung Song return NULL; 51020105ca1STaeung Song } 51120105ca1STaeung Song 51220105ca1STaeung Song static struct perf_config_item *find_config_item(const char *name, 51320105ca1STaeung Song struct perf_config_section *section) 51420105ca1STaeung Song { 51520105ca1STaeung Song struct perf_config_item *item; 51620105ca1STaeung Song 51720105ca1STaeung Song list_for_each_entry(item, §ion->items, node) 51820105ca1STaeung Song if (!strcmp(item->name, name)) 51920105ca1STaeung Song return item; 52020105ca1STaeung Song 52120105ca1STaeung Song return NULL; 52220105ca1STaeung Song } 52320105ca1STaeung Song 52420105ca1STaeung Song static struct perf_config_section *add_section(struct list_head *sections, 52520105ca1STaeung Song const char *section_name) 52620105ca1STaeung Song { 52720105ca1STaeung Song struct perf_config_section *section = zalloc(sizeof(*section)); 52820105ca1STaeung Song 52920105ca1STaeung Song if (!section) 53020105ca1STaeung Song return NULL; 53120105ca1STaeung Song 53220105ca1STaeung Song INIT_LIST_HEAD(§ion->items); 53320105ca1STaeung Song section->name = strdup(section_name); 53420105ca1STaeung Song if (!section->name) { 53520105ca1STaeung Song pr_debug("%s: strdup failed\n", __func__); 53620105ca1STaeung Song free(section); 53720105ca1STaeung Song return NULL; 53820105ca1STaeung Song } 53920105ca1STaeung Song 54020105ca1STaeung Song list_add_tail(§ion->node, sections); 54120105ca1STaeung Song return section; 54220105ca1STaeung Song } 54320105ca1STaeung Song 54420105ca1STaeung Song static struct perf_config_item *add_config_item(struct perf_config_section *section, 54520105ca1STaeung Song const char *name) 54620105ca1STaeung Song { 54720105ca1STaeung Song struct perf_config_item *item = zalloc(sizeof(*item)); 54820105ca1STaeung Song 54920105ca1STaeung Song if (!item) 55020105ca1STaeung Song return NULL; 55120105ca1STaeung Song 55220105ca1STaeung Song item->name = strdup(name); 55320105ca1STaeung Song if (!item->name) { 55420105ca1STaeung Song pr_debug("%s: strdup failed\n", __func__); 55520105ca1STaeung Song free(item); 55620105ca1STaeung Song return NULL; 55720105ca1STaeung Song } 55820105ca1STaeung Song 55920105ca1STaeung Song list_add_tail(&item->node, §ion->items); 56020105ca1STaeung Song return item; 56120105ca1STaeung Song } 56220105ca1STaeung Song 56320105ca1STaeung Song static int set_value(struct perf_config_item *item, const char *value) 56420105ca1STaeung Song { 56520105ca1STaeung Song char *val = strdup(value); 56620105ca1STaeung Song 56720105ca1STaeung Song if (!val) 56820105ca1STaeung Song return -1; 56920105ca1STaeung Song 57020105ca1STaeung Song zfree(&item->value); 57120105ca1STaeung Song item->value = val; 57220105ca1STaeung Song return 0; 57320105ca1STaeung Song } 57420105ca1STaeung Song 57520105ca1STaeung Song static int collect_config(const char *var, const char *value, 57620105ca1STaeung Song void *perf_config_set) 57720105ca1STaeung Song { 57820105ca1STaeung Song int ret = -1; 57920105ca1STaeung Song char *ptr, *key; 58020105ca1STaeung Song char *section_name, *name; 58120105ca1STaeung Song struct perf_config_section *section = NULL; 58220105ca1STaeung Song struct perf_config_item *item = NULL; 58320105ca1STaeung Song struct perf_config_set *set = perf_config_set; 5847db91f25STaeung Song struct list_head *sections; 58520105ca1STaeung Song 5867db91f25STaeung Song if (set == NULL) 5877db91f25STaeung Song return -1; 5887db91f25STaeung Song 5897db91f25STaeung Song sections = &set->sections; 59020105ca1STaeung Song key = ptr = strdup(var); 59120105ca1STaeung Song if (!key) { 59220105ca1STaeung Song pr_debug("%s: strdup failed\n", __func__); 59320105ca1STaeung Song return -1; 59420105ca1STaeung Song } 59520105ca1STaeung Song 59620105ca1STaeung Song section_name = strsep(&ptr, "."); 59720105ca1STaeung Song name = ptr; 59820105ca1STaeung Song if (name == NULL || value == NULL) 59920105ca1STaeung Song goto out_free; 60020105ca1STaeung Song 60120105ca1STaeung Song section = find_section(sections, section_name); 60220105ca1STaeung Song if (!section) { 60320105ca1STaeung Song section = add_section(sections, section_name); 60420105ca1STaeung Song if (!section) 60520105ca1STaeung Song goto out_free; 60620105ca1STaeung Song } 60720105ca1STaeung Song 60820105ca1STaeung Song item = find_config_item(name, section); 60920105ca1STaeung Song if (!item) { 61020105ca1STaeung Song item = add_config_item(section, name); 61120105ca1STaeung Song if (!item) 61220105ca1STaeung Song goto out_free; 61320105ca1STaeung Song } 61420105ca1STaeung Song 61508d090cfSTaeung Song /* perf_config_set can contain both user and system config items. 61608d090cfSTaeung Song * So we should know where each value is from. 61708d090cfSTaeung Song * The classification would be needed when a particular config file 61808d090cfSTaeung Song * is overwrited by setting feature i.e. set_config(). 61908d090cfSTaeung Song */ 62008d090cfSTaeung Song if (strcmp(config_file_name, perf_etc_perfconfig()) == 0) { 62108d090cfSTaeung Song section->from_system_config = true; 62208d090cfSTaeung Song item->from_system_config = true; 62308d090cfSTaeung Song } else { 62408d090cfSTaeung Song section->from_system_config = false; 62508d090cfSTaeung Song item->from_system_config = false; 62608d090cfSTaeung Song } 62708d090cfSTaeung Song 62820105ca1STaeung Song ret = set_value(item, value); 62920105ca1STaeung Song return ret; 63020105ca1STaeung Song 63120105ca1STaeung Song out_free: 63220105ca1STaeung Song free(key); 63320105ca1STaeung Song return -1; 63420105ca1STaeung Song } 63520105ca1STaeung Song 63608d090cfSTaeung Song int perf_config_set__collect(struct perf_config_set *set, const char *file_name, 637c6fc018aSTaeung Song const char *var, const char *value) 638c6fc018aSTaeung Song { 63908d090cfSTaeung Song config_file_name = file_name; 640c6fc018aSTaeung Song return collect_config(var, value, set); 641c6fc018aSTaeung Song } 642c6fc018aSTaeung Song 6438beeb00fSTaeung Song static int perf_config_set__init(struct perf_config_set *set) 6448beeb00fSTaeung Song { 6458beeb00fSTaeung Song int ret = -1; 6468beeb00fSTaeung Song const char *home = NULL; 6473e00cbe8SJiri Olsa char *user_config; 6483e00cbe8SJiri Olsa struct stat st; 6498beeb00fSTaeung Song 6508beeb00fSTaeung Song /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */ 6518beeb00fSTaeung Song if (config_exclusive_filename) 6528beeb00fSTaeung Song return perf_config_from_file(collect_config, config_exclusive_filename, set); 6538beeb00fSTaeung Song if (perf_config_system() && !access(perf_etc_perfconfig(), R_OK)) { 6548beeb00fSTaeung Song if (perf_config_from_file(collect_config, perf_etc_perfconfig(), set) < 0) 6558beeb00fSTaeung Song goto out; 6568beeb00fSTaeung Song } 6578beeb00fSTaeung Song 6588beeb00fSTaeung Song home = getenv("HOME"); 6598beeb00fSTaeung Song 6603e00cbe8SJiri Olsa /* 6613e00cbe8SJiri Olsa * Skip reading user config if: 6623e00cbe8SJiri Olsa * - there is no place to read it from (HOME) 6633e00cbe8SJiri Olsa * - we are asked not to (PERF_CONFIG_NOGLOBAL=1) 6643e00cbe8SJiri Olsa */ 6653e00cbe8SJiri Olsa if (!home || !*home || !perf_config_global()) 6663e00cbe8SJiri Olsa return 0; 6673e00cbe8SJiri Olsa 6683e00cbe8SJiri Olsa user_config = strdup(mkpath("%s/.perfconfig", home)); 6698beeb00fSTaeung Song if (user_config == NULL) { 6704cf134e7SArnaldo Carvalho de Melo pr_warning("Not enough memory to process %s/.perfconfig, ignoring it.", home); 6718beeb00fSTaeung Song goto out; 6728beeb00fSTaeung Song } 6738beeb00fSTaeung Song 674afc45cf5SArnaldo Carvalho de Melo if (stat(user_config, &st) < 0) { 675afc45cf5SArnaldo Carvalho de Melo if (errno == ENOENT) 676afc45cf5SArnaldo Carvalho de Melo ret = 0; 6778beeb00fSTaeung Song goto out_free; 678afc45cf5SArnaldo Carvalho de Melo } 679afc45cf5SArnaldo Carvalho de Melo 680afc45cf5SArnaldo Carvalho de Melo ret = 0; 6818beeb00fSTaeung Song 6828beeb00fSTaeung Song if (st.st_uid && (st.st_uid != geteuid())) { 6834cf134e7SArnaldo Carvalho de Melo pr_warning("File %s not owned by current user or root, ignoring it.", user_config); 6848beeb00fSTaeung Song goto out_free; 6858beeb00fSTaeung Song } 6868beeb00fSTaeung Song 687afc45cf5SArnaldo Carvalho de Melo if (st.st_size) 6888beeb00fSTaeung Song ret = perf_config_from_file(collect_config, user_config, set); 6893e00cbe8SJiri Olsa 6908beeb00fSTaeung Song out_free: 6918beeb00fSTaeung Song free(user_config); 6928beeb00fSTaeung Song out: 6938beeb00fSTaeung Song return ret; 6948beeb00fSTaeung Song } 6958beeb00fSTaeung Song 69620105ca1STaeung Song struct perf_config_set *perf_config_set__new(void) 69720105ca1STaeung Song { 69820105ca1STaeung Song struct perf_config_set *set = zalloc(sizeof(*set)); 69920105ca1STaeung Song 70020105ca1STaeung Song if (set) { 70120105ca1STaeung Song INIT_LIST_HEAD(&set->sections); 7028beeb00fSTaeung Song if (perf_config_set__init(set) < 0) { 70325d8f48fSTaeung Song perf_config_set__delete(set); 70425d8f48fSTaeung Song set = NULL; 70525d8f48fSTaeung Song } 70620105ca1STaeung Song } 70720105ca1STaeung Song 70820105ca1STaeung Song return set; 70920105ca1STaeung Song } 71020105ca1STaeung Song 7118a0a9c7eSTaeung Song int perf_config(config_fn_t fn, void *data) 7128a0a9c7eSTaeung Song { 7138a0a9c7eSTaeung Song int ret = 0; 7148a0a9c7eSTaeung Song char key[BUFSIZ]; 7158a0a9c7eSTaeung Song struct perf_config_section *section; 7168a0a9c7eSTaeung Song struct perf_config_item *item; 7178a0a9c7eSTaeung Song 7188a0a9c7eSTaeung Song if (config_set == NULL) 7198a0a9c7eSTaeung Song return -1; 7208a0a9c7eSTaeung Song 7218a0a9c7eSTaeung Song perf_config_set__for_each_entry(config_set, section, item) { 7228a0a9c7eSTaeung Song char *value = item->value; 7238a0a9c7eSTaeung Song 7248a0a9c7eSTaeung Song if (value) { 7258a0a9c7eSTaeung Song scnprintf(key, sizeof(key), "%s.%s", 7268a0a9c7eSTaeung Song section->name, item->name); 7278a0a9c7eSTaeung Song ret = fn(key, value, data); 7288a0a9c7eSTaeung Song if (ret < 0) { 7298a0a9c7eSTaeung Song pr_err("Error: wrong config key-value pair %s=%s\n", 7308a0a9c7eSTaeung Song key, value); 7318a0a9c7eSTaeung Song break; 7328a0a9c7eSTaeung Song } 7338a0a9c7eSTaeung Song } 7348a0a9c7eSTaeung Song } 7358a0a9c7eSTaeung Song 7368a0a9c7eSTaeung Song return ret; 7378a0a9c7eSTaeung Song } 7388a0a9c7eSTaeung Song 7398a0a9c7eSTaeung Song void perf_config__init(void) 7408a0a9c7eSTaeung Song { 7418a0a9c7eSTaeung Song if (config_set == NULL) 7428a0a9c7eSTaeung Song config_set = perf_config_set__new(); 7438a0a9c7eSTaeung Song } 7448a0a9c7eSTaeung Song 7458a0a9c7eSTaeung Song void perf_config__exit(void) 7468a0a9c7eSTaeung Song { 7478a0a9c7eSTaeung Song perf_config_set__delete(config_set); 7488a0a9c7eSTaeung Song config_set = NULL; 7498a0a9c7eSTaeung Song } 7508a0a9c7eSTaeung Song 7518a0a9c7eSTaeung Song void perf_config__refresh(void) 7528a0a9c7eSTaeung Song { 7538a0a9c7eSTaeung Song perf_config__exit(); 7548a0a9c7eSTaeung Song perf_config__init(); 7558a0a9c7eSTaeung Song } 7568a0a9c7eSTaeung Song 75720105ca1STaeung Song static void perf_config_item__delete(struct perf_config_item *item) 75820105ca1STaeung Song { 75920105ca1STaeung Song zfree(&item->name); 76020105ca1STaeung Song zfree(&item->value); 76120105ca1STaeung Song free(item); 76220105ca1STaeung Song } 76320105ca1STaeung Song 76420105ca1STaeung Song static void perf_config_section__purge(struct perf_config_section *section) 76520105ca1STaeung Song { 76620105ca1STaeung Song struct perf_config_item *item, *tmp; 76720105ca1STaeung Song 76820105ca1STaeung Song list_for_each_entry_safe(item, tmp, §ion->items, node) { 76920105ca1STaeung Song list_del_init(&item->node); 77020105ca1STaeung Song perf_config_item__delete(item); 77120105ca1STaeung Song } 77220105ca1STaeung Song } 77320105ca1STaeung Song 77420105ca1STaeung Song static void perf_config_section__delete(struct perf_config_section *section) 77520105ca1STaeung Song { 77620105ca1STaeung Song perf_config_section__purge(section); 77720105ca1STaeung Song zfree(§ion->name); 77820105ca1STaeung Song free(section); 77920105ca1STaeung Song } 78020105ca1STaeung Song 78120105ca1STaeung Song static void perf_config_set__purge(struct perf_config_set *set) 78220105ca1STaeung Song { 78320105ca1STaeung Song struct perf_config_section *section, *tmp; 78420105ca1STaeung Song 78520105ca1STaeung Song list_for_each_entry_safe(section, tmp, &set->sections, node) { 78620105ca1STaeung Song list_del_init(§ion->node); 78720105ca1STaeung Song perf_config_section__delete(section); 78820105ca1STaeung Song } 78920105ca1STaeung Song } 79020105ca1STaeung Song 79120105ca1STaeung Song void perf_config_set__delete(struct perf_config_set *set) 79220105ca1STaeung Song { 793826424ccSTaeung Song if (set == NULL) 794826424ccSTaeung Song return; 795826424ccSTaeung Song 79620105ca1STaeung Song perf_config_set__purge(set); 79720105ca1STaeung Song free(set); 79820105ca1STaeung Song } 79920105ca1STaeung Song 80086470930SIngo Molnar /* 80186470930SIngo Molnar * Call this to report error for your variable that should not 80286470930SIngo Molnar * get a boolean value (i.e. "[my] var" means "true"). 80386470930SIngo Molnar */ 80486470930SIngo Molnar int config_error_nonbool(const char *var) 80586470930SIngo Molnar { 80662d94b00SArnaldo Carvalho de Melo pr_err("Missing value for '%s'", var); 80762d94b00SArnaldo Carvalho de Melo return -1; 80886470930SIngo Molnar } 80945de34bbSStephane Eranian 81099ce8e9fSJiri Olsa void set_buildid_dir(const char *dir) 81145de34bbSStephane Eranian { 81299ce8e9fSJiri Olsa if (dir) 81399ce8e9fSJiri Olsa scnprintf(buildid_dir, MAXPATHLEN-1, "%s", dir); 81445de34bbSStephane Eranian 81545de34bbSStephane Eranian /* default to $HOME/.debug */ 81645de34bbSStephane Eranian if (buildid_dir[0] == '\0') { 81737194f44STaeung Song char *home = getenv("HOME"); 81837194f44STaeung Song 81937194f44STaeung Song if (home) { 82045de34bbSStephane Eranian snprintf(buildid_dir, MAXPATHLEN-1, "%s/%s", 82137194f44STaeung Song home, DEBUG_CACHE_DIR); 82245de34bbSStephane Eranian } else { 82345de34bbSStephane Eranian strncpy(buildid_dir, DEBUG_CACHE_DIR, MAXPATHLEN-1); 82445de34bbSStephane Eranian } 82545de34bbSStephane Eranian buildid_dir[MAXPATHLEN-1] = '\0'; 82645de34bbSStephane Eranian } 82745de34bbSStephane Eranian /* for communicating with external commands */ 82845de34bbSStephane Eranian setenv("PERF_BUILDID_DIR", buildid_dir, 1); 82945de34bbSStephane Eranian } 830