Add SIGINFO (and for portability to SIGINFO-lacking systems, SIGUSR1)

handling to bsdtar.  When writing archives (including copying via the
@archive directive) a line is output to stderr indicating what is being
done (adding or copying), the path, and how far through the file we are;
extracting currently does not report progress within each file, but
this is likely to happen eventually.

Discussed with:	kientzle
Obtained from:	tarsnap
This commit is contained in:
Colin Percival 2008-05-18 06:24:47 +00:00
parent 1ec1304bdb
commit 06a047f0f1
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=179083
5 changed files with 205 additions and 1 deletions

View File

@ -2,7 +2,7 @@
PROG= bsdtar
BSDTAR_VERSION_STRING=2.5.0b
SRCS= bsdtar.c getdate.y matching.c read.c tree.c util.c write.c
SRCS= bsdtar.c getdate.y matching.c read.c siginfo.c tree.c util.c write.c
WARNS?= 5
DPADD= ${LIBARCHIVE} ${LIBBZ2} ${LIBZ}
LDADD= -larchive -lbz2 -lz

View File

@ -96,6 +96,7 @@ struct bsdtar {
struct matching *matching; /* for matching.c */
struct security *security; /* for read.c */
struct name_cache *uname_cache; /* for write.c */
struct siginfo *siginfo; /* for siginfo.c */
};
void bsdtar_errc(struct bsdtar *, int _eval, int _code,
@ -114,6 +115,11 @@ 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 *);
void tar_mode_c(struct bsdtar *bsdtar);
void tar_mode_r(struct bsdtar *bsdtar);
void tar_mode_t(struct bsdtar *bsdtar);

View File

@ -82,7 +82,21 @@ 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');
/* Restore old SIGINFO + SIGUSR1 handlers. */
siginfo_done(bsdtar);
}
static void
progress_func(void * cookie)
{
struct bsdtar * bsdtar = cookie;
siginfo_printinfo(bsdtar, 0);
}
/*
@ -119,6 +133,12 @@ read_archive(struct bsdtar *bsdtar, char mode)
do_chdir(bsdtar);
if (mode == 'x') {
/* Set an extract callback so that we can handle SIGINFO. */
archive_read_extract_set_progress_callback(a, progress_func,
bsdtar);
}
if (mode == 'x' && bsdtar->option_chroot) {
#if HAVE_CHROOT
if (chroot(".") != 0)
@ -238,6 +258,12 @@ read_archive(struct bsdtar *bsdtar, char mode)
archive_entry_pathname(entry));
fflush(stderr);
}
/* Tell the SIGINFO-handler code what we're doing. */
siginfo_setinfo(bsdtar, "extracting",
archive_entry_pathname(entry), 0);
siginfo_printinfo(bsdtar, 0);
if (bsdtar->option_stdout)
r = archive_read_data_into_fd(a, 1);
else

147
usr.bin/tar/siginfo.c Normal file
View File

