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 	[TR2_SYSENV_ENV_VARS]      = { "GIT_TRACE2_ENV_VARS",
33 				       "trace2.envvars" },
34 
35 	[TR2_SYSENV_DST_DEBUG]     = { "GIT_TRACE2_DST_DEBUG",
36 				       "trace2.destinationdebug" },
37 
38 	[TR2_SYSENV_NORMAL]        = { "GIT_TRACE2",
39 				       "trace2.normaltarget" },
40 	[TR2_SYSENV_NORMAL_BRIEF]  = { "GIT_TRACE2_BRIEF",
41 				       "trace2.normalbrief" },
42 
43 	[TR2_SYSENV_EVENT]         = { "GIT_TRACE2_EVENT",
44 				       "trace2.eventtarget" },
45 	[TR2_SYSENV_EVENT_BRIEF]   = { "GIT_TRACE2_EVENT_BRIEF",
46 				       "trace2.eventbrief" },
47 	[TR2_SYSENV_EVENT_NESTING] = { "GIT_TRACE2_EVENT_NESTING",
48 				       "trace2.eventnesting" },
49 
50 	[TR2_SYSENV_PERF]          = { "GIT_TRACE2_PERF",
51 				       "trace2.perftarget" },
52 	[TR2_SYSENV_PERF_BRIEF]    = { "GIT_TRACE2_PERF_BRIEF",
53 				       "trace2.perfbrief" },
54 
55 	[TR2_SYSENV_MAX_FILES]     = { "GIT_TRACE2_MAX_FILES",
56 				       "trace2.maxfiles" },
57 };
58 /* clang-format on */
59 
tr2_sysenv_cb(const char * key,const char * value,void * d)60 static int tr2_sysenv_cb(const char *key, const char *value, void *d)
61 {
62 	int k;
63 
64 	if (!starts_with(key, "trace2."))
65 		return 0;
66 
67 	for (k = 0; k < ARRAY_SIZE(tr2_sysenv_settings); k++) {
68 		if (!strcmp(key, tr2_sysenv_settings[k].git_config_name)) {
69 			free(tr2_sysenv_settings[k].value);
70 			tr2_sysenv_settings[k].value = xstrdup(value);
71 			return 0;
72 		}
73 	}
74 
75 	return 0;
76 }
77 
78 /*
79  * Load Trace2 settings from the system config (usually "/etc/gitconfig"
80  * unless we were built with a runtime-prefix).  These are intended to
81  * define the default values for Trace2 as requested by the administrator.
82  *
83  * Then override with the Trace2 settings from the global config.
84  */
tr2_sysenv_load(void)85 void tr2_sysenv_load(void)
86 {
87 	if (ARRAY_SIZE(tr2_sysenv_settings) != TR2_SYSENV_MUST_BE_LAST)
88 		BUG("tr2_sysenv_settings size is wrong");
89 
90 	read_very_early_config(tr2_sysenv_cb, NULL);
91 }
92 
93 /*
94  * Return the value for the requested Trace2 setting from these sources:
95  * the system config, the global config, and the environment.
96  */
tr2_sysenv_get(enum tr2_sysenv_variable var)97 const char *tr2_sysenv_get(enum tr2_sysenv_variable var)
98 {
99 	if (var >= TR2_SYSENV_MUST_BE_LAST)
100 		BUG("tr2_sysenv_get invalid var '%d'", var);
101 
102 	if (!tr2_sysenv_settings[var].getenv_called) {
103 		const char *v = getenv(tr2_sysenv_settings[var].env_var_name);
104 		if (v && *v) {
105 			free(tr2_sysenv_settings[var].value);
106 			tr2_sysenv_settings[var].value = xstrdup(v);
107 		}
108 		tr2_sysenv_settings[var].getenv_called = 1;
109 	}
110 
111 	return tr2_sysenv_settings[var].value;
112 }
113 
114 /*
115  * Return a friendly name for this setting that is suitable for printing
116  * in an error messages.
117  */
tr2_sysenv_display_name(enum tr2_sysenv_variable var)118 const char *tr2_sysenv_display_name(enum tr2_sysenv_variable var)
119 {
120 	if (var >= TR2_SYSENV_MUST_BE_LAST)
121 		BUG("tr2_sysenv_get invalid var '%d'", var);
122 
123 	return tr2_sysenv_settings[var].env_var_name;
124 }
125 
tr2_sysenv_release(void)126 void tr2_sysenv_release(void)
127 {
128 	int k;
129 
130 	for (k = 0; k < ARRAY_SIZE(tr2_sysenv_settings); k++)
131 		free(tr2_sysenv_settings[k].value);
132 }
133