X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=restore-src%2Frestore.c;h=da4e5f7aef50ca616b779d541a1510e5d8c5d641;hb=refs%2Ftags%2Fdebian%2F2.5.1-1;hp=35818efec636aefba7ef59b310191248bf9009ac;hpb=6663e25ecad46c729d9be4f8585c51b523ac9044;p=debian%2Famanda diff --git a/restore-src/restore.c b/restore-src/restore.c index 35818ef..da4e5f7 100644 --- a/restore-src/restore.c +++ b/restore-src/restore.c @@ -24,7 +24,7 @@ * 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 */ @@ -37,17 +37,21 @@ #include "changer.h" #include "logfile.h" #include "fileheader.h" +#include "arglist.h" #include +#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; @@ -61,35 +65,66 @@ typedef struct open_output_s { 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, + 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 == '/') { @@ -99,7 +134,9 @@ int lock_logfile() } 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; @@ -110,9 +147,11 @@ int lock_logfile() * 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); @@ -132,8 +171,9 @@ int ignore_partnums; * 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; @@ -148,51 +188,53 @@ dumpfile_t *file; * 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 %d bytes expected %d.", s, bytes_read); + /*NOTREACHCED*/ } - wc += bytes_read; + wc += (off_t)bytes_read; } amfree(buffer); @@ -203,39 +245,54 @@ int fd; * 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"); @@ -248,7 +305,7 @@ char *device; amfree(errstr); } amfree(cur_tapedev); - curslot = stralloc(slotstr); + curslot = newstralloc(curslot, slotstr); amfree(datestamp); amfree(label); if(device) @@ -259,8 +316,8 @@ char *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); @@ -276,9 +333,10 @@ char *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; @@ -288,7 +346,7 @@ int upto; 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){ @@ -321,9 +379,10 @@ int upto; * 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; @@ -353,16 +412,16 @@ dumpfile_t *only_file; 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; @@ -390,31 +449,41 @@ dumpfile_t *only_file; /* 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; @@ -437,7 +506,7 @@ dumpfile_t *only_file; */ 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)){ @@ -460,8 +529,9 @@ dumpfile_t *only_file; /* * 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]; @@ -469,23 +539,23 @@ dumpfile_t *file; 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, @@ -496,8 +566,8 @@ dumpfile_t *file; ".", number, NULL); - if(file->partnum > 0){ - fn = vstralloc(fn, ".", part, NULL); + if (file->partnum > 0) { + vstrextend(&fn, ".", part, NULL); } amfree(sfn); amfree(pad); @@ -506,12 +576,15 @@ dumpfile_t *file; /* -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)); @@ -519,18 +592,23 @@ char *buffer; 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; @@ -544,55 +622,58 @@ char *datestamp, *hostname, *diskname, *level; } -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 < blocksize) { 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); @@ -600,18 +681,13 @@ rst_flags_t *flags; 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 @@ -620,6 +696,14 @@ rst_flags_t *flags; * 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; @@ -638,21 +722,24 @@ rst_flags_t *flags; 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 @@ -679,19 +766,22 @@ rst_flags_t *flags; 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 */ @@ -731,10 +821,11 @@ rst_flags_t *flags; } final_filename = stralloc(tmp_filename); tmp_filename = newvstralloc(tmp_filename, ".tmp", NULL); - if((dest = creat(tmp_filename, CREAT_MODE)) < 0) { + 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); } @@ -750,13 +841,12 @@ rst_flags_t *flags; * 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 @@ -766,15 +856,14 @@ rst_flags_t *flags; ); 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; /* @@ -791,17 +880,15 @@ rst_flags_t *flags; 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); + /*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 */ @@ -821,14 +908,18 @@ rst_flags_t *flags; /* 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; @@ -841,29 +932,38 @@ rst_flags_t *flags; 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*/ } } } @@ -873,22 +973,28 @@ rst_flags_t *flags; * 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; } @@ -896,6 +1002,7 @@ rst_flags_t *flags; 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) { /* @@ -913,42 +1020,56 @@ rst_flags_t *flags; 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); @@ -956,11 +1077,11 @@ rst_flags_t *flags; 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 @@ -969,8 +1090,12 @@ rst_flags_t *flags; */ break; } - perror("restore: write error"); - exit(2); + error("restore: write error: %s", strerror(errno)); + /* NOTREACHED */ + } else if (s < bytes_read) { + error("restore: wrote %d of %d bytes: %s", + s, bytes_read, strerror(errno)); + /* NOTREACHED */ } } else if(isafile) { @@ -988,6 +1113,7 @@ rst_flags_t *flags; 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", @@ -999,9 +1125,10 @@ rst_flags_t *flags; 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: "); @@ -1019,9 +1146,12 @@ rst_flags_t *flags; } 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){ @@ -1063,7 +1193,8 @@ rst_flags_t *flags; } 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); @@ -1073,13 +1204,14 @@ rst_flags_t *flags; } } 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); /* @@ -1087,9 +1219,9 @@ rst_flags_t *flags; * 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; @@ -1098,7 +1230,9 @@ rst_flags_t *flags; 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 { @@ -1108,7 +1242,424 @@ rst_flags_t *flags; 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, + 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(stdin);/* 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(stdin)) == 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, @@ -1118,38 +1669,38 @@ rst_flags_t *flags; * 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, + 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; + ssize_t read_result; + int slot; + char *label = NULL; + seentapes_t *seentapes = NULL; + int ret; - struct seentapes{ - struct seentapes *next; - char *slotstr; - char *label; - dumplist_t *files; - } *seentapes = NULL; + dbprintf(("search_tapes(prompt=%p, use_changer=%d, tapelist=%p, " + "match_list=%p, flags=%p, features=%p)\n", + prompt_out, use_changer, tapelist, match_list, + flags, their_features)); if(!prompt_out) prompt_out = stderr; - if(flags->blocksize) blocksize = flags->blocksize; - else if(blocksize == -1) blocksize = DISK_BLOCK_BYTES; + 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); @@ -1160,16 +1711,18 @@ am_feature_t *their_features; 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*/ } } @@ -1182,8 +1735,10 @@ am_feature_t *their_features; 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); } @@ -1194,8 +1749,7 @@ am_feature_t *their_features; 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); } @@ -1213,6 +1767,11 @@ am_feature_t *their_features; } 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. @@ -1224,187 +1783,114 @@ am_feature_t *their_features; * * (obnoxious, isn't this?) */ - slot_num = 0; - curslot = stralloc(""); - 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, + 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(""); 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); @@ -1417,197 +1903,25 @@ am_feature_t *their_features; * 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; - /* 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); - } - } + 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); - 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; @@ -1633,11 +1947,12 @@ am_feature_t *their_features; /* * 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; @@ -1652,7 +1967,9 @@ rst_flags_t *new_rst_flags() * 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; @@ -1698,14 +2015,15 @@ int check_rst_flags(rst_flags_t *flags) /* * 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); } @@ -1714,20 +2032,45 @@ rst_flags_t *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); + } +} +