177 lines
4.0 KiB
C
177 lines
4.0 KiB
C
#define USE_THE_REPOSITORY_VARIABLE
|
|
|
|
#include "git-compat-util.h"
|
|
#include "gettext.h"
|
|
#include "simple-ipc.h"
|
|
#include "fsmonitor-ipc.h"
|
|
#include "repository.h"
|
|
#include "run-command.h"
|
|
#include "strbuf.h"
|
|
#include "trace2.h"
|
|
|
|
#ifndef HAVE_FSMONITOR_DAEMON_BACKEND
|
|
|
|
/*
|
|
* A trivial implementation of the fsmonitor_ipc__ API for unsupported
|
|
* platforms.
|
|
*/
|
|
|
|
int fsmonitor_ipc__is_supported(void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
const char *fsmonitor_ipc__get_path(struct repository *r UNUSED)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
enum ipc_active_state fsmonitor_ipc__get_state(void)
|
|
{
|
|
return IPC_STATE__OTHER_ERROR;
|
|
}
|
|
|
|
int fsmonitor_ipc__send_query(const char *since_token UNUSED,
|
|
struct strbuf *answer UNUSED)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
int fsmonitor_ipc__send_command(const char *command UNUSED,
|
|
struct strbuf *answer UNUSED)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
#else
|
|
|
|
int fsmonitor_ipc__is_supported(void)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
enum ipc_active_state fsmonitor_ipc__get_state(void)
|
|
{
|
|
return ipc_get_active_state(fsmonitor_ipc__get_path(the_repository));
|
|
}
|
|
|
|
static int spawn_daemon(void)
|
|
{
|
|
struct child_process cmd = CHILD_PROCESS_INIT;
|
|
|
|
cmd.git_cmd = 1;
|
|
cmd.no_stdin = 1;
|
|
cmd.trace2_child_class = "fsmonitor";
|
|
strvec_pushl(&cmd.args, "fsmonitor--daemon", "start", NULL);
|
|
|
|
return run_command(&cmd);
|
|
}
|
|
|
|
int fsmonitor_ipc__send_query(const char *since_token,
|
|
struct strbuf *answer)
|
|
{
|
|
int ret = -1;
|
|
int tried_to_spawn = 0;
|
|
enum ipc_active_state state = IPC_STATE__OTHER_ERROR;
|
|
struct ipc_client_connection *connection = NULL;
|
|
struct ipc_client_connect_options options
|
|
= IPC_CLIENT_CONNECT_OPTIONS_INIT;
|
|
const char *tok = since_token ? since_token : "";
|
|
size_t tok_len = since_token ? strlen(since_token) : 0;
|
|
|
|
options.wait_if_busy = 1;
|
|
options.wait_if_not_found = 0;
|
|
|
|
trace2_region_enter("fsm_client", "query", NULL);
|
|
trace2_data_string("fsm_client", NULL, "query/command", tok);
|
|
|
|
try_again:
|
|
state = ipc_client_try_connect(fsmonitor_ipc__get_path(the_repository),
|
|
&options, &connection);
|
|
|
|
switch (state) {
|
|
case IPC_STATE__LISTENING:
|
|
ret = ipc_client_send_command_to_connection(
|
|
connection, tok, tok_len, answer);
|
|
ipc_client_close_connection(connection);
|
|
|
|
trace2_data_intmax("fsm_client", NULL,
|
|
"query/response-length", answer->len);
|
|
goto done;
|
|
|
|
case IPC_STATE__NOT_LISTENING:
|
|
case IPC_STATE__PATH_NOT_FOUND:
|
|
if (tried_to_spawn)
|
|
goto done;
|
|
|
|
tried_to_spawn++;
|
|
if (spawn_daemon())
|
|
goto done;
|
|
|
|
/*
|
|
* Try again, but this time give the daemon a chance to
|
|
* actually create the pipe/socket.
|
|
*
|
|
* Granted, the daemon just started so it can't possibly have
|
|
* any FS cached yet, so we'll always get a trivial answer.
|
|
* BUT the answer should include a new token that can serve
|
|
* as the basis for subsequent requests.
|
|
*/
|
|
options.wait_if_not_found = 1;
|
|
goto try_again;
|
|
|
|
case IPC_STATE__INVALID_PATH:
|
|
ret = error(_("fsmonitor_ipc__send_query: invalid path '%s'"),
|
|
fsmonitor_ipc__get_path(the_repository));
|
|
goto done;
|
|
|
|
case IPC_STATE__OTHER_ERROR:
|
|
default:
|
|
ret = error(_("fsmonitor_ipc__send_query: unspecified error on '%s'"),
|
|
fsmonitor_ipc__get_path(the_repository));
|
|
goto done;
|
|
}
|
|
|
|
done:
|
|
trace2_region_leave("fsm_client", "query", NULL);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int fsmonitor_ipc__send_command(const char *command,
|
|
struct strbuf *answer)
|
|
{
|
|
struct ipc_client_connection *connection = NULL;
|
|
struct ipc_client_connect_options options
|
|
= IPC_CLIENT_CONNECT_OPTIONS_INIT;
|
|
int ret;
|
|
enum ipc_active_state state;
|
|
const char *c = command ? command : "";
|
|
size_t c_len = command ? strlen(command) : 0;
|
|
|
|
strbuf_reset(answer);
|
|
|
|
options.wait_if_busy = 1;
|
|
options.wait_if_not_found = 0;
|
|
|
|
state = ipc_client_try_connect(fsmonitor_ipc__get_path(the_repository),
|
|
&options, &connection);
|
|
if (state != IPC_STATE__LISTENING) {
|
|
die(_("fsmonitor--daemon is not running"));
|
|
return -1;
|
|
}
|
|
|
|
ret = ipc_client_send_command_to_connection(connection, c, c_len,
|
|
answer);
|
|
ipc_client_close_connection(connection);
|
|
|
|
if (ret == -1) {
|
|
die(_("could not send '%s' command to fsmonitor--daemon"), c);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif
|