about summary refs log tree commit diff
path: root/third_party/git/trace2/tr2_sysenv.c
blob: 5958cfc424b5c520bb5602f25d15004cf4a2bcda (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#include "cache.h"
#include "config.h"
#include "dir.h"
#include "tr2_sysenv.h"

/*
 * Each entry represents a trace2 setting.
 * See Documentation/technical/api-trace2.txt
 */
struct tr2_sysenv_entry {
	const char *env_var_name;
	const char *git_config_name;

	char *value;
	unsigned int getenv_called : 1;
};

/*
 * This table must match "enum tr2_sysenv_variable" in tr2_sysenv.h.
 *
 * The strings in this table are constant and must match the published
 * config and environment variable names as described in the documentation.
 *
 * We do not define entries for the GIT_TRACE2_PARENT_* environment
 * variables because they are transient and used to pass information
 * from parent to child git processes, rather than settings.
 */
/* clang-format off */
static struct tr2_sysenv_entry tr2_sysenv_settings[] = {
	[TR2_SYSENV_CFG_PARAM]     = { "GIT_TRACE2_CONFIG_PARAMS",
				       "trace2.configparams" },

	[TR2_SYSENV_DST_DEBUG]     = { "GIT_TRACE2_DST_DEBUG",
				       "trace2.destinationdebug" },

	[TR2_SYSENV_NORMAL]        = { "GIT_TRACE2",
				       "trace2.normaltarget" },
	[TR2_SYSENV_NORMAL_BRIEF]  = { "GIT_TRACE2_BRIEF",
				       "trace2.normalbrief" },

	[TR2_SYSENV_EVENT]         = { "GIT_TRACE2_EVENT",
				       "trace2.eventtarget" },
	[TR2_SYSENV_EVENT_BRIEF]   = { "GIT_TRACE2_EVENT_BRIEF",
				       "trace2.eventbrief" },
	[TR2_SYSENV_EVENT_NESTING] = { "GIT_TRACE2_EVENT_NESTING",
				       "trace2.eventnesting" },

	[TR2_SYSENV_PERF]          = { "GIT_TRACE2_PERF",
				       "trace2.perftarget" },
	[TR2_SYSENV_PERF_BRIEF]    = { "GIT_TRACE2_PERF_BRIEF",
				       "trace2.perfbrief" },
};
/* clang-format on */

static int tr2_sysenv_cb(const char *key, const char *value, void *d)
{
	int k;

	if (!starts_with(key, "trace2."))
		return 0;

	for (k = 0; k < ARRAY_SIZE(tr2_sysenv_settings); k++) {
		if (!strcmp(key, tr2_sysenv_settings[k].git_config_name)) {
			free(tr2_sysenv_settings[k].value);
			tr2_sysenv_settings[k].value = xstrdup(value);
			return 0;
		}
	}

	return 0;
}

/*
 * Load Trace2 settings from the system config (usually "/etc/gitconfig"
 * unless we were built with a runtime-prefix).  These are intended to
 * define the default values for Trace2 as requested by the administrator.
 *
 * Then override with the Trace2 settings from the global config.
 */
void tr2_sysenv_load(void)
{
	if (ARRAY_SIZE(tr2_sysenv_settings) != TR2_SYSENV_MUST_BE_LAST)
		BUG("tr2_sysenv_settings size is wrong");

	read_very_early_config(tr2_sysenv_cb, NULL);
}

/*
 * Return the value for the requested Trace2 setting from these sources:
 * the system config, the global config, and the environment.
 */
const char *tr2_sysenv_get(enum tr2_sysenv_variable var)
{
	if (var >= TR2_SYSENV_MUST_BE_LAST)
		BUG("tr2_sysenv_get invalid var '%d'", var);

	if (!tr2_sysenv_settings[var].getenv_called) {
		const char *v = getenv(tr2_sysenv_settings[var].env_var_name);
		if (v && *v) {
			free(tr2_sysenv_settings[var].value);
			tr2_sysenv_settings[var].value = xstrdup(v);
		}
		tr2_sysenv_settings[var].getenv_called = 1;
	}

	return tr2_sysenv_settings[var].value;
}

/*
 * Return a friendly name for this setting that is suitable for printing
 * in an error messages.
 */
const char *tr2_sysenv_display_name(enum tr2_sysenv_variable var)
{
	if (var >= TR2_SYSENV_MUST_BE_LAST)
		BUG("tr2_sysenv_get invalid var '%d'", var);

	return tr2_sysenv_settings[var].env_var_name;
}

void tr2_sysenv_release(void)
{
	int k;

	for (k = 0; k < ARRAY_SIZE(tr2_sysenv_settings); k++)
		free(tr2_sysenv_settings[k].value);
}