diff --git a/src/backend/access/transam/xlogarchive.c b/src/backend/access/transam/xlogarchive.c index b3f0602ffd..2d2812b59c 100644 --- a/src/backend/access/transam/xlogarchive.c +++ b/src/backend/access/transam/xlogarchive.c @@ -59,7 +59,6 @@ RestoreArchivedFile(char *path, const char *xlogfname, char *endp; const char *sp; int rc; - bool signaled; struct stat stat_buf; XLogSegNo restartSegNo; XLogRecPtr restartRedoPtr; @@ -289,17 +288,12 @@ RestoreArchivedFile(char *path, const char *xlogfname, * will perform an immediate shutdown when it sees us exiting * unexpectedly. * - * Per the Single Unix Spec, shells report exit status > 128 when a called - * command died on a signal. Also, 126 and 127 are used to report - * problems such as an unfindable command; treat those as fatal errors - * too. + * We treat hard shell errors such as "command not found" as fatal, too. */ - if (WIFSIGNALED(rc) && WTERMSIG(rc) == SIGTERM) + if (wait_result_is_signal(rc, SIGTERM)) proc_exit(1); - signaled = WIFSIGNALED(rc) || WEXITSTATUS(rc) > 125; - - ereport(signaled ? FATAL : DEBUG2, + ereport(wait_result_is_any_signal(rc, true) ? FATAL : DEBUG2, (errmsg("could not restore file \"%s\" from archive: %s", xlogfname, wait_result_to_str(rc)))); @@ -335,7 +329,6 @@ ExecuteRecoveryCommand(const char *command, const char *commandName, bool failOn char *endp; const char *sp; int rc; - bool signaled; XLogSegNo restartSegNo; XLogRecPtr restartRedoPtr; TimeLineID restartTli; @@ -403,12 +396,9 @@ ExecuteRecoveryCommand(const char *command, const char *commandName, bool failOn { /* * If the failure was due to any sort of signal, it's best to punt and - * abort recovery. See also detailed comments on signals in - * RestoreArchivedFile(). + * abort recovery. See comments in RestoreArchivedFile(). */ - signaled = WIFSIGNALED(rc) || WEXITSTATUS(rc) > 125; - - ereport((signaled && failOnSignal) ? FATAL : WARNING, + ereport((failOnSignal && wait_result_is_any_signal(rc, true)) ? FATAL : WARNING, /*------ translator: First %s represents a recovery.conf parameter name like "recovery_end_command", the 2nd is the value of that parameter, the diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index 8ce8ab2c2a..25d19a5118 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -17,7 +17,6 @@ #include #include #include -#include #include "access/heapam.h" #include "access/htup_details.h" @@ -1732,7 +1731,7 @@ ClosePipeToProgram(CopyState cstate) * problem. */ if (cstate->is_copy_from && !cstate->reached_eof && - WIFSIGNALED(pclose_rc) && WTERMSIG(pclose_rc) == SIGPIPE) + wait_result_is_signal(pclose_rc, SIGPIPE)) return; ereport(ERROR, diff --git a/src/backend/postmaster/pgarch.c b/src/backend/postmaster/pgarch.c index 885e85ad8a..e1497e599c 100644 --- a/src/backend/postmaster/pgarch.c +++ b/src/backend/postmaster/pgarch.c @@ -573,13 +573,11 @@ pgarch_archiveXlog(char *xlog) * If either the shell itself, or a called command, died on a signal, * abort the archiver. We do this because system() ignores SIGINT and * SIGQUIT while waiting; so a signal is very likely something that - * should have interrupted us too. If we overreact it's no big deal, - * the postmaster will just start the archiver again. - * - * Per the Single Unix Spec, shells report exit status > 128 when a - * called command died on a signal. + * should have interrupted us too. Also die if the shell got a hard + * "command not found" type of error. If we overreact it's no big + * deal, the postmaster will just start the archiver again. */ - int lev = (WIFSIGNALED(rc) || WEXITSTATUS(rc) > 128) ? FATAL : LOG; + int lev = wait_result_is_any_signal(rc, true) ? FATAL : LOG; if (WIFEXITED(rc)) { diff --git a/src/common/wait_error.c b/src/common/wait_error.c index 941b606999..27f5284998 100644 --- a/src/common/wait_error.c +++ b/src/common/wait_error.c @@ -82,3 +82,46 @@ wait_result_to_str(int exitstatus) return pstrdup(str); } + +/* + * Return true if a wait(2) result indicates that the child process + * died due to the specified signal. + * + * The reason this is worth having a wrapper function for is that + * there are two cases: the signal might have been received by our + * immediate child process, or there might've been a shell process + * between us and the child that died. The shell will, per POSIX, + * report the child death using exit code 128 + signal number. + * + * If there is no possibility of an intermediate shell, this function + * need not (and probably should not) be used. + */ +bool +wait_result_is_signal(int exit_status, int signum) +{ + if (WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum) + return true; + if (WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == 128 + signum) + return true; + return false; +} + +/* + * Return true if a wait(2) result indicates that the child process + * died due to any signal. We consider either direct child death + * or a shell report of child process death as matching the condition. + * + * If include_command_not_found is true, also return true for shell + * exit codes indicating "command not found" and the like + * (specifically, exit codes 126 and 127; see above). + */ +bool +wait_result_is_any_signal(int exit_status, bool include_command_not_found) +{ + if (WIFSIGNALED(exit_status)) + return true; + if (WIFEXITED(exit_status) && + WEXITSTATUS(exit_status) > (include_command_not_found ? 125 : 128)) + return true; + return false; +} diff --git a/src/include/port.h b/src/include/port.h index 0ce72e50e5..9f9253780e 100644 --- a/src/include/port.h +++ b/src/include/port.h @@ -464,5 +464,7 @@ extern char *escape_single_quotes_ascii(const char *src); /* port/wait_error.c */ extern char *wait_result_to_str(int exit_status); +extern bool wait_result_is_signal(int exit_status, int signum); +extern bool wait_result_is_any_signal(int exit_status, bool include_command_not_found); #endif /* PG_PORT_H */