162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * config.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Helper functions for parsing config items. 662306a36Sopenharmony_ci * Originally copied from GIT source. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Copyright (C) Linus Torvalds, 2005 962306a36Sopenharmony_ci * Copyright (C) Johannes Schindelin, 2005 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci#include <errno.h> 1362306a36Sopenharmony_ci#include <sys/param.h> 1462306a36Sopenharmony_ci#include "cache.h" 1562306a36Sopenharmony_ci#include "callchain.h" 1662306a36Sopenharmony_ci#include <subcmd/exec-cmd.h> 1762306a36Sopenharmony_ci#include "util/event.h" /* proc_map_timeout */ 1862306a36Sopenharmony_ci#include "util/hist.h" /* perf_hist_config */ 1962306a36Sopenharmony_ci#include "util/stat.h" /* perf_stat__set_big_num */ 2062306a36Sopenharmony_ci#include "util/evsel.h" /* evsel__hw_names, evsel__use_bpf_counters */ 2162306a36Sopenharmony_ci#include "util/srcline.h" /* addr2line_timeout_ms */ 2262306a36Sopenharmony_ci#include "build-id.h" 2362306a36Sopenharmony_ci#include "debug.h" 2462306a36Sopenharmony_ci#include "config.h" 2562306a36Sopenharmony_ci#include <sys/types.h> 2662306a36Sopenharmony_ci#include <sys/stat.h> 2762306a36Sopenharmony_ci#include <stdlib.h> 2862306a36Sopenharmony_ci#include <unistd.h> 2962306a36Sopenharmony_ci#include <linux/string.h> 3062306a36Sopenharmony_ci#include <linux/zalloc.h> 3162306a36Sopenharmony_ci#include <linux/ctype.h> 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#define MAXNAME (256) 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#define DEBUG_CACHE_DIR ".debug" 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cichar buildid_dir[MAXPATHLEN]; /* root dir for buildid, binary cache */ 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic FILE *config_file; 4162306a36Sopenharmony_cistatic const char *config_file_name; 4262306a36Sopenharmony_cistatic int config_linenr; 4362306a36Sopenharmony_cistatic int config_file_eof; 4462306a36Sopenharmony_cistatic struct perf_config_set *config_set; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ciconst char *config_exclusive_filename; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic int get_next_char(void) 4962306a36Sopenharmony_ci{ 5062306a36Sopenharmony_ci int c; 5162306a36Sopenharmony_ci FILE *f; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci c = '\n'; 5462306a36Sopenharmony_ci if ((f = config_file) != NULL) { 5562306a36Sopenharmony_ci c = fgetc(f); 5662306a36Sopenharmony_ci if (c == '\r') { 5762306a36Sopenharmony_ci /* DOS like systems */ 5862306a36Sopenharmony_ci c = fgetc(f); 5962306a36Sopenharmony_ci if (c != '\n') { 6062306a36Sopenharmony_ci ungetc(c, f); 6162306a36Sopenharmony_ci c = '\r'; 6262306a36Sopenharmony_ci } 6362306a36Sopenharmony_ci } 6462306a36Sopenharmony_ci if (c == '\n') 6562306a36Sopenharmony_ci config_linenr++; 6662306a36Sopenharmony_ci if (c == EOF) { 6762306a36Sopenharmony_ci config_file_eof = 1; 6862306a36Sopenharmony_ci c = '\n'; 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci } 7162306a36Sopenharmony_ci return c; 7262306a36Sopenharmony_ci} 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic char *parse_value(void) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci static char value[1024]; 7762306a36Sopenharmony_ci int quote = 0, comment = 0, space = 0; 7862306a36Sopenharmony_ci size_t len = 0; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci for (;;) { 8162306a36Sopenharmony_ci int c = get_next_char(); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci if (len >= sizeof(value) - 1) 8462306a36Sopenharmony_ci return NULL; 8562306a36Sopenharmony_ci if (c == '\n') { 8662306a36Sopenharmony_ci if (quote) 8762306a36Sopenharmony_ci return NULL; 8862306a36Sopenharmony_ci value[len] = 0; 8962306a36Sopenharmony_ci return value; 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci if (comment) 9262306a36Sopenharmony_ci continue; 9362306a36Sopenharmony_ci if (isspace(c) && !quote) { 9462306a36Sopenharmony_ci space = 1; 9562306a36Sopenharmony_ci continue; 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci if (!quote) { 9862306a36Sopenharmony_ci if (c == ';' || c == '#') { 9962306a36Sopenharmony_ci comment = 1; 10062306a36Sopenharmony_ci continue; 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci } 10362306a36Sopenharmony_ci if (space) { 10462306a36Sopenharmony_ci if (len) 10562306a36Sopenharmony_ci value[len++] = ' '; 10662306a36Sopenharmony_ci space = 0; 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci if (c == '\\') { 10962306a36Sopenharmony_ci c = get_next_char(); 11062306a36Sopenharmony_ci switch (c) { 11162306a36Sopenharmony_ci case '\n': 11262306a36Sopenharmony_ci continue; 11362306a36Sopenharmony_ci case 't': 11462306a36Sopenharmony_ci c = '\t'; 11562306a36Sopenharmony_ci break; 11662306a36Sopenharmony_ci case 'b': 11762306a36Sopenharmony_ci c = '\b'; 11862306a36Sopenharmony_ci break; 11962306a36Sopenharmony_ci case 'n': 12062306a36Sopenharmony_ci c = '\n'; 12162306a36Sopenharmony_ci break; 12262306a36Sopenharmony_ci /* Some characters escape as themselves */ 12362306a36Sopenharmony_ci case '\\': case '"': 12462306a36Sopenharmony_ci break; 12562306a36Sopenharmony_ci /* Reject unknown escape sequences */ 12662306a36Sopenharmony_ci default: 12762306a36Sopenharmony_ci return NULL; 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci value[len++] = c; 13062306a36Sopenharmony_ci continue; 13162306a36Sopenharmony_ci } 13262306a36Sopenharmony_ci if (c == '"') { 13362306a36Sopenharmony_ci quote = 1-quote; 13462306a36Sopenharmony_ci continue; 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci value[len++] = c; 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistatic inline int iskeychar(int c) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci return isalnum(c) || c == '-' || c == '_'; 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistatic int get_value(config_fn_t fn, void *data, char *name, unsigned int len) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci int c; 14862306a36Sopenharmony_ci char *value; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci /* Get the full name */ 15162306a36Sopenharmony_ci for (;;) { 15262306a36Sopenharmony_ci c = get_next_char(); 15362306a36Sopenharmony_ci if (config_file_eof) 15462306a36Sopenharmony_ci break; 15562306a36Sopenharmony_ci if (!iskeychar(c)) 15662306a36Sopenharmony_ci break; 15762306a36Sopenharmony_ci name[len++] = c; 15862306a36Sopenharmony_ci if (len >= MAXNAME) 15962306a36Sopenharmony_ci return -1; 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci name[len] = 0; 16262306a36Sopenharmony_ci while (c == ' ' || c == '\t') 16362306a36Sopenharmony_ci c = get_next_char(); 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci value = NULL; 16662306a36Sopenharmony_ci if (c != '\n') { 16762306a36Sopenharmony_ci if (c != '=') 16862306a36Sopenharmony_ci return -1; 16962306a36Sopenharmony_ci value = parse_value(); 17062306a36Sopenharmony_ci if (!value) 17162306a36Sopenharmony_ci return -1; 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci return fn(name, value, data); 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cistatic int get_extended_base_var(char *name, int baselen, int c) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci do { 17962306a36Sopenharmony_ci if (c == '\n') 18062306a36Sopenharmony_ci return -1; 18162306a36Sopenharmony_ci c = get_next_char(); 18262306a36Sopenharmony_ci } while (isspace(c)); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci /* We require the format to be '[base "extension"]' */ 18562306a36Sopenharmony_ci if (c != '"') 18662306a36Sopenharmony_ci return -1; 18762306a36Sopenharmony_ci name[baselen++] = '.'; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci for (;;) { 19062306a36Sopenharmony_ci int ch = get_next_char(); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci if (ch == '\n') 19362306a36Sopenharmony_ci return -1; 19462306a36Sopenharmony_ci if (ch == '"') 19562306a36Sopenharmony_ci break; 19662306a36Sopenharmony_ci if (ch == '\\') { 19762306a36Sopenharmony_ci ch = get_next_char(); 19862306a36Sopenharmony_ci if (ch == '\n') 19962306a36Sopenharmony_ci return -1; 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci name[baselen++] = ch; 20262306a36Sopenharmony_ci if (baselen > MAXNAME / 2) 20362306a36Sopenharmony_ci return -1; 20462306a36Sopenharmony_ci } 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci /* Final ']' */ 20762306a36Sopenharmony_ci if (get_next_char() != ']') 20862306a36Sopenharmony_ci return -1; 20962306a36Sopenharmony_ci return baselen; 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistatic int get_base_var(char *name) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci int baselen = 0; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci for (;;) { 21762306a36Sopenharmony_ci int c = get_next_char(); 21862306a36Sopenharmony_ci if (config_file_eof) 21962306a36Sopenharmony_ci return -1; 22062306a36Sopenharmony_ci if (c == ']') 22162306a36Sopenharmony_ci return baselen; 22262306a36Sopenharmony_ci if (isspace(c)) 22362306a36Sopenharmony_ci return get_extended_base_var(name, baselen, c); 22462306a36Sopenharmony_ci if (!iskeychar(c) && c != '.') 22562306a36Sopenharmony_ci return -1; 22662306a36Sopenharmony_ci if (baselen > MAXNAME / 2) 22762306a36Sopenharmony_ci return -1; 22862306a36Sopenharmony_ci name[baselen++] = tolower(c); 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_cistatic int perf_parse_file(config_fn_t fn, void *data) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci int comment = 0; 23562306a36Sopenharmony_ci int baselen = 0; 23662306a36Sopenharmony_ci static char var[MAXNAME]; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci /* U+FEFF Byte Order Mark in UTF8 */ 23962306a36Sopenharmony_ci static const unsigned char *utf8_bom = (unsigned char *) "\xef\xbb\xbf"; 24062306a36Sopenharmony_ci const unsigned char *bomptr = utf8_bom; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci for (;;) { 24362306a36Sopenharmony_ci int line, c = get_next_char(); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci if (bomptr && *bomptr) { 24662306a36Sopenharmony_ci /* We are at the file beginning; skip UTF8-encoded BOM 24762306a36Sopenharmony_ci * if present. Sane editors won't put this in on their 24862306a36Sopenharmony_ci * own, but e.g. Windows Notepad will do it happily. */ 24962306a36Sopenharmony_ci if ((unsigned char) c == *bomptr) { 25062306a36Sopenharmony_ci bomptr++; 25162306a36Sopenharmony_ci continue; 25262306a36Sopenharmony_ci } else { 25362306a36Sopenharmony_ci /* Do not tolerate partial BOM. */ 25462306a36Sopenharmony_ci if (bomptr != utf8_bom) 25562306a36Sopenharmony_ci break; 25662306a36Sopenharmony_ci /* No BOM at file beginning. Cool. */ 25762306a36Sopenharmony_ci bomptr = NULL; 25862306a36Sopenharmony_ci } 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci if (c == '\n') { 26162306a36Sopenharmony_ci if (config_file_eof) 26262306a36Sopenharmony_ci return 0; 26362306a36Sopenharmony_ci comment = 0; 26462306a36Sopenharmony_ci continue; 26562306a36Sopenharmony_ci } 26662306a36Sopenharmony_ci if (comment || isspace(c)) 26762306a36Sopenharmony_ci continue; 26862306a36Sopenharmony_ci if (c == '#' || c == ';') { 26962306a36Sopenharmony_ci comment = 1; 27062306a36Sopenharmony_ci continue; 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci if (c == '[') { 27362306a36Sopenharmony_ci baselen = get_base_var(var); 27462306a36Sopenharmony_ci if (baselen <= 0) 27562306a36Sopenharmony_ci break; 27662306a36Sopenharmony_ci var[baselen++] = '.'; 27762306a36Sopenharmony_ci var[baselen] = 0; 27862306a36Sopenharmony_ci continue; 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci if (!isalpha(c)) 28162306a36Sopenharmony_ci break; 28262306a36Sopenharmony_ci var[baselen] = tolower(c); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci /* 28562306a36Sopenharmony_ci * The get_value function might or might not reach the '\n', 28662306a36Sopenharmony_ci * so saving the current line number for error reporting. 28762306a36Sopenharmony_ci */ 28862306a36Sopenharmony_ci line = config_linenr; 28962306a36Sopenharmony_ci if (get_value(fn, data, var, baselen+1) < 0) { 29062306a36Sopenharmony_ci config_linenr = line; 29162306a36Sopenharmony_ci break; 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci pr_err("bad config file line %d in %s\n", config_linenr, config_file_name); 29562306a36Sopenharmony_ci return -1; 29662306a36Sopenharmony_ci} 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_cistatic int parse_unit_factor(const char *end, unsigned long *val) 29962306a36Sopenharmony_ci{ 30062306a36Sopenharmony_ci if (!*end) 30162306a36Sopenharmony_ci return 1; 30262306a36Sopenharmony_ci else if (!strcasecmp(end, "k")) { 30362306a36Sopenharmony_ci *val *= 1024; 30462306a36Sopenharmony_ci return 1; 30562306a36Sopenharmony_ci } 30662306a36Sopenharmony_ci else if (!strcasecmp(end, "m")) { 30762306a36Sopenharmony_ci *val *= 1024 * 1024; 30862306a36Sopenharmony_ci return 1; 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci else if (!strcasecmp(end, "g")) { 31162306a36Sopenharmony_ci *val *= 1024 * 1024 * 1024; 31262306a36Sopenharmony_ci return 1; 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci return 0; 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_cistatic int perf_parse_llong(const char *value, long long *ret) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci if (value && *value) { 32062306a36Sopenharmony_ci char *end; 32162306a36Sopenharmony_ci long long val = strtoll(value, &end, 0); 32262306a36Sopenharmony_ci unsigned long factor = 1; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci if (!parse_unit_factor(end, &factor)) 32562306a36Sopenharmony_ci return 0; 32662306a36Sopenharmony_ci *ret = val * factor; 32762306a36Sopenharmony_ci return 1; 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci return 0; 33062306a36Sopenharmony_ci} 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_cistatic int perf_parse_long(const char *value, long *ret) 33362306a36Sopenharmony_ci{ 33462306a36Sopenharmony_ci if (value && *value) { 33562306a36Sopenharmony_ci char *end; 33662306a36Sopenharmony_ci long val = strtol(value, &end, 0); 33762306a36Sopenharmony_ci unsigned long factor = 1; 33862306a36Sopenharmony_ci if (!parse_unit_factor(end, &factor)) 33962306a36Sopenharmony_ci return 0; 34062306a36Sopenharmony_ci *ret = val * factor; 34162306a36Sopenharmony_ci return 1; 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci return 0; 34462306a36Sopenharmony_ci} 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_cistatic void bad_config(const char *name) 34762306a36Sopenharmony_ci{ 34862306a36Sopenharmony_ci if (config_file_name) 34962306a36Sopenharmony_ci pr_warning("bad config value for '%s' in %s, ignoring...\n", name, config_file_name); 35062306a36Sopenharmony_ci else 35162306a36Sopenharmony_ci pr_warning("bad config value for '%s', ignoring...\n", name); 35262306a36Sopenharmony_ci} 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ciint perf_config_u64(u64 *dest, const char *name, const char *value) 35562306a36Sopenharmony_ci{ 35662306a36Sopenharmony_ci long long ret = 0; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci if (!perf_parse_llong(value, &ret)) { 35962306a36Sopenharmony_ci bad_config(name); 36062306a36Sopenharmony_ci return -1; 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci *dest = ret; 36462306a36Sopenharmony_ci return 0; 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ciint perf_config_int(int *dest, const char *name, const char *value) 36862306a36Sopenharmony_ci{ 36962306a36Sopenharmony_ci long ret = 0; 37062306a36Sopenharmony_ci if (!perf_parse_long(value, &ret)) { 37162306a36Sopenharmony_ci bad_config(name); 37262306a36Sopenharmony_ci return -1; 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci *dest = ret; 37562306a36Sopenharmony_ci return 0; 37662306a36Sopenharmony_ci} 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ciint perf_config_u8(u8 *dest, const char *name, const char *value) 37962306a36Sopenharmony_ci{ 38062306a36Sopenharmony_ci long ret = 0; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci if (!perf_parse_long(value, &ret)) { 38362306a36Sopenharmony_ci bad_config(name); 38462306a36Sopenharmony_ci return -1; 38562306a36Sopenharmony_ci } 38662306a36Sopenharmony_ci *dest = ret; 38762306a36Sopenharmony_ci return 0; 38862306a36Sopenharmony_ci} 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_cistatic int perf_config_bool_or_int(const char *name, const char *value, int *is_bool) 39162306a36Sopenharmony_ci{ 39262306a36Sopenharmony_ci int ret; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci *is_bool = 1; 39562306a36Sopenharmony_ci if (!value) 39662306a36Sopenharmony_ci return 1; 39762306a36Sopenharmony_ci if (!*value) 39862306a36Sopenharmony_ci return 0; 39962306a36Sopenharmony_ci if (!strcasecmp(value, "true") || !strcasecmp(value, "yes") || !strcasecmp(value, "on")) 40062306a36Sopenharmony_ci return 1; 40162306a36Sopenharmony_ci if (!strcasecmp(value, "false") || !strcasecmp(value, "no") || !strcasecmp(value, "off")) 40262306a36Sopenharmony_ci return 0; 40362306a36Sopenharmony_ci *is_bool = 0; 40462306a36Sopenharmony_ci return perf_config_int(&ret, name, value) < 0 ? -1 : ret; 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ciint perf_config_bool(const char *name, const char *value) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci int discard; 41062306a36Sopenharmony_ci return !!perf_config_bool_or_int(name, value, &discard); 41162306a36Sopenharmony_ci} 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_cistatic const char *perf_config_dirname(const char *name, const char *value) 41462306a36Sopenharmony_ci{ 41562306a36Sopenharmony_ci if (!name) 41662306a36Sopenharmony_ci return NULL; 41762306a36Sopenharmony_ci return value; 41862306a36Sopenharmony_ci} 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_cistatic int perf_buildid_config(const char *var, const char *value) 42162306a36Sopenharmony_ci{ 42262306a36Sopenharmony_ci /* same dir for all commands */ 42362306a36Sopenharmony_ci if (!strcmp(var, "buildid.dir")) { 42462306a36Sopenharmony_ci const char *dir = perf_config_dirname(var, value); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci if (!dir) { 42762306a36Sopenharmony_ci pr_err("Invalid buildid directory!\n"); 42862306a36Sopenharmony_ci return -1; 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci strncpy(buildid_dir, dir, MAXPATHLEN-1); 43162306a36Sopenharmony_ci buildid_dir[MAXPATHLEN-1] = '\0'; 43262306a36Sopenharmony_ci } 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci return 0; 43562306a36Sopenharmony_ci} 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cistatic int perf_default_core_config(const char *var, const char *value) 43862306a36Sopenharmony_ci{ 43962306a36Sopenharmony_ci if (!strcmp(var, "core.proc-map-timeout")) 44062306a36Sopenharmony_ci proc_map_timeout = strtoul(value, NULL, 10); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci if (!strcmp(var, "core.addr2line-timeout")) 44362306a36Sopenharmony_ci addr2line_timeout_ms = strtoul(value, NULL, 10); 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci /* Add other config variables here. */ 44662306a36Sopenharmony_ci return 0; 44762306a36Sopenharmony_ci} 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_cistatic int perf_ui_config(const char *var, const char *value) 45062306a36Sopenharmony_ci{ 45162306a36Sopenharmony_ci /* Add other config variables here. */ 45262306a36Sopenharmony_ci if (!strcmp(var, "ui.show-headers")) 45362306a36Sopenharmony_ci symbol_conf.show_hist_headers = perf_config_bool(var, value); 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci return 0; 45662306a36Sopenharmony_ci} 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_cistatic int perf_stat_config(const char *var, const char *value) 45962306a36Sopenharmony_ci{ 46062306a36Sopenharmony_ci if (!strcmp(var, "stat.big-num")) 46162306a36Sopenharmony_ci perf_stat__set_big_num(perf_config_bool(var, value)); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci if (!strcmp(var, "stat.no-csv-summary")) 46462306a36Sopenharmony_ci perf_stat__set_no_csv_summary(perf_config_bool(var, value)); 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci if (!strcmp(var, "stat.bpf-counter-events")) 46762306a36Sopenharmony_ci evsel__bpf_counter_events = strdup(value); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci /* Add other config variables here. */ 47062306a36Sopenharmony_ci return 0; 47162306a36Sopenharmony_ci} 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ciint perf_default_config(const char *var, const char *value, 47462306a36Sopenharmony_ci void *dummy __maybe_unused) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci if (strstarts(var, "core.")) 47762306a36Sopenharmony_ci return perf_default_core_config(var, value); 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci if (strstarts(var, "hist.")) 48062306a36Sopenharmony_ci return perf_hist_config(var, value); 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci if (strstarts(var, "ui.")) 48362306a36Sopenharmony_ci return perf_ui_config(var, value); 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci if (strstarts(var, "call-graph.")) 48662306a36Sopenharmony_ci return perf_callchain_config(var, value); 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci if (strstarts(var, "buildid.")) 48962306a36Sopenharmony_ci return perf_buildid_config(var, value); 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci if (strstarts(var, "stat.")) 49262306a36Sopenharmony_ci return perf_stat_config(var, value); 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci /* Add other config variables here. */ 49562306a36Sopenharmony_ci return 0; 49662306a36Sopenharmony_ci} 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_cistatic int perf_config_from_file(config_fn_t fn, const char *filename, void *data) 49962306a36Sopenharmony_ci{ 50062306a36Sopenharmony_ci int ret; 50162306a36Sopenharmony_ci FILE *f = fopen(filename, "r"); 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci ret = -1; 50462306a36Sopenharmony_ci if (f) { 50562306a36Sopenharmony_ci config_file = f; 50662306a36Sopenharmony_ci config_file_name = filename; 50762306a36Sopenharmony_ci config_linenr = 1; 50862306a36Sopenharmony_ci config_file_eof = 0; 50962306a36Sopenharmony_ci ret = perf_parse_file(fn, data); 51062306a36Sopenharmony_ci fclose(f); 51162306a36Sopenharmony_ci config_file_name = NULL; 51262306a36Sopenharmony_ci } 51362306a36Sopenharmony_ci return ret; 51462306a36Sopenharmony_ci} 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ciconst char *perf_etc_perfconfig(void) 51762306a36Sopenharmony_ci{ 51862306a36Sopenharmony_ci static const char *system_wide; 51962306a36Sopenharmony_ci if (!system_wide) 52062306a36Sopenharmony_ci system_wide = system_path(ETC_PERFCONFIG); 52162306a36Sopenharmony_ci return system_wide; 52262306a36Sopenharmony_ci} 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_cistatic int perf_env_bool(const char *k, int def) 52562306a36Sopenharmony_ci{ 52662306a36Sopenharmony_ci const char *v = getenv(k); 52762306a36Sopenharmony_ci return v ? perf_config_bool(k, v) : def; 52862306a36Sopenharmony_ci} 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ciint perf_config_system(void) 53162306a36Sopenharmony_ci{ 53262306a36Sopenharmony_ci return !perf_env_bool("PERF_CONFIG_NOSYSTEM", 0); 53362306a36Sopenharmony_ci} 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ciint perf_config_global(void) 53662306a36Sopenharmony_ci{ 53762306a36Sopenharmony_ci return !perf_env_bool("PERF_CONFIG_NOGLOBAL", 0); 53862306a36Sopenharmony_ci} 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_cistatic char *home_perfconfig(void) 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci const char *home = NULL; 54362306a36Sopenharmony_ci char *config; 54462306a36Sopenharmony_ci struct stat st; 54562306a36Sopenharmony_ci char path[PATH_MAX]; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci home = getenv("HOME"); 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci /* 55062306a36Sopenharmony_ci * Skip reading user config if: 55162306a36Sopenharmony_ci * - there is no place to read it from (HOME) 55262306a36Sopenharmony_ci * - we are asked not to (PERF_CONFIG_NOGLOBAL=1) 55362306a36Sopenharmony_ci */ 55462306a36Sopenharmony_ci if (!home || !*home || !perf_config_global()) 55562306a36Sopenharmony_ci return NULL; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci config = strdup(mkpath(path, sizeof(path), "%s/.perfconfig", home)); 55862306a36Sopenharmony_ci if (config == NULL) { 55962306a36Sopenharmony_ci pr_warning("Not enough memory to process %s/.perfconfig, ignoring it.\n", home); 56062306a36Sopenharmony_ci return NULL; 56162306a36Sopenharmony_ci } 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci if (stat(config, &st) < 0) 56462306a36Sopenharmony_ci goto out_free; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci if (st.st_uid && (st.st_uid != geteuid())) { 56762306a36Sopenharmony_ci pr_warning("File %s not owned by current user or root, ignoring it.\n", config); 56862306a36Sopenharmony_ci goto out_free; 56962306a36Sopenharmony_ci } 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci if (st.st_size) 57262306a36Sopenharmony_ci return config; 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ciout_free: 57562306a36Sopenharmony_ci free(config); 57662306a36Sopenharmony_ci return NULL; 57762306a36Sopenharmony_ci} 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ciconst char *perf_home_perfconfig(void) 58062306a36Sopenharmony_ci{ 58162306a36Sopenharmony_ci static const char *config; 58262306a36Sopenharmony_ci static bool failed; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci if (failed || config) 58562306a36Sopenharmony_ci return config; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci config = home_perfconfig(); 58862306a36Sopenharmony_ci if (!config) 58962306a36Sopenharmony_ci failed = true; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci return config; 59262306a36Sopenharmony_ci} 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_cistatic struct perf_config_section *find_section(struct list_head *sections, 59562306a36Sopenharmony_ci const char *section_name) 59662306a36Sopenharmony_ci{ 59762306a36Sopenharmony_ci struct perf_config_section *section; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci list_for_each_entry(section, sections, node) 60062306a36Sopenharmony_ci if (!strcmp(section->name, section_name)) 60162306a36Sopenharmony_ci return section; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci return NULL; 60462306a36Sopenharmony_ci} 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_cistatic struct perf_config_item *find_config_item(const char *name, 60762306a36Sopenharmony_ci struct perf_config_section *section) 60862306a36Sopenharmony_ci{ 60962306a36Sopenharmony_ci struct perf_config_item *item; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci list_for_each_entry(item, §ion->items, node) 61262306a36Sopenharmony_ci if (!strcmp(item->name, name)) 61362306a36Sopenharmony_ci return item; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci return NULL; 61662306a36Sopenharmony_ci} 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_cistatic struct perf_config_section *add_section(struct list_head *sections, 61962306a36Sopenharmony_ci const char *section_name) 62062306a36Sopenharmony_ci{ 62162306a36Sopenharmony_ci struct perf_config_section *section = zalloc(sizeof(*section)); 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci if (!section) 62462306a36Sopenharmony_ci return NULL; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci INIT_LIST_HEAD(§ion->items); 62762306a36Sopenharmony_ci section->name = strdup(section_name); 62862306a36Sopenharmony_ci if (!section->name) { 62962306a36Sopenharmony_ci pr_debug("%s: strdup failed\n", __func__); 63062306a36Sopenharmony_ci free(section); 63162306a36Sopenharmony_ci return NULL; 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci list_add_tail(§ion->node, sections); 63562306a36Sopenharmony_ci return section; 63662306a36Sopenharmony_ci} 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_cistatic struct perf_config_item *add_config_item(struct perf_config_section *section, 63962306a36Sopenharmony_ci const char *name) 64062306a36Sopenharmony_ci{ 64162306a36Sopenharmony_ci struct perf_config_item *item = zalloc(sizeof(*item)); 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci if (!item) 64462306a36Sopenharmony_ci return NULL; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci item->name = strdup(name); 64762306a36Sopenharmony_ci if (!item->name) { 64862306a36Sopenharmony_ci pr_debug("%s: strdup failed\n", __func__); 64962306a36Sopenharmony_ci free(item); 65062306a36Sopenharmony_ci return NULL; 65162306a36Sopenharmony_ci } 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci list_add_tail(&item->node, §ion->items); 65462306a36Sopenharmony_ci return item; 65562306a36Sopenharmony_ci} 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_cistatic int set_value(struct perf_config_item *item, const char *value) 65862306a36Sopenharmony_ci{ 65962306a36Sopenharmony_ci char *val = strdup(value); 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci if (!val) 66262306a36Sopenharmony_ci return -1; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci zfree(&item->value); 66562306a36Sopenharmony_ci item->value = val; 66662306a36Sopenharmony_ci return 0; 66762306a36Sopenharmony_ci} 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_cistatic int collect_config(const char *var, const char *value, 67062306a36Sopenharmony_ci void *perf_config_set) 67162306a36Sopenharmony_ci{ 67262306a36Sopenharmony_ci int ret = -1; 67362306a36Sopenharmony_ci char *ptr, *key; 67462306a36Sopenharmony_ci char *section_name, *name; 67562306a36Sopenharmony_ci struct perf_config_section *section = NULL; 67662306a36Sopenharmony_ci struct perf_config_item *item = NULL; 67762306a36Sopenharmony_ci struct perf_config_set *set = perf_config_set; 67862306a36Sopenharmony_ci struct list_head *sections; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci if (set == NULL) 68162306a36Sopenharmony_ci return -1; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci sections = &set->sections; 68462306a36Sopenharmony_ci key = ptr = strdup(var); 68562306a36Sopenharmony_ci if (!key) { 68662306a36Sopenharmony_ci pr_debug("%s: strdup failed\n", __func__); 68762306a36Sopenharmony_ci return -1; 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci section_name = strsep(&ptr, "."); 69162306a36Sopenharmony_ci name = ptr; 69262306a36Sopenharmony_ci if (name == NULL || value == NULL) 69362306a36Sopenharmony_ci goto out_free; 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci section = find_section(sections, section_name); 69662306a36Sopenharmony_ci if (!section) { 69762306a36Sopenharmony_ci section = add_section(sections, section_name); 69862306a36Sopenharmony_ci if (!section) 69962306a36Sopenharmony_ci goto out_free; 70062306a36Sopenharmony_ci } 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci item = find_config_item(name, section); 70362306a36Sopenharmony_ci if (!item) { 70462306a36Sopenharmony_ci item = add_config_item(section, name); 70562306a36Sopenharmony_ci if (!item) 70662306a36Sopenharmony_ci goto out_free; 70762306a36Sopenharmony_ci } 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci /* perf_config_set can contain both user and system config items. 71062306a36Sopenharmony_ci * So we should know where each value is from. 71162306a36Sopenharmony_ci * The classification would be needed when a particular config file 71262306a36Sopenharmony_ci * is overwritten by setting feature i.e. set_config(). 71362306a36Sopenharmony_ci */ 71462306a36Sopenharmony_ci if (strcmp(config_file_name, perf_etc_perfconfig()) == 0) { 71562306a36Sopenharmony_ci section->from_system_config = true; 71662306a36Sopenharmony_ci item->from_system_config = true; 71762306a36Sopenharmony_ci } else { 71862306a36Sopenharmony_ci section->from_system_config = false; 71962306a36Sopenharmony_ci item->from_system_config = false; 72062306a36Sopenharmony_ci } 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci ret = set_value(item, value); 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ciout_free: 72562306a36Sopenharmony_ci free(key); 72662306a36Sopenharmony_ci return ret; 72762306a36Sopenharmony_ci} 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ciint perf_config_set__collect(struct perf_config_set *set, const char *file_name, 73062306a36Sopenharmony_ci const char *var, const char *value) 73162306a36Sopenharmony_ci{ 73262306a36Sopenharmony_ci config_file_name = file_name; 73362306a36Sopenharmony_ci return collect_config(var, value, set); 73462306a36Sopenharmony_ci} 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_cistatic int perf_config_set__init(struct perf_config_set *set) 73762306a36Sopenharmony_ci{ 73862306a36Sopenharmony_ci int ret = -1; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */ 74162306a36Sopenharmony_ci if (config_exclusive_filename) 74262306a36Sopenharmony_ci return perf_config_from_file(collect_config, config_exclusive_filename, set); 74362306a36Sopenharmony_ci if (perf_config_system() && !access(perf_etc_perfconfig(), R_OK)) { 74462306a36Sopenharmony_ci if (perf_config_from_file(collect_config, perf_etc_perfconfig(), set) < 0) 74562306a36Sopenharmony_ci goto out; 74662306a36Sopenharmony_ci } 74762306a36Sopenharmony_ci if (perf_config_global() && perf_home_perfconfig()) { 74862306a36Sopenharmony_ci if (perf_config_from_file(collect_config, perf_home_perfconfig(), set) < 0) 74962306a36Sopenharmony_ci goto out; 75062306a36Sopenharmony_ci } 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ciout: 75362306a36Sopenharmony_ci return ret; 75462306a36Sopenharmony_ci} 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_cistruct perf_config_set *perf_config_set__new(void) 75762306a36Sopenharmony_ci{ 75862306a36Sopenharmony_ci struct perf_config_set *set = zalloc(sizeof(*set)); 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci if (set) { 76162306a36Sopenharmony_ci INIT_LIST_HEAD(&set->sections); 76262306a36Sopenharmony_ci perf_config_set__init(set); 76362306a36Sopenharmony_ci } 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci return set; 76662306a36Sopenharmony_ci} 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_cistruct perf_config_set *perf_config_set__load_file(const char *file) 76962306a36Sopenharmony_ci{ 77062306a36Sopenharmony_ci struct perf_config_set *set = zalloc(sizeof(*set)); 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci if (set) { 77362306a36Sopenharmony_ci INIT_LIST_HEAD(&set->sections); 77462306a36Sopenharmony_ci perf_config_from_file(collect_config, file, set); 77562306a36Sopenharmony_ci } 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci return set; 77862306a36Sopenharmony_ci} 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_cistatic int perf_config__init(void) 78162306a36Sopenharmony_ci{ 78262306a36Sopenharmony_ci if (config_set == NULL) 78362306a36Sopenharmony_ci config_set = perf_config_set__new(); 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci return config_set == NULL; 78662306a36Sopenharmony_ci} 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ciint perf_config_set(struct perf_config_set *set, 78962306a36Sopenharmony_ci config_fn_t fn, void *data) 79062306a36Sopenharmony_ci{ 79162306a36Sopenharmony_ci int ret = 0; 79262306a36Sopenharmony_ci char key[BUFSIZ]; 79362306a36Sopenharmony_ci struct perf_config_section *section; 79462306a36Sopenharmony_ci struct perf_config_item *item; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci perf_config_set__for_each_entry(set, section, item) { 79762306a36Sopenharmony_ci char *value = item->value; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci if (value) { 80062306a36Sopenharmony_ci scnprintf(key, sizeof(key), "%s.%s", 80162306a36Sopenharmony_ci section->name, item->name); 80262306a36Sopenharmony_ci ret = fn(key, value, data); 80362306a36Sopenharmony_ci if (ret < 0) { 80462306a36Sopenharmony_ci pr_err("Error in the given config file: wrong config key-value pair %s=%s\n", 80562306a36Sopenharmony_ci key, value); 80662306a36Sopenharmony_ci /* 80762306a36Sopenharmony_ci * Can't be just a 'break', as perf_config_set__for_each_entry() 80862306a36Sopenharmony_ci * expands to two nested for() loops. 80962306a36Sopenharmony_ci */ 81062306a36Sopenharmony_ci goto out; 81162306a36Sopenharmony_ci } 81262306a36Sopenharmony_ci } 81362306a36Sopenharmony_ci } 81462306a36Sopenharmony_ciout: 81562306a36Sopenharmony_ci return ret; 81662306a36Sopenharmony_ci} 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ciint perf_config(config_fn_t fn, void *data) 81962306a36Sopenharmony_ci{ 82062306a36Sopenharmony_ci if (config_set == NULL && perf_config__init()) 82162306a36Sopenharmony_ci return -1; 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci return perf_config_set(config_set, fn, data); 82462306a36Sopenharmony_ci} 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_civoid perf_config__exit(void) 82762306a36Sopenharmony_ci{ 82862306a36Sopenharmony_ci perf_config_set__delete(config_set); 82962306a36Sopenharmony_ci config_set = NULL; 83062306a36Sopenharmony_ci} 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_civoid perf_config__refresh(void) 83362306a36Sopenharmony_ci{ 83462306a36Sopenharmony_ci perf_config__exit(); 83562306a36Sopenharmony_ci perf_config__init(); 83662306a36Sopenharmony_ci} 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_cistatic void perf_config_item__delete(struct perf_config_item *item) 83962306a36Sopenharmony_ci{ 84062306a36Sopenharmony_ci zfree(&item->name); 84162306a36Sopenharmony_ci zfree(&item->value); 84262306a36Sopenharmony_ci free(item); 84362306a36Sopenharmony_ci} 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_cistatic void perf_config_section__purge(struct perf_config_section *section) 84662306a36Sopenharmony_ci{ 84762306a36Sopenharmony_ci struct perf_config_item *item, *tmp; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci list_for_each_entry_safe(item, tmp, §ion->items, node) { 85062306a36Sopenharmony_ci list_del_init(&item->node); 85162306a36Sopenharmony_ci perf_config_item__delete(item); 85262306a36Sopenharmony_ci } 85362306a36Sopenharmony_ci} 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_cistatic void perf_config_section__delete(struct perf_config_section *section) 85662306a36Sopenharmony_ci{ 85762306a36Sopenharmony_ci perf_config_section__purge(section); 85862306a36Sopenharmony_ci zfree(§ion->name); 85962306a36Sopenharmony_ci free(section); 86062306a36Sopenharmony_ci} 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_cistatic void perf_config_set__purge(struct perf_config_set *set) 86362306a36Sopenharmony_ci{ 86462306a36Sopenharmony_ci struct perf_config_section *section, *tmp; 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci list_for_each_entry_safe(section, tmp, &set->sections, node) { 86762306a36Sopenharmony_ci list_del_init(§ion->node); 86862306a36Sopenharmony_ci perf_config_section__delete(section); 86962306a36Sopenharmony_ci } 87062306a36Sopenharmony_ci} 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_civoid perf_config_set__delete(struct perf_config_set *set) 87362306a36Sopenharmony_ci{ 87462306a36Sopenharmony_ci if (set == NULL) 87562306a36Sopenharmony_ci return; 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci perf_config_set__purge(set); 87862306a36Sopenharmony_ci free(set); 87962306a36Sopenharmony_ci} 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci/* 88262306a36Sopenharmony_ci * Call this to report error for your variable that should not 88362306a36Sopenharmony_ci * get a boolean value (i.e. "[my] var" means "true"). 88462306a36Sopenharmony_ci */ 88562306a36Sopenharmony_ciint config_error_nonbool(const char *var) 88662306a36Sopenharmony_ci{ 88762306a36Sopenharmony_ci pr_err("Missing value for '%s'", var); 88862306a36Sopenharmony_ci return -1; 88962306a36Sopenharmony_ci} 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_civoid set_buildid_dir(const char *dir) 89262306a36Sopenharmony_ci{ 89362306a36Sopenharmony_ci if (dir) 89462306a36Sopenharmony_ci scnprintf(buildid_dir, MAXPATHLEN, "%s", dir); 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci /* default to $HOME/.debug */ 89762306a36Sopenharmony_ci if (buildid_dir[0] == '\0') { 89862306a36Sopenharmony_ci char *home = getenv("HOME"); 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci if (home) { 90162306a36Sopenharmony_ci snprintf(buildid_dir, MAXPATHLEN, "%s/%s", 90262306a36Sopenharmony_ci home, DEBUG_CACHE_DIR); 90362306a36Sopenharmony_ci } else { 90462306a36Sopenharmony_ci strncpy(buildid_dir, DEBUG_CACHE_DIR, MAXPATHLEN-1); 90562306a36Sopenharmony_ci } 90662306a36Sopenharmony_ci buildid_dir[MAXPATHLEN-1] = '\0'; 90762306a36Sopenharmony_ci } 90862306a36Sopenharmony_ci /* for communicating with external commands */ 90962306a36Sopenharmony_ci setenv("PERF_BUILDID_DIR", buildid_dir, 1); 91062306a36Sopenharmony_ci} 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_cistruct perf_config_scan_data { 91362306a36Sopenharmony_ci const char *name; 91462306a36Sopenharmony_ci const char *fmt; 91562306a36Sopenharmony_ci va_list args; 91662306a36Sopenharmony_ci int ret; 91762306a36Sopenharmony_ci}; 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_cistatic int perf_config_scan_cb(const char *var, const char *value, void *data) 92062306a36Sopenharmony_ci{ 92162306a36Sopenharmony_ci struct perf_config_scan_data *d = data; 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci if (!strcmp(var, d->name)) 92462306a36Sopenharmony_ci d->ret = vsscanf(value, d->fmt, d->args); 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci return 0; 92762306a36Sopenharmony_ci} 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ciint perf_config_scan(const char *name, const char *fmt, ...) 93062306a36Sopenharmony_ci{ 93162306a36Sopenharmony_ci struct perf_config_scan_data d = { 93262306a36Sopenharmony_ci .name = name, 93362306a36Sopenharmony_ci .fmt = fmt, 93462306a36Sopenharmony_ci }; 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci va_start(d.args, fmt); 93762306a36Sopenharmony_ci perf_config(perf_config_scan_cb, &d); 93862306a36Sopenharmony_ci va_end(d.args); 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci return d.ret; 94162306a36Sopenharmony_ci} 942