Merge branch 'ds/feature-macros'
[git] / trace2 / tr2_sysenv.c
1 #include "cache.h"
2 #include "config.h"
3 #include "dir.h"
4 #include "tr2_sysenv.h"
5
6 /*
7  * Each entry represents a trace2 setting.
8  * See Documentation/technical/api-trace2.txt
9  */
10 struct tr2_sysenv_entry {
11         const char *env_var_name;
12         const char *git_config_name;
13
14         char *value;
15         unsigned int getenv_called : 1;
16 };
17
18 /*
19  * This table must match "enum tr2_sysenv_variable" in tr2_sysenv.h.
20  *
21  * The strings in this table are constant and must match the published
22  * config and environment variable names as described in the documentation.
23  *
24  * We do not define entries for the GIT_TRACE2_PARENT_* environment
25  * variables because they are transient and used to pass information
26  * from parent to child git processes, rather than settings.
27  */
28 /* clang-format off */
29 static struct tr2_sysenv_entry tr2_sysenv_settings[] = {
30         [TR2_SYSENV_CFG_PARAM]     = { "GIT_TRACE2_CONFIG_PARAMS",
31                                        "trace2.configparams" },
32
33         [TR2_SYSENV_DST_DEBUG]     = { "GIT_TRACE2_DST_DEBUG",
34                                        "trace2.destinationdebug" },
35
36         [TR2_SYSENV_NORMAL]        = { "GIT_TRACE2",
37                                        "trace2.normaltarget" },
38         [TR2_SYSENV_NORMAL_BRIEF]  = { "GIT_TRACE2_BRIEF",
39                                        "trace2.normalbrief" },
40
41         [TR2_SYSENV_EVENT]         = { "GIT_TRACE2_EVENT",
42                                        "trace2.eventtarget" },
43         [TR2_SYSENV_EVENT_BRIEF]   = { "GIT_TRACE2_EVENT_BRIEF",
44                                        "trace2.eventbrief" },
45         [TR2_SYSENV_EVENT_NESTING] = { "GIT_TRACE2_EVENT_NESTING",
46                                        "trace2.eventnesting" },
47
48         [TR2_SYSENV_PERF]          = { "GIT_TRACE2_PERF",
49                                        "trace2.perftarget" },
50         [TR2_SYSENV_PERF_BRIEF]    = { "GIT_TRACE2_PERF_BRIEF",
51                                        "trace2.perfbrief" },
52
53         [TR2_SYSENV_MAX_FILES]     = { "GIT_TRACE2_MAX_FILES",
54                                        "trace2.maxfiles" },
55 };
56 /* clang-format on */
57
58 static int tr2_sysenv_cb(const char *key, const char *value, void *d)
59 {
60         int k;
61
62         if (!starts_with(key, "trace2."))
63                 return 0;
64
65         for (k = 0; k < ARRAY_SIZE(tr2_sysenv_settings); k++) {
66                 if (!strcmp(key, tr2_sysenv_settings[k].git_config_name)) {
67                         free(tr2_sysenv_settings[k].value);
68                         tr2_sysenv_settings[k].value = xstrdup(value);
69                         return 0;
70                 }
71         }
72
73         return 0;
74 }
75
76 /*
77  * Load Trace2 settings from the system config (usually "/etc/gitconfig"
78  * unless we were built with a runtime-prefix).  These are intended to
79  * define the default values for Trace2 as requested by the administrator.
80  *
81  * Then override with the Trace2 settings from the global config.
82  */
83 void tr2_sysenv_load(void)
84 {
85         if (ARRAY_SIZE(tr2_sysenv_settings) != TR2_SYSENV_MUST_BE_LAST)
86                 BUG("tr2_sysenv_settings size is wrong");
87
88         read_very_early_config(tr2_sysenv_cb, NULL);
89 }
90
91 /*
92  * Return the value for the requested Trace2 setting from these sources:
93  * the system config, the global config, and the environment.
94  */
95 const char *tr2_sysenv_get(enum tr2_sysenv_variable var)
96 {
97         if (var >= TR2_SYSENV_MUST_BE_LAST)
98                 BUG("tr2_sysenv_get invalid var '%d'", var);
99
100         if (!tr2_sysenv_settings[var].getenv_called) {
101                 const char *v = getenv(tr2_sysenv_settings[var].env_var_name);
102                 if (v && *v) {
103                         free(tr2_sysenv_settings[var].value);
104                         tr2_sysenv_settings[var].value = xstrdup(v);
105                 }
106                 tr2_sysenv_settings[var].getenv_called = 1;
107         }
108
109         return tr2_sysenv_settings[var].value;
110 }
111
112 /*
113  * Return a friendly name for this setting that is suitable for printing
114  * in an error messages.
115  */
116 const char *tr2_sysenv_display_name(enum tr2_sysenv_variable var)
117 {
118         if (var >= TR2_SYSENV_MUST_BE_LAST)
119                 BUG("tr2_sysenv_get invalid var '%d'", var);
120
121         return tr2_sysenv_settings[var].env_var_name;
122 }
123
124 void tr2_sysenv_release(void)
125 {
126         int k;
127
128         for (k = 0; k < ARRAY_SIZE(tr2_sysenv_settings); k++)
129                 free(tr2_sysenv_settings[k].value);
130 }