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 return RESTORE_STATUS_NEXT_FILE;
1540 /* This function handles processing of a particular tape or holding
1541 disk file. It returns TRUE if it is useful to load another tape.*/
1544 search_a_tape(Device * device,
1545 FILE *prompt_out, /* Where to send any prompts */
1546 rst_flags_t *flags, /* Restore options. */
1547 am_feature_t *their_features,
1548 tapelist_t *desired_tape, /* A list of desired tape files */
1549 GSList *dumpspecs, /* What disks to restore. */
1550 seentapes_t **tape_seen, /* Where to record data on
1552 /* May be NULL. If zeroed, will be filled in with the
1553 first restored file. If already filled in, then we
1554 may only restore other files from the same dump. */
1555 dumpfile_t * first_restored_file,
1558 seentapes_t * tape_seen_head = NULL;
1559 RestoreSource source;
1562 int tapefile_idx = -1;
1564 RestoreFileStatus restore_status = RESTORE_STATUS_NEXT_TAPE;
1566 source.restore_mode = DEVICE_MODE;
1567 source.u.device = device;
1570 if(desired_tape && desired_tape->numfiles > 0)
1574 dbprintf(_("search_a_tape: desired_tape=%p label=%s\n"),
1575 desired_tape, desired_tape->label);
1576 dbprintf(_("tape: numfiles = %d\n"), desired_tape->numfiles);
1577 for (i=0; i < desired_tape->numfiles; i++) {
1578 dbprintf(_("tape: files[%d] = %lld\n"),
1579 i, (long long)desired_tape->files[i]);
1582 dbprintf(_("search_a_tape: no desired_tape\n"));
1584 dbprintf(_("current tapefile_idx = %d\n"), tapefile_idx);
1587 if (check_volume_seen(*tape_seen, device->volume_label)) {
1588 send_message(prompt_out, flags, their_features,
1589 "Skipping repeat tape %s in slot %s",
1590 device->volume_label, curslot);
1593 record_seen_volume(tape_seen, device->volume_label, curslot);
1594 tape_seen_head = *tape_seen;
1597 if (desired_tape && desired_tape->numfiles > 0) {
1598 /* Iterate the tape list, handle each file in order. */
1600 for (file_index = 0; file_index < desired_tape->numfiles;
1602 int file_num = desired_tape->files[file_index];
1603 restore_status = try_restore_single_file(device, file_num, NULL,
1606 first_restored_file,
1607 NULL, tape_seen_head);
1608 if (restore_status != RESTORE_STATUS_NEXT_FILE)
1611 } else if(flags->fsf && flags->amidxtaped) {
1612 /* Restore a single file, then quit. */
1614 try_restore_single_file(device, flags->fsf, NULL, prompt_out, flags,
1615 their_features, first_restored_file,
1616 dumpspecs, tape_seen_head);
1618 /* Search the tape from beginning to end. */
1621 if (flags->fsf > 0) {
1622 file_num = flags->fsf;
1627 if (!flags->amidxtaped) {
1628 g_fprintf(prompt_out, "Restoring from tape %s starting with file %d.\n",
1629 device->volume_label, file_num);
1635 try_restore_single_file(device, file_num, &file_num,
1637 their_features, first_restored_file,
1638 dumpspecs, tape_seen_head);
1639 if (restore_status != RESTORE_STATUS_NEXT_FILE)
1644 /* spit out our accumulated list of dumps, if we're inventorying */
1645 if (logstream != NULL) {
1646 print_tape_inventory(logstream, tape_seen_head, device->volume_time,
1647 device->volume_label, tape_count);
1649 return (restore_status != RESTORE_STATUS_STOP);
1652 static void free_seen_tapes(seentapes_t * seentapes) {
1653 while (seentapes != NULL) {
1654 seentapes_t *tape_seen = seentapes;
1655 seentapes = seentapes->next;
1656 while(tape_seen->files != NULL) {
1657 dumplist_t *temp_dump = tape_seen->files;
1658 tape_seen->files = temp_dump->next;
1659 amfree(temp_dump->file);
1662 amfree(tape_seen->label);
1663 amfree(tape_seen->slotstr);
1669 /* Spit out a list of expected tapes, so people with manual changers know
1671 static void print_expected_tape_list(FILE* prompt_out, FILE* prompt_in,
1672 tapelist_t *tapelist,
1673 rst_flags_t * flags) {
1674 tapelist_t * cur_volume;
1676 g_fprintf(prompt_out, "The following tapes are needed:");
1677 for(cur_volume = tapelist; cur_volume != NULL;
1678 cur_volume = cur_volume->next){
1679 g_fprintf(prompt_out, " %s", cur_volume->label);
1681 g_fprintf(prompt_out, "\n");
1683 if(flags->wait_tape_prompt){
1685 g_fprintf(prompt_out,"Press enter when ready\n");
1687 input = agets(prompt_in);
1689 g_fprintf(prompt_out, "\n");
1694 /* Restore a single holding-disk file. We will fill in this_header
1695 with the header from this restore (if it is not null), and in the
1696 stdout-pipe case, we abort according to last_header. Returns TRUE
1697 if the restore should continue, FALSE if we are done. */
1698 gboolean restore_holding_disk(FILE * prompt_out,
1699 rst_flags_t * flags,
1700 am_feature_t * features,
1702 seentapes_t ** seen,
1704 dumpfile_t * this_header,
1705 dumpfile_t * last_header) {
1706 RestoreSource source;
1707 gboolean read_result;
1710 source.header = &header;
1711 source.restore_mode = HOLDING_MODE;
1712 source.u.holding_fd = robust_open(file->label, 0, 0);
1713 if (source.u.holding_fd < 0) {
1714 send_message(prompt_out, flags, features,
1715 "could not open %s: %s",
1716 file->label, strerror(errno));
1720 g_fprintf(stderr, "Reading %s from fd %d\n",
1721 file->label, source.u.holding_fd);
1723 read_result = read_holding_disk_header(source.header,
1724 source.u.holding_fd, flags);
1726 send_message(prompt_out, flags, features,
1727 "Invalid header reading %s.",
1729 aclose(source.u.holding_fd);
1733 if (!run_dumpspecs(dumpspecs, source.header)) {
1737 if (last_header != NULL && !flags->amidxtaped &&
1738 flags->pipe_to_fd == STDOUT_FILENO &&
1739 !headers_equal(last_header, source.header, 1)) {
1741 } else if (this_header != NULL) {
1742 memcpy(this_header, source.header, sizeof(*this_header));
1746 record_seen_volume(seen, file->label, "<none>");
1747 record_seen_dump(*seen, source.header);
1750 print_header(stderr, source.header);
1752 restore(&source, flags);
1753 aclose(source.u.holding_fd);
1757 /* Ask for a specific manual tape. If we find the right one, then open it
1758 * and return a Device handle. If not, return NULL. Pass a device name, but
1759 * it might be overridden. */
1760 static Device* manual_find_tape(char ** cur_tapedev, tapelist_t * cur_volume,
1761 FILE * prompt_out, FILE * prompt_in,
1762 rst_flags_t * flags,
1763 am_feature_t * features) {
1764 LoadStatus status = LOAD_NEXT;
1768 status = load_manual_tape(cur_tapedev, prompt_out, prompt_in,
1769 flags, features, cur_volume);
1771 if (status == LOAD_STOP)
1774 rval = conditional_device_open(*cur_tapedev, prompt_out, flags,
1775 features, cur_volume);
1781 /* If we have a tapelist, then we mandate restoring in tapelist
1782 order. The logic is simple: Get the next tape, and deal with it,
1783 then move on to the next one. */
1785 restore_from_tapelist(FILE * prompt_out,
1787 tapelist_t * tapelist,
1789 rst_flags_t * flags,
1790 am_feature_t * features,
1792 gboolean use_changer,
1794 tapelist_t * cur_volume;
1795 dumpfile_t first_restored_file;
1796 seentapes_t * seentapes = NULL;
1798 fh_init(&first_restored_file);
1800 for(cur_volume = tapelist; cur_volume != NULL;
1801 cur_volume = cur_volume->next){
1802 if (cur_volume->isafile) {
1803 /* Restore from holding disk; just go. */
1804 if (first_restored_file.type == F_UNKNOWN) {
1805 if (!restore_holding_disk(prompt_out, flags,
1806 features, cur_volume, &seentapes,
1807 NULL, NULL, &first_restored_file)) {
1811 restore_holding_disk(prompt_out, flags, features,
1812 cur_volume, &seentapes,
1813 NULL, &first_restored_file, NULL);
1816 Device * device = NULL;
1818 char * tapedev = NULL;
1819 loadlabel_data data;
1820 data.cur_tapedev = &tapedev;
1821 data.searchlabel = cur_volume->label;
1822 changer_find(&data, scan_init, loadlabel_slot,
1824 device = conditional_device_open(tapedev, prompt_out,
1831 device = manual_find_tape(&cur_tapedev, cur_volume, prompt_out,
1832 prompt_in, flags, features);
1838 g_fprintf(stderr, "Scanning volume %s (slot %s)\n",
1839 device->volume_label,
1842 g_fprintf(stderr, "Scanning volume %s\n",
1843 device->volume_label);
1846 if (!search_a_tape(device, prompt_out, flags, features,
1847 cur_volume, dumpspecs, &seentapes,
1848 &first_restored_file, 0, logstream)) {
1849 g_object_unref(device);
1852 g_object_unref(device);
1856 free_seen_tapes(seentapes);
1859 /* This function works when we are operating without a tapelist
1860 (regardless of whether or not we have a changer). This only happens
1861 when we are using amfetchdump without dump logs, but in the future
1862 may include amrestore as well. The philosophy is to keep loading
1863 tapes until we run out. */
1865 restore_without_tapelist(FILE * prompt_out,
1868 rst_flags_t * flags,
1869 am_feature_t * features,
1871 /* -1 if no changer. */
1875 seentapes_t * seentapes;
1877 dumpfile_t first_restored_file;
1879 /* This loop also aborts if we run out of manual tapes, or
1880 encounter a changer error. */
1882 Device * device = NULL;
1883 if (slot_count > 0) {
1884 while (cur_slot < slot_count && device == NULL) {
1886 changer_loadslot("next", &curslot, &cur_tapedev);
1887 device = conditional_device_open(cur_tapedev, prompt_out,
1890 amfree(cur_tapedev);
1893 if (cur_slot >= slot_count)
1896 g_fprintf(stderr, "Scanning %s (slot %s)\n", device->volume_label,
1899 device = manual_find_tape(&cur_tapedev, NULL, prompt_out,
1900 prompt_in, flags, features);
1906 if (!search_a_tape(device, prompt_out, flags, features,
1907 NULL, dumpspecs, &seentapes, &first_restored_file,
1908 tape_count, logstream)) {
1909 g_object_unref(device);
1912 g_object_unref(device);
1916 free_seen_tapes(seentapes);
1920 * Take a pattern of dumps and restore it blind, a la amrestore. In addition,
1921 * be smart enough to change tapes and continue with minimal operator
1922 * intervention, and write out a record of what was found on tapes in the
1923 * the regular logging format. Can take a tapelist with a specific set of
1924 * tapes to search (rather than "everything I can find"), which in turn can
1925 * optionally list specific files to restore.
1932 tapelist_t * tapelist,
1934 rst_flags_t * flags,
1935 am_feature_t * their_features)
1939 FILE *logstream = NULL;
1940 tapelist_t *desired_tape = NULL;
1941 struct sigaction act, oact;
1945 if(!prompt_out) prompt_out = stderr;
1947 /* Don't die when child closes pipe */
1948 signal(SIGPIPE, SIG_IGN);
1950 /* catch SIGINT with something that'll flush unmerged splits */
1951 act.sa_handler = handle_sigint;
1952 sigemptyset(&act.sa_mask);
1954 if(sigaction(SIGINT, &act, &oact) != 0){
1955 error(_("error setting SIGINT handler: %s"), strerror(errno));
1958 if(flags->delay_assemble || flags->inline_assemble) exitassemble = 1;
1959 else exitassemble = 0;
1961 /* if given a log file, print an inventory of stuff found */
1962 if(flags->inventory_log) {
1963 if(!strcmp(flags->inventory_log, "-")) logstream = stdout;
1964 else if((logstream = fopen(flags->inventory_log, "w+")) == NULL) {
1965 error(_("Couldn't open log file %s for writing: %s"),
1966 flags->inventory_log, strerror(errno));
1971 /* Suss what tape device we're using, whether there's a changer, etc. */
1973 use_changer = changer_init();
1977 if (flags->alt_tapedev) {
1978 cur_tapedev = stralloc(flags->alt_tapedev);
1979 } else if(!cur_tapedev) {
1980 cur_tapedev = getconf_str(CNF_TAPEDEV);
1981 if (cur_tapedev == NULL) {
1982 error(_("No tapedev specified"));
1985 /* XXX oughta complain if no config is loaded */
1986 g_fprintf(stderr, _("%s: Using tapedev %s\n"), get_pname(), cur_tapedev);
1988 else{ /* good, the changer works, see what it can do */
1990 changer_info(&slots, &curslot, &backwards);
1993 if (tapelist && !flags->amidxtaped) {
1994 print_expected_tape_list(prompt_out, prompt_in, tapelist, flags);
1996 desired_tape = tapelist;
1998 if (use_changer) { /* load current slot */
2001 changer_loadslot("current", &curslot, &cur_tapedev);
2005 * If we're not given a tapelist, iterate over everything our changer can
2006 * find. If there's no changer, we'll prompt to be handfed tapes.
2008 * If we *are* given a tapelist, restore from those tapes in the order in
2009 * which they're listed. Unless the changer (if we have one) can't go
2010 * backwards, in which case check every tape we see and restore from it if
2013 * (obnoxious, isn't this?)
2017 restore_from_tapelist(prompt_out, prompt_in, tapelist, dumpspecs,
2018 flags, their_features, cur_tapedev, use_changer,
2021 restore_without_tapelist(prompt_out, prompt_in, dumpspecs, flags,
2022 their_features, cur_tapedev,
2023 (use_changer ? slots : -1),
2027 if(logstream && logstream != stderr && logstream != stdout){
2030 if(flags->delay_assemble || flags->inline_assemble){
2031 flush_open_outputs(1, NULL);
2033 else flush_open_outputs(0, NULL);
2037 * Create a new, clean set of restore flags with some sane default values.
2042 rst_flags_t *flags = alloc(SIZEOF(rst_flags_t));
2044 memset(flags, 0, SIZEOF(rst_flags_t));
2047 flags->comp_type = COMPRESS_FAST_OPT;
2048 flags->inline_assemble = 1;
2049 flags->pipe_to_fd = -1;
2050 flags->check_labels = 1;
2056 * Make sure the set of restore options given is sane. Print errors for
2057 * things that're odd, and return -1 for fatal errors.
2061 rst_flags_t * flags)
2065 if(!flags) return(-1);
2067 if(flags->compress && flags->leave_comp){
2068 g_fprintf(stderr, _("Cannot specify 'compress output' and 'leave compression alone' together\n"));
2072 if(flags->restore_dir != NULL){
2073 struct stat statinfo;
2075 if(flags->pipe_to_fd != -1){
2076 g_fprintf(stderr, _("Specifying output directory and piping output are mutually exclusive\n"));
2079 if(stat(flags->restore_dir, &statinfo) < 0){
2080 g_fprintf(stderr, _("Cannot stat restore target dir '%s': %s\n"),
2081 flags->restore_dir, strerror(errno));
2084 if((statinfo.st_mode & S_IFMT) != S_IFDIR){
2085 g_fprintf(stderr, _("'%s' is not a directory\n"), flags->restore_dir);
2090 if((flags->pipe_to_fd != -1 || flags->compress) &&
2091 (flags->delay_assemble || !flags->inline_assemble)){
2092 g_fprintf(stderr, _("Split dumps *must* be automatically reassembled when piping output or compressing/uncompressing\n"));
2096 if(flags->delay_assemble && flags->inline_assemble){
2097 g_fprintf(stderr, _("Inline split assembling and delayed assembling are mutually exclusive\n"));
2105 * Clean up after a rst_flags_t
2109 rst_flags_t * flags)
2113 amfree(flags->restore_dir);
2114 amfree(flags->alt_tapedev);
2115 amfree(flags->inventory_log);
2121 printf_arglist_function3(
2124 rst_flags_t *, flags,
2125 am_feature_t *, their_features,
2129 char linebuf[STR_SIZE];
2131 arglist_start(argp, format);
2132 g_vsnprintf(linebuf, SIZEOF(linebuf)-1, format, argp);
2135 g_fprintf(stderr,"%s\n", linebuf);
2136 if (flags->amidxtaped && their_features &&
2137 am_has_feature(their_features, fe_amrecover_message)) {
2138 g_fprintf(prompt_out, "MESSAGE %s\r\n", linebuf);