]> git.ipfire.org Git - thirdparty/git.git/blame - fsmonitor-settings.c
Sync with 2.38.5
[thirdparty/git.git] / fsmonitor-settings.c
CommitLineData
1e0ea5c4
JH
1#include "cache.h"
2#include "config.h"
3#include "repository.h"
25c2cab0 4#include "fsmonitor-ipc.h"
1e0ea5c4 5#include "fsmonitor-settings.h"
508c1a57 6#include "fsmonitor-path-utils.h"
1e0ea5c4
JH
7
8/*
9 * We keep this structure defintion private and have getters
10 * for all fields so that we can lazy load it as needed.
11 */
12struct fsmonitor_settings {
13 enum fsmonitor_mode mode;
62a62a28 14 enum fsmonitor_reason reason;
1e0ea5c4
JH
15 char *hook_path;
16};
17
508c1a57
ED
18/*
19 * Remote working directories are problematic for FSMonitor.
20 *
21 * The underlying file system on the server machine and/or the remote
22 * mount type dictates whether notification events are available at
23 * all to remote client machines.
24 *
25 * Kernel differences between the server and client machines also
26 * dictate the how (buffering, frequency, de-dup) the events are
27 * delivered to client machine processes.
28 *
29 * A client machine (such as a laptop) may choose to suspend/resume
30 * and it is unclear (without lots of testing) whether the watcher can
31 * resync after a resume. We might be able to treat this as a normal
32 * "events were dropped by the kernel" event and do our normal "flush
33 * and resync" --or-- we might need to close the existing (zombie?)
34 * notification fd and create a new one.
35 *
36 * In theory, the above issues need to be addressed whether we are
37 * using the Hook or IPC API.
38 *
39 * So (for now at least), mark remote working directories as
40 * incompatible unless 'fsmonitor.allowRemote' is true.
41 *
42 */
43#ifdef HAVE_FSMONITOR_OS_SETTINGS
44static enum fsmonitor_reason check_remote(struct repository *r)
45{
46 int allow_remote = -1; /* -1 unset, 0 not allowed, 1 allowed */
47 int is_remote = fsmonitor__is_fs_remote(r->worktree);
48
49 switch (is_remote) {
50 case 0:
51 return FSMONITOR_REASON_OK;
52 case 1:
53 repo_config_get_bool(r, "fsmonitor.allowremote", &allow_remote);
54 if (allow_remote < 1)
55 return FSMONITOR_REASON_REMOTE;
56 else
57 return FSMONITOR_REASON_OK;
58 default:
59 return FSMONITOR_REASON_ERROR;
60 }
61}
62#endif
63
8f449768 64static enum fsmonitor_reason check_for_incompatible(struct repository *r, int ipc)
62a62a28
JH
65{
66 if (!r->worktree) {
67 /*
68 * Bare repositories don't have a working directory and
69 * therefore have nothing to watch.
70 */
71 return FSMONITOR_REASON_BARE;
72 }
73
d33c804d
JH
74#ifdef HAVE_FSMONITOR_OS_SETTINGS
75 {
76 enum fsmonitor_reason reason;
77
508c1a57
ED
78 reason = check_remote(r);
79 if (reason != FSMONITOR_REASON_OK)
80 return reason;
8f449768 81 reason = fsm_os__incompatible(r, ipc);
d33c804d
JH
82 if (reason != FSMONITOR_REASON_OK)
83 return reason;
84 }
85#endif
86
62a62a28
JH
87 return FSMONITOR_REASON_OK;
88}
89
90static struct fsmonitor_settings *alloc_settings(void)
1e0ea5c4
JH
91{
92 struct fsmonitor_settings *s;
62a62a28
JH
93
94 CALLOC_ARRAY(s, 1);
95 s->mode = FSMONITOR_MODE_DISABLED;
96 s->reason = FSMONITOR_REASON_UNTESTED;
97
98 return s;
99}
100
101static void lookup_fsmonitor_settings(struct repository *r)
102{
1e0ea5c4
JH
103 const char *const_str;
104 int bool_value;
105
106 if (r->settings.fsmonitor)
107 return;
108
1e0ea5c4
JH
109 /*
110 * Overload the existing "core.fsmonitor" config setting (which
111 * has historically been either unset or a hook pathname) to
112 * now allow a boolean value to enable the builtin FSMonitor
113 * or to turn everything off. (This does imply that you can't
114 * use a hook script named "true" or "false", but that's OK.)
115 */
116 switch (repo_config_get_maybe_bool(r, "core.fsmonitor", &bool_value)) {
117
118 case 0: /* config value was set to <bool> */
119 if (bool_value)
120 fsm_settings__set_ipc(r);
62a62a28
JH
121 else
122 fsm_settings__set_disabled(r);
1e0ea5c4
JH
123 return;
124
125 case 1: /* config value was unset */
126 const_str = getenv("GIT_TEST_FSMONITOR");
127 break;
128
129 case -1: /* config value set to an arbitrary string */
130 if (repo_config_get_pathname(r, "core.fsmonitor", &const_str))
131 return; /* should not happen */
132 break;
133
134 default: /* should not happen */
135 return;
136 }
137
62a62a28
JH
138 if (const_str && *const_str)
139 fsm_settings__set_hook(r, const_str);
140 else
141 fsm_settings__set_disabled(r);
1e0ea5c4
JH
142}
143
144enum fsmonitor_mode fsm_settings__get_mode(struct repository *r)
145{
146 if (!r)
147 r = the_repository;
62a62a28
JH
148 if (!r->settings.fsmonitor)
149 lookup_fsmonitor_settings(r);
1e0ea5c4
JH
150
151 return r->settings.fsmonitor->mode;
152}
153
154const char *fsm_settings__get_hook_path(struct repository *r)
155{
156 if (!r)
157 r = the_repository;
62a62a28
JH
158 if (!r->settings.fsmonitor)
159 lookup_fsmonitor_settings(r);
1e0ea5c4
JH
160
161 return r->settings.fsmonitor->hook_path;
162}
163
164void fsm_settings__set_ipc(struct repository *r)
165{
8f449768 166 enum fsmonitor_reason reason = check_for_incompatible(r, 1);
62a62a28
JH
167
168 if (reason != FSMONITOR_REASON_OK) {
169 fsm_settings__set_incompatible(r, reason);
170 return;
171 }
172
173 /*
174 * Caller requested IPC explicitly, so avoid (possibly
175 * recursive) config lookup.
176 */
1e0ea5c4
JH
177 if (!r)
178 r = the_repository;
62a62a28
JH
179 if (!r->settings.fsmonitor)
180 r->settings.fsmonitor = alloc_settings();
1e0ea5c4
JH
181
182 r->settings.fsmonitor->mode = FSMONITOR_MODE_IPC;
62a62a28 183 r->settings.fsmonitor->reason = reason;
1e0ea5c4
JH
184 FREE_AND_NULL(r->settings.fsmonitor->hook_path);
185}
186
187void fsm_settings__set_hook(struct repository *r, const char *path)
188{
8f449768 189 enum fsmonitor_reason reason = check_for_incompatible(r, 0);
62a62a28
JH
190
191 if (reason != FSMONITOR_REASON_OK) {
192 fsm_settings__set_incompatible(r, reason);
193 return;
194 }
195
196 /*
197 * Caller requested hook explicitly, so avoid (possibly
198 * recursive) config lookup.
199 */
1e0ea5c4
JH
200 if (!r)
201 r = the_repository;
62a62a28
JH
202 if (!r->settings.fsmonitor)
203 r->settings.fsmonitor = alloc_settings();
1e0ea5c4
JH
204
205 r->settings.fsmonitor->mode = FSMONITOR_MODE_HOOK;
62a62a28 206 r->settings.fsmonitor->reason = reason;
1e0ea5c4
JH
207 FREE_AND_NULL(r->settings.fsmonitor->hook_path);
208 r->settings.fsmonitor->hook_path = strdup(path);
209}
210
211void fsm_settings__set_disabled(struct repository *r)
212{
213 if (!r)
214 r = the_repository;
62a62a28
JH
215 if (!r->settings.fsmonitor)
216 r->settings.fsmonitor = alloc_settings();
1e0ea5c4
JH
217
218 r->settings.fsmonitor->mode = FSMONITOR_MODE_DISABLED;
62a62a28
JH
219 r->settings.fsmonitor->reason = FSMONITOR_REASON_OK;
220 FREE_AND_NULL(r->settings.fsmonitor->hook_path);
221}
222
223void fsm_settings__set_incompatible(struct repository *r,
224 enum fsmonitor_reason reason)
225{
226 if (!r)
227 r = the_repository;
228 if (!r->settings.fsmonitor)
229 r->settings.fsmonitor = alloc_settings();
230
231 r->settings.fsmonitor->mode = FSMONITOR_MODE_INCOMPATIBLE;
232 r->settings.fsmonitor->reason = reason;
1e0ea5c4
JH
233 FREE_AND_NULL(r->settings.fsmonitor->hook_path);
234}
62a62a28
JH
235
236enum fsmonitor_reason fsm_settings__get_reason(struct repository *r)
237{
238 if (!r)
239 r = the_repository;
240 if (!r->settings.fsmonitor)
241 lookup_fsmonitor_settings(r);
242
243 return r->settings.fsmonitor->reason;
244}
245
25c2cab0 246char *fsm_settings__get_incompatible_msg(struct repository *r,
62a62a28
JH
247 enum fsmonitor_reason reason)
248{
249 struct strbuf msg = STRBUF_INIT;
25c2cab0 250 const char *socket_dir;
62a62a28
JH
251
252 switch (reason) {
253 case FSMONITOR_REASON_UNTESTED:
254 case FSMONITOR_REASON_OK:
255 goto done;
256
5a09991e
JS
257 case FSMONITOR_REASON_BARE: {
258 char *cwd = xgetcwd();
259
62a62a28
JH
260 strbuf_addf(&msg,
261 _("bare repository '%s' is incompatible with fsmonitor"),
5a09991e
JS
262 cwd);
263 free(cwd);
62a62a28 264 goto done;
5a09991e 265 }
5c58fbd2 266
1e7be10d
JH
267 case FSMONITOR_REASON_ERROR:
268 strbuf_addf(&msg,
269 _("repository '%s' is incompatible with fsmonitor due to errors"),
270 r->worktree);
271 goto done;
272
273 case FSMONITOR_REASON_REMOTE:
274 strbuf_addf(&msg,
275 _("remote repository '%s' is incompatible with fsmonitor"),
276 r->worktree);
277 goto done;
278
5c58fbd2
JH
279 case FSMONITOR_REASON_VFS4GIT:
280 strbuf_addf(&msg,
281 _("virtual repository '%s' is incompatible with fsmonitor"),
282 r->worktree);
283 goto done;
ddc5dacf
JH
284
285 case FSMONITOR_REASON_NOSOCKETS:
25c2cab0 286 socket_dir = dirname((char *)fsmonitor_ipc__get_path(r));
ddc5dacf 287 strbuf_addf(&msg,
25c2cab0
ED
288 _("socket directory '%s' is incompatible with fsmonitor due"
289 " to lack of Unix sockets support"),
290 socket_dir);
ddc5dacf 291 goto done;
62a62a28
JH
292 }
293
294 BUG("Unhandled case in fsm_settings__get_incompatible_msg: '%d'",
295 reason);
296
297done:
298 return strbuf_detach(&msg, NULL);
299}