186470930SIngo Molnar /* 286470930SIngo Molnar * GIT - The information manager from hell 386470930SIngo Molnar * 486470930SIngo Molnar * Copyright (C) Linus Torvalds, 2005 586470930SIngo Molnar * Copyright (C) Johannes Schindelin, 2005 686470930SIngo Molnar * 786470930SIngo Molnar */ 886470930SIngo Molnar #include "util.h" 986470930SIngo Molnar #include "cache.h" 1086470930SIngo Molnar #include "exec_cmd.h" 1186470930SIngo Molnar 1286470930SIngo Molnar #define MAXNAME (256) 1386470930SIngo Molnar 1486470930SIngo Molnar static FILE *config_file; 1586470930SIngo Molnar static const char *config_file_name; 1686470930SIngo Molnar static int config_linenr; 1786470930SIngo Molnar static int config_file_eof; 1886470930SIngo Molnar 1986470930SIngo Molnar const char *config_exclusive_filename = NULL; 2086470930SIngo Molnar 2186470930SIngo Molnar static int get_next_char(void) 2286470930SIngo Molnar { 2386470930SIngo Molnar int c; 2486470930SIngo Molnar FILE *f; 2586470930SIngo Molnar 2686470930SIngo Molnar c = '\n'; 2786470930SIngo Molnar if ((f = config_file) != NULL) { 2886470930SIngo Molnar c = fgetc(f); 2986470930SIngo Molnar if (c == '\r') { 3086470930SIngo Molnar /* DOS like systems */ 3186470930SIngo Molnar c = fgetc(f); 3286470930SIngo Molnar if (c != '\n') { 3386470930SIngo Molnar ungetc(c, f); 3486470930SIngo Molnar c = '\r'; 3586470930SIngo Molnar } 3686470930SIngo Molnar } 3786470930SIngo Molnar if (c == '\n') 3886470930SIngo Molnar config_linenr++; 3986470930SIngo Molnar if (c == EOF) { 4086470930SIngo Molnar config_file_eof = 1; 4186470930SIngo Molnar c = '\n'; 4286470930SIngo Molnar } 4386470930SIngo Molnar } 4486470930SIngo Molnar return c; 4586470930SIngo Molnar } 4686470930SIngo Molnar 4786470930SIngo Molnar static char *parse_value(void) 4886470930SIngo Molnar { 4986470930SIngo Molnar static char value[1024]; 50*f37a291cSIngo Molnar int quote = 0, comment = 0, space = 0; 51*f37a291cSIngo Molnar size_t len = 0; 5286470930SIngo Molnar 5386470930SIngo Molnar for (;;) { 5486470930SIngo Molnar int c = get_next_char(); 55*f37a291cSIngo Molnar 5686470930SIngo Molnar if (len >= sizeof(value) - 1) 5786470930SIngo Molnar return NULL; 5886470930SIngo Molnar if (c == '\n') { 5986470930SIngo Molnar if (quote) 6086470930SIngo Molnar return NULL; 6186470930SIngo Molnar value[len] = 0; 6286470930SIngo Molnar return value; 6386470930SIngo Molnar } 6486470930SIngo Molnar if (comment) 6586470930SIngo Molnar continue; 6686470930SIngo Molnar if (isspace(c) && !quote) { 6786470930SIngo Molnar space = 1; 6886470930SIngo Molnar continue; 6986470930SIngo Molnar } 7086470930SIngo Molnar if (!quote) { 7186470930SIngo Molnar if (c == ';' || c == '#') { 7286470930SIngo Molnar comment = 1; 7386470930SIngo Molnar continue; 7486470930SIngo Molnar } 7586470930SIngo Molnar } 7686470930SIngo Molnar if (space) { 7786470930SIngo Molnar if (len) 7886470930SIngo Molnar value[len++] = ' '; 7986470930SIngo Molnar space = 0; 8086470930SIngo Molnar } 8186470930SIngo Molnar if (c == '\\') { 8286470930SIngo Molnar c = get_next_char(); 8386470930SIngo Molnar switch (c) { 8486470930SIngo Molnar case '\n': 8586470930SIngo Molnar continue; 8686470930SIngo Molnar case 't': 8786470930SIngo Molnar c = '\t'; 8886470930SIngo Molnar break; 8986470930SIngo Molnar case 'b': 9086470930SIngo Molnar c = '\b'; 9186470930SIngo Molnar break; 9286470930SIngo Molnar case 'n': 9386470930SIngo Molnar c = '\n'; 9486470930SIngo Molnar break; 9586470930SIngo Molnar /* Some characters escape as themselves */ 9686470930SIngo Molnar case '\\': case '"': 9786470930SIngo Molnar break; 9886470930SIngo Molnar /* Reject unknown escape sequences */ 9986470930SIngo Molnar default: 10086470930SIngo Molnar return NULL; 10186470930SIngo Molnar } 10286470930SIngo Molnar value[len++] = c; 10386470930SIngo Molnar continue; 10486470930SIngo Molnar } 10586470930SIngo Molnar if (c == '"') { 10686470930SIngo Molnar quote = 1-quote; 10786470930SIngo Molnar continue; 10886470930SIngo Molnar } 10986470930SIngo Molnar value[len++] = c; 11086470930SIngo Molnar } 11186470930SIngo Molnar } 11286470930SIngo Molnar 11386470930SIngo Molnar static inline int iskeychar(int c) 11486470930SIngo Molnar { 11586470930SIngo Molnar return isalnum(c) || c == '-'; 11686470930SIngo Molnar } 11786470930SIngo Molnar 11886470930SIngo Molnar static int get_value(config_fn_t fn, void *data, char *name, unsigned int len) 11986470930SIngo Molnar { 12086470930SIngo Molnar int c; 12186470930SIngo Molnar char *value; 12286470930SIngo Molnar 12386470930SIngo Molnar /* Get the full name */ 12486470930SIngo Molnar for (;;) { 12586470930SIngo Molnar c = get_next_char(); 12686470930SIngo Molnar if (config_file_eof) 12786470930SIngo Molnar break; 12886470930SIngo Molnar if (!iskeychar(c)) 12986470930SIngo Molnar break; 13086470930SIngo Molnar name[len++] = tolower(c); 13186470930SIngo Molnar if (len >= MAXNAME) 13286470930SIngo Molnar return -1; 13386470930SIngo Molnar } 13486470930SIngo Molnar name[len] = 0; 13586470930SIngo Molnar while (c == ' ' || c == '\t') 13686470930SIngo Molnar c = get_next_char(); 13786470930SIngo Molnar 13886470930SIngo Molnar value = NULL; 13986470930SIngo Molnar if (c != '\n') { 14086470930SIngo Molnar if (c != '=') 14186470930SIngo Molnar return -1; 14286470930SIngo Molnar value = parse_value(); 14386470930SIngo Molnar if (!value) 14486470930SIngo Molnar return -1; 14586470930SIngo Molnar } 14686470930SIngo Molnar return fn(name, value, data); 14786470930SIngo Molnar } 14886470930SIngo Molnar 14986470930SIngo Molnar static int get_extended_base_var(char *name, int baselen, int c) 15086470930SIngo Molnar { 15186470930SIngo Molnar do { 15286470930SIngo Molnar if (c == '\n') 15386470930SIngo Molnar return -1; 15486470930SIngo Molnar c = get_next_char(); 15586470930SIngo Molnar } while (isspace(c)); 15686470930SIngo Molnar 15786470930SIngo Molnar /* We require the format to be '[base "extension"]' */ 15886470930SIngo Molnar if (c != '"') 15986470930SIngo Molnar return -1; 16086470930SIngo Molnar name[baselen++] = '.'; 16186470930SIngo Molnar 16286470930SIngo Molnar for (;;) { 16386470930SIngo Molnar int c = get_next_char(); 16486470930SIngo Molnar if (c == '\n') 16586470930SIngo Molnar return -1; 16686470930SIngo Molnar if (c == '"') 16786470930SIngo Molnar break; 16886470930SIngo Molnar if (c == '\\') { 16986470930SIngo Molnar c = get_next_char(); 17086470930SIngo Molnar if (c == '\n') 17186470930SIngo Molnar return -1; 17286470930SIngo Molnar } 17386470930SIngo Molnar name[baselen++] = c; 17486470930SIngo Molnar if (baselen > MAXNAME / 2) 17586470930SIngo Molnar return -1; 17686470930SIngo Molnar } 17786470930SIngo Molnar 17886470930SIngo Molnar /* Final ']' */ 17986470930SIngo Molnar if (get_next_char() != ']') 18086470930SIngo Molnar return -1; 18186470930SIngo Molnar return baselen; 18286470930SIngo Molnar } 18386470930SIngo Molnar 18486470930SIngo Molnar static int get_base_var(char *name) 18586470930SIngo Molnar { 18686470930SIngo Molnar int baselen = 0; 18786470930SIngo Molnar 18886470930SIngo Molnar for (;;) { 18986470930SIngo Molnar int c = get_next_char(); 19086470930SIngo Molnar if (config_file_eof) 19186470930SIngo Molnar return -1; 19286470930SIngo Molnar if (c == ']') 19386470930SIngo Molnar return baselen; 19486470930SIngo Molnar if (isspace(c)) 19586470930SIngo Molnar return get_extended_base_var(name, baselen, c); 19686470930SIngo Molnar if (!iskeychar(c) && c != '.') 19786470930SIngo Molnar return -1; 19886470930SIngo Molnar if (baselen > MAXNAME / 2) 19986470930SIngo Molnar return -1; 20086470930SIngo Molnar name[baselen++] = tolower(c); 20186470930SIngo Molnar } 20286470930SIngo Molnar } 20386470930SIngo Molnar 20486470930SIngo Molnar static int perf_parse_file(config_fn_t fn, void *data) 20586470930SIngo Molnar { 20686470930SIngo Molnar int comment = 0; 20786470930SIngo Molnar int baselen = 0; 20886470930SIngo Molnar static char var[MAXNAME]; 20986470930SIngo Molnar 21086470930SIngo Molnar /* U+FEFF Byte Order Mark in UTF8 */ 21186470930SIngo Molnar static const unsigned char *utf8_bom = (unsigned char *) "\xef\xbb\xbf"; 21286470930SIngo Molnar const unsigned char *bomptr = utf8_bom; 21386470930SIngo Molnar 21486470930SIngo Molnar for (;;) { 21586470930SIngo Molnar int c = get_next_char(); 21686470930SIngo Molnar if (bomptr && *bomptr) { 21786470930SIngo Molnar /* We are at the file beginning; skip UTF8-encoded BOM 21886470930SIngo Molnar * if present. Sane editors won't put this in on their 21986470930SIngo Molnar * own, but e.g. Windows Notepad will do it happily. */ 22086470930SIngo Molnar if ((unsigned char) c == *bomptr) { 22186470930SIngo Molnar bomptr++; 22286470930SIngo Molnar continue; 22386470930SIngo Molnar } else { 22486470930SIngo Molnar /* Do not tolerate partial BOM. */ 22586470930SIngo Molnar if (bomptr != utf8_bom) 22686470930SIngo Molnar break; 22786470930SIngo Molnar /* No BOM at file beginning. Cool. */ 22886470930SIngo Molnar bomptr = NULL; 22986470930SIngo Molnar } 23086470930SIngo Molnar } 23186470930SIngo Molnar if (c == '\n') { 23286470930SIngo Molnar if (config_file_eof) 23386470930SIngo Molnar return 0; 23486470930SIngo Molnar comment = 0; 23586470930SIngo Molnar continue; 23686470930SIngo Molnar } 23786470930SIngo Molnar if (comment || isspace(c)) 23886470930SIngo Molnar continue; 23986470930SIngo Molnar if (c == '#' || c == ';') { 24086470930SIngo Molnar comment = 1; 24186470930SIngo Molnar continue; 24286470930SIngo Molnar } 24386470930SIngo Molnar if (c == '[') { 24486470930SIngo Molnar baselen = get_base_var(var); 24586470930SIngo Molnar if (baselen <= 0) 24686470930SIngo Molnar break; 24786470930SIngo Molnar var[baselen++] = '.'; 24886470930SIngo Molnar var[baselen] = 0; 24986470930SIngo Molnar continue; 25086470930SIngo Molnar } 25186470930SIngo Molnar if (!isalpha(c)) 25286470930SIngo Molnar break; 25386470930SIngo Molnar var[baselen] = tolower(c); 25486470930SIngo Molnar if (get_value(fn, data, var, baselen+1) < 0) 25586470930SIngo Molnar break; 25686470930SIngo Molnar } 25786470930SIngo Molnar die("bad config file line %d in %s", config_linenr, config_file_name); 25886470930SIngo Molnar } 25986470930SIngo Molnar 26086470930SIngo Molnar static int parse_unit_factor(const char *end, unsigned long *val) 26186470930SIngo Molnar { 26286470930SIngo Molnar if (!*end) 26386470930SIngo Molnar return 1; 26486470930SIngo Molnar else if (!strcasecmp(end, "k")) { 26586470930SIngo Molnar *val *= 1024; 26686470930SIngo Molnar return 1; 26786470930SIngo Molnar } 26886470930SIngo Molnar else if (!strcasecmp(end, "m")) { 26986470930SIngo Molnar *val *= 1024 * 1024; 27086470930SIngo Molnar return 1; 27186470930SIngo Molnar } 27286470930SIngo Molnar else if (!strcasecmp(end, "g")) { 27386470930SIngo Molnar *val *= 1024 * 1024 * 1024; 27486470930SIngo Molnar return 1; 27586470930SIngo Molnar } 27686470930SIngo Molnar return 0; 27786470930SIngo Molnar } 27886470930SIngo Molnar 27986470930SIngo Molnar static int perf_parse_long(const char *value, long *ret) 28086470930SIngo Molnar { 28186470930SIngo Molnar if (value && *value) { 28286470930SIngo Molnar char *end; 28386470930SIngo Molnar long val = strtol(value, &end, 0); 28486470930SIngo Molnar unsigned long factor = 1; 28586470930SIngo Molnar if (!parse_unit_factor(end, &factor)) 28686470930SIngo Molnar return 0; 28786470930SIngo Molnar *ret = val * factor; 28886470930SIngo Molnar return 1; 28986470930SIngo Molnar } 29086470930SIngo Molnar return 0; 29186470930SIngo Molnar } 29286470930SIngo Molnar 29386470930SIngo Molnar int perf_parse_ulong(const char *value, unsigned long *ret) 29486470930SIngo Molnar { 29586470930SIngo Molnar if (value && *value) { 29686470930SIngo Molnar char *end; 29786470930SIngo Molnar unsigned long val = strtoul(value, &end, 0); 29886470930SIngo Molnar if (!parse_unit_factor(end, &val)) 29986470930SIngo Molnar return 0; 30086470930SIngo Molnar *ret = val; 30186470930SIngo Molnar return 1; 30286470930SIngo Molnar } 30386470930SIngo Molnar return 0; 30486470930SIngo Molnar } 30586470930SIngo Molnar 30686470930SIngo Molnar static void die_bad_config(const char *name) 30786470930SIngo Molnar { 30886470930SIngo Molnar if (config_file_name) 30986470930SIngo Molnar die("bad config value for '%s' in %s", name, config_file_name); 31086470930SIngo Molnar die("bad config value for '%s'", name); 31186470930SIngo Molnar } 31286470930SIngo Molnar 31386470930SIngo Molnar int perf_config_int(const char *name, const char *value) 31486470930SIngo Molnar { 31586470930SIngo Molnar long ret = 0; 31686470930SIngo Molnar if (!perf_parse_long(value, &ret)) 31786470930SIngo Molnar die_bad_config(name); 31886470930SIngo Molnar return ret; 31986470930SIngo Molnar } 32086470930SIngo Molnar 32186470930SIngo Molnar unsigned long perf_config_ulong(const char *name, const char *value) 32286470930SIngo Molnar { 32386470930SIngo Molnar unsigned long ret; 32486470930SIngo Molnar if (!perf_parse_ulong(value, &ret)) 32586470930SIngo Molnar die_bad_config(name); 32686470930SIngo Molnar return ret; 32786470930SIngo Molnar } 32886470930SIngo Molnar 32986470930SIngo Molnar int perf_config_bool_or_int(const char *name, const char *value, int *is_bool) 33086470930SIngo Molnar { 33186470930SIngo Molnar *is_bool = 1; 33286470930SIngo Molnar if (!value) 33386470930SIngo Molnar return 1; 33486470930SIngo Molnar if (!*value) 33586470930SIngo Molnar return 0; 33686470930SIngo Molnar if (!strcasecmp(value, "true") || !strcasecmp(value, "yes") || !strcasecmp(value, "on")) 33786470930SIngo Molnar return 1; 33886470930SIngo Molnar if (!strcasecmp(value, "false") || !strcasecmp(value, "no") || !strcasecmp(value, "off")) 33986470930SIngo Molnar return 0; 34086470930SIngo Molnar *is_bool = 0; 34186470930SIngo Molnar return perf_config_int(name, value); 34286470930SIngo Molnar } 34386470930SIngo Molnar 34486470930SIngo Molnar int perf_config_bool(const char *name, const char *value) 34586470930SIngo Molnar { 34686470930SIngo Molnar int discard; 34786470930SIngo Molnar return !!perf_config_bool_or_int(name, value, &discard); 34886470930SIngo Molnar } 34986470930SIngo Molnar 35086470930SIngo Molnar int perf_config_string(const char **dest, const char *var, const char *value) 35186470930SIngo Molnar { 35286470930SIngo Molnar if (!value) 35386470930SIngo Molnar return config_error_nonbool(var); 35486470930SIngo Molnar *dest = strdup(value); 35586470930SIngo Molnar return 0; 35686470930SIngo Molnar } 35786470930SIngo Molnar 358*f37a291cSIngo Molnar static int perf_default_core_config(const char *var __used, const char *value __used) 35986470930SIngo Molnar { 36086470930SIngo Molnar /* Add other config variables here and to Documentation/config.txt. */ 36186470930SIngo Molnar return 0; 36286470930SIngo Molnar } 36386470930SIngo Molnar 364*f37a291cSIngo Molnar int perf_default_config(const char *var, const char *value, void *dummy __used) 36586470930SIngo Molnar { 36686470930SIngo Molnar if (!prefixcmp(var, "core.")) 36786470930SIngo Molnar return perf_default_core_config(var, value); 36886470930SIngo Molnar 36986470930SIngo Molnar /* Add other config variables here and to Documentation/config.txt. */ 37086470930SIngo Molnar return 0; 37186470930SIngo Molnar } 37286470930SIngo Molnar 37386470930SIngo Molnar int perf_config_from_file(config_fn_t fn, const char *filename, void *data) 37486470930SIngo Molnar { 37586470930SIngo Molnar int ret; 37686470930SIngo Molnar FILE *f = fopen(filename, "r"); 37786470930SIngo Molnar 37886470930SIngo Molnar ret = -1; 37986470930SIngo Molnar if (f) { 38086470930SIngo Molnar config_file = f; 38186470930SIngo Molnar config_file_name = filename; 38286470930SIngo Molnar config_linenr = 1; 38386470930SIngo Molnar config_file_eof = 0; 38486470930SIngo Molnar ret = perf_parse_file(fn, data); 38586470930SIngo Molnar fclose(f); 38686470930SIngo Molnar config_file_name = NULL; 38786470930SIngo Molnar } 38886470930SIngo Molnar return ret; 38986470930SIngo Molnar } 39086470930SIngo Molnar 39186470930SIngo Molnar const char *perf_etc_perfconfig(void) 39286470930SIngo Molnar { 39386470930SIngo Molnar static const char *system_wide; 39486470930SIngo Molnar if (!system_wide) 39586470930SIngo Molnar system_wide = system_path(ETC_PERFCONFIG); 39686470930SIngo Molnar return system_wide; 39786470930SIngo Molnar } 39886470930SIngo Molnar 39986470930SIngo Molnar static int perf_env_bool(const char *k, int def) 40086470930SIngo Molnar { 40186470930SIngo Molnar const char *v = getenv(k); 40286470930SIngo Molnar return v ? perf_config_bool(k, v) : def; 40386470930SIngo Molnar } 40486470930SIngo Molnar 40586470930SIngo Molnar int perf_config_system(void) 40686470930SIngo Molnar { 40786470930SIngo Molnar return !perf_env_bool("PERF_CONFIG_NOSYSTEM", 0); 40886470930SIngo Molnar } 40986470930SIngo Molnar 41086470930SIngo Molnar int perf_config_global(void) 41186470930SIngo Molnar { 41286470930SIngo Molnar return !perf_env_bool("PERF_CONFIG_NOGLOBAL", 0); 41386470930SIngo Molnar } 41486470930SIngo Molnar 41586470930SIngo Molnar int perf_config(config_fn_t fn, void *data) 41686470930SIngo Molnar { 41786470930SIngo Molnar int ret = 0, found = 0; 41886470930SIngo Molnar char *repo_config = NULL; 41986470930SIngo Molnar const char *home = NULL; 42086470930SIngo Molnar 42186470930SIngo Molnar /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */ 42286470930SIngo Molnar if (config_exclusive_filename) 42386470930SIngo Molnar return perf_config_from_file(fn, config_exclusive_filename, data); 42486470930SIngo Molnar if (perf_config_system() && !access(perf_etc_perfconfig(), R_OK)) { 42586470930SIngo Molnar ret += perf_config_from_file(fn, perf_etc_perfconfig(), 42686470930SIngo Molnar data); 42786470930SIngo Molnar found += 1; 42886470930SIngo Molnar } 42986470930SIngo Molnar 43086470930SIngo Molnar home = getenv("HOME"); 43186470930SIngo Molnar if (perf_config_global() && home) { 43286470930SIngo Molnar char *user_config = strdup(mkpath("%s/.perfconfig", home)); 43386470930SIngo Molnar if (!access(user_config, R_OK)) { 43486470930SIngo Molnar ret += perf_config_from_file(fn, user_config, data); 43586470930SIngo Molnar found += 1; 43686470930SIngo Molnar } 43786470930SIngo Molnar free(user_config); 43886470930SIngo Molnar } 43986470930SIngo Molnar 44086470930SIngo Molnar repo_config = perf_pathdup("config"); 44186470930SIngo Molnar if (!access(repo_config, R_OK)) { 44286470930SIngo Molnar ret += perf_config_from_file(fn, repo_config, data); 44386470930SIngo Molnar found += 1; 44486470930SIngo Molnar } 44586470930SIngo Molnar free(repo_config); 44686470930SIngo Molnar if (found == 0) 44786470930SIngo Molnar return -1; 44886470930SIngo Molnar return ret; 44986470930SIngo Molnar } 45086470930SIngo Molnar 45186470930SIngo Molnar /* 45286470930SIngo Molnar * Find all the stuff for perf_config_set() below. 45386470930SIngo Molnar */ 45486470930SIngo Molnar 45586470930SIngo Molnar #define MAX_MATCHES 512 45686470930SIngo Molnar 45786470930SIngo Molnar static struct { 45886470930SIngo Molnar int baselen; 45986470930SIngo Molnar char* key; 46086470930SIngo Molnar int do_not_match; 46186470930SIngo Molnar regex_t* value_regex; 46286470930SIngo Molnar int multi_replace; 46386470930SIngo Molnar size_t offset[MAX_MATCHES]; 46486470930SIngo Molnar enum { START, SECTION_SEEN, SECTION_END_SEEN, KEY_SEEN } state; 46586470930SIngo Molnar int seen; 46686470930SIngo Molnar } store; 46786470930SIngo Molnar 46886470930SIngo Molnar static int matches(const char* key, const char* value) 46986470930SIngo Molnar { 47086470930SIngo Molnar return !strcmp(key, store.key) && 47186470930SIngo Molnar (store.value_regex == NULL || 47286470930SIngo Molnar (store.do_not_match ^ 47386470930SIngo Molnar !regexec(store.value_regex, value, 0, NULL, 0))); 47486470930SIngo Molnar } 47586470930SIngo Molnar 476*f37a291cSIngo Molnar static int store_aux(const char* key, const char* value, void *cb __used) 47786470930SIngo Molnar { 478*f37a291cSIngo Molnar int section_len; 47986470930SIngo Molnar const char *ep; 48086470930SIngo Molnar 48186470930SIngo Molnar switch (store.state) { 48286470930SIngo Molnar case KEY_SEEN: 48386470930SIngo Molnar if (matches(key, value)) { 48486470930SIngo Molnar if (store.seen == 1 && store.multi_replace == 0) { 48586470930SIngo Molnar warning("%s has multiple values", key); 48686470930SIngo Molnar } else if (store.seen >= MAX_MATCHES) { 48786470930SIngo Molnar error("too many matches for %s", key); 48886470930SIngo Molnar return 1; 48986470930SIngo Molnar } 49086470930SIngo Molnar 49186470930SIngo Molnar store.offset[store.seen] = ftell(config_file); 49286470930SIngo Molnar store.seen++; 49386470930SIngo Molnar } 49486470930SIngo Molnar break; 49586470930SIngo Molnar case SECTION_SEEN: 49686470930SIngo Molnar /* 49786470930SIngo Molnar * What we are looking for is in store.key (both 49886470930SIngo Molnar * section and var), and its section part is baselen 49986470930SIngo Molnar * long. We found key (again, both section and var). 50086470930SIngo Molnar * We would want to know if this key is in the same 50186470930SIngo Molnar * section as what we are looking for. We already 50286470930SIngo Molnar * know we are in the same section as what should 50386470930SIngo Molnar * hold store.key. 50486470930SIngo Molnar */ 50586470930SIngo Molnar ep = strrchr(key, '.'); 50686470930SIngo Molnar section_len = ep - key; 50786470930SIngo Molnar 50886470930SIngo Molnar if ((section_len != store.baselen) || 50986470930SIngo Molnar memcmp(key, store.key, section_len+1)) { 51086470930SIngo Molnar store.state = SECTION_END_SEEN; 51186470930SIngo Molnar break; 51286470930SIngo Molnar } 51386470930SIngo Molnar 51486470930SIngo Molnar /* 51586470930SIngo Molnar * Do not increment matches: this is no match, but we 51686470930SIngo Molnar * just made sure we are in the desired section. 51786470930SIngo Molnar */ 51886470930SIngo Molnar store.offset[store.seen] = ftell(config_file); 51986470930SIngo Molnar /* fallthru */ 52086470930SIngo Molnar case SECTION_END_SEEN: 52186470930SIngo Molnar case START: 52286470930SIngo Molnar if (matches(key, value)) { 52386470930SIngo Molnar store.offset[store.seen] = ftell(config_file); 52486470930SIngo Molnar store.state = KEY_SEEN; 52586470930SIngo Molnar store.seen++; 52686470930SIngo Molnar } else { 52786470930SIngo Molnar if (strrchr(key, '.') - key == store.baselen && 52886470930SIngo Molnar !strncmp(key, store.key, store.baselen)) { 52986470930SIngo Molnar store.state = SECTION_SEEN; 53086470930SIngo Molnar store.offset[store.seen] = ftell(config_file); 53186470930SIngo Molnar } 53286470930SIngo Molnar } 53386470930SIngo Molnar } 53486470930SIngo Molnar return 0; 53586470930SIngo Molnar } 53686470930SIngo Molnar 53786470930SIngo Molnar static int store_write_section(int fd, const char* key) 53886470930SIngo Molnar { 53986470930SIngo Molnar const char *dot; 54086470930SIngo Molnar int i, success; 54186470930SIngo Molnar struct strbuf sb = STRBUF_INIT; 54286470930SIngo Molnar 54386470930SIngo Molnar dot = memchr(key, '.', store.baselen); 54486470930SIngo Molnar if (dot) { 54586470930SIngo Molnar strbuf_addf(&sb, "[%.*s \"", (int)(dot - key), key); 54686470930SIngo Molnar for (i = dot - key + 1; i < store.baselen; i++) { 54786470930SIngo Molnar if (key[i] == '"' || key[i] == '\\') 54886470930SIngo Molnar strbuf_addch(&sb, '\\'); 54986470930SIngo Molnar strbuf_addch(&sb, key[i]); 55086470930SIngo Molnar } 55186470930SIngo Molnar strbuf_addstr(&sb, "\"]\n"); 55286470930SIngo Molnar } else { 55386470930SIngo Molnar strbuf_addf(&sb, "[%.*s]\n", store.baselen, key); 55486470930SIngo Molnar } 55586470930SIngo Molnar 556*f37a291cSIngo Molnar success = (write_in_full(fd, sb.buf, sb.len) == (ssize_t)sb.len); 55786470930SIngo Molnar strbuf_release(&sb); 55886470930SIngo Molnar 55986470930SIngo Molnar return success; 56086470930SIngo Molnar } 56186470930SIngo Molnar 56286470930SIngo Molnar static int store_write_pair(int fd, const char* key, const char* value) 56386470930SIngo Molnar { 56486470930SIngo Molnar int i, success; 56586470930SIngo Molnar int length = strlen(key + store.baselen + 1); 56686470930SIngo Molnar const char *quote = ""; 56786470930SIngo Molnar struct strbuf sb = STRBUF_INIT; 56886470930SIngo Molnar 56986470930SIngo Molnar /* 57086470930SIngo Molnar * Check to see if the value needs to be surrounded with a dq pair. 57186470930SIngo Molnar * Note that problematic characters are always backslash-quoted; this 57286470930SIngo Molnar * check is about not losing leading or trailing SP and strings that 57386470930SIngo Molnar * follow beginning-of-comment characters (i.e. ';' and '#') by the 57486470930SIngo Molnar * configuration parser. 57586470930SIngo Molnar */ 57686470930SIngo Molnar if (value[0] == ' ') 57786470930SIngo Molnar quote = "\""; 57886470930SIngo Molnar for (i = 0; value[i]; i++) 57986470930SIngo Molnar if (value[i] == ';' || value[i] == '#') 58086470930SIngo Molnar quote = "\""; 58186470930SIngo Molnar if (i && value[i - 1] == ' ') 58286470930SIngo Molnar quote = "\""; 58386470930SIngo Molnar 58486470930SIngo Molnar strbuf_addf(&sb, "\t%.*s = %s", 58586470930SIngo Molnar length, key + store.baselen + 1, quote); 58686470930SIngo Molnar 58786470930SIngo Molnar for (i = 0; value[i]; i++) 58886470930SIngo Molnar switch (value[i]) { 58986470930SIngo Molnar case '\n': 59086470930SIngo Molnar strbuf_addstr(&sb, "\\n"); 59186470930SIngo Molnar break; 59286470930SIngo Molnar case '\t': 59386470930SIngo Molnar strbuf_addstr(&sb, "\\t"); 59486470930SIngo Molnar break; 59586470930SIngo Molnar case '"': 59686470930SIngo Molnar case '\\': 59786470930SIngo Molnar strbuf_addch(&sb, '\\'); 59886470930SIngo Molnar default: 59986470930SIngo Molnar strbuf_addch(&sb, value[i]); 60086470930SIngo Molnar break; 60186470930SIngo Molnar } 60286470930SIngo Molnar strbuf_addf(&sb, "%s\n", quote); 60386470930SIngo Molnar 604*f37a291cSIngo Molnar success = (write_in_full(fd, sb.buf, sb.len) == (ssize_t)sb.len); 60586470930SIngo Molnar strbuf_release(&sb); 60686470930SIngo Molnar 60786470930SIngo Molnar return success; 60886470930SIngo Molnar } 60986470930SIngo Molnar 61086470930SIngo Molnar static ssize_t find_beginning_of_line(const char* contents, size_t size, 61186470930SIngo Molnar size_t offset_, int* found_bracket) 61286470930SIngo Molnar { 61386470930SIngo Molnar size_t equal_offset = size, bracket_offset = size; 61486470930SIngo Molnar ssize_t offset; 61586470930SIngo Molnar 61686470930SIngo Molnar contline: 61786470930SIngo Molnar for (offset = offset_-2; offset > 0 61886470930SIngo Molnar && contents[offset] != '\n'; offset--) 61986470930SIngo Molnar switch (contents[offset]) { 62086470930SIngo Molnar case '=': equal_offset = offset; break; 62186470930SIngo Molnar case ']': bracket_offset = offset; break; 62286470930SIngo Molnar } 62386470930SIngo Molnar if (offset > 0 && contents[offset-1] == '\\') { 62486470930SIngo Molnar offset_ = offset; 62586470930SIngo Molnar goto contline; 62686470930SIngo Molnar } 62786470930SIngo Molnar if (bracket_offset < equal_offset) { 62886470930SIngo Molnar *found_bracket = 1; 62986470930SIngo Molnar offset = bracket_offset+1; 63086470930SIngo Molnar } else 63186470930SIngo Molnar offset++; 63286470930SIngo Molnar 63386470930SIngo Molnar return offset; 63486470930SIngo Molnar } 63586470930SIngo Molnar 63686470930SIngo Molnar int perf_config_set(const char* key, const char* value) 63786470930SIngo Molnar { 63886470930SIngo Molnar return perf_config_set_multivar(key, value, NULL, 0); 63986470930SIngo Molnar } 64086470930SIngo Molnar 64186470930SIngo Molnar /* 64286470930SIngo Molnar * If value==NULL, unset in (remove from) config, 64386470930SIngo Molnar * if value_regex!=NULL, disregard key/value pairs where value does not match. 64486470930SIngo Molnar * if multi_replace==0, nothing, or only one matching key/value is replaced, 64586470930SIngo Molnar * else all matching key/values (regardless how many) are removed, 64686470930SIngo Molnar * before the new pair is written. 64786470930SIngo Molnar * 64886470930SIngo Molnar * Returns 0 on success. 64986470930SIngo Molnar * 65086470930SIngo Molnar * This function does this: 65186470930SIngo Molnar * 65286470930SIngo Molnar * - it locks the config file by creating ".perf/config.lock" 65386470930SIngo Molnar * 65486470930SIngo Molnar * - it then parses the config using store_aux() as validator to find 65586470930SIngo Molnar * the position on the key/value pair to replace. If it is to be unset, 65686470930SIngo Molnar * it must be found exactly once. 65786470930SIngo Molnar * 65886470930SIngo Molnar * - the config file is mmap()ed and the part before the match (if any) is 65986470930SIngo Molnar * written to the lock file, then the changed part and the rest. 66086470930SIngo Molnar * 66186470930SIngo Molnar * - the config file is removed and the lock file rename()d to it. 66286470930SIngo Molnar * 66386470930SIngo Molnar */ 66486470930SIngo Molnar int perf_config_set_multivar(const char* key, const char* value, 66586470930SIngo Molnar const char* value_regex, int multi_replace) 66686470930SIngo Molnar { 66786470930SIngo Molnar int i, dot; 66886470930SIngo Molnar int fd = -1, in_fd; 66986470930SIngo Molnar int ret = 0; 67086470930SIngo Molnar char* config_filename; 67186470930SIngo Molnar const char* last_dot = strrchr(key, '.'); 67286470930SIngo Molnar 67386470930SIngo Molnar if (config_exclusive_filename) 67486470930SIngo Molnar config_filename = strdup(config_exclusive_filename); 67586470930SIngo Molnar else 67686470930SIngo Molnar config_filename = perf_pathdup("config"); 67786470930SIngo Molnar 67886470930SIngo Molnar /* 67986470930SIngo Molnar * Since "key" actually contains the section name and the real 68086470930SIngo Molnar * key name separated by a dot, we have to know where the dot is. 68186470930SIngo Molnar */ 68286470930SIngo Molnar 68386470930SIngo Molnar if (last_dot == NULL) { 68486470930SIngo Molnar error("key does not contain a section: %s", key); 68586470930SIngo Molnar ret = 2; 68686470930SIngo Molnar goto out_free; 68786470930SIngo Molnar } 68886470930SIngo Molnar store.baselen = last_dot - key; 68986470930SIngo Molnar 69086470930SIngo Molnar store.multi_replace = multi_replace; 69186470930SIngo Molnar 69286470930SIngo Molnar /* 69386470930SIngo Molnar * Validate the key and while at it, lower case it for matching. 69486470930SIngo Molnar */ 69586470930SIngo Molnar store.key = malloc(strlen(key) + 1); 69686470930SIngo Molnar dot = 0; 69786470930SIngo Molnar for (i = 0; key[i]; i++) { 69886470930SIngo Molnar unsigned char c = key[i]; 69986470930SIngo Molnar if (c == '.') 70086470930SIngo Molnar dot = 1; 70186470930SIngo Molnar /* Leave the extended basename untouched.. */ 70286470930SIngo Molnar if (!dot || i > store.baselen) { 70386470930SIngo Molnar if (!iskeychar(c) || (i == store.baselen+1 && !isalpha(c))) { 70486470930SIngo Molnar error("invalid key: %s", key); 70586470930SIngo Molnar free(store.key); 70686470930SIngo Molnar ret = 1; 70786470930SIngo Molnar goto out_free; 70886470930SIngo Molnar } 70986470930SIngo Molnar c = tolower(c); 71086470930SIngo Molnar } else if (c == '\n') { 71186470930SIngo Molnar error("invalid key (newline): %s", key); 71286470930SIngo Molnar free(store.key); 71386470930SIngo Molnar ret = 1; 71486470930SIngo Molnar goto out_free; 71586470930SIngo Molnar } 71686470930SIngo Molnar store.key[i] = c; 71786470930SIngo Molnar } 71886470930SIngo Molnar store.key[i] = 0; 71986470930SIngo Molnar 72086470930SIngo Molnar /* 72186470930SIngo Molnar * If .perf/config does not exist yet, write a minimal version. 72286470930SIngo Molnar */ 72386470930SIngo Molnar in_fd = open(config_filename, O_RDONLY); 72486470930SIngo Molnar if ( in_fd < 0 ) { 72586470930SIngo Molnar free(store.key); 72686470930SIngo Molnar 72786470930SIngo Molnar if ( ENOENT != errno ) { 72886470930SIngo Molnar error("opening %s: %s", config_filename, 72986470930SIngo Molnar strerror(errno)); 73086470930SIngo Molnar ret = 3; /* same as "invalid config file" */ 73186470930SIngo Molnar goto out_free; 73286470930SIngo Molnar } 73386470930SIngo Molnar /* if nothing to unset, error out */ 73486470930SIngo Molnar if (value == NULL) { 73586470930SIngo Molnar ret = 5; 73686470930SIngo Molnar goto out_free; 73786470930SIngo Molnar } 73886470930SIngo Molnar 73986470930SIngo Molnar store.key = (char*)key; 74086470930SIngo Molnar if (!store_write_section(fd, key) || 74186470930SIngo Molnar !store_write_pair(fd, key, value)) 74286470930SIngo Molnar goto write_err_out; 74386470930SIngo Molnar } else { 74486470930SIngo Molnar struct stat st; 74586470930SIngo Molnar char* contents; 746*f37a291cSIngo Molnar ssize_t contents_sz, copy_begin, copy_end; 74786470930SIngo Molnar int i, new_line = 0; 74886470930SIngo Molnar 74986470930SIngo Molnar if (value_regex == NULL) 75086470930SIngo Molnar store.value_regex = NULL; 75186470930SIngo Molnar else { 75286470930SIngo Molnar if (value_regex[0] == '!') { 75386470930SIngo Molnar store.do_not_match = 1; 75486470930SIngo Molnar value_regex++; 75586470930SIngo Molnar } else 75686470930SIngo Molnar store.do_not_match = 0; 75786470930SIngo Molnar 75886470930SIngo Molnar store.value_regex = (regex_t*)malloc(sizeof(regex_t)); 75986470930SIngo Molnar if (regcomp(store.value_regex, value_regex, 76086470930SIngo Molnar REG_EXTENDED)) { 76186470930SIngo Molnar error("invalid pattern: %s", value_regex); 76286470930SIngo Molnar free(store.value_regex); 76386470930SIngo Molnar ret = 6; 76486470930SIngo Molnar goto out_free; 76586470930SIngo Molnar } 76686470930SIngo Molnar } 76786470930SIngo Molnar 76886470930SIngo Molnar store.offset[0] = 0; 76986470930SIngo Molnar store.state = START; 77086470930SIngo Molnar store.seen = 0; 77186470930SIngo Molnar 77286470930SIngo Molnar /* 77386470930SIngo Molnar * After this, store.offset will contain the *end* offset 77486470930SIngo Molnar * of the last match, or remain at 0 if no match was found. 77586470930SIngo Molnar * As a side effect, we make sure to transform only a valid 77686470930SIngo Molnar * existing config file. 77786470930SIngo Molnar */ 77886470930SIngo Molnar if (perf_config_from_file(store_aux, config_filename, NULL)) { 77986470930SIngo Molnar error("invalid config file %s", config_filename); 78086470930SIngo Molnar free(store.key); 78186470930SIngo Molnar if (store.value_regex != NULL) { 78286470930SIngo Molnar regfree(store.value_regex); 78386470930SIngo Molnar free(store.value_regex); 78486470930SIngo Molnar } 78586470930SIngo Molnar ret = 3; 78686470930SIngo Molnar goto out_free; 78786470930SIngo Molnar } 78886470930SIngo Molnar 78986470930SIngo Molnar free(store.key); 79086470930SIngo Molnar if (store.value_regex != NULL) { 79186470930SIngo Molnar regfree(store.value_regex); 79286470930SIngo Molnar free(store.value_regex); 79386470930SIngo Molnar } 79486470930SIngo Molnar 79586470930SIngo Molnar /* if nothing to unset, or too many matches, error out */ 79686470930SIngo Molnar if ((store.seen == 0 && value == NULL) || 79786470930SIngo Molnar (store.seen > 1 && multi_replace == 0)) { 79886470930SIngo Molnar ret = 5; 79986470930SIngo Molnar goto out_free; 80086470930SIngo Molnar } 80186470930SIngo Molnar 80286470930SIngo Molnar fstat(in_fd, &st); 80386470930SIngo Molnar contents_sz = xsize_t(st.st_size); 80486470930SIngo Molnar contents = mmap(NULL, contents_sz, PROT_READ, 80586470930SIngo Molnar MAP_PRIVATE, in_fd, 0); 80686470930SIngo Molnar close(in_fd); 80786470930SIngo Molnar 80886470930SIngo Molnar if (store.seen == 0) 80986470930SIngo Molnar store.seen = 1; 81086470930SIngo Molnar 81186470930SIngo Molnar for (i = 0, copy_begin = 0; i < store.seen; i++) { 81286470930SIngo Molnar if (store.offset[i] == 0) { 81386470930SIngo Molnar store.offset[i] = copy_end = contents_sz; 81486470930SIngo Molnar } else if (store.state != KEY_SEEN) { 81586470930SIngo Molnar copy_end = store.offset[i]; 81686470930SIngo Molnar } else 81786470930SIngo Molnar copy_end = find_beginning_of_line( 81886470930SIngo Molnar contents, contents_sz, 81986470930SIngo Molnar store.offset[i]-2, &new_line); 82086470930SIngo Molnar 82186470930SIngo Molnar if (copy_end > 0 && contents[copy_end-1] != '\n') 82286470930SIngo Molnar new_line = 1; 82386470930SIngo Molnar 82486470930SIngo Molnar /* write the first part of the config */ 82586470930SIngo Molnar if (copy_end > copy_begin) { 82686470930SIngo Molnar if (write_in_full(fd, contents + copy_begin, 82786470930SIngo Molnar copy_end - copy_begin) < 82886470930SIngo Molnar copy_end - copy_begin) 82986470930SIngo Molnar goto write_err_out; 83086470930SIngo Molnar if (new_line && 83186470930SIngo Molnar write_in_full(fd, "\n", 1) != 1) 83286470930SIngo Molnar goto write_err_out; 83386470930SIngo Molnar } 83486470930SIngo Molnar copy_begin = store.offset[i]; 83586470930SIngo Molnar } 83686470930SIngo Molnar 83786470930SIngo Molnar /* write the pair (value == NULL means unset) */ 83886470930SIngo Molnar if (value != NULL) { 83986470930SIngo Molnar if (store.state == START) { 84086470930SIngo Molnar if (!store_write_section(fd, key)) 84186470930SIngo Molnar goto write_err_out; 84286470930SIngo Molnar } 84386470930SIngo Molnar if (!store_write_pair(fd, key, value)) 84486470930SIngo Molnar goto write_err_out; 84586470930SIngo Molnar } 84686470930SIngo Molnar 84786470930SIngo Molnar /* write the rest of the config */ 84886470930SIngo Molnar if (copy_begin < contents_sz) 84986470930SIngo Molnar if (write_in_full(fd, contents + copy_begin, 85086470930SIngo Molnar contents_sz - copy_begin) < 85186470930SIngo Molnar contents_sz - copy_begin) 85286470930SIngo Molnar goto write_err_out; 85386470930SIngo Molnar 85486470930SIngo Molnar munmap(contents, contents_sz); 85586470930SIngo Molnar } 85686470930SIngo Molnar 85786470930SIngo Molnar ret = 0; 85886470930SIngo Molnar 85986470930SIngo Molnar out_free: 86086470930SIngo Molnar free(config_filename); 86186470930SIngo Molnar return ret; 86286470930SIngo Molnar 86386470930SIngo Molnar write_err_out: 86486470930SIngo Molnar goto out_free; 86586470930SIngo Molnar 86686470930SIngo Molnar } 86786470930SIngo Molnar 86886470930SIngo Molnar /* 86986470930SIngo Molnar * Call this to report error for your variable that should not 87086470930SIngo Molnar * get a boolean value (i.e. "[my] var" means "true"). 87186470930SIngo Molnar */ 87286470930SIngo Molnar int config_error_nonbool(const char *var) 87386470930SIngo Molnar { 87486470930SIngo Molnar return error("Missing value for '%s'", var); 87586470930SIngo Molnar } 876