X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=restore-src%2Famrestore.c;h=aef4bafda198f8936f54f31ce99c05ec842394d5;hb=2627875b7d18858bc1f9f7652811e4d8c15a23eb;hp=e1161ba755d96ef8c44ef4c297a9ba0b0eb7b039;hpb=3ab887b9bc819a846c75dd7f2ee5d41fac22b19f;p=debian%2Famanda diff --git a/restore-src/amrestore.c b/restore-src/amrestore.c index e1161ba..aef4baf 100644 --- a/restore-src/amrestore.c +++ b/restore-src/amrestore.c @@ -24,7 +24,7 @@ * file named AUTHORS, in the root directory of this distribution. */ /* - * $Id: amrestore.c,v 1.28.2.4.4.3.2.8 2003/02/09 04:33:13 jrjackson Exp $ + * $Id: amrestore.c 6512 2007-05-24 17:00:24Z ian $ * * retrieves files from an amanda tape */ @@ -39,495 +39,186 @@ */ #include "amanda.h" -#include "tapeio.h" -#include "fileheader.h" #include "util.h" +#include "fileheader.h" +#include "restore.h" +#include "conffile.h" +#include "device.h" +#include "cmdline.h" #define CREAT_MODE 0640 -char *buffer = NULL; - -int compflag, rawflag, pipeflag, headerflag; -int got_sigpipe, file_number; -pid_t compress_pid = -1; -char *compress_type = COMPRESS_FAST_OPT; -int tapedev; -int bytes_read; -long blocksize = -1; -long filefsf = -1; - -/* local functions */ - -void errexit P((void)); -void handle_sigpipe P((int sig)); -int disk_match P((dumpfile_t *file, char *datestamp, - char *hostname, char *diskname)); -char *make_filename P((dumpfile_t *file)); -void read_file_header P((dumpfile_t *file, int isafile)); -static int get_block P((int isafile)); -void restore P((dumpfile_t *file, char *filename, int isafile)); -void usage P((void)); -int main P((int argc, char **argv)); - -void errexit() /* - * Do exit(2) after an error, rather than exit(1). - */ -{ - exit(2); -} - - -void handle_sigpipe(sig) -int sig; -/* - * Signal handler for the SIGPIPE signal. Just sets a flag and returns. - * The act of catching the signal causes the pipe write() to fail with - * EINTR. + * Print usage message and terminate. */ -{ - got_sigpipe++; -} - -int disk_match(file, datestamp, hostname, diskname) -dumpfile_t *file; -char *datestamp, *hostname, *diskname; -/* - * 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. - */ +static void +usage(void) { - if(file->type != F_DUMPFILE) return 0; - - if((*hostname == '\0' || match_host(hostname, file->name)) && - (*diskname == '\0' || match_disk(diskname, file->disk)) && - (*datestamp== '\0' || match_datestamp(datestamp, file->datestamp))) - return 1; - else - return 0; + error(_("Usage: amrestore [-b blocksize] [-r|-c] [-p] [-h] [-f fileno] " + "[-l label] tape-device|holdingfile [hostname [diskname [datestamp " + "[hostname [diskname [datestamp ... ]]]]]]")); + /*NOTREACHED*/ } - -char *make_filename(file) -dumpfile_t *file; -{ - char number[NUM_STR_SIZE]; - char *sfn; - char *fn; - - ap_snprintf(number, sizeof(number), "%d", file->dumplevel); - sfn = sanitise_filename(file->disk); - fn = vstralloc(file->name, - ".", - sfn, - ".", - file->datestamp, - ".", - number, - NULL); - amfree(sfn); - return fn; +/* Checks if the given tape device is actually a holding disk file. We + accomplish this by stat()ing the file; if it is a regular file, we + assume (somewhat dangerously) that it's a holding disk file. If + it doesn't exist or is not a regular file, we assume it's a device + name. + + Returns TRUE if we suspect the device is a holding disk, FALSE + otherwise. */ +static gboolean check_device_type(char * device_name) { + struct stat stat_buf; + int result; + + result = stat(device_name, &stat_buf); + + return !((result != 0 || !S_ISREG(stat_buf.st_mode))); } +static void handle_holding_disk_restore(char * filename, rst_flags_t * flags, + GSList * dumpspecs) { + dumpfile_t this_header; + tapelist_t this_disk; -static int get_block(isafile) -int isafile; -{ - static int test_blocksize = 1; - int buflen; + bzero(&this_disk, sizeof(this_disk)); + this_disk.label = filename; - /* - * If this is the first call, set the blocksize if it was not on - * the command line. Allocate the I/O buffer in any case. - * - * For files, the blocksize is always DISK_BLOCK_BYTES. For tapes, - * we allocate a large buffer and set the size to the length of the - * first (successful) record. - */ - buflen = blocksize; - if(test_blocksize) { - if(blocksize < 0) { - if(isafile) { - blocksize = buflen = DISK_BLOCK_BYTES; - } else { - buflen = MAX_TAPE_BLOCK_BYTES; - } - } - buffer = newalloc(buffer, buflen); - } - if(isafile) { - bytes_read = fullread(tapedev, buffer, buflen); - } else { - bytes_read = tapefd_read(tapedev, buffer, buflen); - if(blocksize < 0 && bytes_read > 0 && bytes_read < buflen) { - char *new_buffer; - - blocksize = bytes_read; - new_buffer = alloc(blocksize); - memcpy(new_buffer, buffer, bytes_read); - amfree(buffer); - buffer = new_buffer; - } + if (!restore_holding_disk(stderr, flags, NULL, &this_disk, NULL, + dumpspecs, &this_header, NULL)) { + g_fprintf(stderr, "%s did not match requested host.\n", filename); + return; } - if(blocksize > 0) { - test_blocksize = 0; - } - return bytes_read; } +static void handle_tape_restore(char * device_name, rst_flags_t * flags, + GSList * dumpspecs, char * check_label) { + Device * device; + DeviceStatusFlags device_status; -void read_file_header(file, isafile) -dumpfile_t *file; -int isafile; -/* - * Reads the first block of a tape file. - */ -{ - bytes_read = get_block(isafile); - if(bytes_read < 0) { - error("error reading file header: %s", strerror(errno)); - } else if(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: %d byte%s\n", - get_pname(), bytes_read, (bytes_read == 1) ? "" : "s"); - } - file->type = F_UNKNOWN; - } else { - parse_file_header(buffer, file, bytes_read); - } - return; -} + dumpfile_t first_restored_file; + device_api_init(); -void restore(file, filename, isafile) -dumpfile_t *file; -char *filename; -int isafile; -/* - * Restore the current file from tape. Depending on the settings of - * the command line flags, the file might need to be compressed or - * uncompressed. If so, a pipe through compress or uncompress is set - * up. The final output usually goes to a file named host.disk.date.lev, - * but with the -p flag the output goes to stdout (and presumably is - * piped to restore). - */ -{ - int rc = 0, dest, out, outpipe[2]; - int wc; - int l, s; - int file_is_compressed; - - /* adjust compression flag */ - - file_is_compressed = file->compressed; - if(!compflag && file_is_compressed && !known_compress_type(file)) { - fprintf(stderr, - "%s: unknown compression suffix %s, can't uncompress\n", - get_pname(), file->comp_suffix); - compflag = 1; + fh_init(&first_restored_file); + + device = device_open(device_name); + g_assert(device != NULL); + if (device->status != DEVICE_STATUS_SUCCESS) { + error("Could not open device %s: %s.\n", device_name, device_error(device)); } - - /* set up final destination file */ - - if(pipeflag) - dest = 1; /* standard output */ - else { - char *filename_ext = NULL; - - if(compflag) { - filename_ext = file_is_compressed ? file->comp_suffix - : COMPRESS_SUFFIX; - } else if(rawflag) { - filename_ext = ".RAW"; - } else { - filename_ext = ""; - } - filename_ext = stralloc2(filename, filename_ext); - - if((dest = creat(filename, CREAT_MODE)) < 0) - error("could not create output file: %s", strerror(errno)); - amfree(filename_ext); + + if (!set_restore_device_read_buffer_size(device, flags)) { + error("Error setting read block size: %s.\n", device_error_or_status(device)); } - - out = dest; - - /* - * If -r or -h, write the header before compress or uncompress pipe. - * Only write DISK_BLOCK_BYTES, regardless of how much was read. - * This makes the output look like a holding disk image, and also - * makes it easier to remove the header (e.g. in amrecover) since - * it has a fixed size. - */ - if(rawflag || headerflag) { - int w; - char *cont_filename; - - if(compflag && !file_is_compressed) { - file->compressed = 1; - ap_snprintf(file->uncompress_cmd, sizeof(file->uncompress_cmd), - " %s %s |", UNCOMPRESS_PATH, -#ifdef UNCOMPRESS_OPT - UNCOMPRESS_OPT -#else - "" -#endif - ); - strncpy(file->comp_suffix, - COMPRESS_SUFFIX, - sizeof(file->comp_suffix)-1); - file->comp_suffix[sizeof(file->comp_suffix)-1] = '\0'; - } - - /* remove CONT_FILENAME from header */ - cont_filename = stralloc(file->cont_filename); - memset(file->cont_filename,'\0',sizeof(file->cont_filename)); - file->blocksize = DISK_BLOCK_BYTES; - build_header(buffer, file, bytes_read); - - if((w = fullwrite(out, buffer, DISK_BLOCK_BYTES)) != DISK_BLOCK_BYTES) { - if(w < 0) { - error("write error: %s", strerror(errno)); - } else { - error("write error: %d instead of %d", w, DISK_BLOCK_BYTES); - } - } - /* add CONT_FILENAME to header */ - strncpy(file->cont_filename, cont_filename, sizeof(file->cont_filename)); + device_status = device_read_label(device); + if (device_status != DEVICE_STATUS_SUCCESS) { + error("Error reading volume label: %s.\n", device_error_or_status(device)); } - /* if -c and file not compressed, insert compress pipe */ + g_assert(device->volume_label != NULL); - if(compflag && !file_is_compressed) { - if(pipe(outpipe) < 0) error("error [pipe: %s]", strerror(errno)); - out = outpipe[1]; - switch(compress_pid = fork()) { - case -1: error("could not fork for %s: %s", - COMPRESS_PATH, strerror(errno)); - default: - aclose(outpipe[0]); - aclose(dest); - break; - case 0: - aclose(outpipe[1]); - if(outpipe[0] != 0) { - if(dup2(outpipe[0], 0) == -1) - error("error [dup2 pipe: %s]", strerror(errno)); - aclose(outpipe[0]); - } - if(dest != 1) { - if(dup2(dest, 1) == -1) - error("error [dup2 dest: %s]", strerror(errno)); - aclose(dest); - } - if (*compress_type == '\0') { - compress_type = NULL; - } - execlp(COMPRESS_PATH, COMPRESS_PATH, compress_type, (char *)0); - error("could not exec %s: %s", COMPRESS_PATH, strerror(errno)); - } + if (!device_start(device, ACCESS_READ, NULL, NULL)) { + error("Could not open device %s for reading: %s.\n", device_name, + device_error(device)); } - /* if not -r or -c, and file is compressed, insert uncompress pipe */ - - else if(!rawflag && !compflag && file_is_compressed) { - /* - * XXX for now we know that for the two compression types we - * understand, .Z and optionally .gz, UNCOMPRESS_PATH will take - * care of both. Later, we may need to reference a table of - * possible uncompress programs. - */ - if(pipe(outpipe) < 0) error("error [pipe: %s]", strerror(errno)); - out = outpipe[1]; - switch(compress_pid = fork()) { - case -1: - error("could not fork for %s: %s", - UNCOMPRESS_PATH, strerror(errno)); - default: - aclose(outpipe[0]); - aclose(dest); - break; - case 0: - aclose(outpipe[1]); - if(outpipe[0] != 0) { - if(dup2(outpipe[0], 0) < 0) - error("dup2 pipe: %s", strerror(errno)); - aclose(outpipe[0]); - } - if(dest != 1) { - if(dup2(dest, 1) < 0) - error("dup2 dest: %s", strerror(errno)); - aclose(dest); - } - (void) execlp(UNCOMPRESS_PATH, UNCOMPRESS_PATH, -#ifdef UNCOMPRESS_OPT - UNCOMPRESS_OPT, -#endif - (char *)0); - error("could not exec %s: %s", UNCOMPRESS_PATH, strerror(errno)); - } + if (check_label != NULL && strcmp(check_label, + device->volume_label) != 0) { + error("Wrong label: Expected %s, found %s.\n", + check_label, device->volume_label); } - - /* copy the rest of the file from tape to the output */ - got_sigpipe = 0; - wc = 0; - do { - bytes_read = get_block(isafile); - if(bytes_read < 0) { - error("read error: %s", strerror(errno)); - } - if(bytes_read == 0 && isafile) { - /* - * See if we need to switch to the next file. - */ - if(file->cont_filename[0] == '\0') { - break; /* no more files */ - } - close(tapedev); - if((tapedev = open(file->cont_filename, O_RDONLY)) == -1) { - char *cont_filename = strrchr(file->cont_filename,'/'); - if(cont_filename) { - cont_filename++; - if((tapedev = open(cont_filename,O_RDONLY)) == -1) { - error("can't open %s: %s", file->cont_filename, - strerror(errno)); - } - else { - fprintf(stderr, "cannot open %s: %s\n", - file->cont_filename, strerror(errno)); - fprintf(stderr, "using %s\n", - cont_filename); - } - } - else { - error("can't open %s: %s", file->cont_filename, - strerror(errno)); - } - } - read_file_header(file, isafile); - if(file->type != F_DUMPFILE && file->type != F_CONT_DUMPFILE) { - fprintf(stderr, "unexpected header type: "); - print_header(stderr, file); - exit(2); - } - continue; - } - for(l = 0; l < bytes_read; l += s) { - if((s = write(out, buffer + l, bytes_read - l)) < 0) { - if(got_sigpipe) { - fprintf(stderr,"Error %d (%s) offset %d+%d, wrote %d\n", - errno, strerror(errno), wc, bytes_read, rc); - fprintf(stderr, - "%s: pipe reader has quit in middle of file.\n", - get_pname()); - } else { - perror("amrestore: write error"); - } - exit(2); - } - } - wc += bytes_read; - } while (bytes_read > 0); - if(pipeflag) { - if(out != dest) { - aclose(out); - } - } else { - aclose(out); - } + search_a_tape(device, stderr, flags, NULL, NULL, dumpspecs, + NULL, &first_restored_file, 0, NULL); } - -void usage() -/* - * Print usage message and terminate. - */ -{ - error("Usage: amrestore [-b blocksize] [-r|-c] [-p] [-h] [-f fileno] [-l label] tape-device|holdingfile [hostname [diskname [datestamp [hostname [diskname [datestamp ... ]]]]]]"); -} - - -int main(argc, argv) -int argc; -char **argv; /* * Parses command line, then loops through all files on tape, restoring * files that match the command line criteria. */ + +int +main( + int argc, + char ** argv) { extern int optind; int opt; - char *errstr; - int isafile; - struct stat stat_tape; - dumpfile_t file; - char *filename = NULL; + int holding_disk_mode; char *tapename = NULL; - struct match_list { - char *hostname; - char *diskname; - char *datestamp; - struct match_list *next; - } *match_list = NULL, *me = NULL; - int found_match; - int arg_state; - amwait_t compress_status; - int fd; - int r = 0; char *e; - char *err; char *label = NULL; + rst_flags_t *rst_flags; + long tmplong; + GSList *dumpspecs; + config_overwrites_t *cfg_ovr; - for(fd = 3; fd < FD_SETSIZE; fd++) { - /* - * Make sure nobody spoofs us with a lot of extra open files - * that would cause an open we do to get a very high file - * descriptor, which in turn might be used as an index into - * an array (e.g. an fd_set). - */ - close(fd); - } + /* + * Configure program for internationalization: + * 1) Only set the message locale for now. + * 2) Set textdomain for all amanda related programs to "amanda" + * We don't want to be forced to support dozens of message catalogs. + */ + setlocale(LC_MESSAGES, "C"); + textdomain("amanda"); + + safe_fd(-1, 0); set_pname("amrestore"); + dbopen(DBG_SUBDIR_SERVER); + + /* Don't die when child closes pipe */ + signal(SIGPIPE, SIG_IGN); + erroutput_type = ERR_INTERACTIVE; + error_exit_status = 2; - onerror(errexit); - signal(SIGPIPE, handle_sigpipe); + rst_flags = new_rst_flags(); + rst_flags->inline_assemble = 0; + cfg_ovr = new_config_overwrites(argc/2); /* handle options */ - while( (opt = getopt(argc, argv, "b:cCd:rpkhf:l:")) != -1) { + while( (opt = getopt(argc, argv, "b:cCd:rphf:l:o:")) != -1) { switch(opt) { case 'b': - blocksize = strtol(optarg, &e, 10); + tmplong = strtol(optarg, &e, 10); + rst_flags->blocksize = (ssize_t)tmplong; if(*e == 'k' || *e == 'K') { - blocksize *= 1024; + rst_flags->blocksize *= 1024; } else if(*e == 'm' || *e == 'M') { - blocksize *= 1024 * 1024; + rst_flags->blocksize *= 1024 * 1024; } else if(*e != '\0') { - error("invalid blocksize value \"%s\"", optarg); - } - if(blocksize < DISK_BLOCK_BYTES) { - error("minimum block size is %dk", DISK_BLOCK_BYTES / 1024); + error(_("invalid blocksize value \"%s\""), optarg); + /*NOTREACHED*/ } break; - case 'c': compflag = 1; break; - case 'C': compflag = 1; compress_type = COMPRESS_BEST_OPT; break; - case 'r': rawflag = 1; break; - case 'p': pipeflag = 1; break; - case 'h': headerflag = 1; break; - case 'f': - filefsf = strtol(optarg, &e, 10); + case 'c': rst_flags->compress = 1; break; + case 'o': + add_config_overwrite_opt(cfg_ovr, optarg); + break; + case 'C': + rst_flags->compress = 1; + rst_flags->comp_type = COMPRESS_BEST_OPT; + break; + case 'r': rst_flags->raw = 1; break; + case 'p': rst_flags->pipe_to_fd = fileno(stdout); break; + case 'h': rst_flags->headers = 1; break; + case 'f': rst_flags->fsf = (off_t)OFF_T_STRTOL(optarg, &e, 10); + /*@ignore@*/ if(*e != '\0') { - error("invalid fileno value \"%s\"", optarg); - } + error(_("invalid fileno value \"%s\""), optarg); + g_assert_not_reached(); + } + /*@end@*/ break; case 'l': + if (label) { + error(_("Cannot specify multiple labels.\n")); + } label = stralloc(optarg); break; default: @@ -535,228 +226,55 @@ char **argv; } } - if(compflag && rawflag) { - fprintf(stderr, - "Cannot specify both -r (raw) and -c (compressed) output.\n"); + /* initialize a generic configuration without reading anything */ + config_init(0, NULL); + apply_config_overwrites(cfg_ovr); + + if (config_errors(NULL) >= CFGERR_WARNINGS) { + config_print_errors(); + if (config_errors(NULL) >= CFGERR_ERRORS) { + g_critical(_("errors processing config file")); + } + } + + if(rst_flags->compress && rst_flags->raw) { + g_fprintf(stderr, + _("Cannot specify both -r (raw) and -c (compressed) output.\n")); usage(); } if(optind >= argc) { - fprintf(stderr, "%s: Must specify tape-device or holdingfile\n", + g_fprintf(stderr, _("%s: Must specify tape-device or holdingfile\n"), get_pname()); usage(); } tapename = argv[optind++]; -#define ARG_GET_HOST 0 -#define ARG_GET_DISK 1 -#define ARG_GET_DATE 2 - - arg_state = ARG_GET_HOST; - while(optind < argc) { - switch(arg_state) { - case ARG_GET_HOST: - /* - * This is a new host/disk/date triple, so allocate a match_list. - */ - me = alloc(sizeof(*me)); - me->hostname = argv[optind++]; - me->diskname = ""; - me->datestamp = ""; - me->next = match_list; - match_list = me; - if(me->hostname[0] != '\0' - && (errstr=validate_regexp(me->hostname)) != NULL) { - fprintf(stderr, "%s: bad hostname regex \"%s\": %s\n", - get_pname(), me->hostname, errstr); - usage(); - } - arg_state = ARG_GET_DISK; - break; - case ARG_GET_DISK: - me->diskname = argv[optind++]; - if(me->diskname[0] != '\0' - && (errstr=validate_regexp(me->diskname)) != NULL) { - fprintf(stderr, "%s: bad diskname regex \"%s\": %s\n", - get_pname(), me->diskname, errstr); - usage(); - } - arg_state = ARG_GET_DATE; - break; - case ARG_GET_DATE: - me->datestamp = argv[optind++]; - if(me->datestamp[0] != '\0' - && (errstr=validate_regexp(me->datestamp)) != NULL) { - fprintf(stderr, "%s: bad datestamp regex \"%s\": %s\n", - get_pname(), me->datestamp, errstr); - usage(); - } - arg_state = ARG_GET_HOST; - break; - } - } - if(match_list == NULL) { - match_list = alloc(sizeof(*match_list)); - match_list->hostname = ""; - match_list->diskname = ""; - match_list->datestamp = ""; - match_list->next = NULL; - } + dumpspecs = cmdline_parse_dumpspecs(argc - optind, argv + optind, + CMDLINE_PARSE_DATESTAMP | + CMDLINE_EMPTY_TO_WILDCARD); - if(tape_stat(tapename,&stat_tape)!=0) { - error("could not stat %s: %s", tapename, strerror(errno)); - } - isafile=S_ISREG((stat_tape.st_mode)); + holding_disk_mode = check_device_type(tapename); - if(label) { - if(isafile) { - fprintf(stderr,"%s: ignoring -l flag when restoring from a file.\n", + if (holding_disk_mode) { + if (label) { + g_fprintf(stderr,_("%s: ignoring -l flag when restoring from a file.\n"), get_pname()); - } - else { - if((err = tape_rewind(tapename)) != NULL) { - error("Could not rewind device '%s': %s", tapename, err); - } - tapedev = tape_open(tapename, 0); - read_file_header(&file, isafile); - if(file.type != F_TAPESTART) { - fprintf(stderr,"Not an amanda tape\n"); - exit (1); - } - if(strcmp(label, file.name) != 0) { - fprintf(stderr,"Wrong label: '%s'\n", file.name); - exit (1); - } - tapefd_close(tapedev); - if((err = tape_rewind(tapename)) != NULL) { - error("Could not rewind device '%s': %s", tapename, err); - } - } - } - file_number = 0; - if(filefsf != -1) { - if(isafile) { - fprintf(stderr,"%s: ignoring -f flag when restoring from a file.\n", + } + + if (rst_flags->fsf > 0) { + g_fprintf(stderr, + "%s: ignoring -f flag when restoring from a file.\n", get_pname()); - } - else { - if((err = tape_rewind(tapename)) != NULL) { - error("Could not rewind device '%s': %s", tapename, err); - } - if((err = tape_fsf(tapename,filefsf)) != NULL) { - error("Could not fsf device '%s': %s", tapename, err); - } - file_number = filefsf; - } - } + } - if(isafile) { - tapedev = open(tapename, 0); + handle_holding_disk_restore(tapename, rst_flags, dumpspecs); } else { - tapedev = tape_open(tapename, 0); - } - if(tapedev < 0) { - error("could not open %s: %s", tapename, strerror(errno)); - } - - read_file_header(&file, isafile); - - if(file.type != F_TAPESTART && !isafile && filefsf == -1) { - fprintf(stderr, "%s: WARNING: not at start of tape, file numbers will be offset\n", - get_pname()); + handle_tape_restore(tapename, rst_flags, dumpspecs, label); } - while(file.type == F_TAPESTART || file.type == F_DUMPFILE) { - amfree(filename); - filename = make_filename(&file); - found_match = 0; - for(me = match_list; me; me = me->next) { - if(disk_match(&file,me->datestamp,me->hostname,me->diskname) != 0) { - found_match = 1; - break; - } - } - fprintf(stderr, "%s: %3d: %s ", - get_pname(), - file_number, - found_match ? "restoring" : "skipping"); - if(file.type != F_DUMPFILE) { - print_header(stderr, &file); - } else { - fprintf(stderr, "%s\n", filename); - } - if(found_match) { - restore(&file, filename, isafile); - if(compress_pid > 0) { - waitpid(compress_pid, &compress_status, 0); - compress_pid = -1; - } - if(pipeflag) { - file_number++; /* for the last message */ - break; - } - } - if(isafile) { - break; - } - /* - * Note that at this point we know we are working with a tape, - * not a holding disk file, so we can call the tape functions - * without checking. - */ - if(bytes_read == 0) { - /* - * If the last read got EOF, how to get to the next - * file depends on how the tape device driver is acting. - * If it is BSD-like, we do not really need to do anything. - * If it is Sys-V-like, we need to either fsf or close/open. - * The good news is, a close/open works in either case, - * so that's what we do. - */ - tapefd_close(tapedev); - if((tapedev = tape_open(tapename, 0)) < 0) { - error("could not open %s: %s", tapename, strerror(errno)); - } - } else { - /* - * If the last read got something (even an error), we can - * do an fsf to get to the next file. - */ - if(tapefd_fsf(tapedev, 1) < 0) { - error("could not fsf %s: %s", tapename, strerror(errno)); - } - } - file_number++; - read_file_header(&file, isafile); - } - if(isafile) { - close(tapedev); - } else { - /* - * See the notes above about advancing to the next file. - */ - if(bytes_read == 0) { - tapefd_close(tapedev); - if((tapedev = tape_open(tapename, 0)) < 0) { - error("could not open %s: %s", tapename, strerror(errno)); - } - } else { - if(tapefd_fsf(tapedev, 1) < 0) { - error("could not fsf %s: %s", tapename, strerror(errno)); - } - } - tapefd_close(tapedev); - } + dumpspec_list_free(dumpspecs); - if((bytes_read <= 0 || file.type == F_TAPEEND) && !isafile) { - fprintf(stderr, "%s: %3d: reached ", get_pname(), file_number); - if(bytes_read <= 0) { - fprintf(stderr, "end of information\n"); - } else { - print_header(stderr,&file); - } - r = 1; - } - return r; + return 0; }