config.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728
  1. /*
  2. * config.c
  3. *
  4. * Helper functions for parsing config items.
  5. * Originally copied from GIT source.
  6. *
  7. * Copyright (C) Linus Torvalds, 2005
  8. * Copyright (C) Johannes Schindelin, 2005
  9. *
  10. */
  11. #include "util.h"
  12. #include "cache.h"
  13. #include <subcmd/exec-cmd.h>
  14. #include "util/hist.h" /* perf_hist_config */
  15. #include "util/llvm-utils.h" /* perf_llvm_config */
  16. #include "config.h"
  17. #define MAXNAME (256)
  18. #define DEBUG_CACHE_DIR ".debug"
  19. char buildid_dir[MAXPATHLEN]; /* root dir for buildid, binary cache */
  20. static FILE *config_file;
  21. static const char *config_file_name;
  22. static int config_linenr;
  23. static int config_file_eof;
  24. const char *config_exclusive_filename;
  25. static int get_next_char(void)
  26. {
  27. int c;
  28. FILE *f;
  29. c = '\n';
  30. if ((f = config_file) != NULL) {
  31. c = fgetc(f);
  32. if (c == '\r') {
  33. /* DOS like systems */
  34. c = fgetc(f);
  35. if (c != '\n') {
  36. ungetc(c, f);
  37. c = '\r';
  38. }
  39. }
  40. if (c == '\n')
  41. config_linenr++;
  42. if (c == EOF) {
  43. config_file_eof = 1;
  44. c = '\n';
  45. }
  46. }
  47. return c;
  48. }
  49. static char *parse_value(void)
  50. {
  51. static char value[1024];
  52. int quote = 0, comment = 0, space = 0;
  53. size_t len = 0;
  54. for (;;) {
  55. int c = get_next_char();
  56. if (len >= sizeof(value) - 1)
  57. return NULL;
  58. if (c == '\n') {
  59. if (quote)
  60. return NULL;
  61. value[len] = 0;
  62. return value;
  63. }
  64. if (comment)
  65. continue;
  66. if (isspace(c) && !quote) {
  67. space = 1;
  68. continue;
  69. }
  70. if (!quote) {
  71. if (c == ';' || c == '#') {
  72. comment = 1;
  73. continue;
  74. }
  75. }
  76. if (space) {
  77. if (len)
  78. value[len++] = ' ';
  79. space = 0;
  80. }
  81. if (c == '\\') {
  82. c = get_next_char();
  83. switch (c) {
  84. case '\n':
  85. continue;
  86. case 't':
  87. c = '\t';
  88. break;
  89. case 'b':
  90. c = '\b';
  91. break;
  92. case 'n':
  93. c = '\n';
  94. break;
  95. /* Some characters escape as themselves */
  96. case '\\': case '"':
  97. break;
  98. /* Reject unknown escape sequences */
  99. default:
  100. return NULL;
  101. }
  102. value[len++] = c;
  103. continue;
  104. }
  105. if (c == '"') {
  106. quote = 1-quote;
  107. continue;
  108. }
  109. value[len++] = c;
  110. }
  111. }
  112. static inline int iskeychar(int c)
  113. {
  114. return isalnum(c) || c == '-' || c == '_';
  115. }
  116. static int get_value(config_fn_t fn, void *data, char *name, unsigned int len)
  117. {
  118. int c;
  119. char *value;
  120. /* Get the full name */
  121. for (;;) {
  122. c = get_next_char();
  123. if (config_file_eof)
  124. break;
  125. if (!iskeychar(c))
  126. break;
  127. name[len++] = c;
  128. if (len >= MAXNAME)
  129. return -1;
  130. }
  131. name[len] = 0;
  132. while (c == ' ' || c == '\t')
  133. c = get_next_char();
  134. value = NULL;
  135. if (c != '\n') {
  136. if (c != '=')
  137. return -1;
  138. value = parse_value();
  139. if (!value)
  140. return -1;
  141. }
  142. return fn(name, value, data);
  143. }
  144. static int get_extended_base_var(char *name, int baselen, int c)
  145. {
  146. do {
  147. if (c == '\n')
  148. return -1;
  149. c = get_next_char();
  150. } while (isspace(c));
  151. /* We require the format to be '[base "extension"]' */
  152. if (c != '"')
  153. return -1;
  154. name[baselen++] = '.';
  155. for (;;) {
  156. int ch = get_next_char();
  157. if (ch == '\n')
  158. return -1;
  159. if (ch == '"')
  160. break;
  161. if (ch == '\\') {
  162. ch = get_next_char();
  163. if (ch == '\n')
  164. return -1;
  165. }
  166. name[baselen++] = ch;
  167. if (baselen > MAXNAME / 2)
  168. return -1;
  169. }
  170. /* Final ']' */
  171. if (get_next_char() != ']')
  172. return -1;
  173. return baselen;
  174. }
  175. static int get_base_var(char *name)
  176. {
  177. int baselen = 0;
  178. for (;;) {
  179. int c = get_next_char();
  180. if (config_file_eof)
  181. return -1;
  182. if (c == ']')
  183. return baselen;
  184. if (isspace(c))
  185. return get_extended_base_var(name, baselen, c);
  186. if (!iskeychar(c) && c != '.')
  187. return -1;
  188. if (baselen > MAXNAME / 2)
  189. return -1;
  190. name[baselen++] = tolower(c);
  191. }
  192. }
  193. static int perf_parse_file(config_fn_t fn, void *data)
  194. {
  195. int comment = 0;
  196. int baselen = 0;
  197. static char var[MAXNAME];
  198. /* U+FEFF Byte Order Mark in UTF8 */
  199. static const unsigned char *utf8_bom = (unsigned char *) "\xef\xbb\xbf";
  200. const unsigned char *bomptr = utf8_bom;
  201. for (;;) {
  202. int line, c = get_next_char();
  203. if (bomptr && *bomptr) {
  204. /* We are at the file beginning; skip UTF8-encoded BOM
  205. * if present. Sane editors won't put this in on their
  206. * own, but e.g. Windows Notepad will do it happily. */
  207. if ((unsigned char) c == *bomptr) {
  208. bomptr++;
  209. continue;
  210. } else {
  211. /* Do not tolerate partial BOM. */
  212. if (bomptr != utf8_bom)
  213. break;
  214. /* No BOM at file beginning. Cool. */
  215. bomptr = NULL;
  216. }
  217. }
  218. if (c == '\n') {
  219. if (config_file_eof)
  220. return 0;
  221. comment = 0;
  222. continue;
  223. }
  224. if (comment || isspace(c))
  225. continue;
  226. if (c == '#' || c == ';') {
  227. comment = 1;
  228. continue;
  229. }
  230. if (c == '[') {
  231. baselen = get_base_var(var);
  232. if (baselen <= 0)
  233. break;
  234. var[baselen++] = '.';
  235. var[baselen] = 0;
  236. continue;
  237. }
  238. if (!isalpha(c))
  239. break;
  240. var[baselen] = tolower(c);
  241. /*
  242. * The get_value function might or might not reach the '\n',
  243. * so saving the current line number for error reporting.
  244. */
  245. line = config_linenr;
  246. if (get_value(fn, data, var, baselen+1) < 0) {
  247. config_linenr = line;
  248. break;
  249. }
  250. }
  251. die("bad config file line %d in %s", config_linenr, config_file_name);
  252. }
  253. static int parse_unit_factor(const char *end, unsigned long *val)
  254. {
  255. if (!*end)
  256. return 1;
  257. else if (!strcasecmp(end, "k")) {
  258. *val *= 1024;
  259. return 1;
  260. }
  261. else if (!strcasecmp(end, "m")) {
  262. *val *= 1024 * 1024;
  263. return 1;
  264. }
  265. else if (!strcasecmp(end, "g")) {
  266. *val *= 1024 * 1024 * 1024;
  267. return 1;
  268. }
  269. return 0;
  270. }
  271. static int perf_parse_llong(const char *value, long long *ret)
  272. {
  273. if (value && *value) {
  274. char *end;
  275. long long val = strtoll(value, &end, 0);
  276. unsigned long factor = 1;
  277. if (!parse_unit_factor(end, &factor))
  278. return 0;
  279. *ret = val * factor;
  280. return 1;
  281. }
  282. return 0;
  283. }
  284. static int perf_parse_long(const char *value, long *ret)
  285. {
  286. if (value && *value) {
  287. char *end;
  288. long val = strtol(value, &end, 0);
  289. unsigned long factor = 1;
  290. if (!parse_unit_factor(end, &factor))
  291. return 0;
  292. *ret = val * factor;
  293. return 1;
  294. }
  295. return 0;
  296. }
  297. static void die_bad_config(const char *name)
  298. {
  299. if (config_file_name)
  300. die("bad config value for '%s' in %s", name, config_file_name);
  301. die("bad config value for '%s'", name);
  302. }
  303. u64 perf_config_u64(const char *name, const char *value)
  304. {
  305. long long ret = 0;
  306. if (!perf_parse_llong(value, &ret))
  307. die_bad_config(name);
  308. return (u64) ret;
  309. }
  310. int perf_config_int(const char *name, const char *value)
  311. {
  312. long ret = 0;
  313. if (!perf_parse_long(value, &ret))
  314. die_bad_config(name);
  315. return ret;
  316. }
  317. static int perf_config_bool_or_int(const char *name, const char *value, int *is_bool)
  318. {
  319. *is_bool = 1;
  320. if (!value)
  321. return 1;
  322. if (!*value)
  323. return 0;
  324. if (!strcasecmp(value, "true") || !strcasecmp(value, "yes") || !strcasecmp(value, "on"))
  325. return 1;
  326. if (!strcasecmp(value, "false") || !strcasecmp(value, "no") || !strcasecmp(value, "off"))
  327. return 0;
  328. *is_bool = 0;
  329. return perf_config_int(name, value);
  330. }
  331. int perf_config_bool(const char *name, const char *value)
  332. {
  333. int discard;
  334. return !!perf_config_bool_or_int(name, value, &discard);
  335. }
  336. const char *perf_config_dirname(const char *name, const char *value)
  337. {
  338. if (!name)
  339. return NULL;
  340. return value;
  341. }
  342. static int perf_buildid_config(const char *var, const char *value)
  343. {
  344. /* same dir for all commands */
  345. if (!strcmp(var, "buildid.dir")) {
  346. const char *dir = perf_config_dirname(var, value);
  347. if (!dir)
  348. return -1;
  349. strncpy(buildid_dir, dir, MAXPATHLEN-1);
  350. buildid_dir[MAXPATHLEN-1] = '\0';
  351. }
  352. return 0;
  353. }
  354. static int perf_default_core_config(const char *var __maybe_unused,
  355. const char *value __maybe_unused)
  356. {
  357. /* Add other config variables here. */
  358. return 0;
  359. }
  360. static int perf_ui_config(const char *var, const char *value)
  361. {
  362. /* Add other config variables here. */
  363. if (!strcmp(var, "ui.show-headers")) {
  364. symbol_conf.show_hist_headers = perf_config_bool(var, value);
  365. return 0;
  366. }
  367. return 0;
  368. }
  369. int perf_default_config(const char *var, const char *value,
  370. void *dummy __maybe_unused)
  371. {
  372. if (!prefixcmp(var, "core."))
  373. return perf_default_core_config(var, value);
  374. if (!prefixcmp(var, "hist."))
  375. return perf_hist_config(var, value);
  376. if (!prefixcmp(var, "ui."))
  377. return perf_ui_config(var, value);
  378. if (!prefixcmp(var, "call-graph."))
  379. return perf_callchain_config(var, value);
  380. if (!prefixcmp(var, "llvm."))
  381. return perf_llvm_config(var, value);
  382. if (!prefixcmp(var, "buildid."))
  383. return perf_buildid_config(var, value);
  384. /* Add other config variables here. */
  385. return 0;
  386. }
  387. static int perf_config_from_file(config_fn_t fn, const char *filename, void *data)
  388. {
  389. int ret;
  390. FILE *f = fopen(filename, "r");
  391. ret = -1;
  392. if (f) {
  393. config_file = f;
  394. config_file_name = filename;
  395. config_linenr = 1;
  396. config_file_eof = 0;
  397. ret = perf_parse_file(fn, data);
  398. fclose(f);
  399. config_file_name = NULL;
  400. }
  401. return ret;
  402. }
  403. const char *perf_etc_perfconfig(void)
  404. {
  405. static const char *system_wide;
  406. if (!system_wide)
  407. system_wide = system_path(ETC_PERFCONFIG);
  408. return system_wide;
  409. }
  410. static int perf_env_bool(const char *k, int def)
  411. {
  412. const char *v = getenv(k);
  413. return v ? perf_config_bool(k, v) : def;
  414. }
  415. static int perf_config_system(void)
  416. {
  417. return !perf_env_bool("PERF_CONFIG_NOSYSTEM", 0);
  418. }
  419. static int perf_config_global(void)
  420. {
  421. return !perf_env_bool("PERF_CONFIG_NOGLOBAL", 0);
  422. }
  423. int perf_config(config_fn_t fn, void *data)
  424. {
  425. int ret = 0, found = 0;
  426. const char *home = NULL;
  427. /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */
  428. if (config_exclusive_filename)
  429. return perf_config_from_file(fn, config_exclusive_filename, data);
  430. if (perf_config_system() && !access(perf_etc_perfconfig(), R_OK)) {
  431. ret += perf_config_from_file(fn, perf_etc_perfconfig(),
  432. data);
  433. found += 1;
  434. }
  435. home = getenv("HOME");
  436. if (perf_config_global() && home) {
  437. char *user_config = strdup(mkpath("%s/.perfconfig", home));
  438. struct stat st;
  439. if (user_config == NULL) {
  440. warning("Not enough memory to process %s/.perfconfig, "
  441. "ignoring it.", home);
  442. goto out;
  443. }
  444. if (stat(user_config, &st) < 0)
  445. goto out_free;
  446. if (st.st_uid && (st.st_uid != geteuid())) {
  447. warning("File %s not owned by current user or root, "
  448. "ignoring it.", user_config);
  449. goto out_free;
  450. }
  451. if (!st.st_size)
  452. goto out_free;
  453. ret += perf_config_from_file(fn, user_config, data);
  454. found += 1;
  455. out_free:
  456. free(user_config);
  457. }
  458. out:
  459. if (found == 0)
  460. return -1;
  461. return ret;
  462. }
  463. static struct perf_config_section *find_section(struct list_head *sections,
  464. const char *section_name)
  465. {
  466. struct perf_config_section *section;
  467. list_for_each_entry(section, sections, node)
  468. if (!strcmp(section->name, section_name))
  469. return section;
  470. return NULL;
  471. }
  472. static struct perf_config_item *find_config_item(const char *name,
  473. struct perf_config_section *section)
  474. {
  475. struct perf_config_item *item;
  476. list_for_each_entry(item, &section->items, node)
  477. if (!strcmp(item->name, name))
  478. return item;
  479. return NULL;
  480. }
  481. static struct perf_config_section *add_section(struct list_head *sections,
  482. const char *section_name)
  483. {
  484. struct perf_config_section *section = zalloc(sizeof(*section));
  485. if (!section)
  486. return NULL;
  487. INIT_LIST_HEAD(&section->items);
  488. section->name = strdup(section_name);
  489. if (!section->name) {
  490. pr_debug("%s: strdup failed\n", __func__);
  491. free(section);
  492. return NULL;
  493. }
  494. list_add_tail(&section->node, sections);
  495. return section;
  496. }
  497. static struct perf_config_item *add_config_item(struct perf_config_section *section,
  498. const char *name)
  499. {
  500. struct perf_config_item *item = zalloc(sizeof(*item));
  501. if (!item)
  502. return NULL;
  503. item->name = strdup(name);
  504. if (!item->name) {
  505. pr_debug("%s: strdup failed\n", __func__);
  506. free(item);
  507. return NULL;
  508. }
  509. list_add_tail(&item->node, &section->items);
  510. return item;
  511. }
  512. static int set_value(struct perf_config_item *item, const char *value)
  513. {
  514. char *val = strdup(value);
  515. if (!val)
  516. return -1;
  517. zfree(&item->value);
  518. item->value = val;
  519. return 0;
  520. }
  521. static int collect_config(const char *var, const char *value,
  522. void *perf_config_set)
  523. {
  524. int ret = -1;
  525. char *ptr, *key;
  526. char *section_name, *name;
  527. struct perf_config_section *section = NULL;
  528. struct perf_config_item *item = NULL;
  529. struct perf_config_set *set = perf_config_set;
  530. struct list_head *sections = &set->sections;
  531. key = ptr = strdup(var);
  532. if (!key) {
  533. pr_debug("%s: strdup failed\n", __func__);
  534. return -1;
  535. }
  536. section_name = strsep(&ptr, ".");
  537. name = ptr;
  538. if (name == NULL || value == NULL)
  539. goto out_free;
  540. section = find_section(sections, section_name);
  541. if (!section) {
  542. section = add_section(sections, section_name);
  543. if (!section)
  544. goto out_free;
  545. }
  546. item = find_config_item(name, section);
  547. if (!item) {
  548. item = add_config_item(section, name);
  549. if (!item)
  550. goto out_free;
  551. }
  552. ret = set_value(item, value);
  553. return ret;
  554. out_free:
  555. free(key);
  556. perf_config_set__delete(set);
  557. return -1;
  558. }
  559. struct perf_config_set *perf_config_set__new(void)
  560. {
  561. struct perf_config_set *set = zalloc(sizeof(*set));
  562. if (set) {
  563. INIT_LIST_HEAD(&set->sections);
  564. perf_config(collect_config, set);
  565. }
  566. return set;
  567. }
  568. static void perf_config_item__delete(struct perf_config_item *item)
  569. {
  570. zfree(&item->name);
  571. zfree(&item->value);
  572. free(item);
  573. }
  574. static void perf_config_section__purge(struct perf_config_section *section)
  575. {
  576. struct perf_config_item *item, *tmp;
  577. list_for_each_entry_safe(item, tmp, &section->items, node) {
  578. list_del_init(&item->node);
  579. perf_config_item__delete(item);
  580. }
  581. }
  582. static void perf_config_section__delete(struct perf_config_section *section)
  583. {
  584. perf_config_section__purge(section);
  585. zfree(&section->name);
  586. free(section);
  587. }
  588. static void perf_config_set__purge(struct perf_config_set *set)
  589. {
  590. struct perf_config_section *section, *tmp;
  591. list_for_each_entry_safe(section, tmp, &set->sections, node) {
  592. list_del_init(&section->node);
  593. perf_config_section__delete(section);
  594. }
  595. }
  596. void perf_config_set__delete(struct perf_config_set *set)
  597. {
  598. perf_config_set__purge(set);
  599. free(set);
  600. }
  601. /*
  602. * Call this to report error for your variable that should not
  603. * get a boolean value (i.e. "[my] var" means "true").
  604. */
  605. int config_error_nonbool(const char *var)
  606. {
  607. return error("Missing value for '%s'", var);
  608. }
  609. void set_buildid_dir(const char *dir)
  610. {
  611. if (dir)
  612. scnprintf(buildid_dir, MAXPATHLEN-1, "%s", dir);
  613. /* default to $HOME/.debug */
  614. if (buildid_dir[0] == '\0') {
  615. char *home = getenv("HOME");
  616. if (home) {
  617. snprintf(buildid_dir, MAXPATHLEN-1, "%s/%s",
  618. home, DEBUG_CACHE_DIR);
  619. } else {
  620. strncpy(buildid_dir, DEBUG_CACHE_DIR, MAXPATHLEN-1);
  621. }
  622. buildid_dir[MAXPATHLEN-1] = '\0';
  623. }
  624. /* for communicating with external commands */
  625. setenv("PERF_BUILDID_DIR", buildid_dir, 1);
  626. }