]> git.ipfire.org Git - thirdparty/git.git/commitdiff
fsmonitor: close inherited file descriptors and detach in daemon
authorPaul Tarjan <github@paulisageek.com>
Thu, 9 Apr 2026 04:59:32 +0000 (04:59 +0000)
committerJunio C Hamano <gitster@pobox.com>
Thu, 9 Apr 2026 17:59:28 +0000 (10:59 -0700)
When the fsmonitor daemon is spawned as a background process, it may
inherit file descriptors from its parent that it does not need.  In
particular, when the test harness or a CI system captures output through
pipes, the daemon can inherit duplicated pipe endpoints.  If the daemon
holds these open, the parent process never sees EOF and may appear to
hang.

Set close_fd_above_stderr on the child process at both daemon startup
paths: the explicit "fsmonitor--daemon start" command and the implicit
spawn triggered by fsmonitor-ipc when a client finds no running daemon.
Also suppress stdout and stderr on the implicit spawn path to prevent
the background daemon from writing to the client's terminal.

Additionally, call setsid() when the daemon starts with --detach to
create a new session and process group.  This prevents the daemon
from being part of the spawning shell's process group, which could
cause the shell's "wait" to block until the daemon exits.

Signed-off-by: Paul Tarjan <github@paulisageek.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/fsmonitor--daemon.c
fsmonitor-ipc.c

index c8ec7b722e953e0ff7d285d78a54d50aa9e229f6..b2a816dc3fea5ecf38b57a93a9b56dfad2323c3f 100644 (file)
@@ -1439,7 +1439,7 @@ done:
        return err;
 }
 
-static int try_to_run_foreground_daemon(int detach_console MAYBE_UNUSED)
+static int try_to_run_foreground_daemon(int detach_console)
 {
        /*
         * Technically, we don't need to probe for an existing daemon
@@ -1459,10 +1459,21 @@ static int try_to_run_foreground_daemon(int detach_console MAYBE_UNUSED)
                fflush(stderr);
        }
 
+       if (detach_console) {
 #ifdef GIT_WINDOWS_NATIVE
-       if (detach_console)
                FreeConsole();
+#else
+               /*
+                * Create a new session so that the daemon is detached
+                * from the parent's process group.  This prevents
+                * shells with job control (e.g. bash with "set -m")
+                * from waiting on the daemon when they wait for a
+                * foreground command that implicitly spawned it.
+                */
+               if (setsid() == -1)
+                       warning_errno(_("setsid failed"));
 #endif
+       }
 
        return !!fsmonitor_run_daemon();
 }
@@ -1525,6 +1536,7 @@ static int try_to_start_background_daemon(void)
        cp.no_stdin = 1;
        cp.no_stdout = 1;
        cp.no_stderr = 1;
+       cp.close_fd_above_stderr = 1;
 
        sbgr = start_bg_command(&cp, bg_wait_cb, NULL,
                                fsmonitor__start_timeout_sec);
index f1b163111194fb7c528e733366da7c280ce36456..6112d130644f04d970c60b0b71203d7603fd2482 100644 (file)
@@ -61,6 +61,9 @@ static int spawn_daemon(void)
 
        cmd.git_cmd = 1;
        cmd.no_stdin = 1;
+       cmd.no_stdout = 1;
+       cmd.no_stderr = 1;
+       cmd.close_fd_above_stderr = 1;
        cmd.trace2_child_class = "fsmonitor";
        strvec_pushl(&cmd.args, "fsmonitor--daemon", "start", NULL);