aboutsummaryrefslogtreecommitdiff
path: root/src/common/wait_error.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2018-12-16 14:32:14 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2018-12-16 14:32:14 -0500
commitade2d61ed09c11a3d374a98c66c8a05cb82a0069 (patch)
tree3779ce740674d985ba824d3fa58af3c14021f571 /src/common/wait_error.c
parent5e09280057a4c3f5db297348ea3e044c9c5f4ef8 (diff)
downloadpostgresql-ade2d61ed09c11a3d374a98c66c8a05cb82a0069.tar.gz
postgresql-ade2d61ed09c11a3d374a98c66c8a05cb82a0069.zip
Improve detection of child-process SIGPIPE failures.
Commit ffa4cbd62 added logic to detect SIGPIPE failure of a COPY child process, but it only worked correctly if the SIGPIPE occurred in the immediate child process. Depending on the shell in use and the complexity of the shell command string, we might instead get back an exit code of 128 + SIGPIPE, representing a shell error exit reporting SIGPIPE in the child process. We could just hack up ClosePipeToProgram() to add the extra case, but it seems like this is a fairly general issue deserving a more general and better-documented solution. I chose to add a couple of functions in src/common/wait_error.c, which is a natural place to know about wait-result encodings, that will test for either a specific child-process signal type or any child-process signal failure. Then, adjust other places that were doing ad-hoc tests of this type to use the common functions. In RestoreArchivedFile, this fixes a race condition affecting whether the process will report an error or just silently proc_exit(1): before, that depended on whether the intermediate shell got SIGTERM'd itself or reported a child process failing on SIGTERM. Like the previous patch, back-patch to v10; we could go further but there seems no real need to. Per report from Erik Rijkers. Discussion: https://postgr.es/m/f3683f87ab1701bea5d86a7742b22432@xs4all.nl
Diffstat (limited to 'src/common/wait_error.c')
-rw-r--r--src/common/wait_error.c43
1 files changed, 43 insertions, 0 deletions
diff --git a/src/common/wait_error.c b/src/common/wait_error.c
index 941b606999b..27f52849982 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;
+}