From c609f0813d64ec8cdf687fa381c6af148d079e6d Mon Sep 17 00:00:00 2001 From: Tim Kientzle Date: Thu, 16 Jul 2009 21:21:18 -0400 Subject: [PATCH] Overhaul the SIGINFO/SIGUSR1 reporting. This is a little simpler and gives a lot more information. In particular, it reports total bytes in/out, total files and compression ratio, in addition to reporting the current file being processed. SVN-Revision: 1223 --- Makefile.am | 1 - tar/CMakeLists.txt | 1 - tar/Makefile | 2 +- tar/bsdtar.c | 53 ++++++++++++- tar/bsdtar.h | 7 +- tar/config_freebsd.h | 1 + tar/read.c | 53 +++++++++---- tar/siginfo.c | 173 ------------------------------------------- tar/write.c | 64 +++++++++------- 9 files changed, 130 insertions(+), 225 deletions(-) delete mode 100644 tar/siginfo.c diff --git a/Makefile.am b/Makefile.am index 34dc9cc53..5426dc9d3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -370,7 +370,6 @@ bsdtar_SOURCES= \ tar/cmdline.c \ tar/getdate.c \ tar/read.c \ - tar/siginfo.c \ tar/subst.c \ tar/tree.c \ tar/tree.h \ diff --git a/tar/CMakeLists.txt b/tar/CMakeLists.txt index 0eb6037e4..1d9896f93 100644 --- a/tar/CMakeLists.txt +++ b/tar/CMakeLists.txt @@ -11,7 +11,6 @@ IF (ENABLE_TAR) cmdline.c getdate.c read.c - siginfo.c subst.c tree.c tree.h diff --git a/tar/Makefile b/tar/Makefile index 298a2fb46..cd1005426 100644 --- a/tar/Makefile +++ b/tar/Makefile @@ -4,7 +4,7 @@ PROG= bsdtar BSDTAR_VERSION_STRING=2.7.900a -SRCS= bsdtar.c cmdline.c getdate.c read.c siginfo.c subst.c tree.c util.c write.c +SRCS= bsdtar.c cmdline.c getdate.c read.c subst.c tree.c util.c write.c SRCS+= err.c line_reader.c matching.c pathmatch.c WARNS?= 5 DPADD= ${LIBARCHIVE} ${LIBBZ2} ${LIBZ} diff --git a/tar/bsdtar.c b/tar/bsdtar.c index 8606608c2..3cf150c13 100644 --- a/tar/bsdtar.c +++ b/tar/bsdtar.c @@ -47,6 +47,9 @@ __FBSDID("$FreeBSD: src/usr.bin/tar/bsdtar.c,v 1.93 2008/11/08 04:43:24 kientzle #ifdef HAVE_PATHS_H #include #endif +#ifdef HAVE_SIGNAL_H +#include +#endif #include #ifdef HAVE_STDLIB_H #include @@ -82,7 +85,34 @@ __FBSDID("$FreeBSD: src/usr.bin/tar/bsdtar.c,v 1.93 2008/11/08 04:43:24 kientzle #define _PATH_DEFTAPE "/dev/tape" #endif -/* External function to parse a date/time string (from getdate.y) */ +static struct bsdtar *_bsdtar; + +#if defined(SIGINFO) || defined(SIGUSR1) +static volatile int siginfo_occurred; + +static void +siginfo_handler(int sig) +{ + (void)sig; /* UNUSED */ + siginfo_occurred = 1; +} + +int +need_report(void) +{ + int r = siginfo_occurred; + siginfo_occurred = 0; + return (r); +} +#else +int +need_report(void) +{ + return (0); +} +#endif + +/* External function to parse a date/time string */ time_t get_date(time_t, const char *); static void long_help(void); @@ -110,11 +140,30 @@ main(int argc, char **argv) * Use a pointer for consistency, but stack-allocated storage * for ease of cleanup. */ - bsdtar = &bsdtar_storage; + _bsdtar = bsdtar = &bsdtar_storage; memset(bsdtar, 0, sizeof(*bsdtar)); bsdtar->fd = -1; /* Mark as "unused" */ option_o = 0; +#if defined(SIGINFO) || defined(SIGUSR1) + { /* Catch SIGINFO and SIGUSR1, if they exist. */ + struct sigaction sa; + sa.sa_handler = siginfo_handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; +#ifdef SIGINFO + if (sigaction(SIGINFO, &sa, NULL)) + lafe_errc(1, errno, "sigaction(SIGINFO) failed"); +#endif +#ifdef SIGUSR1 + /* ... and treat SIGUSR1 the same way as SIGINFO. */ + if (sigaction(SIGUSR1, &sa, NULL)) + lafe_errc(1, errno, "sigaction(SIGUSR1) failed"); +#endif + } +#endif + + /* Need lafe_progname before calling lafe_warnc. */ if (*argv == NULL) lafe_progname = "bsdtar"; diff --git a/tar/bsdtar.h b/tar/bsdtar.h index 0c8dc69ca..ff1aff566 100644 --- a/tar/bsdtar.h +++ b/tar/bsdtar.h @@ -79,7 +79,6 @@ struct bsdtar { int fd; /* Miscellaneous state information */ - struct archive *archive; int argc; char **argv; const char *optarg; @@ -139,14 +138,10 @@ enum { int bsdtar_getopt(struct bsdtar *); void do_chdir(struct bsdtar *); int edit_pathname(struct bsdtar *, struct archive_entry *); +int need_report(void); int pathcmp(const char *a, const char *b); void safe_fprintf(FILE *, const char *fmt, ...); void set_chdir(struct bsdtar *, const char *newdir); -void siginfo_init(struct bsdtar *); -void siginfo_setinfo(struct bsdtar *, const char * oper, - const char * path, int64_t size); -void siginfo_printinfo(struct bsdtar *, off_t progress); -void siginfo_done(struct bsdtar *); void tar_mode_c(struct bsdtar *bsdtar); void tar_mode_r(struct bsdtar *bsdtar); void tar_mode_t(struct bsdtar *bsdtar); diff --git a/tar/config_freebsd.h b/tar/config_freebsd.h index 568f61a18..81313c311 100644 --- a/tar/config_freebsd.h +++ b/tar/config_freebsd.h @@ -55,6 +55,7 @@ #define HAVE_PWD_H 1 #define HAVE_REGEX_H 1 #define HAVE_SETLOCALE 1 +#define HAVE_SIGNAL_H 1 #define HAVE_STDARG_H 1 #define HAVE_STDLIB_H 1 #define HAVE_STRING_H 1 diff --git a/tar/read.c b/tar/read.c index 234bcb76f..3d26a3a5e 100644 --- a/tar/read.c +++ b/tar/read.c @@ -70,6 +70,12 @@ __FBSDID("$FreeBSD: src/usr.bin/tar/read.c,v 1.40 2008/08/21 06:41:14 kientzle E #include "bsdtar.h" #include "err.h" +struct progress_data { + struct bsdtar *bsdtar; + struct archive *archive; + struct archive_entry *entry; +}; + static void list_item_verbose(struct bsdtar *, FILE *, struct archive_entry *); static void read_archive(struct bsdtar *bsdtar, char mode); @@ -85,23 +91,41 @@ tar_mode_t(struct bsdtar *bsdtar) void tar_mode_x(struct bsdtar *bsdtar) { - /* We want to catch SIGINFO and SIGUSR1. */ - siginfo_init(bsdtar); - read_archive(bsdtar, 'x'); if (lafe_unmatched_inclusions_warn(bsdtar->matching, "Not found in archive") != 0) bsdtar->return_value = 1; - /* Restore old SIGINFO + SIGUSR1 handlers. */ - siginfo_done(bsdtar); } static void -progress_func(void * cookie) +progress_func(void *cookie) { - struct bsdtar * bsdtar = cookie; - - siginfo_printinfo(bsdtar, 0); + struct progress_data *progress_data = cookie; + struct bsdtar *bsdtar = progress_data->bsdtar; + struct archive *a = progress_data->archive; + struct archive_entry *entry = progress_data->entry; + uintmax_t comp, uncomp; + + if (!need_report()) + return; + + if (bsdtar->verbose) + fprintf(stderr, "\n"); + if (a != NULL) { + comp = archive_position_compressed(a); + uncomp = archive_position_uncompressed(a); + fprintf(stderr, + "In: %ju bytes, compression %d%%;", + comp, (int)((uncomp - comp) * 100 / uncomp)); + fprintf(stderr, " Out: %d files, %ju bytes\n", + archive_file_count(a), uncomp); + } + if (entry != NULL) { + safe_fprintf(stderr, "Current: %s (%ju bytes)", + archive_entry_pathname(entry), + (uintmax_t)archive_entry_size(entry)); + fprintf(stderr, "\n"); + } } /* @@ -110,6 +134,7 @@ progress_func(void * cookie) static void read_archive(struct bsdtar *bsdtar, char mode) { + struct progress_data progress_data; FILE *out; struct archive *a; struct archive_entry *entry; @@ -142,8 +167,10 @@ read_archive(struct bsdtar *bsdtar, char mode) if (mode == 'x') { /* Set an extract callback so that we can handle SIGINFO. */ + progress_data.bsdtar = bsdtar; + progress_data.archive = a; archive_read_extract_set_progress_callback(a, progress_func, - bsdtar); + &progress_data); } if (mode == 'x' && bsdtar->option_chroot) { @@ -163,6 +190,7 @@ read_archive(struct bsdtar *bsdtar, char mode) break; r = archive_read_next_header(a, &entry); + progress_data.entry = entry; if (r == ARCHIVE_EOF) break; if (r < ARCHIVE_OK) @@ -270,10 +298,7 @@ read_archive(struct bsdtar *bsdtar, char mode) fflush(stderr); } - /* Tell the SIGINFO-handler code what we're doing. */ - siginfo_setinfo(bsdtar, "extracting", - archive_entry_pathname(entry), 0); - siginfo_printinfo(bsdtar, 0); + // TODO siginfo_printinfo(bsdtar, 0); if (bsdtar->option_stdout) r = archive_read_data_into_fd(a, 1); diff --git a/tar/siginfo.c b/tar/siginfo.c deleted file mode 100644 index e7e41b3a0..000000000 --- a/tar/siginfo.c +++ /dev/null @@ -1,173 +0,0 @@ -/*- - * Copyright 2008 Colin Percival - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "bsdtar_platform.h" -__FBSDID("$FreeBSD: src/usr.bin/tar/siginfo.c,v 1.2 2008/05/22 21:08:36 cperciva Exp $"); - -#include -#include -#include -#include -#include - -#include "bsdtar.h" -#include "err.h" - -/* Is there a pending SIGINFO or SIGUSR1? */ -static volatile sig_atomic_t siginfo_received = 0; - -struct siginfo_data { - /* What sort of operation are we doing? */ - char * oper; - - /* What path are we handling? */ - char * path; - - /* How large is the archive entry? */ - int64_t size; - - /* Old signal handlers. */ -#ifdef SIGINFO - struct sigaction siginfo_old; -#endif -#ifdef SIGUSR1 - struct sigaction sigusr1_old; -#endif -}; - -#if defined(SIGINFO) || defined(SIGUSR1) -static void siginfo_handler(int sig); - -/* Handler for SIGINFO / SIGUSR1. */ -static void -siginfo_handler(int sig) -{ - - (void)sig; /* UNUSED */ - - /* Record that SIGINFO or SIGUSR1 has been received. */ - siginfo_received = 1; -} - -void -siginfo_init(struct bsdtar *bsdtar) -{ - struct sigaction sa; - - /* Allocate space for internal structure. */ - if ((bsdtar->siginfo = malloc(sizeof(struct siginfo_data))) == NULL) - lafe_errc(1, errno, "malloc failed"); - - /* Set the strings to NULL so that free() is safe. */ - bsdtar->siginfo->path = bsdtar->siginfo->oper = NULL; - - /* We want to catch SIGINFO, if it exists. */ - sa.sa_handler = siginfo_handler; - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; -#ifdef SIGINFO - if (sigaction(SIGINFO, &sa, &bsdtar->siginfo->siginfo_old)) - lafe_errc(1, errno, "sigaction(SIGINFO) failed"); -#endif -#ifdef SIGUSR1 - /* ... and treat SIGUSR1 the same way as SIGINFO. */ - if (sigaction(SIGUSR1, &sa, &bsdtar->siginfo->sigusr1_old)) - lafe_errc(1, errno, "sigaction(SIGUSR1) failed"); -#endif -} -#else -void -siginfo_init(struct bsdtar *bsdtar) -{ - /* Set the strings to NULL so that free() is safe. */ - bsdtar->siginfo = NULL; -} -#endif - -void -siginfo_setinfo(struct bsdtar *bsdtar, const char * oper, const char * path, - int64_t size) -{ - - /* Free old operation and path strings. */ - if (bsdtar->siginfo == NULL) - return; - free(bsdtar->siginfo->oper); - free(bsdtar->siginfo->path); - - /* Duplicate strings and store entry size. */ - if ((bsdtar->siginfo->oper = strdup(oper)) == NULL) - lafe_errc(1, errno, "Cannot strdup"); - if ((bsdtar->siginfo->path = strdup(path)) == NULL) - lafe_errc(1, errno, "Cannot strdup"); - bsdtar->siginfo->size = size; -} - -void -siginfo_printinfo(struct bsdtar *bsdtar, off_t progress) -{ - - /* If there's a signal to handle and we know what we're doing... */ - if ((siginfo_received == 1) && - (bsdtar->siginfo->path != NULL) && - (bsdtar->siginfo->oper != NULL)) { - if (bsdtar->verbose) - fprintf(stderr, "\n"); - if (bsdtar->siginfo->size > 0) { - safe_fprintf(stderr, "%s %s (%ju / %" PRId64 ")", - bsdtar->siginfo->oper, bsdtar->siginfo->path, - (uintmax_t)progress, bsdtar->siginfo->size); - } else { - safe_fprintf(stderr, "%s %s", - bsdtar->siginfo->oper, bsdtar->siginfo->path); - } - if (!bsdtar->verbose) - fprintf(stderr, "\n"); - siginfo_received = 0; - } -} - -void -siginfo_done(struct bsdtar *bsdtar) -{ - -#ifdef SIGINFO - /* Restore old SIGINFO handler. */ - sigaction(SIGINFO, &bsdtar->siginfo->siginfo_old, NULL); -#endif -#ifdef SIGUSR1 - /* And the old SIGUSR1 handler, too. */ - sigaction(SIGUSR1, &bsdtar->siginfo->sigusr1_old, NULL); -#endif - - if (bsdtar->siginfo) { - /* Free strings. */ - free(bsdtar->siginfo->path); - free(bsdtar->siginfo->oper); - - /* Free internal data structure. */ - free(bsdtar->siginfo); - } -} diff --git a/tar/write.c b/tar/write.c index 0301af747..591a3da26 100644 --- a/tar/write.c +++ b/tar/write.c @@ -123,10 +123,12 @@ static int append_archive_filename(struct bsdtar *, struct archive *, const char *fname); static void archive_names_from_file(struct bsdtar *bsdtar, struct archive *a); -static int copy_file_data(struct bsdtar *bsdtar, - struct archive *a, struct archive *ina); +static int copy_file_data(struct bsdtar *, struct archive *a, + struct archive *ina, struct archive_entry *); static int new_enough(struct bsdtar *, const char *path, const struct stat *); +static void report_write(struct bsdtar *, struct archive *, + struct archive_entry *, int64_t progress); static void test_for_append(struct bsdtar *); static void write_archive(struct archive *, struct bsdtar *); static void write_entry_backend(struct bsdtar *, struct archive *, @@ -475,9 +477,6 @@ write_archive(struct archive *a, struct bsdtar *bsdtar) const char *arg; struct archive_entry *entry, *sparse_entry; - /* We want to catch SIGINFO and SIGUSR1. */ - siginfo_init(bsdtar); - /* Allocate a buffer for file data. */ if ((bsdtar->buff = malloc(FILEDATABUFLEN)) == NULL) lafe_errc(1, 0, "cannot allocate memory"); @@ -554,9 +553,6 @@ cleanup: } archive_write_finish(a); - - /* Restore old SIGINFO + SIGUSR1 handlers. */ - siginfo_done(bsdtar); } /* @@ -572,8 +568,6 @@ archive_names_from_file(struct bsdtar *bsdtar, struct archive *a) struct lafe_line_reader *lr; const char *line; - bsdtar->archive = a; - bsdtar->next_line_is_dir = 0; lr = lafe_line_reader(bsdtar->names_from_file, '\n'); @@ -586,7 +580,7 @@ archive_names_from_file(struct bsdtar *bsdtar, struct archive *a) else { if (*line != '/') do_chdir(bsdtar); /* Handle a deferred -C */ - write_hierarchy(bsdtar, bsdtar->archive, line); + write_hierarchy(bsdtar, a, line); } } lafe_line_reader_free(lr); @@ -652,10 +646,8 @@ append_archive(struct bsdtar *bsdtar, struct archive *a, struct archive *ina) if (bsdtar->verbose) safe_fprintf(stderr, "a %s", archive_entry_pathname(in_entry)); - siginfo_setinfo(bsdtar, "copying", - archive_entry_pathname(in_entry), - archive_entry_size(in_entry)); - siginfo_printinfo(bsdtar, 0); + if (need_report()) + report_write(bsdtar, a, in_entry, 0); e = archive_write_header(a, in_entry); if (e != ARCHIVE_OK) { @@ -672,7 +664,7 @@ append_archive(struct bsdtar *bsdtar, struct archive *a, struct archive *ina) if (e >= ARCHIVE_WARN) { if (archive_entry_size(in_entry) == 0) archive_read_data_skip(ina); - else if (copy_file_data(bsdtar, a, ina)) + else if (copy_file_data(bsdtar, a, ina, in_entry)) exit(1); } @@ -686,15 +678,17 @@ append_archive(struct bsdtar *bsdtar, struct archive *a, struct archive *ina) /* Helper function to copy data between archives. */ static int -copy_file_data(struct bsdtar *bsdtar, struct archive *a, struct archive *ina) +copy_file_data(struct bsdtar *bsdtar, struct archive *a, + struct archive *ina, struct archive_entry *entry) { ssize_t bytes_read; ssize_t bytes_written; - off_t progress = 0; + int64_t progress = 0; bytes_read = archive_read_data(ina, bsdtar->buff, FILEDATABUFLEN); while (bytes_read > 0) { - siginfo_printinfo(bsdtar, progress); + if (need_report()) + report_write(bsdtar, a, entry, progress); bytes_written = archive_write_data(a, bsdtar->buff, bytes_read); @@ -921,14 +915,8 @@ write_hierarchy(struct bsdtar *bsdtar, struct archive *a, const char *path) if (!S_ISREG(st->st_mode)) archive_entry_set_size(entry, 0); - /* Record what we're doing, for SIGINFO / SIGUSR1. */ - siginfo_setinfo(bsdtar, "adding", - archive_entry_pathname(entry), archive_entry_size(entry)); archive_entry_linkify(bsdtar->resolver, &entry, &spare_entry); - /* Handle SIGINFO / SIGUSR1 request if one was made. */ - siginfo_printinfo(bsdtar, 0); - while (entry != NULL) { write_entry_backend(bsdtar, a, entry); archive_entry_free(entry); @@ -998,6 +986,27 @@ write_entry_backend(struct bsdtar *bsdtar, struct archive *a, close(fd); } +static void +report_write(struct bsdtar *bsdtar, struct archive *a, + struct archive_entry *entry, int64_t progress) +{ + uintmax_t comp, uncomp; + if (bsdtar->verbose) + fprintf(stderr, "\n"); + comp = archive_position_compressed(a); + uncomp = archive_position_uncompressed(a); + fprintf(stderr, "In: %d files, %ju bytes;", + archive_file_count(a), uncomp); + fprintf(stderr, + " Out: %ju bytes, compression %d%%\n", + comp, (int)((uncomp - comp) * 100 / uncomp)); + safe_fprintf(stderr, "Current: %s (%ju/%ju bytes)", + archive_entry_pathname(entry), + (uintmax_t)progress, + (uintmax_t)archive_entry_size(entry)); + fprintf(stderr, "\n"); +} + /* Helper function to copy file to archive. */ static int @@ -1006,11 +1015,12 @@ write_file_data(struct bsdtar *bsdtar, struct archive *a, { ssize_t bytes_read; ssize_t bytes_written; - off_t progress = 0; + int64_t progress = 0; bytes_read = read(fd, bsdtar->buff, FILEDATABUFLEN); while (bytes_read > 0) { - siginfo_printinfo(bsdtar, progress); + if (need_report()) + report_write(bsdtar, a, entry, progress); bytes_written = archive_write_data(a, bsdtar->buff, bytes_read); -- 2.47.3