blob: f1b163111194fb7c528e733366da7c280ce36456 [file] [log] [blame]
Patrick Steinhardte7da9382024-06-14 08:50:23 +02001#define USE_THE_REPOSITORY_VARIABLE
2
Elijah Newrenbc5c5ec2023-05-16 06:33:57 +00003#include "git-compat-util.h"
Elijah Newrenf394e092023-03-21 06:25:54 +00004#include "gettext.h"
Jeff Hostetlerd2bd8622022-03-25 18:02:45 +00005#include "simple-ipc.h"
6#include "fsmonitor-ipc.h"
Elijah Newrend1cbe1e2023-04-22 20:17:20 +00007#include "repository.h"
Jeff Hostetlerd2bd8622022-03-25 18:02:45 +00008#include "run-command.h"
9#include "strbuf.h"
10#include "trace2.h"
11
12#ifndef HAVE_FSMONITOR_DAEMON_BACKEND
13
14/*
15 * A trivial implementation of the fsmonitor_ipc__ API for unsupported
16 * platforms.
17 */
18
19int fsmonitor_ipc__is_supported(void)
20{
21 return 0;
22}
23
Jeff King4cb5e0b2023-09-18 18:32:38 -040024const char *fsmonitor_ipc__get_path(struct repository *r UNUSED)
Jeff Hostetlerd2bd8622022-03-25 18:02:45 +000025{
26 return NULL;
27}
28
29enum ipc_active_state fsmonitor_ipc__get_state(void)
30{
31 return IPC_STATE__OTHER_ERROR;
32}
33
Jeff King4cb5e0b2023-09-18 18:32:38 -040034int fsmonitor_ipc__send_query(const char *since_token UNUSED,
35 struct strbuf *answer UNUSED)
Jeff Hostetlerd2bd8622022-03-25 18:02:45 +000036{
37 return -1;
38}
39
Jeff King4cb5e0b2023-09-18 18:32:38 -040040int fsmonitor_ipc__send_command(const char *command UNUSED,
41 struct strbuf *answer UNUSED)
Jeff Hostetlerd2bd8622022-03-25 18:02:45 +000042{
43 return -1;
44}
45
46#else
47
48int fsmonitor_ipc__is_supported(void)
49{
50 return 1;
51}
52
Jeff Hostetlerd2bd8622022-03-25 18:02:45 +000053enum ipc_active_state fsmonitor_ipc__get_state(void)
54{
Eric DeCosta6beb2682022-10-04 17:32:27 +000055 return ipc_get_active_state(fsmonitor_ipc__get_path(the_repository));
Jeff Hostetlerd2bd8622022-03-25 18:02:45 +000056}
57
58static int spawn_daemon(void)
59{
René Scharfed82dbbd2022-10-30 12:52:40 +010060 struct child_process cmd = CHILD_PROCESS_INIT;
Jeff Hostetlerd2bd8622022-03-25 18:02:45 +000061
René Scharfed82dbbd2022-10-30 12:52:40 +010062 cmd.git_cmd = 1;
63 cmd.no_stdin = 1;
64 cmd.trace2_child_class = "fsmonitor";
65 strvec_pushl(&cmd.args, "fsmonitor--daemon", "start", NULL);
66
67 return run_command(&cmd);
Jeff Hostetlerd2bd8622022-03-25 18:02:45 +000068}
69
70int fsmonitor_ipc__send_query(const char *since_token,
71 struct strbuf *answer)
72{
73 int ret = -1;
74 int tried_to_spawn = 0;
75 enum ipc_active_state state = IPC_STATE__OTHER_ERROR;
76 struct ipc_client_connection *connection = NULL;
77 struct ipc_client_connect_options options
78 = IPC_CLIENT_CONNECT_OPTIONS_INIT;
79 const char *tok = since_token ? since_token : "";
80 size_t tok_len = since_token ? strlen(since_token) : 0;
81
82 options.wait_if_busy = 1;
83 options.wait_if_not_found = 0;
84
85 trace2_region_enter("fsm_client", "query", NULL);
86 trace2_data_string("fsm_client", NULL, "query/command", tok);
87
88try_again:
Eric DeCosta6beb2682022-10-04 17:32:27 +000089 state = ipc_client_try_connect(fsmonitor_ipc__get_path(the_repository),
90 &options, &connection);
Jeff Hostetlerd2bd8622022-03-25 18:02:45 +000091
92 switch (state) {
93 case IPC_STATE__LISTENING:
94 ret = ipc_client_send_command_to_connection(
95 connection, tok, tok_len, answer);
96 ipc_client_close_connection(connection);
97
98 trace2_data_intmax("fsm_client", NULL,
99 "query/response-length", answer->len);
100 goto done;
101
102 case IPC_STATE__NOT_LISTENING:
103 case IPC_STATE__PATH_NOT_FOUND:
104 if (tried_to_spawn)
105 goto done;
106
107 tried_to_spawn++;
108 if (spawn_daemon())
109 goto done;
110
111 /*
112 * Try again, but this time give the daemon a chance to
113 * actually create the pipe/socket.
114 *
115 * Granted, the daemon just started so it can't possibly have
116 * any FS cached yet, so we'll always get a trivial answer.
117 * BUT the answer should include a new token that can serve
118 * as the basis for subsequent requests.
119 */
120 options.wait_if_not_found = 1;
121 goto try_again;
122
123 case IPC_STATE__INVALID_PATH:
124 ret = error(_("fsmonitor_ipc__send_query: invalid path '%s'"),
Eric DeCosta6beb2682022-10-04 17:32:27 +0000125 fsmonitor_ipc__get_path(the_repository));
Jeff Hostetlerd2bd8622022-03-25 18:02:45 +0000126 goto done;
127
128 case IPC_STATE__OTHER_ERROR:
129 default:
130 ret = error(_("fsmonitor_ipc__send_query: unspecified error on '%s'"),
Eric DeCosta6beb2682022-10-04 17:32:27 +0000131 fsmonitor_ipc__get_path(the_repository));
Jeff Hostetlerd2bd8622022-03-25 18:02:45 +0000132 goto done;
133 }
134
135done:
136 trace2_region_leave("fsm_client", "query", NULL);
137
138 return ret;
139}
140
141int fsmonitor_ipc__send_command(const char *command,
142 struct strbuf *answer)
143{
144 struct ipc_client_connection *connection = NULL;
145 struct ipc_client_connect_options options
146 = IPC_CLIENT_CONNECT_OPTIONS_INIT;
147 int ret;
148 enum ipc_active_state state;
149 const char *c = command ? command : "";
150 size_t c_len = command ? strlen(command) : 0;
151
152 strbuf_reset(answer);
153
154 options.wait_if_busy = 1;
155 options.wait_if_not_found = 0;
156
Eric DeCosta6beb2682022-10-04 17:32:27 +0000157 state = ipc_client_try_connect(fsmonitor_ipc__get_path(the_repository),
158 &options, &connection);
Jeff Hostetlerd2bd8622022-03-25 18:02:45 +0000159 if (state != IPC_STATE__LISTENING) {
160 die(_("fsmonitor--daemon is not running"));
161 return -1;
162 }
163
164 ret = ipc_client_send_command_to_connection(connection, c, c_len,
165 answer);
166 ipc_client_close_connection(connection);
167
168 if (ret == -1) {
169 die(_("could not send '%s' command to fsmonitor--daemon"), c);
170 return -1;
171 }
172
173 return 0;
174}
175
176#endif