diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2006-12-17 19:08:20 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2006-12-17 19:08:20 +0000 |
commit | c88894602dc97d3c5d5194b86517a5da5d260612 (patch) | |
tree | f75b881c57bf9312b963d53e240b9c14fec3f972 | |
parent | b131b271a0d89b1ff04fd721530f424d0a15f0b2 (diff) | |
download | busybox-w32-c88894602dc97d3c5d5194b86517a5da5d260612.tar.gz busybox-w32-c88894602dc97d3c5d5194b86517a5da5d260612.tar.bz2 busybox-w32-c88894602dc97d3c5d5194b86517a5da5d260612.zip |
tar: report error if child dies while writing out the end of tarball
(e.g. out of disk space).
-rw-r--r-- | archival/tar.c | 47 |
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, | |||
504 | volatile int vfork_exec_errno = 0; | 504 | volatile int vfork_exec_errno = 0; |
505 | char *zip_exec = (gzip == 1) ? "gzip" : "bzip2"; | 505 | char *zip_exec = (gzip == 1) ? "gzip" : "bzip2"; |
506 | 506 | ||
507 | |||
508 | if (pipe(gzipDataPipe) < 0 || pipe(gzipStatusPipe) < 0) | 507 | if (pipe(gzipDataPipe) < 0 || pipe(gzipStatusPipe) < 0) |
509 | bb_perror_msg_and_die("pipe"); | 508 | bb_perror_msg_and_die("pipe"); |
510 | 509 | ||
@@ -585,10 +584,15 @@ static int writeTarFile(const int tar_fd, const int verboseFlag, | |||
585 | if (errorFlag) | 584 | if (errorFlag) |
586 | bb_error_msg("error exit delayed from previous errors"); | 585 | bb_error_msg("error exit delayed from previous errors"); |
587 | 586 | ||
588 | if (gzipPid && waitpid(gzipPid, NULL, 0) == -1) | 587 | if (gzipPid) { |
589 | bb_error_msg("waitpid failed"); | 588 | int status; |
590 | 589 | if (waitpid(gzipPid, &status, 0) == -1) | |
591 | return !errorFlag; | 590 | bb_perror_msg("waitpid"); |
591 | else if (!WIFEXITED(status) || WEXITSTATUS(status)) | ||
592 | /* gzip was killed or has exited with nonzero! */ | ||
593 | errorFlag = TRUE; | ||
594 | } | ||
595 | return errorFlag; | ||
592 | } | 596 | } |
593 | #else | 597 | #else |
594 | int writeTarFile(const int tar_fd, const int verboseFlag, | 598 | int writeTarFile(const int tar_fd, const int verboseFlag, |
@@ -650,6 +654,29 @@ static char get_header_tar_Z(archive_handle_t *archive_handle) | |||
650 | #define get_header_tar_Z 0 | 654 | #define get_header_tar_Z 0 |
651 | #endif | 655 | #endif |
652 | 656 | ||
657 | #ifdef CHECK_FOR_CHILD_EXITCODE | ||
658 | /* Looks like it isn't needed - tar detects malformed (truncated) | ||
659 | * archive if e.g. bunzip2 fails */ | ||
660 | static int child_error; | ||
661 | |||
662 | static void handle_SIGCHLD(int status) | ||
663 | { | ||
664 | /* Actually, 'status' is a signo. We reuse it for other needs */ | ||
665 | |||
666 | /* Wait for any child without blocking */ | ||
667 | if (waitpid(-1, &status, WNOHANG) < 0) | ||
668 | /* wait failed?! I'm confused... */ | ||
669 | return; | ||
670 | |||
671 | if (WIFEXITED(status) && WEXITSTATUS(status)==0) | ||
672 | /* child exited with 0 */ | ||
673 | return; | ||
674 | /* Cannot happen? | ||
675 | if(!WIFSIGNALED(status) && !WIFEXITED(status)) return; */ | ||
676 | child_error = 1; | ||
677 | } | ||
678 | #endif | ||
679 | |||
653 | enum { | 680 | enum { |
654 | OPTBIT_KEEP_OLD = 7, | 681 | OPTBIT_KEEP_OLD = 7, |
655 | USE_FEATURE_TAR_CREATE( OPTBIT_CREATE ,) | 682 | USE_FEATURE_TAR_CREATE( OPTBIT_CREATE ,) |
@@ -862,6 +889,11 @@ int tar_main(int argc, char **argv) | |||
862 | if (base_dir) | 889 | if (base_dir) |
863 | xchdir(base_dir); | 890 | xchdir(base_dir); |
864 | 891 | ||
892 | #ifdef CHECK_FOR_CHILD_EXITCODE | ||
893 | /* We need to know whether child (gzip/bzip/etc) exits abnormally */ | ||
894 | signal(SIGCHLD, handle_SIGCHLD); | ||
895 | #endif | ||
896 | |||
865 | /* create an archive */ | 897 | /* create an archive */ |
866 | if (opt & OPT_CREATE) { | 898 | if (opt & OPT_CREATE) { |
867 | int zipMode = 0; | 899 | int zipMode = 0; |
@@ -869,11 +901,10 @@ int tar_main(int argc, char **argv) | |||
869 | zipMode = 1; | 901 | zipMode = 1; |
870 | if (ENABLE_FEATURE_TAR_BZIP2 && get_header_ptr == get_header_tar_bz2) | 902 | if (ENABLE_FEATURE_TAR_BZIP2 && get_header_ptr == get_header_tar_bz2) |
871 | zipMode = 2; | 903 | zipMode = 2; |
872 | writeTarFile(tar_handle->src_fd, verboseFlag, opt & OPT_DEREFERENCE, | 904 | /* NB: writeTarFile() closes tar_handle->src_fd */ |
905 | return writeTarFile(tar_handle->src_fd, verboseFlag, opt & OPT_DEREFERENCE, | ||
873 | tar_handle->accept, | 906 | tar_handle->accept, |
874 | tar_handle->reject, zipMode); | 907 | tar_handle->reject, zipMode); |
875 | /* NB: writeTarFile() closes tar_handle->src_fd */ | ||
876 | return EXIT_SUCCESS; | ||
877 | } | 908 | } |
878 | 909 | ||
879 | while (get_header_ptr(tar_handle) == EXIT_SUCCESS) | 910 | while (get_header_ptr(tar_handle) == EXIT_SUCCESS) |