summaryrefslogtreecommitdiffhomepage
path: root/archival
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2006-12-17 19:08:20 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2006-12-17 19:08:20 +0000
commitc88894602dc97d3c5d5194b86517a5da5d260612 (patch)
treef75b881c57bf9312b963d53e240b9c14fec3f972 /archival
parentb131b271a0d89b1ff04fd721530f424d0a15f0b2 (diff)
tar: report error if child dies while writing out the end of tarball
(e.g. out of disk space).
Diffstat (limited to 'archival')
-rw-r--r--archival/tar.c47
1 files changed, 39 insertions, 8 deletions
diff --git a/archival/tar.c b/archival/tar.c
index ba7cb0f8c..7465e881b 100644
--- a/archival/tar.c
+++ b/archival/tar.c
@@ -504,7 +504,6 @@ static int writeTarFile(const int tar_fd, const int verboseFlag,
volatile int vfork_exec_errno = 0;
char *zip_exec = (gzip == 1) ? "gzip" : "bzip2";
-
if (pipe(gzipDataPipe) < 0 || pipe(gzipStatusPipe) < 0)
bb_perror_msg_and_die("pipe");
@@ -585,10 +584,15 @@ static int writeTarFile(const int tar_fd, const int verboseFlag,
if (errorFlag)
bb_error_msg("error exit delayed from previous errors");
- if (gzipPid && waitpid(gzipPid, NULL, 0) == -1)
- bb_error_msg("waitpid failed");
-
- return !errorFlag;
+ if (gzipPid) {
+ int status;
+ if (waitpid(gzipPid, &status, 0) == -1)
+ bb_perror_msg("waitpid");
+ else if (!WIFEXITED(status) || WEXITSTATUS(status))
+ /* gzip was killed or has exited with nonzero! */
+ errorFlag = TRUE;
+ }
+ return errorFlag;
}
#else
int writeTarFile(const int tar_fd, const int verboseFlag,
@@ -650,6 +654,29 @@ static char get_header_tar_Z(archive_handle_t *archive_handle)
#define get_header_tar_Z 0
#endif
+#ifdef CHECK_FOR_CHILD_EXITCODE
+/* Looks like it isn't needed - tar detects malformed (truncated)
+ * archive if e.g. bunzip2 fails */
+static int child_error;
+
+static void handle_SIGCHLD(int status)
+{
+ /* Actually, 'status' is a signo. We reuse it for other needs */
+
+ /* Wait for any child without blocking */
+ if (waitpid(-1, &status, WNOHANG) < 0)
+ /* wait failed?! I'm confused... */
+ return;
+
+ if (WIFEXITED(status) && WEXITSTATUS(status)==0)
+ /* child exited with 0 */
+ return;
+ /* Cannot happen?
+ if(!WIFSIGNALED(status) && !WIFEXITED(status)) return; */
+ child_error = 1;
+}
+#endif
+
enum {
OPTBIT_KEEP_OLD = 7,
USE_FEATURE_TAR_CREATE( OPTBIT_CREATE ,)
@@ -862,6 +889,11 @@ int tar_main(int argc, char **argv)
if (base_dir)
xchdir(base_dir);
+#ifdef CHECK_FOR_CHILD_EXITCODE
+ /* We need to know whether child (gzip/bzip/etc) exits abnormally */
+ signal(SIGCHLD, handle_SIGCHLD);
+#endif
+
/* create an archive */
if (opt & OPT_CREATE) {
int zipMode = 0;
@@ -869,11 +901,10 @@ int tar_main(int argc, char **argv)
zipMode = 1;
if (ENABLE_FEATURE_TAR_BZIP2 && get_header_ptr == get_header_tar_bz2)
zipMode = 2;
- writeTarFile(tar_handle->src_fd, verboseFlag, opt & OPT_DEREFERENCE,
+ /* NB: writeTarFile() closes tar_handle->src_fd */
+ return writeTarFile(tar_handle->src_fd, verboseFlag, opt & OPT_DEREFERENCE,
tar_handle->accept,
tar_handle->reject, zipMode);
- /* NB: writeTarFile() closes tar_handle->src_fd */
- return EXIT_SUCCESS;
}
while (get_header_ptr(tar_handle) == EXIT_SUCCESS)