diff --git a/src/backend/postmaster/startup.c b/src/backend/postmaster/startup.c index d897cafb27..ec372b1356 100644 --- a/src/backend/postmaster/startup.c +++ b/src/backend/postmaster/startup.c @@ -132,7 +132,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 a85a1c6de5..b249048f61 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 9ff26c45c2..6742f5f744 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -805,6 +805,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(); @@ -929,6 +933,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 9dc7163a40..a4e1697e3f 100644 --- a/src/backend/utils/error/elog.c +++ b/src/backend/utils/error/elog.c @@ -3703,6 +3703,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; + } +} + + /* * is_log_level_output -- is elevel logically >= log_min_level? * diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h index 7a9ba7f2ff..70b3e1cdbd 100644 --- a/src/include/utils/elog.h +++ b/src/include/utils/elog.h @@ -413,4 +413,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 */