git/fsmonitor-ipc.c
Elijah Newren 68d686460f fsmonitor-ll.h: split this header out of fsmonitor.h
This creates a new fsmonitor-ll.h with most of the functions from
fsmonitor.h, though it leaves three inline functions where they were.
Two-thirds of the files that previously included fsmonitor.h did not
need those three inline functions or the six extra includes those inline
functions required, so this allows them to only include the lower level
header.

Diff best viewed with `--color-moved`.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2023-06-21 13:39:54 -07:00

175 lines
4 KiB
C

#include "git-compat-util.h"
#include "fsmonitor-ll.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)
{
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,
struct strbuf *answer)
{
return -1;
}
int fsmonitor_ipc__send_command(const char *command,
struct strbuf *answer)
{
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