[PATCH v2] tar/cpio: fix verbose output with to-stdout option
ThorstenB via busybox <[email protected]> Sat, 1 Aug 2026 12:13:28 +0200
| Newsgroups | gmane.linux.busybox |
|---|---|
| Message-ID | <[email protected]> |
When verbose/-v and -O/--to-stdout options are combined, verbose output needs to be sent to stderr instead. Verbose output also needs to be line-buffered, so for each archive member, verbose output is emitted before extracting the corresponding file data (tar), (after the file data for cpio). Aligns the behavior with the GNU tar/cpio utilities. Includes test cases. function old new delta cpio_main 565 603 +38 header_list 17 52 +35 header_verbose_list 283 305 +22 tar_main 1195 1210 +15 init_handle 69 80 +11 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 5/0 up/down: 121/0) Total: 121 bytes Signed-off-by: ThorstenB <[email protected]> --- archival/cpio.c | 5 ++- archival/libarchive/header_list.c | 4 +- archival/libarchive/header_verbose_list.c | 11 +++-- archival/libarchive/init_handle.c | 1 + archival/tar.c | 5 ++- include/bb_archive.h | 1 + .../cpio/cpio-verbose-to-standard-output | 44 +++++++++++++++++++ .../tar-verbose-extract-to-standard-output | 41 +++++++++++++++++ ...ar-very-verbose-extract-to-standard-output | 39 ++++++++++++++++ 9 files changed, 144 insertions(+), 7 deletions(-) create mode 100644 testsuite/cpio/cpio-verbose-to-standard-output create mode 100644 testsuite/tar/tar-verbose-extract-to-standard-output create mode 100644 testsuite/tar/tar-very-verbose-extract-to-standard-output diff --git a/archival/cpio.c b/archival/cpio.c index b033b3733..eb7a2eeaa 100644 --- a/archival/cpio.c +++ b/archival/cpio.c @@ -543,8 +543,11 @@ int cpio_main(int argc UNUSED_PARAM, char **argv) } if (opt & OPT_EXTRACT) { archive_handle->action_data = data_extract_all; - if (opt & OPT_2STDOUT) + if (opt & OPT_2STDOUT) { archive_handle->action_data = data_extract_to_stdout; + /* If data goes to stdout, verbose goes to stderr */ + archive_handle->file_header->verbose_fp = stderr; + } } if (opt & OPT_UNCONDITIONAL) { archive_handle->ah_flags |= ARCHIVE_UNLINK_OLD; diff --git a/archival/libarchive/header_list.c b/archival/libarchive/header_list.c index 9490b3635..c2105d223 100644 --- a/archival/libarchive/header_list.c +++ b/archival/libarchive/header_list.c @@ -8,5 +8,7 @@ void FAST_FUNC header_list(const file_header_t *file_header) { //TODO: cpio -vp DIR should output "DIR/NAME", not just "NAME" */ - puts(printable_string(file_header->name)); + fputs(printable_string(file_header->name), file_header->verbose_fp); + fputc('\n', file_header->verbose_fp); + fflush(file_header->verbose_fp); } diff --git a/archival/libarchive/header_verbose_list.c b/archival/libarchive/header_verbose_list.c index e7a09430d..303606b9c 100644 --- a/archival/libarchive/header_verbose_list.c +++ b/archival/libarchive/header_verbose_list.c @@ -29,7 +29,8 @@ void FAST_FUNC header_verbose_list(const file_header_t *file_header) /*sprintf(gid, "%u", (unsigned)file_header->gid);*/ group = utoa(file_header->gid); } - printf("%s %s/%s %9"OFF_FMT"u %4u-%02u-%02u %02u:%02u:%02u %s", + fprintf(file_header->verbose_fp, + "%s %s/%s %9"OFF_FMT"u %4u-%02u-%02u %02u:%02u:%02u %s", bb_mode_string(modestr, file_header->mode), user, group, @@ -46,7 +47,8 @@ void FAST_FUNC header_verbose_list(const file_header_t *file_header) localtime_r(&file_header->mtime, ptm); - printf("%s %u/%u %9"OFF_FMT"u %4u-%02u-%02u %02u:%02u:%02u %s", + fprintf(file_header->verbose_fp, + "%s %u/%u %9"OFF_FMT"u %4u-%02u-%02u %02u:%02u:%02u %s", bb_mode_string(modestr, file_header->mode), (unsigned)file_header->uid, (unsigned)file_header->gid, @@ -63,7 +65,8 @@ void FAST_FUNC header_verbose_list(const file_header_t *file_header) /* NB: GNU tar shows "->" for symlinks and "link to" for hardlinks */ if (file_header->link_target) { - printf(" -> %s", printable_string(file_header->link_target)); + fprintf(file_header->verbose_fp, " -> %s", printable_string(file_header->link_target)); } - bb_putchar('\n'); + fputc('\n', file_header->verbose_fp); + fflush(file_header->verbose_fp); } diff --git a/archival/libarchive/init_handle.c b/archival/libarchive/init_handle.c index 4c64dac58..14a8fe9c3 100644 --- a/archival/libarchive/init_handle.c +++ b/archival/libarchive/init_handle.c @@ -12,6 +12,7 @@ archive_handle_t* FAST_FUNC init_handle(void) /* Initialize default values */ archive_handle = xzalloc(sizeof(archive_handle_t)); archive_handle->file_header = xzalloc(sizeof(file_header_t)); + archive_handle->file_header->verbose_fp = stdout; archive_handle->action_header = header_skip; archive_handle->action_data = data_skip; archive_handle->filter = filter_accept_all; diff --git a/archival/tar.c b/archival/tar.c index 87ad7bb49..54f59d527 100644 --- a/archival/tar.c +++ b/archival/tar.c @@ -1075,8 +1075,11 @@ int tar_main(int argc UNUSED_PARAM, char **argv) if (opt & OPT_EXTRACT) tar_handle->action_data = data_extract_all; - if (opt & OPT_2STDOUT) + if (opt & OPT_2STDOUT) { tar_handle->action_data = data_extract_to_stdout; + /* If archive goes to stdout, verbose goes to stderr */ + tar_handle->file_header->verbose_fp = stderr; + } if (opt & OPT_2COMMAND) { putenv((char*)"TAR_FILETYPE=f"); diff --git a/include/bb_archive.h b/include/bb_archive.h index 1dc77f31d..aeca1daef 100644 --- a/include/bb_archive.h +++ b/include/bb_archive.h @@ -41,6 +41,7 @@ typedef struct file_header_t { mode_t mode; time_t mtime; dev_t device; + FILE* verbose_fp; } file_header_t; struct hardlinks_t; diff --git a/testsuite/cpio/cpio-verbose-to-standard-output b/testsuite/cpio/cpio-verbose-to-standard-output new file mode 100644 index 000000000..9c8267bff --- /dev/null +++ b/testsuite/cpio/cpio-verbose-to-standard-output @@ -0,0 +1,44 @@ +##################################################### +# create test archive +##################################################### +echo "data 1" > file1.txt +echo "data 2" > file2.txt +echo "data 3" > file3.txt +printf '%s\n' file1.txt file2.txt file3.txt | busybox cpio -o -H newc > archive.cpio + +mkdir output +cd output + +##################################################### +# cpio -v --to-stdout: verbose goes to to stderr instead +##################################################### +busybox cpio -iv --to-stdout < ../archive.cpio 2> stderr.txt > /dev/null + +cat > expected.txt << 'EOF' +file1.txt +file2.txt +file3.txt +1 blocks +EOF + +cmp expected.txt stderr.txt + +rm -f file1.txt file2.txt file3.txt + +##################################################### +# is stdout/stderr properly synchronized? +##################################################### +busybox cpio -iv --to-stdout < ../archive.cpio > output.txt 2>&1 + +cat > expected.txt << 'EOF' +data 1 +file1.txt +data 2 +file2.txt +data 3 +file3.txt +1 blocks +EOF + +cmp expected.txt output.txt + diff --git a/testsuite/tar/tar-verbose-extract-to-standard-output b/testsuite/tar/tar-verbose-extract-to-standard-output new file mode 100644 index 000000000..3433920e2 --- /dev/null +++ b/testsuite/tar/tar-verbose-extract-to-standard-output @@ -0,0 +1,41 @@ +# FEATURE: CONFIG_FEATURE_TAR_CREATE + +##################################################### +# create test tar +##################################################### +echo "data 1" > file1.txt +echo "data 2" > file2.txt +echo "data 3" > file3.txt +busybox tar cf test.tar file1.txt file2.txt file3.txt + + +##################################################### +# tar vO: verbose goes to to stderr instead +##################################################### +busybox tar xvOf test.tar 2> stderr.txt > /dev/null + +cat > expected.txt << 'EOF' +file1.txt +file2.txt +file3.txt +EOF + +cmp expected.txt stderr.txt + + +##################################################### +# is stdout/stderr properly synchronized? +##################################################### +busybox tar xvOf test.tar > output.txt 2>&1 + +cat > expected.txt << 'EOF' +file1.txt +data 1 +file2.txt +data 2 +file3.txt +data 3 +EOF + +cmp expected.txt output.txt + diff --git a/testsuite/tar/tar-very-verbose-extract-to-standard-output b/testsuite/tar/tar-very-verbose-extract-to-standard-output new file mode 100644 index 000000000..82f88eddc --- /dev/null +++ b/testsuite/tar/tar-very-verbose-extract-to-standard-output @@ -0,0 +1,39 @@ +# FEATURE: CONFIG_FEATURE_TAR_CREATE + +##################################################### +# create test tar +##################################################### +echo "data 1" > file1.txt +echo "data 2" > file2.txt +echo "data 3" > file3.txt +busybox tar cf test.tar file1.txt file2.txt file3.txt + + +##################################################### +# tar vvO: very verbose output goes to to stderr +##################################################### +busybox tar xvvOf test.tar 2> stderr.txt > /dev/null + +# create expected output +busybox tar tvvf test.tar file1.txt > expected.txt +busybox tar tvvf test.tar file2.txt >> expected.txt +busybox tar tvvf test.tar file3.txt >> expected.txt + +cmp expected.txt stderr.txt + + +##################################################### +# is stdout/stderr properly synchronized? +##################################################### +busybox tar xvvOf test.tar > output.txt 2>&1 + +# create expected output +busybox tar tvvf test.tar file1.txt > expected.txt +cat file1.txt >> expected.txt +busybox tar tvvf test.tar file2.txt >> expected.txt +cat file2.txt >> expected.txt +busybox tar tvvf test.tar file3.txt >> expected.txt +cat file3.txt >> expected.txt + +cmp expected.txt output.txt + -- 2.51.0