Coverage Report

Created: 2024-09-08 06:23

/src/git/fsmonitor-ipc.c
Line
Count
Source (jump to first uncovered line)
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
0
{
21
0
  return 0;
22
0
}
23
24
const char *fsmonitor_ipc__get_path(struct repository *r UNUSED)
25
0
{
26
0
  return NULL;
27
0
}
28
29
enum ipc_active_state fsmonitor_ipc__get_state(void)
30
0
{
31
0
  return IPC_STATE__OTHER_ERROR;
32
0
}
33
34
int fsmonitor_ipc__send_query(const char *since_token UNUSED,
35
            struct strbuf *answer UNUSED)
36
0
{
37
0
  return -1;
38
0
}
39
40
int fsmonitor_ipc__send_command(const char *command UNUSED,
41
        struct strbuf *answer UNUSED)
42
0
{
43
0
  return -1;
44
0
}
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.trace2_child_class = "fsmonitor";
65
  strvec_pushl(&cmd.args, "fsmonitor--daemon", "start", NULL);
66
67
  return run_command(&cmd);
68
}
69
70
int 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
88
try_again:
89
  state = ipc_client_try_connect(fsmonitor_ipc__get_path(the_repository),
90
            &options, &connection);
91
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'"),
125
          fsmonitor_ipc__get_path(the_repository));
126
    goto done;
127
128
  case IPC_STATE__OTHER_ERROR:
129
  default:
130
    ret = error(_("fsmonitor_ipc__send_query: unspecified error on '%s'"),
131
          fsmonitor_ipc__get_path(the_repository));
132
    goto done;
133
  }
134
135
done:
136
  trace2_region_leave("fsm_client", "query", NULL);
137
138
  return ret;
139
}
140
141
int 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
157
  state = ipc_client_try_connect(fsmonitor_ipc__get_path(the_repository),
158
            &options, &connection);
159
  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