diff --git a/src/backend/postmaster/startup.c b/src/backend/postmaster/startup.c index 69077bd2075..c3f5e18b9c9 100644 --- a/src/backend/postmaster/startup.c +++ b/src/backend/postmaster/startup.c @@ -19,6 +19,8 @@ */ #include "postgres.h" +#include + #include "access/xlog.h" #include "libpq/pqsignal.h" #include "miscadmin.h" @@ -102,7 +104,20 @@ StartupProcShutdownHandler(SIGNAL_ARGS) int save_errno = errno; if (in_restore_command) - proc_exit(1); + { + /* + * If we are in a child process (e.g., forked by system() in + * RestoreArchivedFile()), we don't want to call any exit callbacks. + * The parent will take care of that. + */ + if (MyProcPid == (int) getpid()) + proc_exit(1); + else + { + write_stderr_signal_safe("StartupProcShutdownHandler() called in child process\n"); + _exit(1); + } + } else shutdown_requested = true; WakeupRecovery(); diff --git a/src/backend/storage/ipc/ipc.c b/src/backend/storage/ipc/ipc.c index 4045d7d68a0..df89a28d2ff 100644 --- a/src/backend/storage/ipc/ipc.c +++ b/src/backend/storage/ipc/ipc.c @@ -103,6 +103,10 @@ static int on_proc_exit_index, void proc_exit(int code) { + /* not safe if forked by system(), etc. */ + if (MyProcPid != (int) getpid()) + elog(PANIC, "proc_exit() called in child process"); + /* Clean up everything that must be cleaned up */ proc_exit_prepare(code); diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index f323228602f..1e06d6580ce 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -826,6 +826,10 @@ ProcKill(int code, Datum arg) Assert(MyProc != NULL); + /* not safe if forked by system(), etc. */ + if (MyProc->pid != (int) getpid()) + elog(PANIC, "ProcKill() called in child process"); + /* Make sure we're out of the sync rep lists */ SyncRepCleanupAtProcExit(); @@ -955,6 +959,10 @@ AuxiliaryProcKill(int code, Datum arg) Assert(proctype >= 0 && proctype < NUM_AUXILIARY_PROCS); + /* not safe if forked by system(), etc. */ + if (MyProc->pid != (int) getpid()) + elog(PANIC, "AuxiliaryProcKill() called in child process"); + auxproc = &AuxiliaryProcs[proctype]; Assert(MyProc == auxproc); diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c index a3e1c59a829..001b87ea999 100644 --- a/src/backend/utils/error/elog.c +++ b/src/backend/utils/error/elog.c @@ -3590,6 +3590,34 @@ write_stderr(const char *fmt,...) } +/* + * Write a message to STDERR using only async-signal-safe functions. This can + * be used to safely emit a message from a signal handler. + * + * TODO: It is likely possible to safely do a limited amount of string + * interpolation (e.g., %s and %d), but that is not presently supported. + */ +void +write_stderr_signal_safe(const char *str) +{ + int nwritten = 0; + int ntotal = strlen(str); + + while (nwritten < ntotal) + { + int rc; + + rc = write(STDERR_FILENO, str + nwritten, ntotal - nwritten); + + /* Just give up on error. There isn't much else we can do. */ + if (rc == -1) + return; + + nwritten += rc; + } +} + + /* * Adjust the level of a recovery-related message per trace_recovery_messages. * diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h index f53607e12eb..f98a1e8b629 100644 --- a/src/include/utils/elog.h +++ b/src/include/utils/elog.h @@ -453,4 +453,10 @@ extern void set_syslog_parameters(const char *ident, int facility); */ extern void write_stderr(const char *fmt,...) pg_attribute_printf(1, 2); +/* + * Write a message to STDERR using only async-signal-safe functions. This can + * be used to safely emit a message from a signal handler. + */ +extern void write_stderr_signal_safe(const char *fmt); + #endif /* ELOG_H */