@ -0,0 +1,147 @@
/*-
* 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$");
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "bsdtar.h"
/* Is there a pending SIGINFO or SIGUSR1? */
static volatile sig_atomic_t siginfo_received = 0;
struct siginfo {
/* 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
void (*siginfo_old)(int);
#endif
void (*sigusr1_old)(int);
};
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)
{
/* Allocate space for internal structure. */
if ((bsdtar->siginfo = malloc(sizeof(struct siginfo))) == NULL)
bsdtar_errc(bsdtar, 1, errno, "malloc failed");
/* Set the strings to NULL so that free() is safe. */
bsdtar->siginfo->path = bsdtar->siginfo->oper = NULL;
#ifdef SIGINFO
/* We want to catch SIGINFO, if it exists. */
bsdtar->siginfo->siginfo_old = signal(SIGINFO, siginfo_handler);
#endif
/* ... and treat SIGUSR1 the same way as SIGINFO. */
bsdtar->siginfo->sigusr1_old = signal(SIGUSR1, siginfo_handler);
}
void
siginfo_setinfo(struct bsdtar *bsdtar, const char * oper, const char * path,
int64_t size)
{
/* Free old operation and path strings. */
free(bsdtar->siginfo->oper);
free(bsdtar->siginfo->path);
/* Duplicate strings and store entry size. */
if ((bsdtar->siginfo->oper = strdup(oper)) == NULL)
bsdtar_errc(bsdtar, 1, errno, "Cannot strdup");
if ((bsdtar->siginfo->path = strdup(path)) == NULL)
bsdtar_errc(bsdtar, 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. */
signal(SIGINFO, bsdtar->siginfo->siginfo_old);
#endif
/* And the old SIGUSR1 handler, too. */
signal(SIGUSR1, bsdtar->siginfo->sigusr1_old);
/* Free strings. */
free(bsdtar->siginfo->path);
free(bsdtar->siginfo->oper);
/* Free internal data structure. */
free(bsdtar->siginfo);
}

View File

@ -174,6 +174,9 @@ tar_mode_c(struct bsdtar *bsdtar)
if (*bsdtar->argv == NULL && bsdtar->names_from_file == NULL)
bsdtar_errc(bsdtar, 1, 0, "no files or directories specified");
/* We want to catch SIGINFO and SIGUSR1. */
siginfo_init(bsdtar);
a = archive_write_new();
/* Support any format that the library supports. */
@ -242,6 +245,9 @@ tar_mode_c(struct bsdtar *bsdtar)
}
archive_write_finish(a);
/* Restore old SIGINFO + SIGUSR1 handlers. */
siginfo_done(bsdtar);
}
/*
@ -574,6 +580,10 @@ 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);
e = archive_write_header(a, in_entry);
if (e != ARCHIVE_OK) {
@ -606,14 +616,18 @@ copy_file_data(struct bsdtar *bsdtar, struct archive *a, struct archive *ina)
char buff[64*1024];
ssize_t bytes_read;
ssize_t bytes_written;
off_t progress = 0;
bytes_read = archive_read_data(ina, buff, sizeof(buff));
while (bytes_read > 0) {
siginfo_printinfo(bsdtar, progress);
bytes_written = archive_write_data(a, buff, bytes_read);
if (bytes_written < bytes_read) {
bsdtar_warnc(bsdtar, 0, "%s", archive_error_string(a));
return (-1);
}
progress += bytes_written;
bytes_read = archive_read_data(ina, buff, sizeof(buff));
}
@ -881,6 +895,13 @@ write_entry(struct bsdtar *bsdtar, struct archive *a, const struct stat *st,
if (!S_ISREG(st->st_mode))
archive_entry_set_size(entry, 0);
/* Record what we're doing, for the benefit of SIGINFO / SIGUSR1. */
siginfo_setinfo(bsdtar, "adding", archive_entry_pathname(entry),
archive_entry_size(entry));
/* Handle SIGINFO / SIGUSR1 request if one was made. */
siginfo_printinfo(bsdtar, 0);
e = archive_write_header(a, entry);
if (e != ARCHIVE_OK) {
if (!bsdtar->verbose)
@ -923,12 +944,15 @@ write_file_data(struct bsdtar *bsdtar, struct archive *a, int fd)
char buff[64*1024];
ssize_t bytes_read;
ssize_t bytes_written;
off_t progress = 0;
/* XXX TODO: Allocate buffer on heap and store pointer to
* it in bsdtar structure; arrange cleanup as well. XXX */
bytes_read = read(fd, buff, sizeof(buff));
while (bytes_read > 0) {
siginfo_printinfo(bsdtar, progress);
bytes_written = archive_write_data(a, buff, bytes_read);
if (bytes_written < 0) {
/* Write failed; this is bad */
@ -941,6 +965,7 @@ write_file_data(struct bsdtar *bsdtar, struct archive *a, int fd)
"Truncated write; file may have grown while being archived.");
return (0);
}
progress += bytes_written;
bytes_read = read(fd, buff, sizeof(buff));
}
return 0;