Coverage Report

Created: 2026-09-28 06:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/git/fsmonitor-ipc.c
Line
Count
Source
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
0
{
50
0
  return 1;
51
0
}
52
53
enum ipc_active_state fsmonitor_ipc__get_state(void)
54
0
{
55
0
  return ipc_get_active_state(fsmonitor_ipc__get_path(the_repository));
56
0
}
57
58
static int spawn_daemon(void)
59
0
{
60
0
  struct child_process cmd = CHILD_PROCESS_INIT;
61
62
0
  cmd.git_cmd = 1;
63
0
  cmd.no_stdin = 1;
64
0
  cmd.no_stdout = 1;
65
0
  cmd.no_stderr = 1;
66
0
  cmd.close_fd_above_stderr = 1;
67
0
  cmd.trace2_child_class = "fsmonitor";
68
0
  strvec_pushl(&cmd.args, "fsmonitor--daemon", "start", NULL);
69
70
0
  return run_command(&cmd);
71
0
}
72
73
int fsmonitor_ipc__send_query(const char *since_token,
74
            struct strbuf *answer)
75
0
{
76
0
  int ret = -1;
77
0
  int tried_to_spawn = 0;
78
0
  enum ipc_active_state state = IPC_STATE__OTHER_ERROR;
79
0
  struct ipc_client_connection *connection = NULL;
80
0
  struct ipc_client_connect_options options
81
0
    = IPC_CLIENT_CONNECT_OPTIONS_INIT;
82
0
  const char *tok = since_token ? since_token : "";
83
0
  size_t tok_len = since_token ? strlen(since_token) : 0;
84
85
0
  options.wait_if_busy = 1;
86
0
  options.wait_if_not_found = 0;
87
88
0
  trace2_region_enter("fsm_client", "query", NULL);
89
0
  trace2_data_string("fsm_client", NULL, "query/command", tok);
90
91
0
try_again:
92
0
  state = ipc_client_try_connect(fsmonitor_ipc__get_path(the_repository),
93
0
            &options, &connection);
94
95
0
  switch (state) {
96
0
  case IPC_STATE__LISTENING:
97
0
    ret = ipc_client_send_command_to_connection(
98
0
      connection, tok, tok_len, answer);
99
0
    ipc_client_close_connection(connection);
100
101
0
    trace2_data_intmax("fsm_client", NULL,
102
0
           "query/response-length", answer->len);
103
0
    goto done;
104
105
0
  case IPC_STATE__NOT_LISTENING:
106
0
  case IPC_STATE__PATH_NOT_FOUND:
107
0
    if (tried_to_spawn)
108
0
      goto done;
109
110
0
    tried_to_spawn++;
111
0
    if (spawn_daemon())
112
0
      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
0
    options.wait_if_not_found = 1;
124
0
    goto try_again;
125
126
0
  case IPC_STATE__INVALID_PATH:
127
0
    ret = error(_("fsmonitor_ipc__send_query: invalid path '%s'"),
128
0
          fsmonitor_ipc__get_path(the_repository));
129
0
    goto done;
130
131
0
  case IPC_STATE__OTHER_ERROR:
132
0
  default:
133
0
    ret = error(_("fsmonitor_ipc__send_query: unspecified error on '%s'"),
134
0
          fsmonitor_ipc__get_path(the_repository));
135
0
    goto done;
136
0
  }
137
138
0
done:
139
0
  trace2_region_leave("fsm_client", "query", NULL);
140
141
0
  return ret;
142
0
}
143
144
int fsmonitor_ipc__send_command(const char *command,
145
        struct strbuf *answer)
146
0
{
147
0
  struct ipc_client_connection *connection = NULL;
148
0
  struct ipc_client_connect_options options
149
0
    = IPC_CLIENT_CONNECT_OPTIONS_INIT;
150
0
  int ret;
151
0
  enum ipc_active_state state;
152
0
  const char *c = command ? command : "";
153
0
  size_t c_len = command ? strlen(command) : 0;
154
155
0
  strbuf_reset(answer);
156
157
0
  options.wait_if_busy = 1;
158
0
  options.wait_if_not_found = 0;
159
160
0
  state = ipc_client_try_connect(fsmonitor_ipc__get_path(the_repository),
161
0
            &options, &connection);
162
0
  if (state != IPC_STATE__LISTENING) {
163
0
    die(_("fsmonitor--daemon is not running"));
164
0
    return -1;
165
0
  }
166
167
0
  ret = ipc_client_send_command_to_connection(connection, c, c_len,
168
0
                answer);
169
0
  ipc_client_close_connection(connection);
170
171
0
  if (ret == -1) {
172
0
    die(_("could not send '%s' command to fsmonitor--daemon"), c);
173
0
    return -1;
174
0
  }
175
176
0
  return 0;
177
0
}
178
179
#endif