svn commit: r215232 - stable/8/usr.bin/tar

Tim Kientzle kientzle at FreeBSD.org
Sat Nov 13 06:00:28 UTC 2010


Author: kientzle
Date: Sat Nov 13 06:00:27 2010
New Revision: 215232
URL: http://svn.freebsd.org/changeset/base/215232

Log:
  MFC r203568:  Refactor and simplify the SIGINFO/SIGUSR1
  handling.  Switch to a custom function to format 64-bit
  ints to avoid the headache of trying to guess printf
  modifiers on different platforms.

Deleted:
  stable/8/usr.bin/tar/siginfo.c
Modified:
  stable/8/usr.bin/tar/Makefile
  stable/8/usr.bin/tar/bsdtar.c
  stable/8/usr.bin/tar/bsdtar.h
  stable/8/usr.bin/tar/read.c
  stable/8/usr.bin/tar/util.c
  stable/8/usr.bin/tar/write.c
Directory Properties:
  stable/8/usr.bin/tar/   (props changed)

Modified: stable/8/usr.bin/tar/Makefile
==============================================================================
--- stable/8/usr.bin/tar/Makefile	Sat Nov 13 05:55:56 2010	(r215231)
+++ stable/8/usr.bin/tar/Makefile	Sat Nov 13 06:00:27 2010	(r215232)
@@ -9,7 +9,6 @@ SRCS=	bsdtar.c	\
 	getdate.c	\
 	matching.c	\
 	read.c		\
-	siginfo.c	\
 	subst.c		\
 	tree.c		\
 	util.c		\

Modified: stable/8/usr.bin/tar/bsdtar.c
==============================================================================
--- stable/8/usr.bin/tar/bsdtar.c	Sat Nov 13 05:55:56 2010	(r215231)
+++ stable/8/usr.bin/tar/bsdtar.c	Sat Nov 13 06:00:27 2010	(r215232)
@@ -47,6 +47,9 @@ __FBSDID("$FreeBSD$");
 #ifdef HAVE_PATHS_H
 #include <paths.h>
 #endif
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
 #include <stdio.h>
 #ifdef HAVE_STDLIB_H
 #include <stdlib.h>
@@ -82,7 +85,32 @@ __FBSDID("$FreeBSD$");
 #define	_PATH_DEFTAPE "/dev/tape"
 #endif
 
-/* External function to parse a date/time string (from getdate.y) */
+#if defined(HAVE_SIGACTION) && (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);
@@ -114,11 +142,23 @@ main(int argc, char **argv)
 	memset(bsdtar, 0, sizeof(*bsdtar));
 	bsdtar->fd = -1; /* Mark as "unused" */
 	option_o = 0;
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	/* Make sure open() function will be used with a binary mode. */
-	/* on cygwin, we need something similar, but instead link against */
-	/* a special startup object, binmode.o */
-	_set_fmode(_O_BINARY);
+
+#if defined(HAVE_SIGACTION) && (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))
+			bsdtar_errc(1, errno, "sigaction(SIGINFO) failed");
+#endif
+#ifdef SIGUSR1
+		/* ... and treat SIGUSR1 the same way as SIGINFO. */
+		if (sigaction(SIGUSR1, &sa, NULL))
+			bsdtar_errc(1, errno, "sigaction(SIGUSR1) failed");
+#endif
+	}
 #endif
 
 	/* Need bsdtar_progname before calling bsdtar_warnc. */

Modified: stable/8/usr.bin/tar/bsdtar.h
==============================================================================
--- stable/8/usr.bin/tar/bsdtar.h	Sat Nov 13 05:55:56 2010	(r215231)
+++ stable/8/usr.bin/tar/bsdtar.h	Sat Nov 13 06:00:27 2010	(r215232)
@@ -142,16 +142,13 @@ int	exclude_from_file(struct bsdtar *, c
 int	excluded(struct bsdtar *, const char *pathname);
 int	include(struct bsdtar *, const char *pattern);
 int	include_from_file(struct bsdtar *, const char *pathname);
+int	need_report(void);
 int	pathcmp(const char *a, const char *b);
 int	process_lines(struct bsdtar *bsdtar, const char *pathname,
 	    int (*process)(struct bsdtar *, const char *));
 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 *);
+const char *tar_i64toa(int64_t);
 void	tar_mode_c(struct bsdtar *bsdtar);
 void	tar_mode_r(struct bsdtar *bsdtar);
 void	tar_mode_t(struct bsdtar *bsdtar);

Modified: stable/8/usr.bin/tar/read.c
==============================================================================
--- stable/8/usr.bin/tar/read.c	Sat Nov 13 05:55:56 2010	(r215231)
+++ stable/8/usr.bin/tar/read.c	Sat Nov 13 06:00:27 2010	(r215232)
@@ -70,6 +70,12 @@ __FBSDID("$FreeBSD$");
 #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);
@@ -84,22 +90,40 @@ 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');
 
 	unmatched_inclusions_warn(bsdtar, "Not found in archive");
