builtin/maintenance: fix locking with "--detach"

When running git-maintenance(1), we create a lockfile that is supposed
to keep other maintenance processes from running at the same time. This
lockfile is broken though in case the "--detach" flag is passed: the
lockfile is created by the parent process and will be cleaned up either
manually or on exit. But when detaching, the parent will exit before all
of the background maintenance tasks have been run, and consequently the
lock only covers a smaller part of the whole maintenance process.

Fix this bug by reassigning all tempfiles from the parent process to the
child process when daemonizing so that it becomes the responsibility of
the child to clean them up.

Note that this is a broader fix, as we now always reassign tempfiles
when daemonizing. This is a natural consequence of the semantics of
`daemonize()` though, as it essentially promises to continue running the
current process in the background. It is thus sensible to have that
function perform the whole dance of assigning resources to the child
process, including tempfiles.

There's only a single other caller in "daemon.c", but that process
doesn't create any tempfiles before the call to `daemonize()` and is
thus not impacted by this change.

Reported-by: Jean-Christophe Manciot <actionmystique@gmail.com>
Helped-by: Jeff King <peff@peff.net>
Helped-by: Derrick Stolee <stolee@gmail.com>
Co-authored-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Patrick Steinhardt
2026-05-13 09:31:13 +02:00
committed by Junio C Hamano
parent 94f057755b
commit 6e95b07e5f
5 changed files with 111 additions and 1 deletions

16
setup.c
View File

@@ -2162,12 +2162,26 @@ int daemonize(void)
errno = ENOSYS;
return -1;
#else
switch (fork()) {
pid_t parent_pid = getpid();
pid_t child_pid = fork();
switch (child_pid) {
case 0:
/*
* We're in the child process, so we take ownership of
* all tempfiles.
*/
reassign_tempfile_ownership(parent_pid, getpid());
break;
case -1:
die_errno(_("fork failed"));
default:
/*
* We're in the parent process, so we drop ownership of
* all tempfiles to prevent us from removing them upon
* exit.
*/
reassign_tempfile_ownership(parent_pid, child_pid);
exit(0);
}
if (setsid() == -1)