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:
parent
1ec1304bdb
commit
06a047f0f1
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=179083
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
147
usr.bin/tar/siginfo.c
Normal 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);
|
||||
}
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user