Raw
1 #define USE_THE_REPOSITORY_VARIABLE
2
3 #include "git-compat-util.h"
4 #include "gettext.h"
5 #include "simple-ipc.h"
6 #include "fsmonitor-ipc.h"
7 #include "repository.h"
8 #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
19 int fsmonitor_ipc__is_supported(void)
20 {
21 return 0;
22 }
23
24 const char *fsmonitor_ipc__get_path(struct repository *r UNUSED)
25 {
26 return NULL;
27 }
28
29 enum ipc_active_state fsmonitor_ipc__get_state(void)
30 {
31 return IPC_STATE__OTHER_ERROR;
32 }
33
34 int fsmonitor_ipc__send_query(const char *since_token UNUSED,
35 struct strbuf *answer UNUSED)
36 {
37 return -1;
38 }
39
40 int fsmonitor_ipc__send_command(const char *command UNUSED,
41 struct strbuf *answer UNUSED)
42 {
43 return -1;
44 }
45
46 #else
47
48 int fsmonitor_ipc__is_supported(void)
49 {
50 return 1;
51 }
52
53 enum ipc_active_state fsmonitor_ipc__get_state(void)
54 {
55 return ipc_get_active_state(fsmonitor_ipc__get_path(the_repository));
56 }
57
58 static int spawn_daemon(void)
59 {
60 struct child_process cmd = CHILD_PROCESS_INIT;
61
62 cmd.git_cmd = 1;
63 cmd.no_stdin = 1;
64 cmd.no_stdout = 1;
65 cmd.no_stderr = 1;
66 cmd.close_fd_above_stderr = 1;
67 cmd.trace2_child_class = "fsmonitor";
68 strvec_pushl(&cmd.args, "fsmonitor--daemon", "start", NULL);
69
70 return run_command(&cmd);
71 }
72
73 int fsmonitor_ipc__send_query(const char *since_token,
74 struct strbuf *answer)
75 {
76 int ret = -1;
77 int tried_to_spawn = 0;
78 enum ipc_active_state state = IPC_STATE__OTHER_ERROR;
79 struct ipc_client_connection *connection = NULL;
80 struct ipc_client_connect_options options
81 = IPC_CLIENT_CONNECT_OPTIONS_INIT;
82 const char *tok = since_token ? since_token : "";
83 size_t tok_len = since_token ? strlen(since_token) : 0;
84
85 options.wait_if_busy = 1;
86 options.wait_if_not_found = 0;
87
88 trace2_region_enter("fsm_client", "query", NULL);
89 trace2_data_string("fsm_client", NULL, "query/command", tok);
90
91 try_again:
92 state = ipc_client_try_connect(fsmonitor_ipc__get_path(the_repository),
93 &options, &connection);
94
95 switch (state) {
96 case IPC_STATE__LISTENING:
97 ret = ipc_client_send_command_to_connection(
98 connection, tok, tok_len, answer);
99 ipc_client_close_connection(connection);
100
101 trace2_data_intmax("fsm_client", NULL,
102 "query/response-length", answer->len);
103 goto done;
104
105 case IPC_STATE__NOT_LISTENING:
106 case IPC_STATE__PATH_NOT_FOUND:
107 if (tried_to_spawn)
108 goto done;
109
110 tried_to_spawn++;
111 if (spawn_daemon())
112 goto done;
113
114 /*
115 * Try again, but this time give the daemon a chance to
116 * actually create the pipe/socket.
117 *
118 * Granted, the daemon just started so it can't possibly have
119 * any FS cached yet, so we'll always get a trivial answer.
120 * BUT the answer should include a new token that can serve
121 * as the basis for subsequent requests.
122 */
123 options.wait_if_not_found = 1;
124 goto try_again;
125
126 case IPC_STATE__INVALID_PATH:
127 ret = error(_("fsmonitor_ipc__send_query: invalid path '%s'"),
128 fsmonitor_ipc__get_path(the_repository));
129 goto done;
130
131 case IPC_STATE__OTHER_ERROR:
132 default:
133 ret = error(_("fsmonitor_ipc__send_query: unspecified error on '%s'"),
134 fsmonitor_ipc__get_path(the_repository));
135 goto done;
136 }
137
138 done:
139 trace2_region_leave("fsm_client", "query", NULL);
140
141 return ret;
142 }
143
144 int fsmonitor_ipc__send_command(const char *command,
145 struct strbuf *answer)
146 {
147 struct ipc_client_connection *connection = NULL;
148 struct ipc_client_connect_options options
149 = IPC_CLIENT_CONNECT_OPTIONS_INIT;
150 int ret;
151 enum ipc_active_state state;
152 const char *c = command ? command : "";
153 size_t c_len = command ? strlen(command) : 0;
154
155 strbuf_reset(answer);
156
157 options.wait_if_busy = 1;
158 options.wait_if_not_found = 0;
159
160 state = ipc_client_try_connect(fsmonitor_ipc__get_path(the_repository),
161 &options, &connection);
162 if (state != IPC_STATE__LISTENING) {
163 die(_("fsmonitor--daemon is not running"));
164 return -1;
165 }
166
167 ret = ipc_client_send_command_to_connection(connection, c, c_len,
168 answer);
169 ipc_client_close_connection(connection);
170
171 if (ret == -1) {
172 die(_("could not send '%s' command to fsmonitor--daemon"), c);
173 return -1;
174 }
175
176 return 0;
177 }
178
179 #endif