From c88894602dc97d3c5d5194b86517a5da5d260612 Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Sun, 17 Dec 2006 19:08:20 +0000 Subject: tar: report error if child dies while writing out the end of tarball (e.g. out of disk space). --- archival/tar.c | 47 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 8 deletions(-) (limited to 'archival/tar.c') 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) -- cgit v1.2.3