source src/sysdir.c
Line | Flow | Count | Block(s) | Source |
---|---|---|---|---|
1 | - | /* | ||
2 | - | * Copyright (C) the libgit2 contributors. All rights reserved. | ||
3 | - | * | ||
4 | - | * This file is part of libgit2, distributed under the GNU GPL v2 with | ||
5 | - | * a Linking Exception. For full terms see the included COPYING file. | ||
6 | - | */ | ||
7 | - | |||
8 | - | #include "sysdir.h" | ||
9 | - | |||
10 | - | #include "global.h" | ||
11 | - | #include "buffer.h" | ||
12 | - | #include "path.h" | ||
13 | - | #include <ctype.h> | ||
14 | - | #if GIT_WIN32 | ||
15 | - | #include "win32/findfile.h" | ||
16 | - | #else | ||
17 | - | #include <unistd.h> | ||
18 | - | #include <pwd.h> | ||
19 | - | #endif | ||
20 | - | |||
21 | 9 | 2 | static int git_sysdir_guess_programdata_dirs(git_buf *out) | |
22 | - | { | ||
23 | - | #ifdef GIT_WIN32 | ||
24 | - | return git_win32__find_programdata_dirs(out); | ||
25 | - | #else | ||
26 | 9 | 2 | git_buf_clear(out); | |
27 | 9 | 3 | return 0; | |
28 | - | #endif | ||
29 | - | } | ||
30 | - | |||
31 | 10 | 2 | static int git_sysdir_guess_system_dirs(git_buf *out) | |
32 | - | { | ||
33 | - | #ifdef GIT_WIN32 | ||
34 | - | return git_win32__find_system_dirs(out, L"etc\\"); | ||
35 | - | #else | ||
36 | 10 | 2 | return git_buf_sets(out, "/etc"); | |
37 | - | #endif | ||
38 | - | } | ||
39 | - | |||
40 | - | #ifndef GIT_WIN32 | ||
41 | ##### | 2 | static int get_passwd_home(git_buf *out, uid_t uid) | |
42 | - | { | ||
43 | - | struct passwd pwd, *pwdptr; | ||
44 | ##### | 2 | char *buf = NULL; | |
45 | - | long buflen; | ||
46 | - | int error; | ||
47 | - | |||
48 | ##### | 2,3 | assert(out); | |
49 | - | |||
50 | ##### | 4,5 | if ((buflen = sysconf(_SC_GETPW_R_SIZE_MAX)) == -1) | |
51 | ##### | 6 | buflen = 1024; | |
52 | - | |||
53 | - | do { | ||
54 | ##### | 7 | buf = git__realloc(buf, buflen); | |
55 | ##### | 8 | error = getpwuid_r(uid, &pwd, buf, buflen, &pwdptr); | |
56 | ##### | 9 | buflen *= 2; | |
57 | ##### | 9,10 | } while (error == ERANGE && buflen <= 8192); | |
58 | - | |||
59 | ##### | 11 | if (error) { | |
60 | ##### | 12 | git_error_set(GIT_ERROR_OS, "failed to get passwd entry"); | |
61 | ##### | 13 | goto out; | |
62 | - | } | ||
63 | - | |||
64 | ##### | 14 | if (!pwdptr) { | |
65 | ##### | 15 | git_error_set(GIT_ERROR_OS, "no passwd entry found for user"); | |
66 | ##### | 16 | goto out; | |
67 | - | } | ||
68 | - | |||
69 | ##### | 17,18 | if ((error = git_buf_puts(out, pwdptr->pw_dir)) < 0) | |
70 | ##### | 19 | goto out; | |
71 | - | |||
72 | - | out: | ||
73 | ##### | 20 | git__free(buf); | |
74 | ##### | 21 | return error; | |
75 | - | } | ||
76 | - | #endif | ||
77 | - | |||
78 | 51 | 2 | static int git_sysdir_guess_global_dirs(git_buf *out) | |
79 | - | { | ||
80 | - | #ifdef GIT_WIN32 | ||
81 | - | return git_win32__find_global_dirs(out); | ||
82 | - | #else | ||
83 | - | int error; | ||
84 | - | uid_t uid, euid; | ||
85 | - | const char *sandbox_id; | ||
86 | - | |||
87 | 51 | 2 | uid = getuid(); | |
88 | 51 | 3 | euid = geteuid(); | |
89 | - | |||
90 | - | /** | ||
91 | - | * If APP_SANDBOX_CONTAINER_ID is set, we are running in a | ||
92 | - | * sandboxed environment on macOS. | ||
93 | - | */ | ||
94 | 51 | 4 | sandbox_id = getenv("APP_SANDBOX_CONTAINER_ID"); | |
95 | - | |||
96 | - | /* | ||
97 | - | * In case we are running setuid, use the configuration | ||
98 | - | * of the effective user. | ||
99 | - | * | ||
100 | - | * If we are running in a sandboxed environment on macOS, | ||
101 | - | * we have to get the HOME dir from the password entry file. | ||
102 | - | */ | ||
103 | 51 | 5,6 | if (!sandbox_id && uid == euid) | |
104 | 51 | 7 | error = git__getenv(out, "HOME"); | |
105 | - | else | ||
106 | ##### | 8 | error = get_passwd_home(out, euid); | |
107 | - | |||
108 | 51 | 9 | if (error == GIT_ENOTFOUND) { | |
109 | 1 | 10 | git_error_clear(); | |
110 | 1 | 11 | error = 0; | |
111 | - | } | ||
112 | - | |||
113 | 51 | 12 | return error; | |
114 | - | #endif | ||
115 | - | } | ||
116 | - | |||
117 | 9 | 2 | static int git_sysdir_guess_xdg_dirs(git_buf *out) | |
118 | - | { | ||
119 | - | #ifdef GIT_WIN32 | ||
120 | - | return git_win32__find_xdg_dirs(out); | ||
121 | - | #else | ||
122 | 9 | 2 | git_buf env = GIT_BUF_INIT; | |
123 | - | int error; | ||
124 | - | uid_t uid, euid; | ||
125 | - | |||
126 | 9 | 2 | uid = getuid(); | |
127 | 9 | 3 | euid = geteuid(); | |
128 | - | |||
129 | - | /* | ||
130 | - | * In case we are running setuid, only look up passwd | ||
131 | - | * directory of the effective user. | ||
132 | - | */ | ||
133 | 9 | 4 | if (uid == euid) { | |
134 | 9 | 5,6 | if ((error = git__getenv(&env, "XDG_CONFIG_HOME")) == 0) | |
135 | ##### | 7 | error = git_buf_joinpath(out, env.ptr, "git"); | |
136 | - | |||
137 | 9 | 8-10 | if (error == GIT_ENOTFOUND && (error = git__getenv(&env, "HOME")) == 0) | |
138 | 9 | 11,12 | error = git_buf_joinpath(out, env.ptr, ".config/git"); | |
139 | - | } else { | ||
140 | ##### | 13,14 | if ((error = get_passwd_home(&env, euid)) == 0) | |
141 | ##### | 15 | error = git_buf_joinpath(out, env.ptr, ".config/git"); | |
142 | - | } | ||
143 | - | |||
144 | 9 | 16 | if (error == GIT_ENOTFOUND) { | |
145 | ##### | 17 | git_error_clear(); | |
146 | ##### | 18 | error = 0; | |
147 | - | } | ||
148 | - | |||
149 | 9 | 19 | git_buf_dispose(&env); | |
150 | 9 | 20 | return error; | |
151 | - | #endif | ||
152 | - | } | ||
153 | - | |||
154 | 9 | 2 | static int git_sysdir_guess_template_dirs(git_buf *out) | |
155 | - | { | ||
156 | - | #ifdef GIT_WIN32 | ||
157 | - | return git_win32__find_system_dirs(out, L"share\\git-core\\templates"); | ||
158 | - | #else | ||
159 | 9 | 2 | return git_buf_sets(out, "/usr/share/git-core/templates"); | |
160 | - | #endif | ||
161 | - | } | ||
162 | - | |||
163 | - | struct git_sysdir__dir { | ||
164 | - | git_buf buf; | ||
165 | - | int (*guess)(git_buf *out); | ||
166 | - | }; | ||
167 | - | |||
168 | - | static struct git_sysdir__dir git_sysdir__dirs[] = { | ||
169 | - | { GIT_BUF_INIT, git_sysdir_guess_system_dirs }, | ||
170 | - | { GIT_BUF_INIT, git_sysdir_guess_global_dirs }, | ||
171 | - | { GIT_BUF_INIT, git_sysdir_guess_xdg_dirs }, | ||
172 | - | { GIT_BUF_INIT, git_sysdir_guess_programdata_dirs }, | ||
173 | - | { GIT_BUF_INIT, git_sysdir_guess_template_dirs }, | ||
174 | - | }; | ||
175 | - | |||
176 | 9 | 2 | static void git_sysdir_global_shutdown(void) | |
177 | - | { | ||
178 | - | size_t i; | ||
179 | - | |||
180 | 54 | 2,4,5 | for (i = 0; i < ARRAY_SIZE(git_sysdir__dirs); ++i) | |
181 | 45 | 3 | git_buf_dispose(&git_sysdir__dirs[i].buf); | |
182 | 9 | 6 | } | |
183 | - | |||
184 | 9 | 2 | int git_sysdir_global_init(void) | |
185 | - | { | ||
186 | - | size_t i; | ||
187 | 9 | 2 | int error = 0; | |
188 | - | |||
189 | 54 | 2,4-6 | for (i = 0; !error && i < ARRAY_SIZE(git_sysdir__dirs); i++) | |
190 | 45 | 3 | error = git_sysdir__dirs[i].guess(&git_sysdir__dirs[i].buf); | |
191 | - | |||
192 | 9 | 7 | git__on_shutdown(git_sysdir_global_shutdown); | |
193 | - | |||
194 | 9 | 8 | return error; | |
195 | - | } | ||
196 | - | |||
197 | 119177 | 2 | static int git_sysdir_check_selector(git_sysdir_t which) | |
198 | - | { | ||
199 | 119177 | 2 | if (which < ARRAY_SIZE(git_sysdir__dirs)) | |
200 | 119177 | 3 | return 0; | |
201 | - | |||
202 | ##### | 4 | git_error_set(GIT_ERROR_INVALID, "config directory selector out of range"); | |
203 | ##### | 5 | return -1; | |
204 | - | } | ||
205 | - | |||
206 | - | |||
207 | 118806 | 2 | int git_sysdir_get(const git_buf **out, git_sysdir_t which) | |
208 | - | { | ||
209 | 118806 | 2,3 | assert(out); | |
210 | - | |||
211 | 118806 | 4 | *out = NULL; | |
212 | - | |||
213 | 118812 | 4-6 | GIT_ERROR_CHECK_ERROR(git_sysdir_check_selector(which)); | |
214 | - | |||
215 | 118812 | 7 | *out = &git_sysdir__dirs[which].buf; | |
216 | 118812 | 7 | return 0; | |
217 | - | } | ||
218 | - | |||
219 | - | #define PATH_MAGIC "$PATH" | ||
220 | - | |||
221 | 369 | 2 | int git_sysdir_set(git_sysdir_t which, const char *search_path) | |
222 | - | { | ||
223 | 369 | 2 | const char *expand_path = NULL; | |
224 | 369 | 2 | git_buf merge = GIT_BUF_INIT; | |
225 | - | |||
226 | 369 | 2-4 | GIT_ERROR_CHECK_ERROR(git_sysdir_check_selector(which)); | |
227 | - | |||
228 | 369 | 5 | if (search_path != NULL) | |
229 | 326 | 6 | expand_path = strstr(search_path, PATH_MAGIC); | |
230 | - | |||
231 | - | /* reset the default if this path has been cleared */ | ||
232 | 369 | 7 | if (!search_path) | |
233 | 43 | 8 | git_sysdir__dirs[which].guess(&git_sysdir__dirs[which].buf); | |
234 | - | |||
235 | - | /* if $PATH is not referenced, then just set the path */ | ||
236 | 369 | 9 | if (!expand_path) { | |
237 | 352 | 10 | if (search_path) | |
238 | 309 | 11 | git_buf_sets(&git_sysdir__dirs[which].buf, search_path); | |
239 | - | |||
240 | 352 | 12 | goto done; | |
241 | - | } | ||
242 | - | |||
243 | - | /* otherwise set to join(before $PATH, old value, after $PATH) */ | ||
244 | 17 | 13 | if (expand_path > search_path) | |
245 | 8 | 14 | git_buf_set(&merge, search_path, expand_path - search_path); | |
246 | - | |||
247 | 17 | 15,16 | if (git_buf_len(&git_sysdir__dirs[which].buf)) | |
248 | 17 | 17 | git_buf_join(&merge, GIT_PATH_LIST_SEPARATOR, | |
249 | 17 | 17 | merge.ptr, git_sysdir__dirs[which].buf.ptr); | |
250 | - | |||
251 | 17 | 18 | expand_path += strlen(PATH_MAGIC); | |
252 | 17 | 18 | if (*expand_path) | |
253 | 9 | 19 | git_buf_join(&merge, GIT_PATH_LIST_SEPARATOR, merge.ptr, expand_path); | |
254 | - | |||
255 | 17 | 20 | git_buf_swap(&git_sysdir__dirs[which].buf, &merge); | |
256 | 17 | 21 | git_buf_dispose(&merge); | |
257 | - | |||
258 | - | done: | ||
259 | 369 | 22,23 | if (git_buf_oom(&git_sysdir__dirs[which].buf)) | |
260 | ##### | 24 | return -1; | |
261 | - | |||
262 | 369 | 25 | return 0; | |
263 | - | } | ||
264 | - | |||
265 | - | 2 | suppressed: function cannot be solved git_sysdir_find_in_dirlist (automatic due to inconsistent arc counts in .gcda files)static int git_sysdir_find_in_dirlist( | |
266 | - | git_buf *path, | ||
267 | - | const char *name, | ||
268 | - | git_sysdir_t which, | ||
269 | - | const char *label) | ||
270 | - | { | ||
271 | - | size_t len; | ||
272 | - | 2 | suppressed: function cannot be solved git_sysdir_find_in_dirlist (automatic due to inconsistent arc counts in .gcda files) const char *scan, *next = NULL; | |
273 | - | const git_buf *syspath; | ||
274 | - | |||
275 | - | 2-4 | suppressed: function cannot be solved git_sysdir_find_in_dirlist (automatic due to inconsistent arc counts in .gcda files) GIT_ERROR_CHECK_ERROR(git_sysdir_get(&syspath, which)); | |
276 | - | 5-7 | suppressed: function cannot be solved git_sysdir_find_in_dirlist (automatic due to inconsistent arc counts in .gcda files) if (!syspath || !git_buf_len(syspath)) | |
277 | - | goto done; | ||
278 | - | |||
279 | - | 8,30,31 | suppressed: function cannot be solved git_sysdir_find_in_dirlist (automatic due to inconsistent arc counts in .gcda files) for (scan = git_buf_cstr(syspath); scan; scan = next) { | |
280 | - | /* find unescaped separator or end of string */ | ||
281 | - | 9,13,14 | suppressed: function cannot be solved git_sysdir_find_in_dirlist (automatic due to inconsistent arc counts in .gcda files) for (next = scan; *next; ++next) { | |
282 | - | 10,11 | suppressed: function cannot be solved git_sysdir_find_in_dirlist (automatic due to inconsistent arc counts in .gcda files) if (*next == GIT_PATH_LIST_SEPARATOR && | |
283 | - | 12 | suppressed: function cannot be solved git_sysdir_find_in_dirlist (automatic due to inconsistent arc counts in .gcda files) (next <= scan || next[-1] != '\\')) | |
284 | - | break; | ||
285 | - | } | ||
286 | - | |||
287 | - | 15 | suppressed: function cannot be solved git_sysdir_find_in_dirlist (automatic due to inconsistent arc counts in .gcda files) len = (size_t)(next - scan); | |
288 | - | 15-17 | suppressed: function cannot be solved git_sysdir_find_in_dirlist (automatic due to inconsistent arc counts in .gcda files) next = (*next ? next + 1 : NULL); | |
289 | - | 18 | suppressed: function cannot be solved git_sysdir_find_in_dirlist (automatic due to inconsistent arc counts in .gcda files) if (!len) | |
290 | - | 19 | suppressed: function cannot be solved git_sysdir_find_in_dirlist (automatic due to inconsistent arc counts in .gcda files) continue; | |
291 | - | |||
292 | - | 20-22 | suppressed: function cannot be solved git_sysdir_find_in_dirlist (automatic due to inconsistent arc counts in .gcda files) GIT_ERROR_CHECK_ERROR(git_buf_set(path, scan, len)); | |
293 | - | 23 | suppressed: function cannot be solved git_sysdir_find_in_dirlist (automatic due to inconsistent arc counts in .gcda files) if (name) | |
294 | - | 24-26 | suppressed: function cannot be solved git_sysdir_find_in_dirlist (automatic due to inconsistent arc counts in .gcda files) GIT_ERROR_CHECK_ERROR(git_buf_joinpath(path, path->ptr, name)); | |
295 | - | |||
296 | - | 27,28 | suppressed: function cannot be solved git_sysdir_find_in_dirlist (automatic due to inconsistent arc counts in .gcda files) if (git_path_exists(path->ptr)) | |
297 | - | 29 | suppressed: function cannot be solved git_sysdir_find_in_dirlist (automatic due to inconsistent arc counts in .gcda files) return 0; | |
298 | - | } | ||
299 | - | |||
300 | - | done: | ||
301 | - | 32 | suppressed: function cannot be solved git_sysdir_find_in_dirlist (automatic due to inconsistent arc counts in .gcda files) git_buf_dispose(path); | |
302 | - | 33 | suppressed: function cannot be solved git_sysdir_find_in_dirlist (automatic due to inconsistent arc counts in .gcda files) git_error_set(GIT_ERROR_OS, "the %s file '%s' doesn't exist", label, name); | |
303 | - | 34 | suppressed: function cannot be solved git_sysdir_find_in_dirlist (automatic due to inconsistent arc counts in .gcda files) return GIT_ENOTFOUND; | |
304 | - | } | ||
305 | - | |||
306 | 99751 | 2 | int git_sysdir_find_system_file(git_buf *path, const char *filename) | |
307 | - | { | ||
308 | 99751 | 2 | return git_sysdir_find_in_dirlist( | |
309 | - | path, filename, GIT_SYSDIR_SYSTEM, "system"); | ||
310 | - | } | ||
311 | - | |||
312 | 4184 | 2 | int git_sysdir_find_global_file(git_buf *path, const char *filename) | |
313 | - | { | ||
314 | 4184 | 2 | return git_sysdir_find_in_dirlist( | |
315 | - | path, filename, GIT_SYSDIR_GLOBAL, "global"); | ||
316 | - | } | ||
317 | - | |||
318 | 6646 | 2 | int git_sysdir_find_xdg_file(git_buf *path, const char *filename) | |
319 | - | { | ||
320 | 6646 | 2 | return git_sysdir_find_in_dirlist( | |
321 | - | path, filename, GIT_SYSDIR_XDG, "global/xdg"); | ||
322 | - | } | ||
323 | - | |||
324 | 4090 | 2 | int git_sysdir_find_programdata_file(git_buf *path, const char *filename) | |
325 | - | { | ||
326 | 4090 | 2 | return git_sysdir_find_in_dirlist( | |
327 | - | path, filename, GIT_SYSDIR_PROGRAMDATA, "ProgramData"); | ||
328 | - | } | ||
329 | - | |||
330 | ##### | 2 | int git_sysdir_find_template_dir(git_buf *path) | |
331 | - | { | ||
332 | ##### | 2 | return git_sysdir_find_in_dirlist( | |
333 | - | path, NULL, GIT_SYSDIR_TEMPLATE, "template"); | ||
334 | - | } | ||
335 | - | |||
336 | 9 | 2 | int git_sysdir_expand_global_file(git_buf *path, const char *filename) | |
337 | - | { | ||
338 | - | int error; | ||
339 | - | |||
340 | 9 | 2,3 | if ((error = git_sysdir_find_global_file(path, NULL)) == 0) { | |
341 | 9 | 4 | if (filename) | |
342 | 8 | 5 | error = git_buf_joinpath(path, path->ptr, filename); | |
343 | - | } | ||
344 | - | |||
345 | 9 | 6 | return error; | |
346 | - | } |