* file named AUTHORS, in the root directory of this distribution.
*/
/*
- * $Id: restore.c,v 1.28 2006/03/14 13:12:01 martinea Exp $
+ * $Id: restore.c,v 1.52 2006/08/23 11:41:54 martinea Exp $
*
* retrieves files from an amanda tape
*/
#include "changer.h"
#include "logfile.h"
#include "fileheader.h"
+#include "arglist.h"
#include <signal.h>
+#define LOAD_STOP -1
+#define LOAD_CHANGER -2
+
int file_number;
/* stuff we're stuck having global */
-static long blocksize = -1;
+static size_t blocksize = (size_t)SSIZE_MAX;
static char *cur_tapedev = NULL;
static char *searchlabel = NULL;
static int backwards;
static int exitassemble = 0;
-static int tapefd, nslots;
+static int tapefd;
char *rst_conf_logdir = NULL;
char *rst_conf_logfile = NULL;
int outfd;
} open_output_t;
-
typedef struct dumplist_s {
struct dumplist_s *next;
dumpfile_t *file;
} dumplist_t;
+typedef struct seentapes_s {
+ struct seentapes_s *next;
+ char *slotstr;
+ char *label;
+ dumplist_t *files;
+} seentapes_t;
+
static open_output_t *open_outputs = NULL;
static dumplist_t *alldumps_list = NULL;
-static ssize_t get_block P((int tapefd, char *buffer, int isafile));
-static void append_file_to_fd P((char *filename, int fd));
-static int headers_equal P((dumpfile_t *file1, dumpfile_t *file2, int ignore_partnums));
-static int already_have_dump P((dumpfile_t *file));
-
/* local functions */
-static void handle_sigint(sig)
-int sig;
+static ssize_t get_block(int tapefd, char *buffer, int isafile);
+static void append_file_to_fd(char *filename, int fd);
+static int headers_equal(dumpfile_t *file1, dumpfile_t *file2, int ignore_partnums);
+static int already_have_dump(dumpfile_t *file);
+static void handle_sigint(int sig);
+static int scan_init(void *ud, int rc, int ns, int bk, int s);
+int loadlabel_slot(void *ud, int rc, char *slotstr, char *device);
+void drain_file(int tapefd, rst_flags_t *flags);
+char *label_of_current_slot(char *cur_tapedev, FILE *prompt_out,
+ int *tapefd, dumpfile_t *file, rst_flags_t *flags,
+ am_feature_t *their_features,
+ ssize_t *read_result, tapelist_t *desired_tape);
+
+int load_next_tape(char **cur_tapedev, FILE *prompt_out, int backwards,
+ rst_flags_t *flags, am_feature_t *their_features,
+ tapelist_t *desired_tape);
+int load_manual_tape(char **cur_tapedev, FILE *prompt_out, FILE *prompt_in,
+ rst_flags_t *flags, am_feature_t *their_features,
+ tapelist_t *desired_tape);
+void search_a_tape(char *cur_tapedev, FILE *prompt_out, rst_flags_t *flags,
+ am_feature_t *their_features, tapelist_t *desired_tape,
+ int isafile, match_list_t *match_list,
+ seentapes_t *tape_seen, dumpfile_t *file,
+ dumpfile_t *prev_rst_file, dumpfile_t *tapestart,
+ int slot_num, ssize_t *read_result);
+
/*
* We might want to flush any open dumps and unmerged splits before exiting
* on SIGINT, so do so.
*/
+static void
+handle_sigint(
+ int sig)
{
+ (void)sig; /* Quiet unused parameter warning */
+
flush_open_outputs(exitassemble, NULL);
if(rst_conf_logfile) unlink(rst_conf_logfile);
exit(0);
}
-int lock_logfile()
+int
+lock_logfile(void)
{
rst_conf_logdir = getconf_str(CNF_LOGDIR);
if (*rst_conf_logdir == '/') {
}
rst_conf_logfile = vstralloc(rst_conf_logdir, "/log", NULL);
if (access(rst_conf_logfile, F_OK) == 0) {
- error("%s exists: amdump or amflush is already running, or you must run amcleanup", rst_conf_logfile);
+ dbprintf(("%s exists: amdump or amflush is already running, "
+ "or you must run amcleanup\n", rst_conf_logfile));
+ return 0;
}
log_add(L_INFO, get_pname());
return 1;
* number, and datestamp, and 0 if not. The part number can be optionally
* ignored.
*/
-int headers_equal (file1, file2, ignore_partnums)
-dumpfile_t *file1, *file2;
-int ignore_partnums;
+int
+headers_equal(
+ dumpfile_t *file1,
+ dumpfile_t *file2,
+ int ignore_partnums)
{
if(!file1 || !file2) return(0);
* See whether we're already pulled an exact copy of the given file (chunk
* number and all). Returns 0 if not, 1 if so.
*/
-int already_have_dump(file)
-dumpfile_t *file;
+int
+already_have_dump(
+ dumpfile_t *file)
{
dumplist_t *fileentry = NULL;
* Open the named file and append its contents to the (hopefully open) file
* descriptor supplies.
*/
-static void append_file_to_fd(filename, fd)
-char *filename;
-int fd;
+static void
+append_file_to_fd(
+ char * filename,
+ int fd)
{
ssize_t bytes_read;
ssize_t s;
- off_t wc = 0;
+ off_t wc = (off_t)0;
char *buffer;
- if(blocksize == -1)
+ if(blocksize == SIZE_MAX)
blocksize = DISK_BLOCK_BYTES;
buffer = alloc(blocksize);
if((tapefd = open(filename, O_RDONLY)) == -1) {
error("can't open %s: %s", filename, strerror(errno));
- /* NOTREACHED */
+ /*NOTREACHED*/
}
for (;;) {
bytes_read = get_block(tapefd, buffer, 1); /* same as isafile = 1 */
if(bytes_read < 0) {
error("read error: %s", strerror(errno));
- /* NOTREACHED */
+ /*NOTREACHED*/
}
if (bytes_read == 0)
break;
- s = fullwrite(fd, buffer, bytes_read);
+ s = fullwrite(fd, buffer, (size_t)bytes_read);
if (s < bytes_read) {
- fprintf(stderr,"Error %d (%s) offset " OFF_T_FMT "+" AM64_FMT ", wrote " AM64_FMT "\n",
- errno, strerror(errno), wc, (am64_t)bytes_read, (am64_t)s);
+ fprintf(stderr,"Error (%s) offset " OFF_T_FMT "+" OFF_T_FMT ", wrote " OFF_T_FMT "\n",
+ strerror(errno), (OFF_T_FMT_TYPE)wc,
+ (OFF_T_FMT_TYPE)bytes_read, (OFF_T_FMT_TYPE)s);
if (s < 0) {
if((errno == EPIPE) || (errno == ECONNRESET)) {
- error("%s: pipe reader has quit in middle of file.\n",
+ error("%s: pipe reader has quit in middle of file.",
get_pname());
- /* NOTREACHED */
+ /*NOTREACHED*/
}
error("restore: write error = %s", strerror(errno));
- /* NOTREACHED */
+ /*NOTREACHED*/
}
- error("Short write: wrote %d bytes expected %d\n", s, bytes_read);
- /* NOTREACHCED */
+ error("Short write: wrote " SSIZE_T_FMT " bytes expected " SSIZE_T_FMT ".", s, bytes_read);
+ /*NOTREACHCED*/
}
- wc += bytes_read;
+ wc += (off_t)bytes_read;
}
amfree(buffer);
* Tape changer support routines, stolen brazenly from amtape
*/
static int
-scan_init(ud, rc, ns, bk, s)
- void * ud;
- int rc, ns, bk, s;
+scan_init(
+ void * ud,
+ int rc,
+ int ns,
+ int bk,
+ int s)
{
- if(rc)
- error("could not get changer info: %s", changer_resultstr);
+ (void)ud; /* Quiet unused parameter warning */
+ (void)ns; /* Quiet unused parameter warning */
+ (void)s; /* Quiet unused parameter warning */
- nslots = ns;
+ if(rc) {
+ error("could not get changer info: %s", changer_resultstr);
+ /*NOTREACHED*/
+ }
backwards = bk;
return 0;
}
-int loadlabel_slot(ud, rc, slotstr, device)
- void *ud;
-int rc;
-char *slotstr;
-char *device;
+
+int
+loadlabel_slot(
+ void * ud,
+ int rc,
+ char * slotstr,
+ char * device)
{
char *errstr;
char *datestamp = NULL;
char *label = NULL;
+ (void)ud; /* Quiet unused parameter warning */
- if(rc > 1)
+ if(rc > 1) {
error("could not load slot %s: %s", slotstr, changer_resultstr);
- else if(rc == 1)
+ /*NOTREACHED*/
+ } else if(rc == 1) {
fprintf(stderr, "%s: slot %s: %s\n",
get_pname(), slotstr, changer_resultstr);
- else if((errstr = tape_rdlabel(device, &datestamp, &label)) != NULL)
+ } else if((errstr = tape_rdlabel(device, &datestamp, &label)) != NULL) {
fprintf(stderr, "%s: slot %s: %s\n", get_pname(), slotstr, errstr);
- else {
- fprintf(stderr, "%s: slot %s: date %-8s label %s",
- get_pname(), slotstr, datestamp, label);
+ } else {
+ if(strlen(datestamp)>8)
+ fprintf(stderr, "%s: slot %s: date %-14s label %s",
+ get_pname(), slotstr, datestamp, label);
+ else
+ fprintf(stderr, "%s: slot %s: date %-8s label %s",
+ get_pname(), slotstr, datestamp, label);
if(strcmp(label, FAKE_LABEL) != 0
&& strcmp(label, searchlabel) != 0)
fprintf(stderr, " (wrong tape)\n");
amfree(errstr);
}
amfree(cur_tapedev);
- curslot = stralloc(slotstr);
+ curslot = newstralloc(curslot, slotstr);
amfree(datestamp);
amfree(label);
if(device)
amfree(datestamp);
amfree(label);
- if(cur_tapedev) amfree(cur_tapedev);
- curslot = stralloc(slotstr);
+ amfree(cur_tapedev);
+ curslot = newstralloc(curslot, slotstr);
if(!device) return(1);
cur_tapedev = stralloc(device);
* Check whether we've read all of the preceding parts of a given split dump,
* generally used to see if we're done and can close the thing.
*/
-int have_all_parts (file, upto)
-dumpfile_t *file;
-int upto;
+int
+have_all_parts (
+ dumpfile_t *file,
+ int upto)
{
int c;
int *foundparts = NULL;
if(upto < 1) upto = file->totalparts;
- foundparts = alloc(sizeof(int) * upto);
+ foundparts = alloc(SIZEOF(*foundparts) * upto);
for(c = 0 ; c< upto; c++) foundparts[c] = 0;
for(fileentry=alldumps_list;fileentry; fileentry=fileentry->next){
* string them together. If given an optional file header argument, flush
* only that dump and do not flush/free any others.
*/
-void flush_open_outputs(reassemble, only_file)
-int reassemble;
-dumpfile_t *only_file;
+void
+flush_open_outputs(
+ int reassemble,
+ dumpfile_t *only_file)
{
open_output_t *cur_out = NULL, *prev = NULL;
find_result_t *sorted_files = NULL;
if(only_file && !headers_equal(cur_file, only_file, 1)){
continue;
}
- cur_find_res = alloc(sizeof(find_result_t));
- memset(cur_find_res, '\0', sizeof(find_result_t));
- cur_find_res->datestamp = atoi(cur_file->datestamp);
+ cur_find_res = alloc(SIZEOF(find_result_t));
+ memset(cur_find_res, '\0', SIZEOF(find_result_t));
+ cur_find_res->timestamp = stralloc(cur_file->datestamp);
cur_find_res->hostname = stralloc(cur_file->name);
cur_find_res->diskname = stralloc(cur_file->disk);
cur_find_res->level = cur_file->dumplevel;
if(cur_file->partnum < 1) cur_find_res->partnum = stralloc("--");
else{
char part_str[NUM_STR_SIZE];
- snprintf(part_str, sizeof(part_str), "%d", cur_file->partnum);
+ snprintf(part_str, SIZEOF(part_str), "%d", cur_file->partnum);
cur_find_res->partnum = stralloc(part_str);
}
cur_find_res->user_ptr = (void*)cur_out;
/* is it a continuation of one we've been writing? */
if(main_file && cur_file->partnum > lastpartnum &&
headers_equal(cur_file, main_file, 1)){
+ char *cur_filename;
+ char *main_filename;
/* effectively changing filehandles */
aclose(cur_out->outfd);
cur_out->outfd = outfd;
+ cur_filename = make_filename(cur_file);
+ main_filename = make_filename(main_file);
fprintf(stderr, "Merging %s with %s\n",
- make_filename(cur_file), make_filename(main_file));
- append_file_to_fd(make_filename(cur_file), outfd);
- if(unlink(make_filename(cur_file)) < 0){
+ cur_filename, main_filename);
+ append_file_to_fd(cur_filename, outfd);
+ if(unlink(cur_filename) < 0){
fprintf(stderr, "Failed to unlink %s: %s\n",
- make_filename(cur_file), strerror(errno));
+ cur_filename, strerror(errno));
}
+ amfree(cur_filename);
+ amfree(main_filename);
}
/* or a new file? */
- else{
+ else {
if(outfd >= 0) aclose(outfd);
- if(main_file) amfree(main_file);
- main_file = alloc(sizeof(dumpfile_t));
- memcpy(main_file, cur_file, sizeof(dumpfile_t));
+ amfree(main_file);
+ main_file = alloc(SIZEOF(dumpfile_t));
+ memcpy(main_file, cur_file, SIZEOF(dumpfile_t));
outfd = cur_out->outfd;
- if(outfd < 0){
- if((outfd = open(make_filename(cur_file), O_RDWR|O_APPEND)) < 0){
- error("Couldn't open %s for appending: %s\n",
- make_filename(cur_file), strerror(errno));
+ if(outfd < 0) {
+ char *cur_filename = make_filename(cur_file);
+ open(cur_filename, O_RDWR|O_APPEND);
+ if (outfd < 0) {
+ error("Couldn't open %s for appending: %s",
+ cur_filename, strerror(errno));
+ /*NOTREACHED*/
}
+ amfree(cur_filename);
}
}
lastpartnum = cur_file->partnum;
*/
for(cur_out=open_outputs; cur_out; cur_out=cur_out->next){
dumpfile_t *cur_file = NULL;
- if(prev) amfree(prev);
+ amfree(prev);
cur_file = cur_out->file;
/* if we requested a particular file, do only that one */
if(only_file && !headers_equal(cur_file, only_file, 1)){
/*
* Turn a fileheader into a string suited for use on the filesystem.
*/
-char *make_filename(file)
-dumpfile_t *file;
+char *
+make_filename(
+ dumpfile_t *file)
{
char number[NUM_STR_SIZE];
char part[NUM_STR_SIZE];
char *sfn = NULL;
char *fn = NULL;
char *pad = NULL;
- int padlen = 0;
+ size_t padlen = 0;
- snprintf(number, sizeof(number), "%d", file->dumplevel);
- snprintf(part, sizeof(part), "%d", file->partnum);
+ snprintf(number, SIZEOF(number), "%d", file->dumplevel);
+ snprintf(part, SIZEOF(part), "%d", file->partnum);
- if(file->totalparts < 0){
- snprintf(totalparts, sizeof(totalparts), "UNKNOWN");
+ if(file->totalparts < 0) {
+ snprintf(totalparts, SIZEOF(totalparts), "UNKNOWN");
}
- else{
- snprintf(totalparts, sizeof(totalparts), "%d", file->totalparts);
+ else {
+ snprintf(totalparts, SIZEOF(totalparts), "%d", file->totalparts);
}
padlen = strlen(totalparts) + 1 - strlen(part);
pad = alloc(padlen);
memset(pad, '0', padlen);
pad[padlen - 1] = '\0';
- snprintf(part, sizeof(part), "%s%d", pad, file->partnum);
+ snprintf(part, SIZEOF(part), "%s%d", pad, file->partnum);
sfn = sanitise_filename(file->disk);
fn = vstralloc(file->name,
".",
number,
NULL);
- if(file->partnum > 0){
- fn = vstralloc(fn, ".", part, NULL);
+ if (file->partnum > 0) {
+ vstrextend(&fn, ".", part, NULL);
}
amfree(sfn);
amfree(pad);
/*
-XXX Making this thing a lib functiong broke a lot of assumptions everywhere,
-but I think I've found them all. Maybe. Damn globals all over the place.
-*/
-static ssize_t get_block(tapefd, buffer, isafile)
-int tapefd, isafile;
-char *buffer;
+ * XXX Making this thing a lib functiong broke a lot of assumptions everywhere,
+ * but I think I've found them all. Maybe. Damn globals all over the place.
+ */
+
+static ssize_t
+get_block(
+ int tapefd,
+ char * buffer,
+ int isafile)
{
if(isafile)
return (fullread(tapefd, buffer, blocksize));
return(tapefd_read(tapefd, buffer, blocksize));
}
-int disk_match(file, datestamp, hostname, diskname, level)
-dumpfile_t *file;
-char *datestamp, *hostname, *diskname, *level;
/*
* Returns 1 if the current dump file matches the hostname and diskname
* regular expressions given on the command line, 0 otherwise. As a
* special case, empty regexs are considered equivalent to ".*": they
* match everything.
*/
+
+int
+disk_match(
+ dumpfile_t *file,
+ char * datestamp,
+ char * hostname,
+ char * diskname,
+ char * level)
{
char level_str[NUM_STR_SIZE];
- snprintf(level_str, sizeof(level_str), "%d", file->dumplevel);
+ snprintf(level_str, SIZEOF(level_str), "%d", file->dumplevel);
if(file->type != F_DUMPFILE && file->type != F_SPLIT_DUMPFILE) return 0;
}
-void read_file_header(file, tapefd, isafile, flags)
-dumpfile_t *file;
-int tapefd;
-int isafile;
-rst_flags_t *flags;
/*
* Reads the first block of a tape file.
*/
+
+ssize_t
+read_file_header(
+ dumpfile_t * file,
+ int tapefd,
+ int isafile,
+ rst_flags_t * flags)
{
ssize_t bytes_read;
char *buffer;
if(flags->blocksize > 0)
- blocksize = flags->blocksize;
- else if(blocksize == -1)
+ blocksize = (size_t)flags->blocksize;
+ else if(blocksize == (size_t)SSIZE_MAX)
blocksize = DISK_BLOCK_BYTES;
buffer = alloc(blocksize);
bytes_read = get_block(tapefd, buffer, isafile);
if(bytes_read < 0) {
- error("error reading file header: %s", strerror(errno));
- /* NOTREACHED */
- }
-
- if(bytes_read < blocksize) {
+ fprintf(stderr, "%s: error reading file header: %s\n",
+ get_pname(), strerror(errno));
+ file->type = F_UNKNOWN;
+ } else if((size_t)bytes_read < DISK_BLOCK_BYTES) {
if(bytes_read == 0) {
fprintf(stderr, "%s: missing file header block\n", get_pname());
} else {
- fprintf(stderr, "%s: short file header block: " AM64_FMT " byte%s\n",
- get_pname(), (am64_t)bytes_read, (bytes_read == 1) ? "" : "s");
+ fprintf(stderr, "%s: short file header block: " OFF_T_FMT " byte%s\n",
+ get_pname(), (OFF_T_FMT_TYPE)bytes_read, (bytes_read == 1) ? "" : "s");
}
file->type = F_UNKNOWN;
} else {
- parse_file_header(buffer, file, bytes_read);
+ parse_file_header(buffer, file, (size_t)bytes_read);
}
amfree(buffer);
+ return bytes_read;
}
-void drain_file(tapefd, flags)
-int tapefd;
-rst_flags_t *flags;
+void
+drain_file(
+ int tapefd,
+ rst_flags_t * flags)
{
ssize_t bytes_read;
char *buffer;
if(flags->blocksize)
- blocksize = flags->blocksize;
- else if(blocksize == -1)
+ blocksize = (size_t)flags->blocksize;
+ else if(blocksize == (size_t)SSIZE_MAX)
blocksize = DISK_BLOCK_BYTES;
buffer = alloc(blocksize);
bytes_read = get_block(tapefd, buffer, 0);
if(bytes_read < 0) {
error("drain read error: %s", strerror(errno));
+ /*NOTREACHED*/
}
} while (bytes_read > 0);
amfree(buffer);
}
-ssize_t restore(file, filename, tapefd, isafile, flags)
-dumpfile_t *file;
-char *filename;
-int tapefd;
-int isafile;
-rst_flags_t *flags;
/*
* Restore the current file from tape. Depending on the settings of
* the command line flags, the file might need to be compressed or
* but with the -p flag the output goes to stdout (and presumably is
* piped to restore).
*/
+
+ssize_t
+restore(
+ dumpfile_t * file,
+ char * filename,
+ int tapefd,
+ int isafile,
+ rst_flags_t * flags)
{
int dest = -1, out;
ssize_t s;
int pipe[2];
} pipes[3];
+ memset(pipes, -1, SIZEOF(pipes));
if(flags->blocksize)
- blocksize = flags->blocksize;
- else if(blocksize == -1)
+ blocksize = (size_t)flags->blocksize;
+ else if(blocksize == (size_t)SSIZE_MAX)
blocksize = DISK_BLOCK_BYTES;
if(already_have_dump(file)){
- fprintf(stderr, " *** Duplicate file %s, one is probably an aborted write\n", make_filename(file));
+ char *filename = make_filename(file);
+ fprintf(stderr, " *** Duplicate file %s, one is probably an aborted write\n", filename);
+ amfree(filename);
check_for_aborted = 1;
}
/* store a shorthand record of this dump */
- tempdump = alloc(sizeof(dumplist_t));
- tempdump->file = alloc(sizeof(dumpfile_t));
+ tempdump = alloc(SIZEOF(dumplist_t));
+ tempdump->file = alloc(SIZEOF(dumpfile_t));
tempdump->next = NULL;
- memcpy(tempdump->file, file, sizeof(dumpfile_t));
+ memcpy(tempdump->file, file, SIZEOF(dumpfile_t));
/*
* If we're appending chunked files to one another, and if this is a
flags->leave_comp = 1;
}
if(myout == NULL){
- myout = alloc(sizeof(open_output_t));
- memset(myout, 0, sizeof(open_output_t));
+ myout = alloc(SIZEOF(open_output_t));
+ memset(myout, 0, SIZEOF(open_output_t));
}
}
else{
- myout = alloc(sizeof(open_output_t));
- memset(myout, 0, sizeof(open_output_t));
+ myout = alloc(SIZEOF(open_output_t));
+ memset(myout, 0, SIZEOF(open_output_t));
}
if(is_continuation && flags->pipe_to_fd == -1){
+ char *filename;
+ filename = make_filename(myout->file);
fprintf(stderr, "%s: appending to %s\n", get_pname(),
- make_filename(myout->file));
+ filename);
+ amfree(filename);
}
/* adjust compression flag */
amfree(tmp_filename);
tmp_filename = tmpstr;
}
- final_filename = stralloc(tmp_filename);
- tmp_filename = newvstralloc(tmp_filename, ".tmp", NULL);
- if((dest = creat(tmp_filename, CREAT_MODE)) < 0) {
+ final_filename = tmp_filename;
+ tmp_filename = vstralloc(final_filename, ".tmp", NULL);
+ if((dest = open(tmp_filename, (O_CREAT | O_RDWR | O_TRUNC),
+ CREAT_MODE)) < 0) {
error("could not create output file %s: %s",
- tmp_filename, strerror(errno));
- /*NOTREACHED*/
+ tmp_filename, strerror(errno));
+ /*NOTREACHED*/
}
amfree(filename_ext);
}
* it has a fixed size.
*/
if(flags->raw || (flags->headers && !is_continuation)) {
- int w;
- char *cont_filename;
+ ssize_t w;
dumpfile_t tmp_hdr;
if(flags->compress && !file_is_compressed) {
file->compressed = 1;
- snprintf(file->uncompress_cmd, sizeof(file->uncompress_cmd),
+ snprintf(file->uncompress_cmd, SIZEOF(file->uncompress_cmd),
" %s %s |", UNCOMPRESS_PATH,
#ifdef UNCOMPRESS_OPT
UNCOMPRESS_OPT
);
strncpy(file->comp_suffix,
COMPRESS_SUFFIX,
- sizeof(file->comp_suffix)-1);
- file->comp_suffix[sizeof(file->comp_suffix)-1] = '\0';
+ SIZEOF(file->comp_suffix)-1);
+ file->comp_suffix[SIZEOF(file->comp_suffix)-1] = '\0';
}
- memcpy(&tmp_hdr, file, sizeof(dumpfile_t));
+ memcpy(&tmp_hdr, file, SIZEOF(dumpfile_t));
/* remove CONT_FILENAME from header */
- cont_filename = stralloc(file->cont_filename);
- memset(file->cont_filename,'\0',sizeof(file->cont_filename));
+ memset(file->cont_filename,'\0',SIZEOF(file->cont_filename));
file->blocksize = DISK_BLOCK_BYTES;
/*
if((w = fullwrite(out, buffer, DISK_BLOCK_BYTES)) != DISK_BLOCK_BYTES) {
if(w < 0) {
error("write error: %s", strerror(errno));
+ /*NOTREACHED*/
} else {
- error("write error: %d instead of %d", w, DISK_BLOCK_BYTES);
+ error("write error: " SSIZE_T_FMT " instead of %d", w, DISK_BLOCK_BYTES);
+ /*NOTREACHED*/
}
}
amfree(buffer);
- /* add CONT_FILENAME to header */
-#if 0
-// strncpy(file->cont_filename, cont_filename, sizeof(file->cont_filename));
-#endif
- amfree(cont_filename);
- memcpy(file, &tmp_hdr, sizeof(dumpfile_t));
+
+ memcpy(file, &tmp_hdr, SIZEOF(dumpfile_t));
}
/* find out if compression or uncompression is needed here */
|| file->type != F_SPLIT_DUMPFILE))
need_uncompress=1;
- if(!flags->raw && file->encrypted)
+ if(!flags->raw && file->encrypted && !is_continuation
+ && (flags->inline_assemble || file->type != F_SPLIT_DUMPFILE))
need_decrypt=1;
/* Setup pipes for decryption / compression / uncompression */
stage = 0;
if (need_decrypt) {
- if (pipe(&pipes[stage].pipe[0]) < 0)
+ if (pipe(&pipes[stage].pipe[0]) < 0) {
error("error [pipe[%d]: %s]", stage, strerror(errno));
+ /*NOTREACHED*/
+ }
stage++;
}
if (need_compress || need_uncompress) {
- if (pipe(&pipes[stage].pipe[0]) < 0)
+ if (pipe(&pipes[stage].pipe[0]) < 0) {
error("error [pipe[%d]: %s]", stage, strerror(errno));
+ /*NOTREACHED*/
+ }
stage++;
}
pipes[stage].pipe[0] = -1;
switch(myout->comp_enc_pid = fork()) {
case -1:
error("could not fork for decrypt: %s", strerror(errno));
+ /*NOTREACHED*/
+
default:
aclose(pipes[stage].pipe[0]);
aclose(pipes[stage+1].pipe[1]);
stage++;
break;
+
case 0:
- if(dup2(pipes[stage].pipe[0], 0) == -1)
+ if(dup2(pipes[stage].pipe[0], 0) == -1) {
error("error decrypt stdin [dup2 %d %d: %s]", stage,
pipes[stage].pipe[0], strerror(errno));
+ /*NOTREACHED*/
+ }
- if(dup2(pipes[stage+1].pipe[1], 1) == -1)
+ if(dup2(pipes[stage+1].pipe[1], 1) == -1) {
error("error decrypt stdout [dup2 %d %d: %s]", stage + 1,
pipes[stage+1].pipe[1], strerror(errno));
+ /*NOTREACHED*/
+ }
safe_fd(-1, 0);
if (*file->srv_encrypt) {
(void) execlp(file->srv_encrypt, file->srv_encrypt,
- file->srv_decrypt_opt, NULL);
+ file->srv_decrypt_opt, (char *)NULL);
error("could not exec %s: %s", file->srv_encrypt, strerror(errno));
+ /*NOTREACHED*/
} else if (*file->clnt_encrypt) {
(void) execlp(file->clnt_encrypt, file->clnt_encrypt,
- file->clnt_decrypt_opt, NULL);
+ file->clnt_decrypt_opt, (char *)NULL);
error("could not exec %s: %s", file->clnt_encrypt, strerror(errno));
+ /*NOTREACHED*/
}
}
}
* Insert a compress pipe
*/
switch(myout->comp_enc_pid = fork()) {
- case -1: error("could not fork for %s: %s",
- COMPRESS_PATH, strerror(errno));
+ case -1:
+ error("could not fork for %s: %s", COMPRESS_PATH, strerror(errno));
+ /*NOTREACHED*/
+
default:
aclose(pipes[stage].pipe[0]);
aclose(pipes[stage+1].pipe[1]);
stage++;
break;
+
case 0:
- if(dup2(pipes[stage].pipe[0], 0) == -1)
+ if(dup2(pipes[stage].pipe[0], 0) == -1) {
error("error compress stdin [dup2 %d %d: %s]", stage,
pipes[stage].pipe[0], strerror(errno));
+ /*NOTREACHED*/
+ }
- if(dup2(pipes[stage+1].pipe[1], 1) == -1)
+ if(dup2(pipes[stage+1].pipe[1], 1) == -1) {
error("error compress stdout [dup2 %d %d: %s]", stage + 1,
pipes[stage+1].pipe[1], strerror(errno));
-
+ /*NOTREACHED*/
+ }
if (*flags->comp_type == '\0') {
flags->comp_type = NULL;
}
safe_fd(-1, 0);
(void) execlp(COMPRESS_PATH, COMPRESS_PATH, flags->comp_type, (char *)0);
error("could not exec %s: %s", COMPRESS_PATH, strerror(errno));
+ /*NOTREACHED*/
}
} else if(need_uncompress) {
/*
case -1:
error("could not fork for %s: %s",
UNCOMPRESS_PATH, strerror(errno));
+ /*NOTREACHED*/
+
default:
aclose(pipes[stage].pipe[0]);
aclose(pipes[stage+1].pipe[1]);
stage++;
break;
+
case 0:
- if(dup2(pipes[stage].pipe[0], 0) == -1)
+ if(dup2(pipes[stage].pipe[0], 0) == -1) {
error("error uncompress stdin [dup2 %d %d: %s]", stage,
pipes[stage].pipe[0], strerror(errno));
+ /*NOTREACHED*/
+ }
- if(dup2(pipes[stage+1].pipe[1], 1) == -1)
+ if(dup2(pipes[stage+1].pipe[1], 1) == -1) {
error("error uncompress stdout [dup2 %d %d: %s]", stage + 1,
pipes[stage+1].pipe[1], strerror(errno));
+ /*NOTREACHED*/
+ }
safe_fd(-1, 0);
if (*file->srvcompprog) {
- (void) execlp(file->srvcompprog, file->srvcompprog, "-d", NULL);
- error("could not exec %s: %s", file->srvcompprog, strerror(errno));
+ (void) execlp(file->srvcompprog, file->srvcompprog, "-d",
+ (char *)NULL);
+ error("could not exec %s: %s", file->srvcompprog,
+ strerror(errno));
+ /*NOTREACHED*/
} else if (*file->clntcompprog) {
- (void) execlp(file->clntcompprog, file->clntcompprog, "-d", NULL);
- error("could not exec %s: %s", file->clntcompprog, strerror(errno));
+ (void) execlp(file->clntcompprog, file->clntcompprog, "-d",
+ (char *)NULL);
+ error("could not exec %s: %s", file->clntcompprog,
+ strerror(errno));
+ /*NOTREACHED*/
} else {
(void) execlp(UNCOMPRESS_PATH, UNCOMPRESS_PATH,
#ifdef UNCOMPRESS_OPT
UNCOMPRESS_OPT,
#endif
- (char *)0);
+ (char *)NULL);
error("could not exec %s: %s", UNCOMPRESS_PATH, strerror(errno));
+ /*NOTREACHED*/
}
}
}
/* copy the rest of the file from tape to the output */
if(flags->blocksize > 0)
- blocksize = flags->blocksize;
- else if(blocksize == -1)
+ blocksize = (size_t)flags->blocksize;
+ else if(blocksize == SIZE_MAX)
blocksize = DISK_BLOCK_BYTES;
buffer = alloc(blocksize);
bytes_read = get_block(tapefd, buffer, isafile);
if(bytes_read < 0) {
error("restore read error: %s", strerror(errno));
- /* NOTREACHED */
+ /*NOTREACHED*/
}
if(bytes_read > 0) {
- if((s = fullwrite(pipes[0].pipe[1], buffer, bytes_read)) < 0) {
+ if((s = fullwrite(pipes[0].pipe[1], buffer, (size_t)bytes_read)) < 0) {
if ((errno == EPIPE) || (errno == ECONNRESET)) {
/*
* reading program has ended early
*/
break;
}
- perror("restore: write error");
- exit(2);
+ error("restore: write error: %s", strerror(errno));
+ /* NOTREACHED */
+ } else if (s < bytes_read) {
+ error("restore: wrote " SSIZE_T_FMT " of " SSIZE_T_FMT " bytes: %s",
+ s, bytes_read, strerror(errno));
+ /* NOTREACHED */
}
}
else if(isafile) {
if((tapefd = open(cont_filename,O_RDONLY)) == -1) {
error("can't open %s: %s", file->cont_filename,
strerror(errno));
+ /*NOTREACHED*/
}
else {
fprintf(stderr, "cannot open %s: %s\n",
else {
error("can't open %s: %s", file->cont_filename,
strerror(errno));
+ /*NOTREACHED*/
}
}
- read_file_header(file, tapefd, isafile, flags);
+ bytes_read = read_file_header(file, tapefd, isafile, flags);
if(file->type != F_DUMPFILE && file->type != F_CONT_DUMPFILE
&& file->type != F_SPLIT_DUMPFILE) {
fprintf(stderr, "unexpected header type: ");
}
if(!is_continuation){
if(tmp_filename && stat(tmp_filename, &statinfo) < 0){
- error("Can't stat the file I just created (%s)!\n", tmp_filename);
+ error("Can't stat the file I just created (%s)!", tmp_filename);
+ /*NOTREACHED*/
+ } else {
+ statinfo.st_size = (off_t)0;
}
- if(check_for_aborted){
+ if (check_for_aborted && final_filename) {
char *old_dump = final_filename;
struct stat oldstat;
if(stat(old_dump, &oldstat) >= 0){
}
else{
fprintf(stderr, "Older restore is larger, using that\n");
- unlink(tmp_filename);
+ if (tmp_filename)
+ unlink(tmp_filename);
amfree(tempdump->file);
amfree(tempdump);
amfree(tmp_filename);
}
}
if(tmp_filename && final_filename &&
- rename(tmp_filename, final_filename) < 0){
- error("Can't rename %s to %s: %s\n", tmp_filename, final_filename,
- strerror(errno));
+ rename(tmp_filename, final_filename) < 0) {
+ error("Can't rename %s to %s: %s",
+ tmp_filename, final_filename, strerror(errno));
+ /*NOTREACHED*/
}
}
- if(tmp_filename) amfree(tmp_filename);
- if(final_filename) amfree(final_filename);
+ amfree(tmp_filename);
+ amfree(final_filename);
/*
* structures (we waited in case we needed to give up)
*/
if(!is_continuation){
- oldout = alloc(sizeof(open_output_t));
- oldout->file = alloc(sizeof(dumpfile_t));
- memcpy(oldout->file, file, sizeof(dumpfile_t));
+ oldout = alloc(SIZEOF(open_output_t));
+ oldout->file = alloc(SIZEOF(dumpfile_t));
+ memcpy(oldout->file, file, SIZEOF(dumpfile_t));
if(flags->inline_assemble) oldout->outfd = pipes[0].pipe[1];
else oldout->outfd = -1;
oldout->comp_enc_pid = -1;
open_outputs = oldout;
}
if(alldumps_list){
- for(fileentry=alldumps_list;fileentry->next;fileentry=fileentry->next);
+ fileentry = alldumps_list;
+ while (fileentry->next != NULL)
+ fileentry=fileentry->next;
fileentry->next = tempdump;
}
else {
return (bytes_read);
}
+/* return NULL if the label is not the expected one */
+/* return the label if it is the expected one, and set *tapefd to a */
+/* file descriptor to the tapedev */
+char *
+label_of_current_slot(
+ char *cur_tapedev,
+ FILE *prompt_out,
+ int *tapefd,
+ dumpfile_t *file,
+ rst_flags_t *flags,
+ am_feature_t *their_features,
+ ssize_t *read_result,
+ tapelist_t *desired_tape)
+{
+ struct stat stat_tape;
+ char *label = NULL;
+ int wrongtape = 0;
+ char *err;
+ if (!cur_tapedev) {
+ send_message(prompt_out, flags, their_features,
+ "no tapedev specified");
+ } else if (tape_stat(cur_tapedev, &stat_tape) !=0 ) {
+ send_message(prompt_out, flags, their_features,
+ "could not stat '%s': %s",
+ cur_tapedev, strerror(errno));
+ wrongtape = 1;
+ } else if((err = tape_rewind(cur_tapedev)) != NULL) {
+ send_message(prompt_out, flags, their_features,
+ "Could not rewind device '%s': %s",
+ cur_tapedev, err);
+ wrongtape = 1;
+ /* err should not be freed */
+ } else if((*tapefd = tape_open(cur_tapedev, 0)) < 0){
+ send_message(prompt_out, flags, their_features,
+ "could not open tape device %s: %s",
+ cur_tapedev, strerror(errno));
+ wrongtape = 1;
+ }
+
+ if (!wrongtape) {
+ *read_result = read_file_header(file, *tapefd, 0, flags);
+ if (file->type != F_TAPESTART) {
+ send_message(prompt_out, flags, their_features,
+ "Not an amanda tape");
+ tapefd_close(*tapefd);
+ } else {
+ if (flags->check_labels && desired_tape &&
+ strcmp(file->name, desired_tape->label) != 0) {
+ send_message(prompt_out, flags, their_features,
+ "Label mismatch, got %s and expected %s",
+ file->name, desired_tape->label);
+ tapefd_close(*tapefd);
+ }
+ else {
+ label = stralloc(file->name);
+ }
+ }
+ }
+ return label;
+}
+
+/* return >0 the number of slot move */
+/* return LOAD_STOP if the search must be stopped */
+/* return LOAD_CHANGER if the changer search the library */
+int
+load_next_tape(
+ char **cur_tapedev,
+ FILE *prompt_out,
+ int backwards,
+ rst_flags_t *flags,
+ am_feature_t *their_features,
+ tapelist_t *desired_tape)
+{
+ int ret = -1;
+
+ if (desired_tape) {
+ send_message(prompt_out, flags, their_features,
+ "Looking for tape %s...",
+ desired_tape->label);
+ if (backwards) {
+ searchlabel = desired_tape->label;
+ changer_find(NULL, scan_init, loadlabel_slot,
+ desired_tape->label);
+ ret = LOAD_CHANGER;
+ } else {
+ amfree(curslot);
+ changer_loadslot("next", &curslot,
+ cur_tapedev);
+ ret = 1;
+ }
+ } else {
+ assert(!flags->amidxtaped);
+ amfree(curslot);
+ changer_loadslot("next", &curslot, cur_tapedev);
+ ret = 1;
+ }
+ return ret;
+}
+
+
+/* return 0 a new tape is loaded */
+/* return -1 no new tape */
+int
+load_manual_tape(
+ char **cur_tapedev,
+ FILE *prompt_out,
+ FILE *prompt_in,
+ rst_flags_t *flags,
+ am_feature_t *their_features,
+ tapelist_t *desired_tape)
+{
+ int ret = 0;
+ char *input = NULL;
+
+ if (flags->amidxtaped) {
+ if (their_features &&
+ am_has_feature(their_features,
+ fe_amrecover_FEEDME)) {
+ fprintf(prompt_out, "FEEDME %s\r\n",
+ desired_tape->label);
+ fflush(prompt_out);
+ input = agets(prompt_in);/* Strips \n but not \r */
+ if(!input) {
+ error("Connection lost with amrecover");
+ /*NOTREACHED*/
+ } else if (strcmp("OK\r", input) == 0) {
+ } else if (strncmp("TAPE ", input, 5) == 0) {
+ amfree(*cur_tapedev);
+ *cur_tapedev = alloc(1025);
+ if (sscanf(input, "TAPE %1024s\r", *cur_tapedev) != 1) {
+ error("Got bad response from amrecover: %s", input);
+ /*NOTREACHED*/
+ }
+ } else {
+ send_message(prompt_out, flags, their_features,
+ "Got bad response from amrecover: %s", input);
+ error("Got bad response from amrecover: %s", input);
+ /*NOTREACHED*/
+ }
+ } else {
+ send_message(prompt_out, flags, their_features,
+ "Client doesn't support fe_amrecover_FEEDME");
+ error("Client doesn't support fe_amrecover_FEEDME");
+ /*NOTREACHED*/
+ }
+ }
+ else {
+ if (desired_tape) {
+ fprintf(prompt_out,
+ "Insert tape labeled %s in device %s \n"
+ "and press enter, ^D to finish reading tapes\n",
+ desired_tape->label, *cur_tapedev);
+ } else {
+ fprintf(prompt_out,"Insert a tape to search and press "
+ "enter, ^D to finish reading tapes\n");
+ }
+ fflush(prompt_out);
+ if((input = agets(prompt_in)) == NULL)
+ ret = -1;
+ }
+
+ amfree(input);
+ return ret;
+}
+
+
+void
+search_a_tape(
+ char *cur_tapedev,
+ FILE *prompt_out,
+ rst_flags_t *flags,
+ am_feature_t *their_features,
+ tapelist_t *desired_tape,
+ int isafile,
+ match_list_t *match_list,
+ seentapes_t *tape_seen,
+ dumpfile_t *file,
+ dumpfile_t *prev_rst_file,
+ dumpfile_t *tapestart,
+ int slot_num,
+ ssize_t *read_result)
+{
+ off_t filenum;
+ dumplist_t *fileentry = NULL;
+ int tapefile_idx = -1;
+ int i;
+ char *logline = NULL;
+ FILE *logstream = NULL;
+ off_t fsf_by;
+
+ filenum = (off_t)0;
+ if(desired_tape && desired_tape->numfiles > 0)
+ tapefile_idx = 0;
+
+ if (desired_tape) {
+ dbprintf(("search_a_tape: desired_tape=%p label=%s\n",
+ desired_tape, desired_tape->label));
+ dbprintf(("tape: numfiles = %d\n", desired_tape->numfiles));
+ for (i=0; i < desired_tape->numfiles; i++) {
+ dbprintf(("tape: files[%d] = " OFF_T_FMT "\n",
+ i, (OFF_T_FMT_TYPE)desired_tape->files[i]));
+ }
+ } else {
+ dbprintf(("search_a_tape: no desired_tape\n"));
+ }
+ dbprintf(("current tapefile_idx = %d\n", tapefile_idx));
+
+ /* if we know where we're going, fastforward there */
+ if(flags->fsf && !isafile){
+ /* If we have a tapelist entry, filenums will be store there */
+ if(tapefile_idx >= 0) {
+ fsf_by = desired_tape->files[tapefile_idx];
+ } else {
+ /*
+ * older semantics assume we're restoring one file, with the fsf
+ * flag being the filenum on tape for said file
+ */
+ fsf_by = (flags->fsf == 0) ? (off_t)0 : (off_t)1;
+ }
+ if(fsf_by > (off_t)0){
+ if(tapefd_rewind(tapefd) < 0) {
+ send_message(prompt_out, flags, their_features,
+ "Could not rewind device %s: %s",
+ cur_tapedev, strerror(errno));
+ error("Could not rewind device %s: %s",
+ cur_tapedev, strerror(errno));
+ /*NOTREACHED*/
+ }
+
+ if(tapefd_fsf(tapefd, fsf_by) < 0) {
+ send_message(prompt_out, flags, their_features,
+ "Could not fsf device %s by " OFF_T_FMT ": %s",
+ cur_tapedev, (OFF_T_FMT_TYPE)fsf_by,
+ strerror(errno));
+ error("Could not fsf device %s by " OFF_T_FMT ": %s",
+ cur_tapedev, (OFF_T_FMT_TYPE)fsf_by,
+ strerror(errno));
+ /*NOTREACHED*/
+ }
+ else {
+ filenum = fsf_by;
+ }
+ *read_result = read_file_header(file, tapefd, isafile, flags);
+ }
+ }
+
+ while((file->type == F_TAPESTART || file->type == F_DUMPFILE ||
+ file->type == F_SPLIT_DUMPFILE) &&
+ (tapefile_idx < 0 || tapefile_idx < desired_tape->numfiles)) {
+ int found_match = 0;
+ match_list_t *me;
+ dumplist_t *tempdump = NULL;
+
+ /* store record of this dump for inventorying purposes */
+ tempdump = alloc(SIZEOF(dumplist_t));
+ tempdump->file = alloc(SIZEOF(dumpfile_t));
+ tempdump->next = NULL;
+ memcpy(tempdump->file, &file, SIZEOF(dumpfile_t));
+ if(tape_seen->files){
+ fileentry = tape_seen->files;
+ while (fileentry->next != NULL)
+ fileentry = fileentry->next;
+ fileentry->next = tempdump;
+ }
+ else {
+ tape_seen->files = tempdump;
+ }
+
+ /* see if we need to restore the thing */
+ if(isafile)
+ found_match = 1;
+ else if(tapefile_idx >= 0){ /* do it by explicit file #s */
+ if(filenum == desired_tape->files[tapefile_idx]){
+ found_match = 1;
+ tapefile_idx++;
+ }
+ }
+ else{ /* search and match headers */
+ for(me = match_list; me; me = me->next) {
+ if(disk_match(file, me->datestamp, me->hostname,
+ me->diskname, me->level) != 0){
+ found_match = 1;
+ break;
+ }
+ }
+ }
+
+ if(found_match){
+ char *filename = make_filename(file);
+
+ fprintf(stderr, "%s: " OFF_T_FMT ": restoring ",
+ get_pname(), (OFF_T_FMT_TYPE)filenum);
+ print_header(stderr, file);
+ *read_result = restore(file, filename, tapefd, isafile, flags);
+ filenum++;
+ amfree(filename);
+ }
+
+ /* advance to the next file, fast-forwarding where reasonable */
+ if (!isafile) {
+ if (*read_result == 0) {
+ tapefd_close(tapefd);
+ if((tapefd = tape_open(cur_tapedev, 0)) < 0) {
+ send_message(prompt_out, flags, their_features,
+ "could not open %s: %s",
+ cur_tapedev, strerror(errno));
+ error("could not open %s: %s",
+ cur_tapedev, strerror(errno));
+ /*NOTREACHED*/
+ }
+ /* if the file is not what we're looking for fsf to next one */
+ }
+ else if (!found_match) {
+ if (tapefd_fsf(tapefd, (off_t)1) < 0) {
+ send_message(prompt_out, flags, their_features,
+ "Could not fsf device %s: %s",
+ cur_tapedev, strerror(errno));
+ error("Could not fsf device %s: %s",
+ cur_tapedev, strerror(errno));
+ /*NOTREACHED*/
+ }
+ filenum ++;
+ }
+ else if (flags->fsf && (tapefile_idx >= 0) &&
+ (tapefile_idx < desired_tape->numfiles)) {
+ fsf_by = desired_tape->files[tapefile_idx] - filenum;
+ if (fsf_by > (off_t)0) {
+ if(tapefd_fsf(tapefd, fsf_by) < 0) {
+ send_message(prompt_out, flags, their_features,
+ "Could not fsf device %s by "
+ OFF_T_FMT ": %s",
+ cur_tapedev, (OFF_T_FMT_TYPE)fsf_by,
+ strerror(errno));
+ error("Could not fsf device %s by " OFF_T_FMT ": %s",
+ cur_tapedev, (OFF_T_FMT_TYPE)fsf_by,
+ strerror(errno));
+ /*NOTREACHED*/
+ }
+ filenum = desired_tape->files[tapefile_idx];
+ }
+ }
+ } /* !isafile */
+
+ memcpy(prev_rst_file, file, SIZEOF(dumpfile_t));
+
+ if(isafile)
+ break;
+ *read_result = read_file_header(file, tapefd, isafile, flags);
+
+ /* only restore a single dump, if piping to stdout */
+ if (!headers_equal(prev_rst_file, file, 1) &&
+ (flags->pipe_to_fd == fileno(stdout)) && found_match) {
+ break;
+ }
+ } /* while we keep seeing headers */
+
+ if (!isafile) {
+ if (file->type == F_EMPTY) {
+ aclose(tapefd);
+ if((tapefd = tape_open(cur_tapedev, 0)) < 0) {
+ send_message(prompt_out, flags, their_features,
+ "could not open %s: %s",
+ cur_tapedev, strerror(errno));
+ error("could not open %s: %s",
+ cur_tapedev, strerror(errno));
+ /*NOTREACHED*/
+ }
+ } else {
+ if (tapefd_fsf(tapefd, (off_t)1) < 0) {
+ send_message(prompt_out, flags, their_features,
+ "could not fsf %s: %s",
+ cur_tapedev, strerror(errno));;
+ error("could not fsf %s: %s",
+ cur_tapedev, strerror(errno));
+ /*NOTREACHED*/
+ }
+ }
+ }
+ tapefd_close(tapefd);
+
+ /* spit out our accumulated list of dumps, if we're inventorying */
+ if (logstream) {
+ logline = log_genstring(L_START, "taper",
+ "datestamp %s label %s tape %d",
+ tapestart->datestamp, tapestart->name,
+ slot_num);
+ fprintf(logstream, "%s", logline);
+ for(fileentry=tape_seen->files; fileentry; fileentry=fileentry->next){
+ logline = NULL;
+ switch (fileentry->file->type) {
+ case F_DUMPFILE:
+ logline = log_genstring(L_SUCCESS, "taper",
+ "%s %s %s %d [faked log entry]",
+ fileentry->file->name,
+ fileentry->file->disk,
+ fileentry->file->datestamp,
+ fileentry->file->dumplevel);
+ break;
+ case F_SPLIT_DUMPFILE:
+ logline = log_genstring(L_CHUNK, "taper",
+ "%s %s %s %d %d [faked log entry]",
+ fileentry->file->name,
+ fileentry->file->disk,
+ fileentry->file->datestamp,
+ fileentry->file->partnum,
+ fileentry->file->dumplevel);
+ break;
+ default:
+ break;
+ }
+ if(logline){
+ fprintf(logstream, "%s", logline);
+ amfree(logline);
+ fflush(logstream);
+ }
+ }
+ }
+}
/*
* Take a pattern of dumps and restore it blind, a la amrestore. In addition,
* tapes to search (rather than "everything I can find"), which in turn can
* optionally list specific files to restore.
*/
-void search_tapes(prompt_out, use_changer, tapelist, match_list, flags, their_features)
-FILE *prompt_out;
-int use_changer;
-tapelist_t *tapelist;
-match_list_t *match_list;
-rst_flags_t *flags;
-am_feature_t *their_features;
+void
+search_tapes(
+ FILE * prompt_out,
+ FILE *prompt_in,
+ int use_changer,
+ tapelist_t * tapelist,
+ match_list_t * match_list,
+ rst_flags_t * flags,
+ am_feature_t * their_features)
{
- struct stat stat_tape;
- char *err;
int have_changer = 1;
int slot_num = -1;
int slots = -1;
- int filenum;
FILE *logstream = NULL;
- dumplist_t *fileentry = NULL;
tapelist_t *desired_tape = NULL;
struct sigaction act, oact;
- int newtape = 1;
- ssize_t bytes_read = 0;
-
- struct seentapes{
- struct seentapes *next;
- char *slotstr;
- char *label;
- dumplist_t *files;
- } *seentapes = NULL;
+ ssize_t read_result;
+ int slot;
+ char *label = NULL;
+ seentapes_t *seentapes = NULL;
+ int ret;
if(!prompt_out) prompt_out = stderr;
- if(flags->blocksize) blocksize = flags->blocksize;
- else if(blocksize == -1) blocksize = DISK_BLOCK_BYTES;
+ dbprintf(("search_tapes(prompt_out=%d, prompt_in=%d, use_changer=%d, "
+ "tapelist=%p, "
+ "match_list=%p, flags=%p, features=%p)\n",
+ fileno(prompt_out), fileno(prompt_in), use_changer, tapelist,
+ match_list, flags, their_features));
+
+ if(flags->blocksize)
+ blocksize = (size_t)flags->blocksize;
+ else if(blocksize == (size_t)SSIZE_MAX)
+ blocksize = DISK_BLOCK_BYTES;
/* Don't die when child closes pipe */
signal(SIGPIPE, SIG_IGN);
act.sa_flags = 0;
if(sigaction(SIGINT, &act, &oact) != 0){
error("error setting SIGINT handler: %s", strerror(errno));
+ /*NOTREACHED*/
}
if(flags->delay_assemble || flags->inline_assemble) exitassemble = 1;
else exitassemble = 0;
/* if given a log file, print an inventory of stuff found */
- if(flags->inventory_log){
+ if(flags->inventory_log) {
if(!strcmp(flags->inventory_log, "-")) logstream = stdout;
- else if((logstream = fopen(flags->inventory_log, "w+")) == NULL){
- error("Couldn't open log file %s for writing: %s\n",
+ else if((logstream = fopen(flags->inventory_log, "w+")) == NULL) {
+ error("Couldn't open log file %s for writing: %s",
flags->inventory_log, strerror(errno));
+ /*NOTREACHED*/
}
}
/* Suss what tape device we're using, whether there's a changer, etc. */
if(!use_changer || (have_changer = changer_init()) == 0) {
- if(flags->alt_tapedev) cur_tapedev = stralloc(flags->alt_tapedev);
- else if(!cur_tapedev) cur_tapedev = getconf_str(CNF_TAPEDEV);
+ if (flags->alt_tapedev) {
+ cur_tapedev = stralloc(flags->alt_tapedev);
+ } else if(!cur_tapedev) {
+ cur_tapedev = getconf_str(CNF_TAPEDEV);
+ if (cur_tapedev == NULL) {
+ error("No tapedev specified");
+ }
+ }
/* XXX oughta complain if no config is loaded */
fprintf(stderr, "%s: Using tapedev %s\n", get_pname(), cur_tapedev);
have_changer = 0;
} else if (have_changer != 1) {
error("changer initialization failed: %s", strerror(errno));
+ /*NOTREACHED*/
}
else{ /* good, the changer works, see what it can do */
+ amfree(curslot);
changer_info(&slots, &curslot, &backwards);
}
what to load
*/
fprintf(prompt_out, "The following tapes are needed:");
- for(desired_tape = tapelist;
- desired_tape != NULL;
+ for(desired_tape = tapelist; desired_tape != NULL;
desired_tape = desired_tape->next){
fprintf(prompt_out, " %s", desired_tape->label);
}
char *input = NULL;
fprintf(prompt_out,"Press enter when ready\n");
fflush(prompt_out);
- input = agets(stdin);
+ input = agets(prompt_in);
amfree(input);
fprintf(prompt_out, "\n");
fflush(prompt_out);
}
desired_tape = tapelist;
+ if(use_changer && !cur_tapedev) { /* load current slot */
+ amfree(curslot);
+ changer_loadslot("current", &curslot, &cur_tapedev);
+ }
+
/*
* If we're not given a tapelist, iterate over everything our changer can
* find. If there's no changer, we'll prompt to be handfed tapes.
*
* (obnoxious, isn't this?)
*/
- slot_num = 0;
- curslot = stralloc("<none>");
- while(desired_tape || ((slot_num < slots || !have_changer) && !tapelist)){
- char *label = NULL;
- struct seentapes *tape_seen = NULL;
+
+ do { /* all desired tape */
+ seentapes_t *tape_seen = NULL;
dumpfile_t file, tapestart, prev_rst_file;
- char *logline = NULL;
- int tapefile_idx = -1;
- int wrongtape = 0;
int isafile = 0;
+ read_result = 0;
- /*
- * Deal with instances where we're being asked to restore from a file
- */
- if(desired_tape && desired_tape->isafile){
+ slot_num = 0;
+
+ memset(&file, 0, SIZEOF(file));
+
+ if (desired_tape && desired_tape->isafile) {
isafile = 1;
- if ((tapefd = open(desired_tape->label, 0)) == -1){
- fprintf(stderr, "could not open %s: %s\n",
- desired_tape->label, strerror(errno));
- continue;
+ if ((tapefd = open(desired_tape->label, 0)) == -1) {
+ send_message(prompt_out, flags, their_features,
+ "could not open %s: %s",
+ desired_tape->label, strerror(errno));
+ continue;
}
- fprintf(stderr, "Reading %s to fd %d\n", desired_tape->label, tapefd);
+ fprintf(stderr, "Reading %s to fd %d\n",
+ desired_tape->label, tapefd);
- read_file_header(&file, tapefd, 1, flags);
+ read_result = read_file_header(&file, tapefd, 1, flags);
label = stralloc(desired_tape->label);
- }
- /*
- * Make sure we can read whatever tape is loaded, then grab the label.
- */
- else if(cur_tapedev && newtape){
- if(tape_stat(cur_tapedev,&stat_tape)!=0) {
- error("could not stat %s: %s", cur_tapedev, strerror(errno));
+ } else {
+ /* check current_slot */
+ label = label_of_current_slot(cur_tapedev, prompt_out,
+ &tapefd, &file, flags,
+ their_features, &read_result,
+ desired_tape);
+ while (label==NULL && slot_num < slots &&
+ use_changer) {
+ /*
+ * If we have an incorrect tape loaded, go try to find
+ * the right one
+ * (or just see what the next available one is).
+ */
+ slot = load_next_tape(&cur_tapedev, prompt_out,
+ backwards, flags,
+ their_features, desired_tape);
+ if(slot == LOAD_STOP) {
+ slot_num = slots;
+ amfree(label);
+ } else {
+ if (slot == LOAD_CHANGER)
+ slot_num = slots;
+ else /* slot > 0 */
+ slot_num += slot;
+
+ /* check current_slot */
+ label = label_of_current_slot(cur_tapedev, prompt_out,
+ &tapefd, &file, flags,
+ their_features, &read_result,
+ desired_tape);
+ }
}
- if((err = tape_rewind(cur_tapedev)) != NULL) {
- fprintf(stderr, "Could not rewind device '%s': %s\n",
- cur_tapedev, err);
- wrongtape = 1;
- }
- if((tapefd = tape_open(cur_tapedev, 0)) < 0){
- fprintf(stderr, "could not open tape device %s: %s\n",
- cur_tapedev, strerror(errno));
- wrongtape = 1;
+ if (label == NULL) {
+ ret = load_manual_tape(&cur_tapedev, prompt_out, prompt_in,
+ flags,
+ their_features, desired_tape);
+ if (ret == 0) {
+ label = label_of_current_slot(cur_tapedev, prompt_out,
+ &tapefd, &file, flags,
+ their_features, &read_result,
+ desired_tape);
+ }
}
- if (!wrongtape) {
- read_file_header(&file, tapefd, 0, flags);
- if (file.type != F_TAPESTART) {
- fprintf(stderr, "Not an amanda tape\n");
- tapefd_close(tapefd);
- wrongtape = 1;
- } else {
- memcpy(&tapestart, &file, sizeof(dumpfile_t));
- label = stralloc(file.name);
- }
- }
- } else if(newtape) {
- wrongtape = 1; /* nothing loaded */
- bytes_read = -1;
+ if (label)
+ memcpy(&tapestart, &file, SIZEOF(dumpfile_t));
}
+
+ if (!label)
+ continue;
/*
* Skip this tape if we did it already. Note that this would let
* duplicate labels through, so long as they were in the same slot.
* I'm over it, are you?
*/
- if(label && newtape && !isafile && !wrongtape){
- for(tape_seen = seentapes; tape_seen; tape_seen = tape_seen->next){
- if(!strcmp(tape_seen->label, label) &&
- !strcmp(tape_seen->slotstr, curslot)){
- fprintf(stderr, "Saw repeat tape %s in slot %s\n", label, curslot);
- wrongtape = 1;
+ if (!isafile) {
+ for (tape_seen = seentapes; tape_seen;
+ tape_seen = tape_seen->next) {
+ if (!strcmp(tape_seen->label, label) &&
+ !strcmp(tape_seen->slotstr, curslot)){
+ send_message(prompt_out, flags, their_features,
+ "Saw repeat tape %s in slot %s",
+ label, curslot);
amfree(label);
break;
}
}
}
- /*
- * See if we've got the tape we were looking for, if we were looking
- * for something specific.
- */
- if((desired_tape || !cur_tapedev) && newtape && !isafile && !wrongtape){
- if(!label || (flags->check_labels &&
- desired_tape && strcmp(label, desired_tape->label) != 0)){
- if(label){
- fprintf(stderr, "Label mismatch, got %s and expected %s\n", label, desired_tape->label);
- if(have_changer && !backwards){
- fprintf(stderr, "Changer can't go backwards, restoring anyway\n");
- }
- else wrongtape = 1;
- }
- else fprintf(stderr, "No tape device initialized yet\n");
- }
- }
-
-
- /*
- * If we have an incorrect tape loaded, go try to find the right one
- * (or just see what the next available one is).
- */
- if((wrongtape || !newtape) && !isafile){
- if(desired_tape){
- tapefd_close(tapefd);
- if(have_changer){
- fprintf(stderr,"Looking for tape %s...\n", desired_tape->label);
- if(backwards){
- searchlabel = desired_tape->label;
- changer_find(NULL, scan_init, loadlabel_slot, desired_tape->label);
- }
- else{
- changer_loadslot("next", &curslot, &cur_tapedev);
- }
- while(have_changer && !cur_tapedev){
- fprintf(stderr, "Changer did not set the tape device (slot empty or changer misconfigured?)\n");
- changer_loadslot("next", &curslot, &cur_tapedev);
- }
- }
- else {
- char *input = NULL;
-
- if (!flags->amidxtaped) {
- fprintf(prompt_out,
- "Insert tape labeled %s in device %s "
- "and press return\n",
- desired_tape->label, cur_tapedev);
- fflush(prompt_out);
- input = agets(stdin);
- amfree(input);
- } else if (their_features &&
- am_has_feature(their_features,
- fe_amrecover_FEEDME)) {
- fprintf(prompt_out, "FEEDME %s\n",
- desired_tape->label);
- fflush(prompt_out);
- input = agets(stdin); /* Strips \n but not \r */
- if (strcmp("OK\r", input) != 0) {
- error("Got bad response from amrecover: %s",
- input);
- }
- amfree(input);
- } else {
- error("Client doesn't support fe_amrecover_FEEDME");
- }
- }
- }
- else{
- assert(!flags->amidxtaped);
- if(have_changer){
- if(slot_num == 0)
- changer_loadslot("first", &curslot, &cur_tapedev);
- else
- changer_loadslot("next", &curslot, &cur_tapedev);
- if(have_changer && !cur_tapedev)
- error("Changer did not set the tape device, probably misconfigured");
- }
- else {
- /* XXX need a condition for ending processing? */
- char *input = NULL;
- fprintf(prompt_out,"Insert a tape to search and press enter, ^D to finish reading tapes\n");
- fflush(prompt_out);
- if((input = agets(stdin)) == NULL) break;
- amfree(input);
- }
- }
- newtape = 1;
- amfree(label);
+ if(!label)
continue;
- }
-
- newtape = 0;
- slot_num++;
+ if(!curslot)
+ curslot = stralloc("<none>");
if(!isafile){
fprintf(stderr, "Scanning %s (slot %s)\n", label, curslot);
fflush(stderr);
}
- tape_seen = alloc(sizeof(struct seentapes));
- memset(tape_seen, '\0', sizeof(struct seentapes));
+ tape_seen = alloc(SIZEOF(seentapes_t));
+ memset(tape_seen, '\0', SIZEOF(seentapes_t));
tape_seen->label = label;
tape_seen->slotstr = stralloc(curslot);
* have one) contains a list of files to restore, obey that instead
* of checking for matching headers on all files.
*/
- filenum = 0;
- if(desired_tape && desired_tape->numfiles > 0) tapefile_idx = 0;
- /* if we know where we're going, fastforward there */
- if(flags->fsf && !isafile){
- int fsf_by = 0;
+ search_a_tape(cur_tapedev, prompt_out, flags, their_features,
+ desired_tape, isafile, match_list, tape_seen,
+ &file, &prev_rst_file, &tapestart, slot_num,
+ &read_result);
- /* If we have a tapelist entry, filenums will be store there */
- if(tapefile_idx >= 0)
- fsf_by = desired_tape->files[tapefile_idx];
- /*
- * older semantics assume we're restoring one file, with the fsf
- * flag being the filenum on tape for said file
- */
- else fsf_by = flags->fsf;
-
- if(fsf_by > 0){
- if(tapefd_rewind(tapefd) < 0) {
- error("Could not rewind device %s: %s", cur_tapedev,
- strerror(errno));
- }
-
- if(tapefd_fsf(tapefd, fsf_by) < 0) {
- error("Could not fsf device %s by %d: %s", cur_tapedev, fsf_by,
- strerror(errno));
- }
- else {
- filenum = fsf_by;
- }
- read_file_header(&file, tapefd, isafile, flags);
- }
- }
-
- while((file.type == F_TAPESTART || file.type == F_DUMPFILE ||
- file.type == F_SPLIT_DUMPFILE) &&
- (tapefile_idx < 0 || tapefile_idx < desired_tape->numfiles)) {
- int found_match = 0;
- match_list_t *me;
- dumplist_t *tempdump = NULL;
-
- /* store record of this dump for inventorying purposes */
- tempdump = alloc(sizeof(dumplist_t));
- tempdump->file = alloc(sizeof(dumpfile_t));
- tempdump->next = NULL;
- memcpy(tempdump->file, &file, sizeof(dumpfile_t));
- if(tape_seen->files){
- for(fileentry=tape_seen->files;
- fileentry->next;
- fileentry=fileentry->next);
- fileentry->next = tempdump;
- }
- else tape_seen->files = tempdump;
-
- /* see if we need to restore the thing */
- if(isafile) found_match = 1;
- else if(tapefile_idx >= 0){ /* do it by explicit file #s */
- if(filenum == desired_tape->files[tapefile_idx]){
- found_match = 1;
- tapefile_idx++;
- }
- }
- else{ /* search and match headers */
- for(me = match_list; me; me = me->next) {
- if(disk_match(&file, me->datestamp, me->hostname,
- me->diskname, me->level) != 0){
- found_match = 1;
- break;
- }
- }
- }
-
- if(found_match){
- char *filename = make_filename(&file);
- fprintf(stderr, "%s: %3d: restoring ", get_pname(), filenum);
- print_header(stderr, &file);
- bytes_read = restore(&file, filename, tapefd, isafile, flags);
- filenum ++;
- amfree(filename);
- }
-
- /* advance to the next file, fast-forwarding where reasonable */
- if(bytes_read == 0 && !isafile) {
- tapefd_close(tapefd);
- if((tapefd = tape_open(cur_tapedev, 0)) < 0) {
- error("could not open %s: %s",
- cur_tapedev, strerror(errno));
- }
- } else if(!isafile){
- /* cheat and jump ahead to where we're going if we can */
- if (!found_match && flags->fsf) {
- drain_file(tapefd, flags);
- filenum ++;
- } else if(tapefile_idx >= 0 &&
- tapefile_idx < desired_tape->numfiles &&
- flags->fsf){
- int fsf_by = desired_tape->files[tapefile_idx] - filenum;
- if(fsf_by > 0){
- if(tapefd_fsf(tapefd, fsf_by) < 0) {
- error("Could not fsf device %s by %d: %s", cur_tapedev, fsf_by,
- strerror(errno));
- }
- else filenum = desired_tape->files[tapefile_idx];
- }
- } else if (!found_match && flags->fsf) {
- /* ... or fsf by 1, whatever */
- if(tapefd_fsf(tapefd, 1) < 0) {
- error("could not fsf device %s: %s",
- cur_tapedev, strerror(errno));
- } else {
- filenum ++;
- }
- }
- }
-
-
- memcpy(&prev_rst_file, &file, sizeof(dumpfile_t));
-
-
- if(isafile)
- break;
- read_file_header(&file, tapefd, isafile, flags);
-
- /* only restore a single dump, if piping to stdout */
- if(!headers_equal(&prev_rst_file, &file, 1) &&
- flags->pipe_to_fd == fileno(stdout)) break;
- } /* while we keep seeing headers */
-
- if(!isafile){
- if(bytes_read == 0) {
- /* XXX is this dain-bramaged? */
- aclose(tapefd);
- if((tapefd = tape_open(cur_tapedev, 0)) < 0) {
- error("could not open %s: %s",
- cur_tapedev, strerror(errno));
- }
- } else{
- if(tapefd_fsf(tapefd, 1) < 0) {
- error("could not fsf %s: %s",
- cur_tapedev, strerror(errno));
- }
- }
- }
- tapefd_close(tapefd);
-
- /* spit out our accumulated list of dumps, if we're inventorying */
- if(logstream){
- logline = log_genstring(L_START, "taper",
- "datestamp %s label %s tape %d",
- tapestart.datestamp, tapestart.name, slot_num);
- fprintf(logstream, logline);
- for(fileentry=tape_seen->files; fileentry; fileentry=fileentry->next){
- logline = NULL;
- switch(fileentry->file->type){
- case F_DUMPFILE:
- logline = log_genstring(L_SUCCESS, "taper",
- "%s %s %s %d [faked log entry]",
- fileentry->file->name,
- fileentry->file->disk,
- fileentry->file->datestamp,
- fileentry->file->dumplevel);
- break;
- case F_SPLIT_DUMPFILE:
- logline = log_genstring(L_CHUNK, "taper",
- "%s %s %s %d %d [faked log entry]",
- fileentry->file->name,
- fileentry->file->disk,
- fileentry->file->datestamp,
- fileentry->file->partnum,
- fileentry->file->dumplevel);
- break;
- default:
- break;
- }
- if(logline){
- fprintf(logstream, logline);
- amfree(logline);
- fflush(logstream);
- }
- }
- }
fprintf(stderr, "%s: Search of %s complete\n",
get_pname(), tape_seen->label);
- if(desired_tape) desired_tape = desired_tape->next;
+ if (desired_tape) desired_tape = desired_tape->next;
/* only restore a single dump, if piping to stdout */
- if(!headers_equal(&prev_rst_file, &file, 1) &&
- flags->pipe_to_fd == fileno(stdout)) break;
- }
+ if (!headers_equal(&prev_rst_file, &file, 1) &&
+ flags->pipe_to_fd == fileno(stdout))
+ break;
+
+ } while (desired_tape);
- while(seentapes != NULL) {
- struct seentapes *tape_seen = seentapes;
+ while (seentapes != NULL) {
+ seentapes_t *tape_seen = seentapes;
seentapes = seentapes->next;
while(tape_seen->files != NULL) {
dumplist_t *temp_dump = tape_seen->files;
/*
* Create a new, clean set of restore flags with some sane default values.
*/
-rst_flags_t *new_rst_flags()
+rst_flags_t *
+new_rst_flags(void)
{
- rst_flags_t *flags = alloc(sizeof(rst_flags_t));
+ rst_flags_t *flags = alloc(SIZEOF(rst_flags_t));
- memset(flags, 0, sizeof(rst_flags_t));
+ memset(flags, 0, SIZEOF(rst_flags_t));
flags->fsf = 1;
flags->comp_type = COMPRESS_FAST_OPT;
* Make sure the set of restore options given is sane. Print errors for
* things that're odd, and return -1 for fatal errors.
*/
-int check_rst_flags(rst_flags_t *flags)
+int
+check_rst_flags(
+ rst_flags_t * flags)
{
int ret = 0;
/*
* Clean up after a rst_flags_t
*/
-void free_rst_flags(flags)
-rst_flags_t *flags;
+void
+free_rst_flags(
+ rst_flags_t * flags)
{
if(!flags) return;
- if(flags->restore_dir) amfree(flags->restore_dir);
- if(flags->alt_tapedev) amfree(flags->alt_tapedev);
- if(flags->inventory_log) amfree(flags->inventory_log);
+ amfree(flags->restore_dir);
+ amfree(flags->alt_tapedev);
+ amfree(flags->inventory_log);
amfree(flags);
}
/*
* Clean up after a match_list_t
*/
-void free_match_list(match_list)
-match_list_t *match_list;
+void
+free_match_list(
+ match_list_t * match_list)
{
match_list_t *me;
match_list_t *prev = NULL;
for(me = match_list; me; me = me->next){
/* XXX freeing these is broken? can't work out why */
-/* if(me->hostname) amfree(me->hostname);
- if(me->diskname) amfree(me->diskname);
- if(me->datestamp) amfree(me->datestamp);
- if(me->level) amfree(me->level); */
- if(prev) amfree(prev);
+/* amfree(me->hostname);
+ amfree(me->diskname);
+ amfree(me->datestamp);
+ amfree(me->level); */
+ amfree(prev);
prev = me;
}
- if(prev) amfree(prev);
+ amfree(prev);
}
+
+
+printf_arglist_function3(
+ void send_message,
+ FILE *, prompt_out,
+ rst_flags_t *, flags,
+ am_feature_t *, their_features,
+ char *, format)
+{
+ va_list argp;
+ char linebuf[STR_SIZE];
+
+ arglist_start(argp, format);
+ vsnprintf(linebuf, SIZEOF(linebuf)-1, format, argp);
+ arglist_end(argp);
+
+ fprintf(stderr,"%s\n", linebuf);
+ if (flags->amidxtaped && their_features &&
+ am_has_feature(their_features, fe_amrecover_message)) {
+ fprintf(prompt_out, "MESSAGE %s\r\n", linebuf);
+ fflush(prompt_out);
+ }
+}
+