Imported Upstream version 2.5.1
[debian/amanda] / restore-src / restore.c
index 35818efec636aefba7ef59b310191248bf9009ac..da4e5f7aef50ca616b779d541a1510e5d8c5d641 100644 (file)
@@ -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
  */
 #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;
@@ -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("<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,
+                                      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);
@@ -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);
+    }
+}
+