| #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 |