Hello
An automated claude review pointed out an issue caused by 2e2751e6976:
it removed the SIGCHLD reset from PostgresMain(), but that code also
ran for standalone backends, which never call InitPostmasterChild().
postgres --single now keeps whatever SIGCHLD disposition it inherited,
and if that is SIG_IGN, pclose() fails:
$ python3 -c 'import os,signal,sys; signal.signal(signal.SIGCHLD,
signal.SIG_IGN); os.execvp(sys.argv[1], sys.argv[1:])' \
postgres --single -D data postgres
backend> COPY (SELECT 1) TO PROGRAM 'cat > /dev/null';
ERROR: could not close pipe to external command: No child processes
The attached patch adds the same reset to InitStandaloneProcess().
From 16b6b1c181b1a49eef098fc65f4c928358f9d7b9 Mon Sep 17 00:00:00 2001
From: Zsolt Parragi <[email protected]>
Date: Thu, 12 Nov 2026 00:00:22 +0000
Subject: [PATCH v1] Reset SIGCHLD in standalone backends too
Commit 2e2751e6976 moved resetting SIGCHLD from PostgresMain() to
InitPostmasterChild(). But the reset in PostgresMain() also ran in
single-user mode, which doesn't call InitPostmasterChild(). If the
standalone backend was started with SIGCHLD ignored, children are now
reaped automatically, and e.g. COPY TO PROGRAM fails with "could not
close pipe to external command: No child processes".
To fix, reset it in InitStandaloneProcess() as well.
Discussion: https://www.postgresql.org/message-id/[email protected]
---
src/backend/utils/init/miscinit.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
index 27bafafcd86..e9c923df861 100644
--- a/src/backend/utils/init/miscinit.c
+++ b/src/backend/utils/init/miscinit.c
@@ -210,6 +210,12 @@ InitStandaloneProcess(const char *argv0)
pqinitmask();
sigprocmask(SIG_SETMASK, &BlockSig, NULL);
+ /*
+ * Reset SIGCHLD, in case we were started with it ignored. See
+ * InitPostmasterChild.
+ */
+ pqsignal(SIGCHLD, PG_SIG_DFL);
+
/* Compute paths, no postmaster to inherit from */
if (my_exec_path[0] == '\0')
{
--
2.56.0