2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1998 University of Maryland at College Park
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of U.M. not be used in advertising or
11 * publicity pertaining to distribution of the software without specific,
12 * written prior permission. U.M. makes no representations about the
13 * suitability of this software for any purpose. It is provided "as is"
14 * without express or implied warranty.
16 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 * Authors: the Amanda Development Team. Its members are listed in a
24 * file named AUTHORS, in the root directory of this distribution.
27 * $Id: restore.c 6512 2007-05-24 17:00:24Z ian $
29 * retrieves files from an amanda tape
38 #include "fileheader.h"
42 #include <timestamp.h>
49 LOAD_NEXT = 1, /* An unknown new slot has been loaded. */
50 LOAD_CHANGER = -2, /* The requested slot has been loaded. */
51 LOAD_STOP = -1, /* The search is complete. */
55 RESTORE_STATUS_NEXT_FILE,
56 RESTORE_STATUS_NEXT_TAPE,
62 /* stuff we're stuck having global */
64 static int exitassemble = 0;
66 char *rst_conf_logdir = NULL;
67 char *rst_conf_logfile = NULL;
68 static char *curslot = NULL;
70 typedef struct open_output_s {
71 struct open_output_s *next;
78 typedef struct dumplist_s {
79 struct dumplist_s *next;
84 struct seentapes_s *next;
90 static open_output_t *open_outputs = NULL;
91 static dumplist_t *alldumps_list = NULL;
95 static void append_file_to_fd(char *filename, int fd);
96 static int headers_equal(dumpfile_t *file1, dumpfile_t *file2, int ignore_partnums);
97 static int already_have_dump(dumpfile_t *file);
98 static void handle_sigint(int sig);
99 static int scan_init(void *ud, int rc, int ns, int bk, int s);
100 static Device * conditional_device_open(char * tapedev, FILE * orompt_out,
102 am_feature_t * their_features,
103 tapelist_t * desired_tape);
104 int loadlabel_slot(void *ud, int rc, char *slotstr, char *device);
105 char *label_of_current_slot(char *cur_tapedev, FILE *prompt_out,
106 int *tapefd, dumpfile_t *file, rst_flags_t *flags,
107 am_feature_t *their_features,
108 ssize_t *read_result, tapelist_t *desired_tape);
110 LoadStatus load_next_tape(char **cur_tapedev, FILE *prompt_out, int backwards,
111 rst_flags_t *flags, am_feature_t *their_features,
112 tapelist_t *desired_tape);
113 LoadStatus load_manual_tape(char **cur_tapedev, FILE *prompt_out, FILE *prompt_in,
114 rst_flags_t *flags, am_feature_t *their_features,
115 tapelist_t *desired_tape);
118 * We might want to flush any open dumps and unmerged splits before exiting
119 * on SIGINT, so do so.
125 (void)sig; /* Quiet unused parameter warning */
127 flush_open_outputs(exitassemble, NULL);
128 if(rst_conf_logfile) unlink(rst_conf_logfile);
135 rst_conf_logdir = config_dir_relative(getconf_str(CNF_LOGDIR));
136 rst_conf_logfile = vstralloc(rst_conf_logdir, "/log", NULL);
137 if (access(rst_conf_logfile, F_OK) == 0) {
138 dbprintf(_("%s exists: amdump or amflush is already running, "
139 "or you must run amcleanup\n"), rst_conf_logfile);
142 log_add(L_INFO, get_pname());
147 * Return 1 if the two fileheaders match in name, disk, type, split chunk part
148 * number, and datestamp, and 0 if not. The part number can be optionally
157 if(!file1 || !file2) return(0);
159 if(file1->dumplevel == file2->dumplevel &&
160 file1->type == file2->type &&
161 !strcmp(file1->datestamp, file2->datestamp) &&
162 !strcmp(file1->name, file2->name) &&
163 !strcmp(file1->disk, file2->disk) &&
164 (ignore_partnums || file1->partnum == file2->partnum)){
172 * See whether we're already pulled an exact copy of the given file (chunk
173 * number and all). Returns 0 if not, 1 if so.
179 dumplist_t *fileentry = NULL;
182 for(fileentry=alldumps_list;fileentry;fileentry=fileentry->next){
183 if(headers_equal(file, fileentry->file, 0)) return(1);
189 * Open the named file and append its contents to the (hopefully open) file
190 * descriptor supplies.
199 read_fd = robust_open(filename, O_RDONLY, 0);
201 error(_("can't open %s: %s"), filename, strerror(errno));
205 if (!do_consumer_producer_queue(fd_read_producer, GINT_TO_POINTER(read_fd),
207 GINT_TO_POINTER(write_fd))) {
208 error("Error copying data from file \"%s\" to fd %d.\n",
210 g_assert_not_reached();
216 /* A user_init function for changer_find(). See changer.h for
219 scan_init(G_GNUC_UNUSED void * ud, int rc, G_GNUC_UNUSED int ns,
220 int bk, G_GNUC_UNUSED int s) {
222 error(_("could not get changer info: %s"), changer_resultstr);
235 /* DANGER WILL ROBINSON: This function references globals:
239 loadlabel_slot(void * datap,
244 loadlabel_data * data = (loadlabel_data*)datap;
246 ReadLabelStatusFlags label_status;
248 g_return_val_if_fail(rc > 1 || device_name != NULL, 0);
249 g_return_val_if_fail(slotstr != NULL, 0);
254 error(_("could not load slot %s: %s"), slotstr, changer_resultstr);
255 g_assert_not_reached();
259 g_fprintf(stderr, _("%s: slot %s: %s\n"),
260 get_pname(), slotstr, changer_resultstr);
264 device = device_open(device_name);
265 if (device == NULL) {
266 g_fprintf(stderr, "%s: slot %s: Could not open device.\n",
267 get_pname(), slotstr);
271 device_set_startup_properties_from_config(device);
272 label_status = device_read_label(device);
273 if (label_status != READ_LABEL_STATUS_SUCCESS) {
275 g_english_strjoinv_and_free
276 (g_flags_nick_to_strv(label_status,
277 READ_LABEL_STATUS_FLAGS_TYPE), "or");
278 g_fprintf(stderr, "%s: slot %s: Error reading tape label:\n"
280 get_pname(), slotstr, get_pname(), slotstr, errstr);
281 g_object_unref(device);
285 g_assert(device->volume_label != NULL);
286 if (device->volume_label == NULL) {
287 g_fprintf(stderr, "%s: slot %s: Could not read tape label.\n",
288 get_pname(), slotstr);
289 g_object_unref(device);
293 if (!device_start(device, ACCESS_READ, NULL, NULL)) {
294 g_fprintf(stderr, "%s: slot %s: Could not open device for reading.\n",
295 get_pname(), slotstr);
299 g_fprintf(stderr, "%s: slot %s: time %-14s label %s",
300 get_pname(), slotstr, device->volume_time, device->volume_label);
302 if(strcmp(device->volume_label, data->searchlabel) != 0) {
303 g_fprintf(stderr, " (wrong tape)\n");
304 g_object_unref(device);
308 g_fprintf(stderr, " (exact label match)\n");
310 g_object_unref(device);
311 curslot = newstralloc(curslot, slotstr);
312 amfree(*(data->cur_tapedev));
313 *(data->cur_tapedev) = stralloc(device_name);
318 /* non-local functions follow */
323 * Check whether we've read all of the preceding parts of a given split dump,
324 * generally used to see if we're done and can close the thing.
332 int *foundparts = NULL;
333 dumplist_t *fileentry = NULL;
335 if(!file || file->partnum < 1) return(0);
337 if(upto < 1) upto = file->totalparts;
339 foundparts = alloc(SIZEOF(*foundparts) * upto);
340 for(c = 0 ; c< upto; c++) foundparts[c] = 0;
342 for(fileentry=alldumps_list;fileentry; fileentry=fileentry->next){
343 dumpfile_t *cur_file = fileentry->file;
344 if(headers_equal(file, cur_file, 1)){
345 if(cur_file->partnum > upto){
350 foundparts[cur_file->partnum - 1] = 1;
354 for(c = 0 ; c< upto; c++){
366 * Free up the open filehandles and memory we were using to track in-progress
367 * dumpfiles (generally for split ones we're putting back together). If
368 * applicable, also find the ones that are continuations of one another and
369 * string them together. If given an optional file header argument, flush
370 * only that dump and do not flush/free any others.
375 dumpfile_t *only_file)
377 open_output_t *cur_out = NULL, *prev = NULL;
378 find_result_t *sorted_files = NULL;
379 amwait_t compress_status;
382 g_fprintf(stderr, "\n");
386 * Deal with any split dumps we've been working on, appending pieces
387 * that haven't yet been appended and closing filehandles we've been
391 find_result_t *cur_find_res = NULL;
392 int outfd = -1, lastpartnum = -1;
393 dumpfile_t *main_file = NULL;
394 cur_out = open_outputs;
396 /* stick the dumpfile_t's into a list find_result_t's so that we can
397 abuse existing sort functionality */
398 for(cur_out=open_outputs; cur_out; cur_out=cur_out->next){
399 find_result_t *cur_find_res = NULL;
400 dumpfile_t *cur_file = cur_out->file;
401 /* if we requested a particular file, do only that one */
402 if(only_file && !headers_equal(cur_file, only_file, 1)){
405 cur_find_res = alloc(SIZEOF(find_result_t));
406 memset(cur_find_res, '\0', SIZEOF(find_result_t));
407 cur_find_res->timestamp = stralloc(cur_file->datestamp);
408 cur_find_res->hostname = stralloc(cur_file->name);
409 cur_find_res->diskname = stralloc(cur_file->disk);
410 cur_find_res->level = cur_file->dumplevel;
411 if(cur_file->partnum < 1) cur_find_res->partnum = stralloc("--");
413 char part_str[NUM_STR_SIZE];
414 g_snprintf(part_str, SIZEOF(part_str), "%d", cur_file->partnum);
415 cur_find_res->partnum = stralloc(part_str);
417 cur_find_res->user_ptr = (void*)cur_out;
419 cur_find_res->next = sorted_files;
420 sorted_files = cur_find_res;
422 sort_find_result("hkdlp", &sorted_files);
424 /* now we have an in-order list of the files we need to concatenate */
425 cur_find_res = sorted_files;
426 for(cur_find_res=sorted_files;
428 cur_find_res=cur_find_res->next){
429 dumpfile_t *cur_file = NULL;
430 cur_out = (open_output_t*)cur_find_res->user_ptr;
431 cur_file = cur_out->file;
433 /* if we requested a particular file, do only that one */
434 if(only_file && !headers_equal(cur_file, only_file, 1)){
438 if(cur_file->type == F_SPLIT_DUMPFILE) {
439 /* is it a continuation of one we've been writing? */
440 if(main_file && cur_file->partnum > lastpartnum &&
441 headers_equal(cur_file, main_file, 1)){
445 /* effectively changing filehandles */
446 aclose(cur_out->outfd);
447 cur_out->outfd = outfd;
449 cur_filename = make_filename(cur_file);
450 main_filename = make_filename(main_file);
451 g_fprintf(stderr, _("Merging %s with %s\n"),
452 cur_filename, main_filename);
453 append_file_to_fd(cur_filename, outfd);
454 if(unlink(cur_filename) < 0){
455 g_fprintf(stderr, _("Failed to unlink %s: %s\n"),
456 cur_filename, strerror(errno));
458 amfree(cur_filename);
459 amfree(main_filename);
463 if(outfd >= 0) aclose(outfd);
465 main_file = alloc(SIZEOF(dumpfile_t));
466 memcpy(main_file, cur_file, SIZEOF(dumpfile_t));
467 outfd = cur_out->outfd;
469 char *cur_filename = make_filename(cur_file);
470 open(cur_filename, O_RDWR|O_APPEND);
472 error(_("Couldn't open %s for appending: %s"),
473 cur_filename, strerror(errno));
476 amfree(cur_filename);
479 lastpartnum = cur_file->partnum;
482 aclose(cur_out->outfd);
490 free_find_result(&sorted_files);
494 * Now that the split dump closure is done, free up resources we don't
497 for(cur_out=open_outputs; cur_out; cur_out=cur_out->next){
498 dumpfile_t *cur_file = NULL;
500 cur_file = cur_out->file;
501 /* if we requested a particular file, do only that one */
502 if(only_file && !headers_equal(cur_file, only_file, 1)){
506 aclose(cur_out->outfd);
509 if(cur_out->comp_enc_pid > 0){
510 waitpid(cur_out->comp_enc_pid, &compress_status, 0);
512 amfree(cur_out->file);
520 * Turn a fileheader into a string suited for use on the filesystem.
526 char number[NUM_STR_SIZE];
527 char part[NUM_STR_SIZE];
528 char totalparts[NUM_STR_SIZE];
534 g_snprintf(number, SIZEOF(number), "%d", file->dumplevel);
535 g_snprintf(part, SIZEOF(part), "%d", file->partnum);
537 if(file->totalparts < 0) {
538 g_snprintf(totalparts, SIZEOF(totalparts), "UNKNOWN");
541 g_snprintf(totalparts, SIZEOF(totalparts), "%d", file->totalparts);
543 padlen = strlen(totalparts) + 1 - strlen(part);
545 memset(pad, '0', padlen);
546 pad[padlen - 1] = '\0';
548 g_snprintf(part, SIZEOF(part), "%s%d", pad, file->partnum);
550 sfn = sanitise_filename(file->disk);
551 fn = vstralloc(file->name,
559 if (file->partnum > 0) {
560 vstrextend(&fn, ".", part, NULL);
567 /* Returns 1 if the dump file matches the hostname and diskname
568 * regular expressions given on the command line, 0 otherwise. As a
569 * special case, empty regexs and NULLs are considered equivalent to
570 * ".*": they match everything.
572 * @param file: the file to examine
573 * @param datestamp: the datestamp regex, or NULL for any
574 * @param hostname: the hostname regex, or NULL for any
575 * @param diskname: the diskname regex, or NULL for any
576 * @param level: the level regex, or NULL for any
577 * @returns: 1 if the dump file matches
587 char level_str[NUM_STR_SIZE];
588 g_snprintf(level_str, SIZEOF(level_str), "%d", file->dumplevel);
590 if(file->type != F_DUMPFILE && file->type != F_SPLIT_DUMPFILE) return 0;
592 if((!hostname || *hostname == '\0' || match_host(hostname, file->name)) &&
593 (!diskname || *diskname == '\0' || match_disk(diskname, file->disk)) &&
594 (!datestamp || *datestamp == '\0' || match_datestamp(datestamp, file->datestamp)) &&
595 (!level || *level == '\0' || match_level(level, level_str)))
602 * Reads the first block of a holding disk file.
606 read_holding_disk_header(
615 if(flags->blocksize > 0)
616 blocksize = (size_t)flags->blocksize;
618 blocksize = DISK_BLOCK_BYTES;
619 buffer = alloc(blocksize);
621 bytes_read = fullread(tapefd, buffer, blocksize);
623 g_fprintf(stderr, _("%s: error reading file header: %s\n"),
624 get_pname(), strerror(errno));
625 file->type = F_UNKNOWN;
626 } else if((size_t)bytes_read < DISK_BLOCK_BYTES) {
627 if(bytes_read == 0) {
628 g_fprintf(stderr, _("%s: missing file header block\n"), get_pname());
631 plural(_("%s: short file header block: %zd byte"),
632 _("%s: short file header block: %zd bytes\n"),
634 get_pname(), (size_t)bytes_read);
636 file->type = F_UNKNOWN;
638 parse_file_header(buffer, file, (size_t)bytes_read);
641 return (file->type != F_UNKNOWN &&
642 file->type != F_EMPTY &&
643 file->type != F_WEIRD);
647 * Restore the current file from tape. Depending on the settings of
648 * the command line flags, the file might need to be compressed or
649 * uncompressed. If so, a pipe through compress or uncompress is set
650 * up. The final output usually goes to a file named host.disk.date.lev,
651 * but with the -p flag the output goes to stdout (and presumably is
656 /* FIXME: Mondo function that needs refactoring. */
657 void restore(RestoreSource * source,
661 int file_is_compressed;
662 int is_continuation = 0;
663 int check_for_aborted = 0;
664 char *tmp_filename = NULL, *final_filename = NULL;
665 struct stat statinfo;
666 open_output_t *myout = NULL, *oldout = NULL;
667 dumplist_t *tempdump = NULL, *fileentry = NULL;
669 int need_compress=0, need_uncompress=0, need_decrypt=0;
676 filename = make_filename(source->header);
678 memset(pipes, -1, SIZEOF(pipes));
680 if(already_have_dump(source->header)){
681 g_fprintf(stderr, _(" *** Duplicate file %s, one is probably an aborted write\n"), filename);
682 check_for_aborted = 1;
685 /* store a shorthand record of this dump */
686 tempdump = malloc(SIZEOF(dumplist_t));
687 tempdump->file = malloc(SIZEOF(dumpfile_t));
688 tempdump->next = NULL;
689 memcpy(tempdump->file, source->header, SIZEOF(dumpfile_t));
692 * If we're appending chunked files to one another, and if this is a
693 * continuation of a file we just restored, and we've still got the
694 * output handle from that previous restore, we're golden. Phew.
696 if(flags->inline_assemble && source->header->type == F_SPLIT_DUMPFILE){
697 myout = open_outputs;
698 while(myout != NULL){
699 if(myout->file->type == F_SPLIT_DUMPFILE &&
700 headers_equal(source->header, myout->file, 1)){
701 if(source->header->partnum == myout->lastpartnum + 1){
708 if(myout != NULL) myout->lastpartnum = source->header->partnum;
709 else if(source->header->partnum != 1){
710 g_fprintf(stderr, _("%s: Chunk out of order, will save to disk and append to output.\n"), get_pname());
711 flags->pipe_to_fd = -1;
713 flags->leave_comp = 1;
716 myout = alloc(SIZEOF(open_output_t));
717 memset(myout, 0, SIZEOF(open_output_t));
721 myout = alloc(SIZEOF(open_output_t));
722 memset(myout, 0, SIZEOF(open_output_t));
726 if(is_continuation && flags->pipe_to_fd == -1){
728 filename = make_filename(myout->file);
729 g_fprintf(stderr, _("%s: appending to %s\n"), get_pname(),
734 /* adjust compression flag */
735 file_is_compressed = source->header->compressed;
736 if(!flags->compress && file_is_compressed &&
737 !known_compress_type(source->header)) {
739 _("%s: unknown compression suffix %s, can't uncompress\n"),
740 get_pname(), source->header->comp_suffix);
744 /* set up final destination file */
746 if(is_continuation && myout != NULL) {
749 if(flags->pipe_to_fd != -1) {
750 dest = flags->pipe_to_fd;
752 char *filename_ext = NULL;
754 if(flags->compress) {
755 filename_ext = file_is_compressed ? source->header->comp_suffix
757 } else if(flags->raw) {
758 filename_ext = ".RAW";
762 filename_ext = stralloc2(filename, filename_ext);
763 tmp_filename = stralloc(filename_ext);
764 if(flags->restore_dir != NULL) {
765 char *tmpstr = vstralloc(flags->restore_dir, "/",
767 amfree(tmp_filename);
768 tmp_filename = tmpstr;
770 final_filename = tmp_filename;
771 tmp_filename = vstralloc(final_filename, ".tmp", NULL);
772 if((dest = open(tmp_filename, (O_CREAT | O_RDWR | O_TRUNC),
774 error(_("could not create output file %s: %s"),
775 tmp_filename, strerror(errno));
778 amfree(filename_ext);
785 * If -r or -h, write the header before compress or uncompress pipe.
786 * Only write DISK_BLOCK_BYTES, regardless of how much was read.
787 * This makes the output look like a holding disk image, and also
788 * makes it easier to remove the header (e.g. in amrecover) since
789 * it has a fixed size.
791 if(flags->raw || (flags->headers && !is_continuation)) {
795 if(flags->compress && !file_is_compressed) {
796 source->header->compressed = 1;
797 g_snprintf(source->header->uncompress_cmd,
798 SIZEOF(source->header->uncompress_cmd),
799 " %s %s |", UNCOMPRESS_PATH,
800 #ifdef UNCOMPRESS_OPT
806 strncpy(source->header->comp_suffix,
808 SIZEOF(source->header->comp_suffix)-1);
809 source->header->comp_suffix[SIZEOF(source->header->comp_suffix)-1]
813 memcpy(&tmp_hdr, source->header, SIZEOF(dumpfile_t));
815 /* remove CONT_FILENAME from header */
816 memset(source->header->cont_filename, '\0',
817 SIZEOF(source->header->cont_filename));
818 source->header->blocksize = DISK_BLOCK_BYTES;
821 * Dumb down split file headers as well, so that older versions of
822 * things like amrecover won't gag on them.
824 if(source->header->type == F_SPLIT_DUMPFILE && flags->mask_splits){
825 source->header->type = F_DUMPFILE;
828 buffer = alloc(DISK_BLOCK_BYTES);
829 buffer = build_header(source->header, DISK_BLOCK_BYTES);
831 if((w = fullwrite(out, buffer,
832 DISK_BLOCK_BYTES)) != DISK_BLOCK_BYTES) {
834 error(_("write error: %s"), strerror(errno));
837 error(_("write error: %zd instead of %d"), w, DISK_BLOCK_BYTES);
842 memcpy(source->header, &tmp_hdr, SIZEOF(dumpfile_t));
845 /* find out if compression or uncompression is needed here */
846 if(flags->compress && !file_is_compressed && !is_continuation
847 && !flags->leave_comp
848 && (flags->inline_assemble ||
849 source->header->type != F_SPLIT_DUMPFILE))
852 if(!flags->raw && !flags->compress && file_is_compressed
853 && !is_continuation && !flags->leave_comp && (flags->inline_assemble
854 || source->header->type != F_SPLIT_DUMPFILE))
857 if(!flags->raw && source->header->encrypted && !is_continuation &&
858 (flags->inline_assemble || source->header->type != F_SPLIT_DUMPFILE)) {
862 /* Setup pipes for decryption / compression / uncompression */
865 if (pipe(&pipes[stage].pipe[0]) < 0) {
866 error(_("error [pipe[%d]: %s]"), stage, strerror(errno));
872 if (need_compress || need_uncompress) {
873 if (pipe(&pipes[stage].pipe[0]) < 0) {
874 error(_("error [pipe[%d]: %s]"), stage, strerror(errno));
879 pipes[stage].pipe[0] = -1;
880 pipes[stage].pipe[1] = out;
884 /* decrypt first if it's encrypted and no -r */
886 switch(myout->comp_enc_pid = fork()) {
888 error(_("could not fork for decrypt: %s"), strerror(errno));
892 aclose(pipes[stage].pipe[0]);
893 aclose(pipes[stage+1].pipe[1]);
898 if(dup2(pipes[stage].pipe[0], 0) == -1) {
899 error(_("error decrypt stdin [dup2 %d %d: %s]"), stage,
900 pipes[stage].pipe[0], strerror(errno));
904 if(dup2(pipes[stage+1].pipe[1], 1) == -1) {
905 error(_("error decrypt stdout [dup2 %d %d: %s]"), stage + 1,
906 pipes[stage+1].pipe[1], strerror(errno));
911 if (source->header->srv_encrypt[0] != '\0') {
912 (void) execlp(source->header->srv_encrypt,
913 source->header->srv_encrypt,
914 source->header->srv_decrypt_opt, NULL);
915 error("could not exec %s: %s",
916 source->header->srv_encrypt, strerror(errno));
917 g_assert_not_reached();
918 } else if (source->header->clnt_encrypt[0] != '\0') {
919 (void) execlp(source->header->clnt_encrypt,
920 source->header->clnt_encrypt,
921 source->header->clnt_decrypt_opt, NULL);
922 error("could not exec %s: %s",
923 source->header->clnt_encrypt, strerror(errno));
924 g_assert_not_reached();
931 * Insert a compress pipe
933 switch(myout->comp_enc_pid = fork()) {
935 error(_("could not fork for %s: %s"), COMPRESS_PATH, strerror(errno));
939 aclose(pipes[stage].pipe[0]);
940 aclose(pipes[stage+1].pipe[1]);
945 if(dup2(pipes[stage].pipe[0], 0) == -1) {
946 error(_("error compress stdin [dup2 %d %d: %s]"), stage,
947 pipes[stage].pipe[0], strerror(errno));
951 if(dup2(pipes[stage+1].pipe[1], 1) == -1) {
952 error(_("error compress stdout [dup2 %d %d: %s]"), stage + 1,
953 pipes[stage+1].pipe[1], strerror(errno));
956 if (*flags->comp_type == '\0') {
957 flags->comp_type = NULL;
961 (void) execlp(COMPRESS_PATH, COMPRESS_PATH, flags->comp_type, (char *)0);
962 error(_("could not exec %s: %s"), COMPRESS_PATH, strerror(errno));
965 } else if(need_uncompress) {
967 * If not -r, -c, -l, and file is compressed, and split reassembly
968 * options are sane, insert uncompress pipe
972 * XXX for now we know that for the two compression types we
973 * understand, .Z and optionally .gz, UNCOMPRESS_PATH will take
974 * care of both. Later, we may need to reference a table of
975 * possible uncompress programs.
977 switch(myout->comp_enc_pid = fork()) {
979 error(_("could not fork for %s: %s"),
980 UNCOMPRESS_PATH, strerror(errno));
984 aclose(pipes[stage].pipe[0]);
985 aclose(pipes[stage+1].pipe[1]);
990 if(dup2(pipes[stage].pipe[0], 0) == -1) {
991 error(_("error uncompress stdin [dup2 %d %d: %s]"), stage,
992 pipes[stage].pipe[0], strerror(errno));
996 if(dup2(pipes[stage+1].pipe[1], 1) == -1) {
997 error(_("error uncompress stdout [dup2 %d %d: %s]"), stage + 1,
998 pipes[stage+1].pipe[1], strerror(errno));
1003 if (source->header->srvcompprog[0] != '\0') {
1004 (void) execlp(source->header->srvcompprog,
1005 source->header->srvcompprog, "-d", NULL);
1006 error("could not exec %s: %s", source->header->srvcompprog,
1008 g_assert_not_reached();
1009 } else if (source->header->clntcompprog[0] != '\0') {
1010 (void) execlp(source->header->clntcompprog,
1011 source->header->clntcompprog, "-d", NULL);
1012 error("could not exec %s: %s", source->header->clntcompprog,
1014 g_assert_not_reached();
1016 (void) execlp(UNCOMPRESS_PATH, UNCOMPRESS_PATH,
1017 #ifdef UNCOMPRESS_OPT
1021 error(_("could not exec %s: %s"), UNCOMPRESS_PATH, strerror(errno));
1027 /* copy the rest of the file from tape to the output */
1028 if (source->restore_mode == HOLDING_MODE) {
1030 int fd = source->u.holding_fd;
1031 memcpy(& file, source->header, sizeof(file));
1033 do_consumer_producer_queue(fd_read_producer,
1034 GINT_TO_POINTER(fd),
1036 GINT_TO_POINTER(pipes[0].pipe[1]));
1038 * See if we need to switch to the next file in a holding restore
1040 if(file.cont_filename[0] == '\0') {
1041 break; /* no more files */
1044 if((fd = open(file.cont_filename, O_RDONLY)) == -1) {
1045 char *cont_filename =
1046 strrchr(file.cont_filename,'/');
1049 if((fd = open(cont_filename,O_RDONLY)) == -1) {
1050 error(_("can't open %s: %s"), file.cont_filename,
1055 g_fprintf(stderr, _("cannot open %s: %s\n"),
1056 file.cont_filename, strerror(errno));
1057 g_fprintf(stderr, _("using %s\n"),
1062 error(_("can't open %s: %s"), file.cont_filename,
1067 read_holding_disk_header(&file, fd, flags);
1068 if(file.type != F_DUMPFILE && file.type != F_CONT_DUMPFILE
1069 && file.type != F_SPLIT_DUMPFILE) {
1070 g_fprintf(stderr, _("unexpected header type: "));
1071 print_header(stderr, source->header);
1076 device_read_to_fd(source->u.device, pipes[0].pipe[1]);
1079 if(!flags->inline_assemble) {
1083 if(!is_continuation){
1084 if(tmp_filename && stat(tmp_filename, &statinfo) < 0){
1085 error(_("Can't stat the file I just created (%s)!"), tmp_filename);
1088 statinfo.st_size = (off_t)0;
1090 if (check_for_aborted && final_filename) {
1091 char *old_dump = final_filename;
1092 struct stat oldstat;
1093 if(stat(old_dump, &oldstat) >= 0){
1094 if(oldstat.st_size <= statinfo.st_size){
1095 dumplist_t *prev_fileentry = NULL;
1096 open_output_t *prev_out = NULL;
1097 g_fprintf(stderr, _("Newer restore is larger, using that\n"));
1098 /* nuke the old dump's entry in alldump_list */
1099 for(fileentry=alldumps_list;
1101 fileentry=fileentry->next){
1102 if(headers_equal(source->header,
1103 fileentry->file, 0)){
1105 prev_fileentry->next = fileentry->next;
1108 alldumps_list = fileentry->next;
1113 prev_fileentry = fileentry;
1115 myout = open_outputs;
1116 while(myout != NULL){
1117 if(headers_equal(source->header, myout->file, 0)){
1118 if(myout->outfd >= 0)
1119 aclose(myout->outfd);
1121 prev_out->next = myout->next;
1123 else open_outputs = myout->next;
1128 myout = myout->next;
1132 g_fprintf(stderr, _("Older restore is larger, using that\n"));
1134 unlink(tmp_filename);
1135 amfree(tempdump->file);
1137 amfree(tmp_filename);
1138 amfree(final_filename);
1144 if(tmp_filename && final_filename &&
1145 rename(tmp_filename, final_filename) < 0) {
1146 error(_("Can't rename %s to %s: %s"),
1147 tmp_filename, final_filename, strerror(errno));
1151 amfree(tmp_filename);
1152 amfree(final_filename);
1156 * actually insert tracking data for this file into our various
1157 * structures (we waited in case we needed to give up)
1159 if(!is_continuation){
1160 oldout = alloc(SIZEOF(open_output_t));
1161 oldout->file = alloc(SIZEOF(dumpfile_t));
1162 memcpy(oldout->file, source->header, SIZEOF(dumpfile_t));
1163 if(flags->inline_assemble) oldout->outfd = pipes[0].pipe[1];
1164 else oldout->outfd = -1;
1165 oldout->comp_enc_pid = -1;
1166 oldout->lastpartnum = source->header->partnum;
1167 oldout->next = open_outputs;
1168 open_outputs = oldout;
1171 fileentry = alldumps_list;
1172 while (fileentry->next != NULL)
1173 fileentry=fileentry->next;
1174 fileentry->next = tempdump;
1177 alldumps_list = tempdump;
1181 /* return NULL if the label is not the expected one */
1182 /* returns a Device handle if it is the expected one. */
1183 /* FIXME: Was label_of_current_slot */
1185 conditional_device_open(char *tapedev,
1188 am_feature_t *their_features,
1189 tapelist_t *desired_tape)
1193 if (tapedev == NULL) {
1194 send_message(prompt_out, flags, their_features,
1195 _("Volume labeled '%s' not found."), desired_tape->label);
1199 rval = device_open(tapedev);
1201 send_message(prompt_out, flags, their_features,
1202 "Error opening device '%s'.",
1207 device_set_startup_properties_from_config(rval);
1208 device_read_label(rval);
1210 if (rval->volume_label == NULL) {
1211 send_message(prompt_out, flags, their_features,
1212 "Not an amanda tape");
1213 g_object_unref(rval);
1217 if (!device_start(rval, ACCESS_READ, NULL, NULL)) {
1218 send_message(prompt_out, flags, their_features,
1219 "Colud not open device %s for reading.\n",
1224 if (flags->check_labels && desired_tape &&
1225 strcmp(rval->volume_label, desired_tape->label) != 0) {
1226 send_message(prompt_out, flags, their_features,
1227 "Label mismatch, got %s and expected %s",
1228 rval->volume_label, desired_tape->label);
1229 g_object_unref(rval);
1236 /* Do the right thing to try and load the next required tape. See
1237 LoadStatus above for return value meaning. */
1244 am_feature_t *their_features,
1245 tapelist_t *desired_tape)
1248 send_message(prompt_out, flags, their_features,
1249 _("Looking for tape %s..."),
1250 desired_tape->label);
1252 loadlabel_data data;
1253 data.cur_tapedev = cur_tapedev;
1254 data.searchlabel = desired_tape->label;
1255 changer_find(&data, scan_init, loadlabel_slot,
1256 desired_tape->label);
1257 return LOAD_CHANGER;
1260 changer_loadslot("next", &curslot,
1265 assert(!flags->amidxtaped);
1267 changer_loadslot("next", &curslot, cur_tapedev);
1271 g_assert_not_reached();
1275 /* will never return LOAD_CHANGER. */
1282 am_feature_t *their_features,
1283 tapelist_t *desired_tape)
1287 if (flags->amidxtaped) {
1288 if (their_features &&
1289 am_has_feature(their_features,
1290 fe_amrecover_FEEDME)) {
1291 g_fprintf(prompt_out, "FEEDME %s\r\n",
1292 desired_tape->label);
1294 input = agets(prompt_in);/* Strips \n but not \r */
1296 error(_("Connection lost with amrecover"));
1298 } else if (strcmp("OK\r", input) == 0) {
1299 } else if (strncmp("TAPE ", input, 5) == 0) {
1300 amfree(*tapedev_ptr);
1301 *tapedev_ptr = alloc(1025);
1302 if (sscanf(input, "TAPE %1024s\r", *tapedev_ptr) != 1) {
1303 error(_("Got bad response from amrecover: %s"), input);
1307 send_message(prompt_out, flags, their_features,
1308 _("Got bad response from amrecover: %s"), input);
1309 error(_("Got bad response from amrecover: %s"), input);
1313 send_message(prompt_out, flags, their_features,
1314 _("Client doesn't support fe_amrecover_FEEDME"));
1315 error(_("Client doesn't support fe_amrecover_FEEDME"));
1321 g_fprintf(prompt_out,
1322 _("Insert tape labeled %s in device %s \n"
1323 "and press enter, ^D to finish reading tapes\n"),
1324 desired_tape->label, *tapedev_ptr);
1326 g_fprintf(prompt_out,_("Insert a tape to search and press "
1327 "enter, ^D to finish reading tapes\n"));
1330 if((input = agets(prompt_in)) == NULL)
1338 /* Search a seen-tapes list for a particular name, to see if we've already
1339 * processed this tape. Returns TRUE if this label has already been seen. */
1340 static gboolean check_volume_seen(seentapes_t * list, char * label) {
1341 seentapes_t * cur_tape;
1342 for (cur_tape = list; cur_tape != NULL; cur_tape = cur_tape->next) {
1343 if (strcmp(cur_tape->label, label) == 0) {
1350 /* Add a volume to the seen tapes list. */
1351 static void record_seen_volume(seentapes_t ** list, char * label,
1353 seentapes_t * new_entry;
1358 new_entry = malloc(sizeof(seentapes_t));
1359 new_entry->label = stralloc(label);
1360 if (slotstr == NULL) {
1361 new_entry->slotstr = NULL;
1363 new_entry->slotstr = stralloc(slotstr);
1365 new_entry->files = NULL;
1366 new_entry->next = *list;
1370 /* Record a specific dump on a volume. */
1371 static void record_seen_dump(seentapes_t * volume, dumpfile_t * header) {
1372 dumplist_t * this_dump;
1377 this_dump = malloc(sizeof(*this_dump));
1378 this_dump->file = g_memdup(header, sizeof(*header));
1379 this_dump->next = NULL;
1380 if (volume->files) {
1381 dumplist_t * tmp_dump = volume->files;
1382 while (tmp_dump->next != NULL) {
1383 tmp_dump = tmp_dump->next;
1385 tmp_dump->next = this_dump;
1387 volume->files = this_dump;
1391 static void print_tape_inventory(FILE * logstream, seentapes_t * tape_seen,
1392 char * timestamp, char * label,
1395 dumplist_t * fileentry;
1397 logline = log_genstring(L_START, "taper",
1398 "datestamp %s label %s tape %d",
1399 timestamp, label, tape_count);
1400 fputs(logline, logstream);
1402 for(fileentry=tape_seen->files; fileentry; fileentry=fileentry->next){
1403 switch (fileentry->file->type) {
1405 logline = log_genstring(L_SUCCESS, "taper",
1406 "%s %s %s %d [faked log entry]",
1407 fileentry->file->name,
1408 fileentry->file->disk,
1409 fileentry->file->datestamp,
1410 fileentry->file->dumplevel);
1412 case F_SPLIT_DUMPFILE:
1413 logline = log_genstring(L_CHUNK, "taper",
1414 "%s %s %s %d %d [faked log entry]",
1415 fileentry->file->name,
1416 fileentry->file->disk,
1417 fileentry->file->datestamp,
1418 fileentry->file->partnum,
1419 fileentry->file->dumplevel);
1424 if(logline != NULL){
1425 fputs(logline, logstream);
1432 /* Check if the given header matches the given dumpspecs. Returns
1433 TRUE if dumpspecs is NULL and false if the header is NULL. Returns
1434 true if the header matches the match list. */
1435 static gboolean run_dumpspecs(GSList * dumpspecs,
1436 dumpfile_t * header) {
1439 if (dumpspecs == NULL)
1445 ds = (dumpspec_t *)dumpspecs->data;
1446 if (disk_match(header, ds->datestamp, ds->host,
1447 ds->disk, ds->level) != 0) {
1450 dumpspecs = dumpspecs->next;
1456 /* A wrapper around restore() above. This function does some extra
1457 checking to seek to the file in question and ensure that we really,
1458 really want to use it.
1460 The next_file argument provides instruction on what to do if the
1461 requested file does not exist on the volume: If next_file is NULL
1462 then if the requested file is missing the function will return
1463 RESTORE_STATUS_NEXT_FILE. If next_file is not NULL then the first
1464 extant file whose number is equal to or greater than file_num will
1465 be attempted. *next_file will be filled in with the number of the
1466 file following the one that was attempted. */
1467 static RestoreFileStatus
1468 try_restore_single_file(Device * device, int file_num, int* next_file,
1470 rst_flags_t * flags,
1471 am_feature_t * their_features,
1472 dumpfile_t * first_restored_file,
1474 seentapes_t * tape_seen) {
1475 RestoreSource source;
1476 source.u.device = device;
1477 source.restore_mode = DEVICE_MODE;
1479 source.header = device_seek_file(device, file_num);
1481 if (source.header == NULL) {
1482 /* This definitely indicates an error. */
1483 send_message(prompt_out, flags, their_features,
1484 "Could not seek device %s to file %d.",
1485 device->device_name, file_num);
1486 return RESTORE_STATUS_NEXT_TAPE;
1487 } else if (source.header->type == F_TAPEEND) {
1488 amfree(source.header);
1489 return RESTORE_STATUS_NEXT_TAPE;
1490 } else if (device->file != file_num) {
1491 if (next_file == NULL) {
1492 send_message(prompt_out, flags, their_features,
1493 "Requested file %d does not exist.",
1495 return RESTORE_STATUS_NEXT_FILE;
1497 send_message(prompt_out, flags, their_features,
1498 "Skipped from file %d to file %d.",
1499 file_num, device->file);
1500 file_num = device->file;
1504 if (next_file != NULL) {
1505 *next_file = file_num + 1;
1508 g_return_val_if_fail(source.header->type == F_DUMPFILE ||
1509 source.header->type == F_CONT_DUMPFILE ||
1510 source.header->type == F_SPLIT_DUMPFILE,
1511 RESTORE_STATUS_NEXT_FILE);
1514 if (!run_dumpspecs(dumpspecs, source.header)) {
1515 if(!flags->amidxtaped) {
1516 g_fprintf(prompt_out, "%s: %d: skipping ",
1517 get_pname(), file_num);
1518 print_header(prompt_out, source.header);
1520 return RESTORE_STATUS_NEXT_FILE;
1523 if (first_restored_file != NULL &&
1524 first_restored_file->type != F_UNKNOWN &&
1525 !headers_equal(first_restored_file, source.header, 1) &&
1526 (flags->pipe_to_fd == fileno(stdout))) {
1527 return RESTORE_STATUS_STOP;
1530 if (!flags->amidxtaped) {
1531 g_fprintf(stderr, "%s: %d: restoring ",
1532 get_pname(), file_num);
1533 print_header(stderr, source.header);
1535 record_seen_dump(tape_seen, source.header);
1536 restore(&source, flags);
1537 if (first_restored_file) {
1538 memcpy(first_restored_file, source.header, sizeof(dumpfile_t));
1540 return RESTORE_STATUS_NEXT_FILE;
1543 /* This function handles processing of a particular tape or holding
1544 disk file. It returns TRUE if it is useful to load another tape.*/
1547 search_a_tape(Device * device,
1548 FILE *prompt_out, /* Where to send any prompts */
1549 rst_flags_t *flags, /* Restore options. */
1550 am_feature_t *their_features,
1551 tapelist_t *desired_tape, /* A list of desired tape files */
1552 GSList *dumpspecs, /* What disks to restore. */
1553 seentapes_t **tape_seen, /* Where to record data on
1555 /* May be NULL. If zeroed, will be filled in with the
1556 first restored file. If already filled in, then we
1557 may only restore other files from the same dump. */
1558 dumpfile_t * first_restored_file,
1561 seentapes_t * tape_seen_head = NULL;
1562 RestoreSource source;
1565 int tapefile_idx = -1;
1567 RestoreFileStatus restore_status = RESTORE_STATUS_NEXT_TAPE;
1569 source.restore_mode = DEVICE_MODE;
1570 source.u.device = device;
1573 if(desired_tape && desired_tape->numfiles > 0)
1577 dbprintf(_("search_a_tape: desired_tape=%p label=%s\n"),
1578 desired_tape, desired_tape->label);
1579 dbprintf(_("tape: numfiles = %d\n"), desired_tape->numfiles);
1580 for (i=0; i < desired_tape->numfiles; i++) {
1581 dbprintf(_("tape: files[%d] = %lld\n"),
1582 i, (long long)desired_tape->files[i]);
1585 dbprintf(_("search_a_tape: no desired_tape\n"));
1587 dbprintf(_("current tapefile_idx = %d\n"), tapefile_idx);
1590 if (check_volume_seen(*tape_seen, device->volume_label)) {
1591 send_message(prompt_out, flags, their_features,
1592 "Skipping repeat tape %s in slot %s",
1593 device->volume_label, curslot);
1596 record_seen_volume(tape_seen, device->volume_label, curslot);
1597 tape_seen_head = *tape_seen;
1600 if (desired_tape && desired_tape->numfiles > 0) {
1601 /* Iterate the tape list, handle each file in order. */
1603 for (file_index = 0; file_index < desired_tape->numfiles;
1605 int file_num = desired_tape->files[file_index];
1606 restore_status = try_restore_single_file(device, file_num, NULL,
1609 first_restored_file,
1610 NULL, tape_seen_head);
1611 if (restore_status != RESTORE_STATUS_NEXT_FILE)
1614 } else if(flags->fsf && flags->amidxtaped) {
1615 /* Restore a single file, then quit. */
1617 try_restore_single_file(device, flags->fsf, NULL, prompt_out, flags,
1618 their_features, first_restored_file,
1619 dumpspecs, tape_seen_head);
1621 /* Search the tape from beginning to end. */
1624 if (flags->fsf > 0) {
1625 file_num = flags->fsf;
1630 if (!flags->amidxtaped) {
1631 g_fprintf(prompt_out, "Restoring from tape %s starting with file %d.\n",
1632 device->volume_label, file_num);
1638 try_restore_single_file(device, file_num, &file_num,
1640 their_features, first_restored_file,
1641 dumpspecs, tape_seen_head);
1642 if (restore_status != RESTORE_STATUS_NEXT_FILE)
1647 /* spit out our accumulated list of dumps, if we're inventorying */
1648 if (logstream != NULL) {
1649 print_tape_inventory(logstream, tape_seen_head, device->volume_time,
1650 device->volume_label, tape_count);
1652 return (restore_status != RESTORE_STATUS_STOP);
1655 static void free_seen_tapes(seentapes_t * seentapes) {
1656 while (seentapes != NULL) {
1657 seentapes_t *tape_seen = seentapes;
1658 seentapes = seentapes->next;
1659 while(tape_seen->files != NULL) {
1660 dumplist_t *temp_dump = tape_seen->files;
1661 tape_seen->files = temp_dump->next;
1662 amfree(temp_dump->file);
1665 amfree(tape_seen->label);
1666 amfree(tape_seen->slotstr);
1672 /* Spit out a list of expected tapes, so people with manual changers know
1674 static void print_expected_tape_list(FILE* prompt_out, FILE* prompt_in,
1675 tapelist_t *tapelist,
1676 rst_flags_t * flags) {
1677 tapelist_t * cur_volume;
1679 g_fprintf(prompt_out, "The following tapes are needed:");
1680 for(cur_volume = tapelist; cur_volume != NULL;
1681 cur_volume = cur_volume->next){
1682 g_fprintf(prompt_out, " %s", cur_volume->label);
1684 g_fprintf(prompt_out, "\n");
1686 if(flags->wait_tape_prompt){
1688 g_fprintf(prompt_out,"Press enter when ready\n");
1690 input = agets(prompt_in);
1692 g_fprintf(prompt_out, "\n");
1697 /* Restore a single holding-disk file. We will fill in this_header
1698 with the header from this restore (if it is not null), and in the
1699 stdout-pipe case, we abort according to last_header. Returns TRUE
1700 if the restore should continue, FALSE if we are done. */
1701 gboolean restore_holding_disk(FILE * prompt_out,
1702 rst_flags_t * flags,
1703 am_feature_t * features,
1705 seentapes_t ** seen,
1707 dumpfile_t * this_header,
1708 dumpfile_t * last_header) {
1709 RestoreSource source;
1710 gboolean read_result;
1713 source.header = &header;
1714 source.restore_mode = HOLDING_MODE;
1715 source.u.holding_fd = robust_open(file->label, 0, 0);
1716 if (source.u.holding_fd < 0) {
1717 send_message(prompt_out, flags, features,
1718 "could not open %s: %s",
1719 file->label, strerror(errno));
1723 g_fprintf(stderr, "Reading %s from fd %d\n",
1724 file->label, source.u.holding_fd);
1726 read_result = read_holding_disk_header(source.header,
1727 source.u.holding_fd, flags);
1729 send_message(prompt_out, flags, features,
1730 "Invalid header reading %s.",
1732 aclose(source.u.holding_fd);
1736 if (!run_dumpspecs(dumpspecs, source.header)) {
1740 if (last_header != NULL && !flags->amidxtaped &&
1741 flags->pipe_to_fd == STDOUT_FILENO &&
1742 last_header->type != F_UNKNOWN &&
1743 !headers_equal(last_header, source.header, 1)) {
1745 } else if (this_header != NULL) {
1746 memcpy(this_header, source.header, sizeof(*this_header));
1750 record_seen_volume(seen, file->label, "<none>");
1751 record_seen_dump(*seen, source.header);
1754 print_header(stderr, source.header);
1756 restore(&source, flags);
1757 aclose(source.u.holding_fd);
1761 /* Ask for a specific manual tape. If we find the right one, then open it
1762 * and return a Device handle. If not, return NULL. Pass a device name, but
1763 * it might be overridden. */
1764 static Device* manual_find_tape(char ** cur_tapedev, tapelist_t * cur_volume,
1765 FILE * prompt_out, FILE * prompt_in,
1766 rst_flags_t * flags,
1767 am_feature_t * features) {
1768 LoadStatus status = LOAD_NEXT;
1772 status = load_manual_tape(cur_tapedev, prompt_out, prompt_in,
1773 flags, features, cur_volume);
1775 if (status == LOAD_STOP)
1778 rval = conditional_device_open(*cur_tapedev, prompt_out, flags,
1779 features, cur_volume);
1785 /* If we have a tapelist, then we mandate restoring in tapelist
1786 order. The logic is simple: Get the next tape, and deal with it,
1787 then move on to the next one. */
1789 restore_from_tapelist(FILE * prompt_out,
1791 tapelist_t * tapelist,
1793 rst_flags_t * flags,
1794 am_feature_t * features,
1796 gboolean use_changer,
1798 tapelist_t * cur_volume;
1799 dumpfile_t first_restored_file;
1800 seentapes_t * seentapes = NULL;
1802 fh_init(&first_restored_file);
1804 for(cur_volume = tapelist; cur_volume != NULL;
1805 cur_volume = cur_volume->next){
1806 if (cur_volume->isafile) {
1807 /* Restore from holding disk; just go. */
1808 if (first_restored_file.type == F_UNKNOWN) {
1809 if (!restore_holding_disk(prompt_out, flags,
1810 features, cur_volume, &seentapes,
1811 NULL, NULL, &first_restored_file)) {
1815 restore_holding_disk(prompt_out, flags, features,
1816 cur_volume, &seentapes,
1817 NULL, &first_restored_file, NULL);
1819 if (flags->pipe_to_fd == fileno(stdout)) {
1823 Device * device = NULL;
1825 char * tapedev = NULL;
1826 loadlabel_data data;
1827 data.cur_tapedev = &tapedev;
1828 data.searchlabel = cur_volume->label;
1829 changer_find(&data, scan_init, loadlabel_slot,
1831 device = conditional_device_open(tapedev, prompt_out,
1838 device = manual_find_tape(&cur_tapedev, cur_volume, prompt_out,
1839 prompt_in, flags, features);
1845 g_fprintf(stderr, "Scanning volume %s (slot %s)\n",
1846 device->volume_label,
1849 g_fprintf(stderr, "Scanning volume %s\n",
1850 device->volume_label);
1853 if (!search_a_tape(device, prompt_out, flags, features,
1854 cur_volume, dumpspecs, &seentapes,
1855 &first_restored_file, 0, logstream)) {
1856 g_object_unref(device);
1859 g_object_unref(device);
1863 free_seen_tapes(seentapes);
1866 /* This function works when we are operating without a tapelist
1867 (regardless of whether or not we have a changer). This only happens
1868 when we are using amfetchdump without dump logs, but in the future
1869 may include amrestore as well. The philosophy is to keep loading
1870 tapes until we run out. */
1872 restore_without_tapelist(FILE * prompt_out,
1875 rst_flags_t * flags,
1876 am_feature_t * features,
1878 /* -1 if no changer. */
1882 seentapes_t * seentapes;
1884 dumpfile_t first_restored_file;
1886 fh_init(&first_restored_file);
1888 /* This loop also aborts if we run out of manual tapes, or
1889 encounter a changer error. */
1891 Device * device = NULL;
1892 if (slot_count > 0) {
1893 while (cur_slot < slot_count && device == NULL) {
1895 changer_loadslot("next", &curslot, &cur_tapedev);
1896 device = conditional_device_open(cur_tapedev, prompt_out,
1899 amfree(cur_tapedev);
1902 if (cur_slot >= slot_count)
1905 g_fprintf(stderr, "Scanning %s (slot %s)\n", device->volume_label,
1908 device = manual_find_tape(&cur_tapedev, NULL, prompt_out,
1909 prompt_in, flags, features);
1915 if (!search_a_tape(device, prompt_out, flags, features,
1916 NULL, dumpspecs, &seentapes, &first_restored_file,
1917 tape_count, logstream)) {
1918 g_object_unref(device);
1921 g_object_unref(device);
1925 free_seen_tapes(seentapes);
1929 * Take a pattern of dumps and restore it blind, a la amrestore. In addition,
1930 * be smart enough to change tapes and continue with minimal operator
1931 * intervention, and write out a record of what was found on tapes in the
1932 * the regular logging format. Can take a tapelist with a specific set of
1933 * tapes to search (rather than "everything I can find"), which in turn can
1934 * optionally list specific files to restore.
1941 tapelist_t * tapelist,
1943 rst_flags_t * flags,
1944 am_feature_t * their_features)
1948 FILE *logstream = NULL;
1949 tapelist_t *desired_tape = NULL;
1950 struct sigaction act, oact;
1954 if(!prompt_out) prompt_out = stderr;
1956 /* Don't die when child closes pipe */
1957 signal(SIGPIPE, SIG_IGN);
1959 /* catch SIGINT with something that'll flush unmerged splits */
1960 act.sa_handler = handle_sigint;
1961 sigemptyset(&act.sa_mask);
1963 if(sigaction(SIGINT, &act, &oact) != 0){
1964 error(_("error setting SIGINT handler: %s"), strerror(errno));
1967 if(flags->delay_assemble || flags->inline_assemble) exitassemble = 1;
1968 else exitassemble = 0;
1970 /* if given a log file, print an inventory of stuff found */
1971 if(flags->inventory_log) {
1972 if(!strcmp(flags->inventory_log, "-")) logstream = stdout;
1973 else if((logstream = fopen(flags->inventory_log, "w+")) == NULL) {
1974 error(_("Couldn't open log file %s for writing: %s"),
1975 flags->inventory_log, strerror(errno));
1980 /* Suss what tape device we're using, whether there's a changer, etc. */
1982 use_changer = changer_init();
1986 if (flags->alt_tapedev) {
1987 cur_tapedev = stralloc(flags->alt_tapedev);
1988 } else if(!cur_tapedev) {
1989 cur_tapedev = getconf_str(CNF_TAPEDEV);
1990 if (cur_tapedev == NULL) {
1991 error(_("No tapedev specified"));
1994 /* XXX oughta complain if no config is loaded */
1995 g_fprintf(stderr, _("%s: Using tapedev %s\n"), get_pname(), cur_tapedev);
1997 else{ /* good, the changer works, see what it can do */
1999 changer_info(&slots, &curslot, &backwards);
2002 if (tapelist && !flags->amidxtaped) {
2003 print_expected_tape_list(prompt_out, prompt_in, tapelist, flags);
2005 desired_tape = tapelist;
2007 if (use_changer) { /* load current slot */
2010 changer_loadslot("current", &curslot, &cur_tapedev);
2014 * If we're not given a tapelist, iterate over everything our changer can
2015 * find. If there's no changer, we'll prompt to be handfed tapes.
2017 * If we *are* given a tapelist, restore from those tapes in the order in
2018 * which they're listed. Unless the changer (if we have one) can't go
2019 * backwards, in which case check every tape we see and restore from it if
2022 * (obnoxious, isn't this?)
2026 restore_from_tapelist(prompt_out, prompt_in, tapelist, dumpspecs,
2027 flags, their_features, cur_tapedev, use_changer,
2030 restore_without_tapelist(prompt_out, prompt_in, dumpspecs, flags,
2031 their_features, cur_tapedev,
2032 (use_changer ? slots : -1),
2036 if(logstream && logstream != stderr && logstream != stdout){
2039 if(flags->delay_assemble || flags->inline_assemble){
2040 flush_open_outputs(1, NULL);
2042 else flush_open_outputs(0, NULL);
2046 * Create a new, clean set of restore flags with some sane default values.
2051 rst_flags_t *flags = alloc(SIZEOF(rst_flags_t));
2053 memset(flags, 0, SIZEOF(rst_flags_t));
2056 flags->comp_type = COMPRESS_FAST_OPT;
2057 flags->inline_assemble = 1;
2058 flags->pipe_to_fd = -1;
2059 flags->check_labels = 1;
2065 * Make sure the set of restore options given is sane. Print errors for
2066 * things that're odd, and return -1 for fatal errors.
2070 rst_flags_t * flags)
2074 if(!flags) return(-1);
2076 if(flags->compress && flags->leave_comp){
2077 g_fprintf(stderr, _("Cannot specify 'compress output' and 'leave compression alone' together\n"));
2081 if(flags->restore_dir != NULL){
2082 struct stat statinfo;
2084 if(flags->pipe_to_fd != -1){
2085 g_fprintf(stderr, _("Specifying output directory and piping output are mutually exclusive\n"));
2088 if(stat(flags->restore_dir, &statinfo) < 0){
2089 g_fprintf(stderr, _("Cannot stat restore target dir '%s': %s\n"),
2090 flags->restore_dir, strerror(errno));
2093 if((statinfo.st_mode & S_IFMT) != S_IFDIR){
2094 g_fprintf(stderr, _("'%s' is not a directory\n"), flags->restore_dir);
2099 if((flags->pipe_to_fd != -1 || flags->compress) &&
2100 (flags->delay_assemble || !flags->inline_assemble)){
2101 g_fprintf(stderr, _("Split dumps *must* be automatically reassembled when piping output or compressing/uncompressing\n"));
2105 if(flags->delay_assemble && flags->inline_assemble){
2106 g_fprintf(stderr, _("Inline split assembling and delayed assembling are mutually exclusive\n"));
2114 * Clean up after a rst_flags_t
2118 rst_flags_t * flags)
2122 amfree(flags->restore_dir);
2123 amfree(flags->alt_tapedev);
2124 amfree(flags->inventory_log);
2130 printf_arglist_function3(
2133 rst_flags_t *, flags,
2134 am_feature_t *, their_features,
2138 char linebuf[STR_SIZE];
2140 arglist_start(argp, format);
2141 g_vsnprintf(linebuf, SIZEOF(linebuf)-1, format, argp);
2144 g_fprintf(stderr,"%s\n", linebuf);
2145 if (flags->amidxtaped && their_features &&
2146 am_has_feature(their_features, fe_amrecover_message)) {
2147 g_fprintf(prompt_out, "MESSAGE %s\r\n", linebuf);