-	/* 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;
+	uint64_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: %s bytes, compression %d%%;",
+		    tar_i64toa(comp), (int)((uncomp - comp) * 100 / uncomp));
+		fprintf(stderr, "  Out: %d files, %s bytes\n",
+		    archive_file_count(a), tar_i64toa(uncomp));
+	}
+	if (entry != NULL) {
+		safe_fprintf(stderr, "Current: %s",
+		    archive_entry_pathname(entry));
+		fprintf(stderr, " (%s bytes)\n",
+		    tar_i64toa(archive_entry_size(entry)));
+	}
 }
 
 /*
@@ -108,6 +132,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;
@@ -140,8 +165,10 @@ read_archive(struct bsdtar *bsdtar, char
 
 	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) {
@@ -161,6 +188,7 @@ read_archive(struct bsdtar *bsdtar, char
 			break;
 
 		r = archive_read_next_header(a, &entry);
+		progress_data.entry = entry;
 		if (r == ARCHIVE_EOF)
 			break;
 		if (r < ARCHIVE_OK)
@@ -268,10 +296,7 @@ read_archive(struct bsdtar *bsdtar, char
 				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);

Modified: stable/8/usr.bin/tar/util.c
==============================================================================
--- stable/8/usr.bin/tar/util.c	Sat Nov 13 05:55:56 2010	(r215231)
+++ stable/8/usr.bin/tar/util.c	Sat Nov 13 06:00:27 2010	(r215232)
@@ -559,6 +559,28 @@ edit_pathname(struct bsdtar *bsdtar, str
 }
 
 /*
+ * It would be nice to just use printf() for formatting large numbers,
+ * but the compatibility problems are quite a headache.  Hence the
+ * following simple utility function.
+ */
+const char *
+tar_i64toa(int64_t n0)
+{
+	static char buff[24];
+	int64_t n = n0 < 0 ? -n0 : n0;
+	char *p = buff + sizeof(buff);
+
+	*--p = '\0';
+	do {
+		*--p = '0' + (int)(n % 10);
+		n /= 10;
+	} while (n > 0);
+	if (n0 < 0)
+		*--p = '-';
+	return p;
+}
+
+/*
  * Like strcmp(), but try to be a little more aware of the fact that
  * we're comparing two paths.  Right now, it just handles leading
  * "./" and trailing '/' specially, so that "a/b/" == "./a/b"

Modified: stable/8/usr.bin/tar/write.c
==============================================================================
--- stable/8/usr.bin/tar/write.c	Sat Nov 13 05:55:56 2010	(r215231)
+++ stable/8/usr.bin/tar/write.c	Sat Nov 13 06:00:27 2010	(r215232)
@@ -127,10 +127,12 @@ static void		 archive_names_from_file(st
 			     struct archive *a);
 static int		 archive_names_from_file_helper(struct bsdtar *bsdtar,
 			     const char *line);
-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 *,
@@ -414,9 +416,6 @@ write_archive(struct archive *a, struct 
 	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)
 		bsdtar_errc(1, 0, "cannot allocate memory");
@@ -488,14 +487,11 @@ cleanup:
 	bsdtar->diskreader = NULL;
 
 	if (bsdtar->option_totals) {
-		fprintf(stderr, "Total bytes written: " BSDTAR_FILESIZE_PRINTF "\n",
-		    (BSDTAR_FILESIZE_TYPE)archive_position_compressed(a));
+		fprintf(stderr, "Total bytes written: %s\n",
+		    tar_i64toa(archive_position_compressed(a)));
 	}
 
 	archive_write_finish(a);
-
-	/* Restore old SIGINFO + SIGUSR1 handlers. */
-	siginfo_done(bsdtar);
 }
 
 /*
@@ -591,10 +587,8 @@ append_archive(struct bsdtar *bsdtar, st
 		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) {
@@ -611,7 +605,7 @@ append_archive(struct bsdtar *bsdtar, st
 		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);
 		}
 
@@ -625,7 +619,8 @@ append_archive(struct bsdtar *bsdtar, st
 
 /* 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;
@@ -633,7 +628,8 @@ copy_file_data(struct bsdtar *bsdtar, st
 
 	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);
@@ -839,14 +835,8 @@ write_hierarchy(struct bsdtar *bsdtar, s
 		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);
@@ -916,6 +906,28 @@ write_entry_backend(struct bsdtar *bsdta
 		close(fd);
 }
 
+static void
+report_write(struct bsdtar *bsdtar, struct archive *a,
+    struct archive_entry *entry, int64_t progress)
+{
+	uint64_t comp, uncomp;
+	if (bsdtar->verbose)
+		fprintf(stderr, "\n");
+	comp = archive_position_compressed(a);
+	uncomp = archive_position_uncompressed(a);
+	fprintf(stderr, "In: %d files, %s bytes;",
+	    archive_file_count(a), tar_i64toa(uncomp));
+	fprintf(stderr,
+	    " Out: %s bytes, compression %d%%\n",
+	    tar_i64toa(comp), (int)((uncomp - comp) * 100 / uncomp));
+	/* Can't have two calls to tar_i64toa() pending, so split the output. */
+	safe_fprintf(stderr, "Current: %s (%s",
+	    archive_entry_pathname(entry),
+	    tar_i64toa(progress));
+	fprintf(stderr, "/%s bytes)\n",
+	    tar_i64toa(archive_entry_size(entry)));
+}
+
 
 /* Helper function to copy file to archive. */
 static int
@@ -928,7 +940,8 @@ write_file_data(struct bsdtar *bsdtar, s
 
 	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);


More information about the svn-src-all mailing list