Merge branches 'imx/pata' and 'imx/sata' into next/driver
[pandora-kernel.git] / tools / perf / util / config.c
1 /*
2  * GIT - The information manager from hell
3  *
4  * Copyright (C) Linus Torvalds, 2005
5  * Copyright (C) Johannes Schindelin, 2005
6  *
7  */
8 #include "util.h"
9 #include "cache.h"
10 #include "exec_cmd.h"
11
12 #define MAXNAME (256)
13
14 #define DEBUG_CACHE_DIR ".debug"
15
16
17 char buildid_dir[MAXPATHLEN]; /* root dir for buildid, binary cache */
18
19 static FILE *config_file;
20 static const char *config_file_name;
21 static int config_linenr;
22 static int config_file_eof;
23
24 static const char *config_exclusive_filename;
25
26 static int get_next_char(void)
27 {
28         int c;
29         FILE *f;
30
31         c = '\n';
32         if ((f = config_file) != NULL) {
33                 c = fgetc(f);
34                 if (c == '\r') {
35                         /* DOS like systems */
36                         c = fgetc(f);
37                         if (c != '\n') {
38                                 ungetc(c, f);
39                                 c = '\r';
40                         }
41                 }
42                 if (c == '\n')
43                         config_linenr++;
44                 if (c == EOF) {
45                         config_file_eof = 1;
46                         c = '\n';
47                 }
48         }
49         return c;
50 }
51
52 static char *parse_value(void)
53 {
54         static char value[1024];
55         int quote = 0, comment = 0, space = 0;
56         size_t len = 0;
57
58         for (;;) {
59                 int c = get_next_char();
60
61                 if (len >= sizeof(value) - 1)
62                         return NULL;
63                 if (c == '\n') {
64                         if (quote)
65                                 return NULL;
66                         value[len] = 0;
67                         return value;
68                 }
69                 if (comment)
70                         continue;
71                 if (isspace(c) && !quote) {
72                         space = 1;
73                         continue;
74                 }
75                 if (!quote) {
76                         if (c == ';' || c == '#') {
77                                 comment = 1;
78                                 continue;
79                         }
80                 }
81                 if (space) {
82                         if (len)
83                                 value[len++] = ' ';
84                         space = 0;
85                 }
86                 if (c == '\\') {
87                         c = get_next_char();
88                         switch (c) {
89                         case '\n':
90                                 continue;
91                         case 't':
92                                 c = '\t';
93                                 break;
94                         case 'b':
95                                 c = '\b';
96                                 break;
97                         case 'n':
98                                 c = '\n';
99                                 break;
100                         /* Some characters escape as themselves */
101                         case '\\': case '"':
102                                 break;
103                         /* Reject unknown escape sequences */
104                         default:
105                                 return NULL;
106                         }
107                         value[len++] = c;
108                         continue;
109                 }
110                 if (c == '"') {
111                         quote = 1-quote;
112                         continue;
113                 }
114                 value[len++] = c;
115         }
116 }
117
118 static inline int iskeychar(int c)
119 {
120         return isalnum(c) || c == '-';
121 }
122
123 static int get_value(config_fn_t fn, void *data, char *name, unsigned int len)
124 {
125         int c;
126         char *value;
127
128         /* Get the full name */
129         for (;;) {
130                 c = get_next_char();
131                 if (config_file_eof)
132                         break;
133                 if (!iskeychar(c))
134                         break;
135                 name[len++] = c;
136                 if (len >= MAXNAME)
137                         return -1;
138         }
139         name[len] = 0;
140         while (c == ' ' || c == '\t')
141                 c = get_next_char();
142
143         value = NULL;
144         if (c != '\n') {
145                 if (c != '=')
146                         return -1;
147                 value = parse_value();
148                 if (!value)
149                         return -1;
150         }
151         return fn(name, value, data);
152 }
153
154 static int get_extended_base_var(char *name, int baselen, int c)
155 {
156         do {
157                 if (c == '\n')
158                         return -1;
159                 c = get_next_char();
160         } while (isspace(c));
161
162         /* We require the format to be '[base "extension"]' */
163         if (c != '"')
164                 return -1;
165         name[baselen++] = '.';
166
167         for (;;) {
168                 int ch = get_next_char();
169
170                 if (ch == '\n')
171                         return -1;
172                 if (ch == '"')
173                         break;
174                 if (ch == '\\') {
175                         ch = get_next_char();
176                         if (ch == '\n')
177                                 return -1;
178                 }
179                 name[baselen++] = ch;
180                 if (baselen > MAXNAME / 2)
181                         return -1;
182         }
183
184         /* Final ']' */
185         if (get_next_char() != ']')
186                 return -1;
187         return baselen;
188 }
189
190 static int get_base_var(char *name)
191 {
192         int baselen = 0;
193
194         for (;;) {
195                 int c = get_next_char();
196                 if (config_file_eof)
197                         return -1;
198                 if (c == ']')
199                         return baselen;
200                 if (isspace(c))
201                         return get_extended_base_var(name, baselen, c);
202                 if (!iskeychar(c) && c != '.')
203                         return -1;
204                 if (baselen > MAXNAME / 2)
205                         return -1;
206                 name[baselen++] = tolower(c);
207         }
208 }
209
210 static int perf_parse_file(config_fn_t fn, void *data)
211 {
212         int comment = 0;
213         int baselen = 0;
214         static char var[MAXNAME];
215
216         /* U+FEFF Byte Order Mark in UTF8 */
217         static const unsigned char *utf8_bom = (unsigned char *) "\xef\xbb\xbf";
218         const unsigned char *bomptr = utf8_bom;
219
220         for (;;) {
221                 int c = get_next_char();
222                 if (bomptr && *bomptr) {
223                         /* We are at the file beginning; skip UTF8-encoded BOM
224                          * if present. Sane editors won't put this in on their
225                          * own, but e.g. Windows Notepad will do it happily. */
226                         if ((unsigned char) c == *bomptr) {
227                                 bomptr++;
228                                 continue;
229                         } else {
230                                 /* Do not tolerate partial BOM. */
231                                 if (bomptr != utf8_bom)
232                                         break;
233                                 /* No BOM at file beginning. Cool. */
234                                 bomptr = NULL;
235                         }
236                 }
237                 if (c == '\n') {
238                         if (config_file_eof)
239                                 return 0;
240                         comment = 0;
241                         continue;
242                 }
243                 if (comment || isspace(c))
244                         continue;
245                 if (c == '#' || c == ';') {
246                         comment = 1;
247                         continue;
248                 }
249                 if (c == '[') {
250                         baselen = get_base_var(var);
251                         if (baselen <= 0)
252                                 break;
253                         var[baselen++] = '.';
254                         var[baselen] = 0;
255                         continue;
256                 }
257                 if (!isalpha(c))
258                         break;
259                 var[baselen] = tolower(c);
260                 if (get_value(fn, data, var, baselen+1) < 0)
261                         break;
262         }
263         die("bad config file line %d in %s", config_linenr, config_file_name);
264 }
265
266 static int parse_unit_factor(const char *end, unsigned long *val)
267 {
268         if (!*end)
269                 return 1;
270         else if (!strcasecmp(end, "k")) {
271                 *val *= 1024;
272                 return 1;
273         }
274         else if (!strcasecmp(end, "m")) {
275                 *val *= 1024 * 1024;
276                 return 1;
277         }
278         else if (!strcasecmp(end, "g")) {
279                 *val *= 1024 * 1024 * 1024;
280                 return 1;
281         }
282         return 0;
283 }
284
285 static int perf_parse_long(const char *value, long *ret)
286 {
287         if (value && *value) {
288                 char *end;
289                 long val = strtol(value, &end, 0);
290                 unsigned long factor = 1;
291                 if (!parse_unit_factor(end, &factor))
292                         return 0;
293                 *ret = val * factor;
294                 return 1;
295         }
296         return 0;
297 }
298
299 static void die_bad_config(const char *name)
300 {
301         if (config_file_name)
302                 die("bad config value for '%s' in %s", name, config_file_name);
303         die("bad config value for '%s'", name);
304 }
305
306 int perf_config_int(const char *name, const char *value)
307 {
308         long ret = 0;
309         if (!perf_parse_long(value, &ret))
310                 die_bad_config(name);
311         return ret;
312 }
313
314 static int perf_config_bool_or_int(const char *name, const char *value, int *is_bool)
315 {
316         *is_bool = 1;
317         if (!value)
318                 return 1;
319         if (!*value)
320                 return 0;
321         if (!strcasecmp(value, "true") || !strcasecmp(value, "yes") || !strcasecmp(value, "on"))
322                 return 1;
323         if (!strcasecmp(value, "false") || !strcasecmp(value, "no") || !strcasecmp(value, "off"))
324                 return 0;
325         *is_bool = 0;
326         return perf_config_int(name, value);
327 }
328
329 int perf_config_bool(const char *name, const char *value)
330 {
331         int discard;
332         return !!perf_config_bool_or_int(name, value, &discard);
333 }
334
335 const char *perf_config_dirname(const char *name, const char *value)
336 {
337         if (!name)
338                 return NULL;
339         return value;
340 }
341
342 static int perf_default_core_config(const char *var __used, const char *value __used)
343 {
344         /* Add other config variables here and to Documentation/config.txt. */
345         return 0;
346 }
347
348 int perf_default_config(const char *var, const char *value, void *dummy __used)
349 {
350         if (!prefixcmp(var, "core."))
351                 return perf_default_core_config(var, value);
352
353         /* Add other config variables here and to Documentation/config.txt. */
354         return 0;
355 }
356
357 static int perf_config_from_file(config_fn_t fn, const char *filename, void *data)
358 {
359         int ret;
360         FILE *f = fopen(filename, "r");
361
362         ret = -1;
363         if (f) {
364                 config_file = f;
365                 config_file_name = filename;
366                 config_linenr = 1;
367                 config_file_eof = 0;
368                 ret = perf_parse_file(fn, data);
369                 fclose(f);
370                 config_file_name = NULL;
371         }
372         return ret;
373 }
374
375 static const char *perf_etc_perfconfig(void)
376 {
377         static const char *system_wide;
378         if (!system_wide)
379                 system_wide = system_path(ETC_PERFCONFIG);
380         return system_wide;
381 }
382
383 static int perf_env_bool(const char *k, int def)
384 {
385         const char *v = getenv(k);
386         return v ? perf_config_bool(k, v) : def;
387 }
388
389 static int perf_config_system(void)
390 {
391         return !perf_env_bool("PERF_CONFIG_NOSYSTEM", 0);
392 }
393
394 static int perf_config_global(void)
395 {
396         return !perf_env_bool("PERF_CONFIG_NOGLOBAL", 0);
397 }
398
399 int perf_config(config_fn_t fn, void *data)
400 {
401         int ret = 0, found = 0;
402         const char *home = NULL;
403
404         /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */
405         if (config_exclusive_filename)
406                 return perf_config_from_file(fn, config_exclusive_filename, data);
407         if (perf_config_system() && !access(perf_etc_perfconfig(), R_OK)) {
408                 ret += perf_config_from_file(fn, perf_etc_perfconfig(),
409                                             data);
410                 found += 1;
411         }
412
413         home = getenv("HOME");
414         if (perf_config_global() && home) {
415                 char *user_config = strdup(mkpath("%s/.perfconfig", home));
416                 struct stat st;
417
418                 if (user_config == NULL) {
419                         warning("Not enough memory to process %s/.perfconfig, "
420                                 "ignoring it.", home);
421                         goto out;
422                 }
423
424                 if (stat(user_config, &st) < 0)
425                         goto out_free;
426
427                 if (st.st_uid && (st.st_uid != geteuid())) {
428                         warning("File %s not owned by current user or root, "
429                                 "ignoring it.", user_config);
430                         goto out_free;
431                 }
432
433                 if (!st.st_size)
434                         goto out_free;
435
436                 ret += perf_config_from_file(fn, user_config, data);
437                 found += 1;
438 out_free:
439                 free(user_config);
440         }
441 out:
442         if (found == 0)
443                 return -1;
444         return ret;
445 }
446
447 /*
448  * Call this to report error for your variable that should not
449  * get a boolean value (i.e. "[my] var" means "true").
450  */
451 int config_error_nonbool(const char *var)
452 {
453         return error("Missing value for '%s'", var);
454 }
455
456 struct buildid_dir_config {
457         char *dir;
458 };
459
460 static int buildid_dir_command_config(const char *var, const char *value,
461                                       void *data)
462 {
463         struct buildid_dir_config *c = data;
464         const char *v;
465
466         /* same dir for all commands */
467         if (!prefixcmp(var, "buildid.") && !strcmp(var + 8, "dir")) {
468                 v = perf_config_dirname(var, value);
469                 if (!v)
470                         return -1;
471                 strncpy(c->dir, v, MAXPATHLEN-1);
472                 c->dir[MAXPATHLEN-1] = '\0';
473         }
474         return 0;
475 }
476
477 static void check_buildid_dir_config(void)
478 {
479         struct buildid_dir_config c;
480         c.dir = buildid_dir;
481         perf_config(buildid_dir_command_config, &c);
482 }
483
484 void set_buildid_dir(void)
485 {
486         buildid_dir[0] = '\0';
487
488         /* try config file */
489         check_buildid_dir_config();
490
491         /* default to $HOME/.debug */
492         if (buildid_dir[0] == '\0') {
493                 char *v = getenv("HOME");
494                 if (v) {
495                         snprintf(buildid_dir, MAXPATHLEN-1, "%s/%s",
496                                  v, DEBUG_CACHE_DIR);
497                 } else {
498                         strncpy(buildid_dir, DEBUG_CACHE_DIR, MAXPATHLEN-1);
499                 }
500                 buildid_dir[MAXPATHLEN-1] = '\0';
501         }
502         /* for communicating with external commands */
503         setenv("PERF_BUILDID_DIR", buildid_dir, 1);
504 }