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"
41 #include "server_util.h"
43 #include <timestamp.h>
50 LOAD_NEXT = 1, /* An unknown new slot has been loaded. */
51 LOAD_CHANGER = -2, /* The requested slot has been loaded. */
52 LOAD_STOP = -1, /* The search is complete. */
56 RESTORE_STATUS_NEXT_FILE,
57 RESTORE_STATUS_NEXT_TAPE,
63 /* stuff we're stuck having global */
65 static int exitassemble = 0;
67 char *rst_conf_logdir = NULL;
68 char *rst_conf_logfile = NULL;
69 static char *curslot = NULL;
71 typedef struct open_output_s {
72 struct open_output_s *next;
79 typedef struct dumplist_s {
80 struct dumplist_s *next;
85 struct seentapes_s *next;
91 static open_output_t *open_outputs = NULL;
92 static dumplist_t *alldumps_list = NULL;
96 static void append_file_to_fd(char *filename, int fd);
97 static int headers_equal(dumpfile_t *file1, dumpfile_t *file2, int ignore_partnums);
98 static int already_have_dump(dumpfile_t *file);
99 static void handle_sigint(int sig);
100 static int scan_init(void *ud, int rc, int ns, int bk, int s);
101 static Device * conditional_device_open(char * tapedev, FILE * orompt_out,
103 am_feature_t * their_features,
104 tapelist_t * desired_tape);
105 int loadlabel_slot(void *ud, int rc, char *slotstr, char *device);
106 char *label_of_current_slot(char *cur_tapedev, FILE *prompt_out,
107 int *tapefd, dumpfile_t *file, rst_flags_t *flags,
108 am_feature_t *their_features,
109 ssize_t *read_result, tapelist_t *desired_tape);
111 LoadStatus load_next_tape(char **cur_tapedev, FILE *prompt_out, int backwards,
112 rst_flags_t *flags, am_feature_t *their_features,
113 tapelist_t *desired_tape);
114 LoadStatus load_manual_tape(char **cur_tapedev, FILE *prompt_out, FILE *prompt_in,
115 rst_flags_t *flags, am_feature_t *their_features,
116 tapelist_t *desired_tape);
119 * We might want to flush any open dumps and unmerged splits before exiting
120 * on SIGINT, so do so.
126 (void)sig; /* Quiet unused parameter warning */
128 flush_open_outputs(exitassemble, NULL);
129 if (rst_conf_logfile) {
130 unlink(rst_conf_logfile);
131 log_add(L_INFO, "pid-done %ld\n", (long)getpid());
139 rst_conf_logdir = config_dir_relative(getconf_str(CNF_LOGDIR));
140 rst_conf_logfile = vstralloc(rst_conf_logdir, "/log", NULL);
141 if (access(rst_conf_logfile, F_OK) == 0) {
142 run_amcleanup(get_config_name());
144 if (access(rst_conf_logfile, F_OK) == 0) {
145 char *process_name = get_master_process(rst_conf_logfile);
146 dbprintf(_("%s exists: %s is already running, "
147 "or you must run amcleanup\n"), rst_conf_logfile,
149 amfree(process_name);
152 log_add(L_INFO, "%s", get_pname());
157 * Return 1 if the two fileheaders match in name, disk, type, split chunk part
158 * number, and datestamp, and 0 if not. The part number can be optionally
167 if(!file1 || !file2) return(0);
169 if(file1->dumplevel == file2->dumplevel &&
170 file1->type == file2->type &&
171 !strcmp(file1->datestamp, file2->datestamp) &&
172 !strcmp(file1->name, file2->name) &&
173 !strcmp(file1->disk, file2->disk) &&
174 (ignore_partnums || file1->partnum == file2->partnum)){
182 * See whether we're already pulled an exact copy of the given file (chunk
183 * number and all). Returns 0 if not, 1 if so.
189 dumplist_t *fileentry = NULL;
192 for(fileentry=alldumps_list;fileentry;fileentry=fileentry->next){
193 if(headers_equal(file, fileentry->file, 0)) return(1);
199 * Open the named file and append its contents to the (hopefully open) file
200 * descriptor supplies.
207 queue_fd_t queue_fd_write = {write_fd, NULL};
208 queue_fd_t queue_fd_read = {0, NULL};
211 queue_fd_read.fd = robust_open(filename, O_RDONLY, 0);
212 if (queue_fd_read.fd < 0) {
213 error(_("can't open %s: %s"), filename, strerror(errno));
217 if (!do_consumer_producer_queue(fd_read_producer, &queue_fd_read,
218 fd_write_consumer, &queue_fd_write)) {
219 if (queue_fd_read.errmsg && queue_fd_write.errmsg) {
220 error("Error copying data from file \"%s\" to fd %d: %s: %s.\n",
221 filename, queue_fd_write.fd, queue_fd_read.errmsg,
222 queue_fd_write.errmsg);
223 } else if (queue_fd_read.errmsg) {
224 error("Error copying data from file \"%s\" to fd %d: %s.\n",
225 filename, queue_fd_write.fd, queue_fd_read.errmsg);
226 } else if (queue_fd_write.errmsg) {
227 error("Error copying data from file \"%s\" to fd %d: %s.\n",
228 filename, queue_fd_write.fd, queue_fd_write.errmsg);
230 error("Error copying data from file \"%s\" to fd %d.\n",
231 filename, queue_fd_write.fd);
233 g_assert_not_reached();
236 aclose(queue_fd_read.fd);
239 /* A user_init function for changer_find(). See changer.h for
242 scan_init(G_GNUC_UNUSED void * ud, int rc, G_GNUC_UNUSED int ns,
243 int bk, G_GNUC_UNUSED int s) {
245 error(_("could not get changer info: %s"), changer_resultstr);
259 /* DANGER WILL ROBINSON: This function references globals:
263 loadlabel_slot(void * datap,
268 loadlabel_data * data = (loadlabel_data*)datap;
270 DeviceStatusFlags device_status;
272 g_return_val_if_fail(rc > 1 || device_name != NULL, 0);
273 g_return_val_if_fail(slotstr != NULL, 0);
278 error(_("could not load slot %s: %s"), slotstr, changer_resultstr);
279 g_assert_not_reached();
283 g_fprintf(stderr, _("%s: slot %s: %s\n"),
284 get_pname(), slotstr, changer_resultstr);
288 device = device_open(device_name);
289 g_assert(device != NULL);
290 if (device->status != DEVICE_STATUS_SUCCESS) {
291 g_fprintf(stderr, "%s: slot %s: Could not open device: %s.\n",
292 get_pname(), slotstr, device_error(device));
296 if (!device_configure(device, TRUE)) {
297 g_fprintf(stderr, "%s: slot %s: Error configuring device:\n"
299 get_pname(), slotstr, get_pname(), slotstr, device_error_or_status(device));
300 g_object_unref(device);
304 if (!set_restore_device_read_buffer_size(device, data->flags)) {
305 g_fprintf(stderr, "%s: slot %s: Error setting read block size:\n"
307 get_pname(), slotstr, get_pname(), slotstr, device_error_or_status(device));
308 g_object_unref(device);
311 device_status = device_read_label(device);
312 if (device_status != DEVICE_STATUS_SUCCESS) {
313 g_fprintf(stderr, "%s: slot %s: Error reading tape label:\n"
315 get_pname(), slotstr, get_pname(), slotstr, device_error_or_status(device));
316 g_object_unref(device);
320 g_assert(device->volume_label != NULL);
321 if (device->volume_label == NULL) {
322 g_fprintf(stderr, "%s: slot %s: Could not read tape label.\n",
323 get_pname(), slotstr);
324 g_object_unref(device);
328 if (!device_start(device, ACCESS_READ, NULL, NULL)) {
329 g_fprintf(stderr, "%s: slot %s: Could not open device for reading: %s.\n",
330 get_pname(), slotstr, device_error(device));
334 g_fprintf(stderr, "%s: slot %s: time %-14s label %s",
335 get_pname(), slotstr, device->volume_time, device->volume_label);
337 if(strcmp(device->volume_label, data->searchlabel) != 0) {
338 g_fprintf(stderr, " (wrong tape)\n");
339 g_object_unref(device);
343 g_fprintf(stderr, " (exact label match)\n");
345 g_object_unref(device);
346 curslot = newstralloc(curslot, slotstr);
347 amfree(*(data->cur_tapedev));
348 *(data->cur_tapedev) = stralloc(device_name);
353 /* non-local functions follow */
358 * Check whether we've read all of the preceding parts of a given split dump,
359 * generally used to see if we're done and can close the thing.
367 int *foundparts = NULL;
368 dumplist_t *fileentry = NULL;
370 if(!file || file->partnum < 1) return(0);
372 if(upto < 1) upto = file->totalparts;
374 foundparts = alloc(SIZEOF(*foundparts) * upto);
375 for(c = 0 ; c< upto; c++) foundparts[c] = 0;
377 for(fileentry=alldumps_list;fileentry; fileentry=fileentry->next){
378 dumpfile_t *cur_file = fileentry->file;
379 if(headers_equal(file, cur_file, 1)){
380 if(cur_file->partnum > upto){
385 foundparts[cur_file->partnum - 1] = 1;
389 for(c = 0 ; c< upto; c++){
401 * Free up the open filehandles and memory we were using to track in-progress
402 * dumpfiles (generally for split ones we're putting back together). If
403 * applicable, also find the ones that are continuations of one another and
404 * string them together. If given an optional file header argument, flush
405 * only that dump and do not flush/free any others.
410 dumpfile_t *only_file)
412 open_output_t *cur_out = NULL, *prev = NULL;
413 find_result_t *sorted_files = NULL;
414 amwait_t compress_status;
417 g_fprintf(stderr, "\n");
421 * Deal with any split dumps we've been working on, appending pieces
422 * that haven't yet been appended and closing filehandles we've been
426 find_result_t *cur_find_res = NULL;
427 int outfd = -1, lastpartnum = -1;
428 dumpfile_t *main_file = NULL;
429 cur_out = open_outputs;
431 /* stick the dumpfile_t's into a list find_result_t's so that we can
432 abuse existing sort functionality */
433 for(cur_out=open_outputs; cur_out; cur_out=cur_out->next){
434 find_result_t *cur_find_res = NULL;
435 dumpfile_t *cur_file = cur_out->file;
436 /* if we requested a particular file, do only that one */
437 if(only_file && !headers_equal(cur_file, only_file, 1)){
440 cur_find_res = alloc(SIZEOF(find_result_t));
441 memset(cur_find_res, '\0', SIZEOF(find_result_t));
442 cur_find_res->timestamp = stralloc(cur_file->datestamp);
443 cur_find_res->hostname = stralloc(cur_file->name);
444 cur_find_res->diskname = stralloc(cur_file->disk);
445 cur_find_res->level = cur_file->dumplevel;
446 if(cur_file->partnum < 1) cur_find_res->partnum = stralloc("--");
448 char part_str[NUM_STR_SIZE];
449 g_snprintf(part_str, SIZEOF(part_str), "%d", cur_file->partnum);
450 cur_find_res->partnum = stralloc(part_str);
452 cur_find_res->user_ptr = (void*)cur_out;
454 cur_find_res->next = sorted_files;
455 sorted_files = cur_find_res;
457 sort_find_result("hkdlp", &sorted_files);
459 /* now we have an in-order list of the files we need to concatenate */
460 cur_find_res = sorted_files;
461 for(cur_find_res=sorted_files;
463 cur_find_res=cur_find_res->next){
464 dumpfile_t *cur_file = NULL;
465 cur_out = (open_output_t*)cur_find_res->user_ptr;
466 cur_file = cur_out->file;
468 /* if we requested a particular file, do only that one */
469 if(only_file && !headers_equal(cur_file, only_file, 1)){
473 if(cur_file->type == F_SPLIT_DUMPFILE) {
474 /* is it a continuation of one we've been writing? */
475 if(main_file && cur_file->partnum > lastpartnum &&
476 headers_equal(cur_file, main_file, 1)){
480 /* effectively changing filehandles */
481 aclose(cur_out->outfd);
482 cur_out->outfd = outfd;
484 cur_filename = make_filename(cur_file);
485 main_filename = make_filename(main_file);
486 g_fprintf(stderr, _("Merging %s with %s\n"),
487 cur_filename, main_filename);
488 append_file_to_fd(cur_filename, outfd);
489 if(unlink(cur_filename) < 0){
490 g_fprintf(stderr, _("Failed to unlink %s: %s\n"),
491 cur_filename, strerror(errno));
493 amfree(cur_filename);
494 amfree(main_filename);
498 if(outfd >= 0) aclose(outfd);
500 main_file = alloc(SIZEOF(dumpfile_t));
501 memcpy(main_file, cur_file, SIZEOF(dumpfile_t));
502 outfd = cur_out->outfd;
504 char *cur_filename = make_filename(cur_file);
505 open(cur_filename, O_RDWR|O_APPEND);
507 error(_("Couldn't open %s for appending: %s"),
508 cur_filename, strerror(errno));
511 amfree(cur_filename);
514 lastpartnum = cur_file->partnum;
517 aclose(cur_out->outfd);
525 free_find_result(&sorted_files);
529 * Now that the split dump closure is done, free up resources we don't
532 for(cur_out=open_outputs; cur_out; cur_out=cur_out->next){
533 dumpfile_t *cur_file = NULL;
535 cur_file = cur_out->file;
536 /* if we requested a particular file, do only that one */
537 if(only_file && !headers_equal(cur_file, only_file, 1)){
541 aclose(cur_out->outfd);
544 if(cur_out->comp_enc_pid > 0){
545 waitpid(cur_out->comp_enc_pid, &compress_status, 0);
547 amfree(cur_out->file);
555 * Turn a fileheader into a string suited for use on the filesystem.
561 char number[NUM_STR_SIZE];
562 char part[NUM_STR_SIZE];
563 char totalparts[NUM_STR_SIZE];
569 g_snprintf(number, SIZEOF(number), "%d", file->dumplevel);
570 g_snprintf(part, SIZEOF(part), "%d", file->partnum);
572 if(file->totalparts < 0) {
573 g_snprintf(totalparts, SIZEOF(totalparts), "UNKNOWN");
576 g_snprintf(totalparts, SIZEOF(totalparts), "%d", file->totalparts);
578 padlen = strlen(totalparts) + 1 - strlen(part);
580 memset(pad, '0', padlen);
581 pad[padlen - 1] = '\0';
583 g_snprintf(part, SIZEOF(part), "%s%d", pad, file->partnum);
585 sfn = sanitise_filename(file->disk);
586 fn = vstralloc(file->name,
594 if (file->partnum > 0) {
595 vstrextend(&fn, ".", part, NULL);
602 /* Returns 1 if the dump file matches the hostname and diskname
603 * regular expressions given on the command line, 0 otherwise. As a
604 * special case, empty regexs and NULLs are considered equivalent to
605 * ".*": they match everything.
607 * @param file: the file to examine
608 * @param datestamp: the datestamp regex, or NULL for any
609 * @param hostname: the hostname regex, or NULL for any
610 * @param diskname: the diskname regex, or NULL for any
611 * @param level: the level regex, or NULL for any
612 * @returns: 1 if the dump file matches
622 char level_str[NUM_STR_SIZE];
623 g_snprintf(level_str, SIZEOF(level_str), "%d", file->dumplevel);
625 if(file->type != F_DUMPFILE && file->type != F_SPLIT_DUMPFILE) return 0;
627 if((!hostname || *hostname == '\0' || match_host(hostname, file->name)) &&
628 (!diskname || *diskname == '\0' || match_disk(diskname, file->disk)) &&
629 (!datestamp || *datestamp == '\0' || match_datestamp(datestamp, file->datestamp)) &&
630 (!level || *level == '\0' || match_level(level, level_str)))
637 * Reads the first block of a holding disk file.
641 read_holding_disk_header(
650 if(flags->blocksize > 0)
651 blocksize = (size_t)flags->blocksize;
653 blocksize = DISK_BLOCK_BYTES;
654 buffer = alloc(blocksize);
656 bytes_read = full_read(tapefd, buffer, blocksize);
657 if(bytes_read < blocksize) {
660 errtxt = "Unexpected EOF";
662 errtxt = strerror(errno);
664 if (bytes_read == 0) {
665 g_fprintf(stderr, _("%s: missing file header block: %s\n"),
666 get_pname(), errtxt);
669 plural(_("%s: short file header block: %zd byte: %s"),
670 _("%s: short file header block: %zd bytes: %s\n"),
672 get_pname(), bytes_read, errtxt);
674 file->type = F_UNKNOWN;
676 parse_file_header(buffer, file, bytes_read);
679 return (file->type != F_UNKNOWN &&
680 file->type != F_EMPTY &&
681 file->type != F_WEIRD);
685 * Restore the current file from tape. Depending on the settings of
686 * the command line flags, the file might need to be compressed or
687 * uncompressed. If so, a pipe through compress or uncompress is set
688 * up. The final output usually goes to a file named host.disk.date.lev,
689 * but with the -p flag the output goes to stdout (and presumably is
694 /* FIXME: Mondo function that needs refactoring. */
695 void restore(RestoreSource * source,
699 int file_is_compressed;
700 int is_continuation = 0;
701 int check_for_aborted = 0;
702 char *tmp_filename = NULL, *final_filename = NULL;
703 struct stat statinfo;
704 open_output_t *free_myout = NULL, *myout = NULL, *oldout = NULL;
705 dumplist_t *tempdump = NULL, *fileentry = NULL;
707 int need_compress=0, need_uncompress=0, need_decrypt=0;
714 filename = make_filename(source->header);
716 memset(pipes, -1, SIZEOF(pipes));
718 if(already_have_dump(source->header)){
719 g_fprintf(stderr, _(" *** Duplicate file %s, one is probably an aborted write\n"), filename);
720 check_for_aborted = 1;
723 /* store a shorthand record of this dump */
724 tempdump = malloc(SIZEOF(dumplist_t));
725 tempdump->file = malloc(SIZEOF(dumpfile_t));
726 tempdump->next = NULL;
727 memcpy(tempdump->file, source->header, SIZEOF(dumpfile_t));
730 * If we're appending chunked files to one another, and if this is a
731 * continuation of a file we just restored, and we've still got the
732 * output handle from that previous restore, we're golden. Phew.
734 if(flags->inline_assemble && source->header->type == F_SPLIT_DUMPFILE){
735 myout = open_outputs;
736 while(myout != NULL){
737 if(myout->file->type == F_SPLIT_DUMPFILE &&
738 headers_equal(source->header, myout->file, 1)){
739 if(source->header->partnum == myout->lastpartnum + 1){
746 if(myout != NULL) myout->lastpartnum = source->header->partnum;
747 else if(source->header->partnum != 1){
748 g_fprintf(stderr, _("%s: Chunk out of order, will save to disk and append to output.\n"), get_pname());
749 flags->pipe_to_fd = -1;
751 flags->leave_comp = 1;
754 free_myout = myout = alloc(SIZEOF(open_output_t));
755 memset(myout, 0, SIZEOF(open_output_t));
759 free_myout = myout = alloc(SIZEOF(open_output_t));
760 memset(myout, 0, SIZEOF(open_output_t));
764 if(is_continuation && flags->pipe_to_fd == -1){
766 filename = make_filename(myout->file);
767 g_fprintf(stderr, _("%s: appending to %s\n"), get_pname(),
772 /* adjust compression flag */
773 file_is_compressed = source->header->compressed;
774 if(!flags->compress && file_is_compressed &&
775 !known_compress_type(source->header)) {
777 _("%s: unknown compression suffix %s, can't uncompress\n"),
778 get_pname(), source->header->comp_suffix);
782 /* set up final destination file */
784 if(is_continuation && myout != NULL) {
787 if(flags->pipe_to_fd != -1) {
788 dest = flags->pipe_to_fd;
790 char *filename_ext = NULL;
792 if(flags->compress) {
793 filename_ext = file_is_compressed ? source->header->comp_suffix
795 } else if(flags->raw) {
796 filename_ext = ".RAW";
800 filename_ext = stralloc2(filename, filename_ext);
801 tmp_filename = stralloc(filename_ext);
802 if(flags->restore_dir != NULL) {
803 char *tmpstr = vstralloc(flags->restore_dir, "/",
805 amfree(tmp_filename);
806 tmp_filename = tmpstr;
808 final_filename = tmp_filename;
809 tmp_filename = vstralloc(final_filename, ".tmp", NULL);
810 if((dest = open(tmp_filename, (O_CREAT | O_RDWR | O_TRUNC),
812 error(_("could not create output file %s: %s"),
813 tmp_filename, strerror(errno));
816 amfree(filename_ext);
823 * If -r or -h, write the header before compress or uncompress pipe.
824 * Only write DISK_BLOCK_BYTES, regardless of how much was read.
825 * This makes the output look like a holding disk image, and also
826 * makes it easier to remove the header (e.g. in amrecover) since
827 * it has a fixed size.
829 if(flags->raw || (flags->headers && !is_continuation)) {
834 if(flags->compress && !file_is_compressed) {
835 source->header->compressed = 1;
836 g_snprintf(source->header->uncompress_cmd,
837 SIZEOF(source->header->uncompress_cmd),
838 " %s %s |", UNCOMPRESS_PATH,
839 #ifdef UNCOMPRESS_OPT
845 strncpy(source->header->comp_suffix,
847 SIZEOF(source->header->comp_suffix)-1);
848 source->header->comp_suffix[SIZEOF(source->header->comp_suffix)-1]
852 memcpy(&tmp_hdr, source->header, SIZEOF(dumpfile_t));
854 /* remove CONT_FILENAME from header */
855 memset(source->header->cont_filename, '\0',
856 SIZEOF(source->header->cont_filename));
857 dle_str = clean_dle_str_for_client(source->header->dle_str);
858 source->header->dle_str = dle_str;
859 source->header->blocksize = DISK_BLOCK_BYTES;
862 * Dumb down split file headers as well, so that older versions of
863 * things like amrecover won't gag on them.
865 if(source->header->type == F_SPLIT_DUMPFILE && flags->mask_splits){
866 source->header->type = F_DUMPFILE;
869 buffer = alloc(DISK_BLOCK_BYTES);
870 buffer = build_header(source->header, DISK_BLOCK_BYTES);
872 if((w = full_write(out, buffer,
873 DISK_BLOCK_BYTES)) != DISK_BLOCK_BYTES) {
875 error(_("write error: %s"), strerror(errno));
878 error(_("write error: %zd instead of %d"), w, DISK_BLOCK_BYTES);
883 memcpy(source->header, &tmp_hdr, SIZEOF(dumpfile_t));
886 /* find out if compression or uncompression is needed here */
887 if(flags->compress && !file_is_compressed && !is_continuation
888 && !flags->leave_comp
889 && (flags->inline_assemble ||
890 source->header->type != F_SPLIT_DUMPFILE))
893 if(!flags->raw && !flags->compress && file_is_compressed
894 && !is_continuation && !flags->leave_comp && (flags->inline_assemble
895 || source->header->type != F_SPLIT_DUMPFILE))
898 if(!flags->raw && source->header->encrypted && !is_continuation &&
899 (flags->inline_assemble || source->header->type != F_SPLIT_DUMPFILE)) {
903 /* Setup pipes for decryption / compression / uncompression */
906 if (pipe(&pipes[stage].pipe[0]) < 0) {
907 error(_("error [pipe[%d]: %s]"), stage, strerror(errno));
913 if (need_compress || need_uncompress) {
914 if (pipe(&pipes[stage].pipe[0]) < 0) {
915 error(_("error [pipe[%d]: %s]"), stage, strerror(errno));
920 pipes[stage].pipe[0] = -1;
921 pipes[stage].pipe[1] = out;
925 /* decrypt first if it's encrypted and no -r */
927 switch(myout->comp_enc_pid = fork()) {
929 error(_("could not fork for decrypt: %s"), strerror(errno));
933 aclose(pipes[stage].pipe[0]);
934 aclose(pipes[stage+1].pipe[1]);
939 if(dup2(pipes[stage].pipe[0], 0) == -1) {
940 error(_("error decrypt stdin [dup2 %d %d: %s]"), stage,
941 pipes[stage].pipe[0], strerror(errno));
945 if(dup2(pipes[stage+1].pipe[1], 1) == -1) {
946 error(_("error decrypt stdout [dup2 %d %d: %s]"), stage + 1,
947 pipes[stage+1].pipe[1], strerror(errno));
952 if (source->header->srv_encrypt[0] != '\0') {
953 (void) execlp(source->header->srv_encrypt,
954 source->header->srv_encrypt,
955 source->header->srv_decrypt_opt, NULL);
956 error("could not exec %s: %s",
957 source->header->srv_encrypt, strerror(errno));
958 g_assert_not_reached();
959 } else if (source->header->clnt_encrypt[0] != '\0') {
960 (void) execlp(source->header->clnt_encrypt,
961 source->header->clnt_encrypt,
962 source->header->clnt_decrypt_opt, NULL);
963 error("could not exec %s: %s",
964 source->header->clnt_encrypt, strerror(errno));
965 g_assert_not_reached();
972 * Insert a compress pipe
974 switch(myout->comp_enc_pid = fork()) {
976 error(_("could not fork for %s: %s"), COMPRESS_PATH, strerror(errno));
980 aclose(pipes[stage].pipe[0]);
981 aclose(pipes[stage+1].pipe[1]);
986 if(dup2(pipes[stage].pipe[0], 0) == -1) {
987 error(_("error compress stdin [dup2 %d %d: %s]"), stage,
988 pipes[stage].pipe[0], strerror(errno));
992 if(dup2(pipes[stage+1].pipe[1], 1) == -1) {
993 error(_("error compress stdout [dup2 %d %d: %s]"), stage + 1,
994 pipes[stage+1].pipe[1], strerror(errno));
997 if (*flags->comp_type == '\0') {
998 flags->comp_type = NULL;
1002 (void) execlp(COMPRESS_PATH, COMPRESS_PATH, flags->comp_type, (char *)0);
1003 error(_("could not exec %s: %s"), COMPRESS_PATH, strerror(errno));
1006 } else if(need_uncompress) {
1008 * If not -r, -c, -l, and file is compressed, and split reassembly
1009 * options are sane, insert uncompress pipe
1013 * XXX for now we know that for the two compression types we
1014 * understand, .Z and optionally .gz, UNCOMPRESS_PATH will take
1015 * care of both. Later, we may need to reference a table of
1016 * possible uncompress programs.
1018 switch(myout->comp_enc_pid = fork()) {
1020 error(_("could not fork for %s: %s"),
1021 UNCOMPRESS_PATH, strerror(errno));
1025 aclose(pipes[stage].pipe[0]);
1026 aclose(pipes[stage+1].pipe[1]);
1031 if(dup2(pipes[stage].pipe[0], 0) == -1) {
1032 error(_("error uncompress stdin [dup2 %d %d: %s]"), stage,
1033 pipes[stage].pipe[0], strerror(errno));
1037 if(dup2(pipes[stage+1].pipe[1], 1) == -1) {
1038 error(_("error uncompress stdout [dup2 %d %d: %s]"), stage + 1,
1039 pipes[stage+1].pipe[1], strerror(errno));
1044 if (source->header->srvcompprog[0] != '\0') {
1045 (void) execlp(source->header->srvcompprog,
1046 source->header->srvcompprog, "-d", NULL);
1047 error("could not exec %s: %s", source->header->srvcompprog,
1049 g_assert_not_reached();
1050 } else if (source->header->clntcompprog[0] != '\0') {
1051 (void) execlp(source->header->clntcompprog,
1052 source->header->clntcompprog, "-d", NULL);
1053 error("could not exec %s: %s", source->header->clntcompprog,
1055 g_assert_not_reached();
1057 (void) execlp(UNCOMPRESS_PATH, UNCOMPRESS_PATH,
1058 #ifdef UNCOMPRESS_OPT
1062 error(_("could not exec %s: %s"), UNCOMPRESS_PATH, strerror(errno));
1068 /* copy the rest of the file from tape to the output */
1069 if (source->restore_mode == HOLDING_MODE) {
1071 queue_fd_t queue_read = {source->u.holding_fd, NULL};
1072 queue_fd_t queue_write = {pipes[0].pipe[1], NULL};
1073 memcpy(& file, source->header, sizeof(file));
1075 do_consumer_producer_queue(fd_read_producer,
1079 /* TODO: Check error */
1081 * See if we need to switch to the next file in a holding restore
1083 if(file.cont_filename[0] == '\0') {
1084 break; /* no more files */
1086 aclose(queue_read.fd);
1087 if((queue_read.fd = open(file.cont_filename, O_RDONLY)) == -1) {
1088 char *cont_filename =
1089 strrchr(file.cont_filename,'/');
1092 if((queue_read.fd = open(cont_filename,O_RDONLY)) == -1) {
1093 error(_("can't open %s: %s"), file.cont_filename,
1098 g_fprintf(stderr, _("cannot open %s: %s\n"),
1099 file.cont_filename, strerror(errno));
1100 g_fprintf(stderr, _("using %s\n"),
1105 error(_("can't open %s: %s"), file.cont_filename,
1110 read_holding_disk_header(&file, queue_read.fd, flags);
1111 if(file.type != F_DUMPFILE && file.type != F_CONT_DUMPFILE
1112 && file.type != F_SPLIT_DUMPFILE) {
1113 g_fprintf(stderr, _("unexpected header type: "));
1114 print_header(stderr, source->header);
1119 queue_fd_t queue_fd = {pipes[0].pipe[1], NULL};
1120 device_read_to_fd(source->u.device, &queue_fd);
1121 /* TODO: Check error */
1125 if(!flags->inline_assemble) {
1129 if(!is_continuation){
1130 if(tmp_filename && stat(tmp_filename, &statinfo) < 0){
1131 error(_("Can't stat the file I just created (%s)!"), tmp_filename);
1134 statinfo.st_size = (off_t)0;
1136 if (check_for_aborted && final_filename) {
1137 char *old_dump = final_filename;
1138 struct stat oldstat;
1139 if(stat(old_dump, &oldstat) >= 0){
1140 if(oldstat.st_size <= statinfo.st_size){
1141 dumplist_t *prev_fileentry = NULL;
1142 open_output_t *prev_out = NULL;
1143 g_fprintf(stderr, _("Newer restore is larger, using that\n"));
1144 /* nuke the old dump's entry in alldump_list */
1145 for(fileentry=alldumps_list;
1147 fileentry=fileentry->next){
1148 if(headers_equal(source->header,
1149 fileentry->file, 0)){
1151 prev_fileentry->next = fileentry->next;
1154 alldumps_list = fileentry->next;
1159 prev_fileentry = fileentry;
1161 myout = open_outputs;
1162 while(myout != NULL){
1163 if(headers_equal(source->header, myout->file, 0)){
1164 if(myout->outfd >= 0)
1165 aclose(myout->outfd);
1167 prev_out->next = myout->next;
1169 else open_outputs = myout->next;
1174 myout = myout->next;
1178 g_fprintf(stderr, _("Older restore is larger, using that\n"));
1180 unlink(tmp_filename);
1181 amfree(tempdump->file);
1183 amfree(tmp_filename);
1184 amfree(final_filename);
1190 if(tmp_filename && final_filename &&
1191 rename(tmp_filename, final_filename) < 0) {
1192 error(_("Can't rename %s to %s: %s"),
1193 tmp_filename, final_filename, strerror(errno));
1197 amfree(tmp_filename);
1198 amfree(final_filename);
1202 * actually insert tracking data for this file into our various
1203 * structures (we waited in case we needed to give up)
1205 if(!is_continuation){
1206 oldout = alloc(SIZEOF(open_output_t));
1207 oldout->file = alloc(SIZEOF(dumpfile_t));
1208 memcpy(oldout->file, source->header, SIZEOF(dumpfile_t));
1209 if(flags->inline_assemble) oldout->outfd = pipes[0].pipe[1];
1210 else oldout->outfd = -1;
1211 oldout->comp_enc_pid = -1;
1212 oldout->lastpartnum = source->header->partnum;
1213 oldout->next = open_outputs;
1214 open_outputs = oldout;
1217 fileentry = alldumps_list;
1218 while (fileentry->next != NULL)
1219 fileentry=fileentry->next;
1220 fileentry->next = tempdump;
1223 alldumps_list = tempdump;
1228 set_restore_device_read_buffer_size(
1232 /* if the user specified a blocksize, try to use it */
1233 if (flags->blocksize) {
1237 bzero(&val, sizeof(GValue));
1239 g_value_init(&val, G_TYPE_UINT);
1240 g_value_set_uint(&val, flags->blocksize);
1241 success = device_property_set(device, PROPERTY_READ_BUFFER_SIZE, &val);
1242 g_value_unset(&val);
1244 if (device->status == DEVICE_STATUS_SUCCESS) {
1245 /* device doesn't have this property, so quietly ignore it */
1246 g_warning(_("Device %s does not support PROPERTY_READ_BUFFER_SIZE; ignoring block size %zd"),
1247 device->device_name, flags->blocksize);
1249 /* it's a real error */
1258 /* return NULL if the label is not the expected one */
1259 /* returns a Device handle if it is the expected one. */
1260 /* FIXME: Was label_of_current_slot */
1262 conditional_device_open(char *tapedev,
1265 am_feature_t *their_features,
1266 tapelist_t *desired_tape)
1270 if (tapedev == NULL) {
1271 send_message(prompt_out, flags, their_features,
1272 _("Volume labeled '%s' not found."), desired_tape->label);
1276 rval = device_open(tapedev);
1277 g_assert(rval != NULL);
1278 if (rval->status != DEVICE_STATUS_SUCCESS) {
1279 send_message(prompt_out, flags, their_features,
1280 "Error opening device '%s': %s.",
1281 tapedev, device_error(rval));
1282 g_object_unref(rval);
1286 if (!device_configure(rval, TRUE)) {
1287 g_fprintf(stderr, "Error configuring device: %s\n", device_error_or_status(rval));
1288 g_object_unref(rval);
1292 if (!set_restore_device_read_buffer_size(rval, flags)) {
1293 send_message(prompt_out, flags, their_features,
1294 "Error setting read block size on '%s': %s.",
1295 tapedev, device_error(rval));
1296 g_object_unref(rval);
1299 device_read_label(rval);
1301 if (rval->volume_label == NULL) {
1302 char *errstr = stralloc2("Not an amanda tape: ",
1303 device_error(rval));
1304 send_message(prompt_out, flags, their_features, "%s", errstr);
1306 g_object_unref(rval);
1310 if (!device_start(rval, ACCESS_READ, NULL, NULL)) {
1311 send_message(prompt_out, flags, their_features,
1312 "Colud not open device %s for reading: %s.\n",
1313 tapedev, device_error(rval));
1317 if (flags->check_labels && desired_tape &&
1318 strcmp(rval->volume_label, desired_tape->label) != 0) {
1319 send_message(prompt_out, flags, their_features,
1320 "Label mismatch, got %s and expected %s",
1321 rval->volume_label, desired_tape->label);
1322 g_object_unref(rval);
1329 /* Do the right thing to try and load the next required tape. See
1330 LoadStatus above for return value meaning. */
1337 am_feature_t *their_features,
1338 tapelist_t *desired_tape)
1341 send_message(prompt_out, flags, their_features,
1342 _("Looking for tape %s..."),
1343 desired_tape->label);
1345 loadlabel_data data;
1346 data.cur_tapedev = cur_tapedev;
1347 data.searchlabel = desired_tape->label;
1349 changer_find(&data, scan_init, loadlabel_slot,
1350 desired_tape->label);
1351 return LOAD_CHANGER;
1354 changer_loadslot("next", &curslot,
1359 assert(!flags->amidxtaped);
1361 changer_loadslot("next", &curslot, cur_tapedev);
1365 g_assert_not_reached();
1369 /* will never return LOAD_CHANGER. */
1376 am_feature_t *their_features,
1377 tapelist_t *desired_tape)
1381 if (flags->amidxtaped) {
1382 if (their_features &&
1383 am_has_feature(their_features,
1384 fe_amrecover_FEEDME)) {
1385 g_fprintf(prompt_out, "FEEDME %s\r\n",
1386 desired_tape->label);
1388 input = agets(prompt_in);/* Strips \n but not \r */
1390 error(_("Connection lost with amrecover"));
1392 } else if (strcmp("OK\r", input) == 0) {
1393 } else if (strncmp("TAPE ", input, 5) == 0) {
1394 amfree(*tapedev_ptr);
1395 *tapedev_ptr = alloc(1025);
1396 if (sscanf(input, "TAPE %1024s\r", *tapedev_ptr) != 1) {
1397 error(_("Got bad response from amrecover: %s"), input);
1401 send_message(prompt_out, flags, their_features,
1402 _("Got bad response from amrecover: %s"), input);
1403 error(_("Got bad response from amrecover: %s"), input);
1407 send_message(prompt_out, flags, their_features,
1408 _("Client doesn't support fe_amrecover_FEEDME"));
1409 error(_("Client doesn't support fe_amrecover_FEEDME"));
1415 g_fprintf(prompt_out,
1416 _("Insert tape labeled %s in device %s \n"
1417 "and press enter, ^D to finish reading tapes\n"),
1418 desired_tape->label, *tapedev_ptr);
1420 g_fprintf(prompt_out,_("Insert a tape to search and press "
1421 "enter, ^D to finish reading tapes\n"));
1424 if((input = agets(prompt_in)) == NULL)
1432 /* Search a seen-tapes list for a particular name, to see if we've already
1433 * processed this tape. Returns TRUE if this label has already been seen. */
1434 static gboolean check_volume_seen(seentapes_t * list, char * label) {
1435 seentapes_t * cur_tape;
1436 for (cur_tape = list; cur_tape != NULL; cur_tape = cur_tape->next) {
1437 if (strcmp(cur_tape->label, label) == 0) {
1444 /* Add a volume to the seen tapes list. */
1445 static void record_seen_volume(seentapes_t ** list, char * label,
1447 seentapes_t * new_entry;
1452 new_entry = malloc(sizeof(seentapes_t));
1453 new_entry->label = stralloc(label);
1454 if (slotstr == NULL) {
1455 new_entry->slotstr = NULL;
1457 new_entry->slotstr = stralloc(slotstr);
1459 new_entry->files = NULL;
1460 new_entry->next = *list;
1464 /* Record a specific dump on a volume. */
1465 static void record_seen_dump(seentapes_t * volume, dumpfile_t * header) {
1466 dumplist_t * this_dump;
1471 this_dump = malloc(sizeof(*this_dump));
1472 this_dump->file = g_memdup(header, sizeof(*header));
1473 this_dump->next = NULL;
1474 if (volume->files) {
1475 dumplist_t * tmp_dump = volume->files;
1476 while (tmp_dump->next != NULL) {
1477 tmp_dump = tmp_dump->next;
1479 tmp_dump->next = this_dump;
1481 volume->files = this_dump;
1485 static void print_tape_inventory(FILE * logstream, seentapes_t * tape_seen,
1486 char * timestamp, char * label,
1489 dumplist_t * fileentry;
1491 logline = log_genstring(L_START, "taper",
1492 "datestamp %s label %s tape %d",
1493 timestamp, label, tape_count);
1494 fputs(logline, logstream);
1496 for(fileentry=tape_seen->files; fileentry; fileentry=fileentry->next){
1497 switch (fileentry->file->type) {
1499 logline = log_genstring(L_SUCCESS, "taper",
1500 "%s %s %s %d [faked log entry]",
1501 fileentry->file->name,
1502 fileentry->file->disk,
1503 fileentry->file->datestamp,
1504 fileentry->file->dumplevel);
1506 case F_SPLIT_DUMPFILE:
1507 logline = log_genstring(L_CHUNK, "taper",
1508 "%s %s %s %d %d [faked log entry]",
1509 fileentry->file->name,
1510 fileentry->file->disk,
1511 fileentry->file->datestamp,
1512 fileentry->file->partnum,
1513 fileentry->file->dumplevel);
1518 if(logline != NULL){
1519 fputs(logline, logstream);
1526 /* Check if the given header matches the given dumpspecs. Returns
1527 TRUE if dumpspecs is NULL and false if the header is NULL. Returns
1528 true if the header matches the match list. */
1529 static gboolean run_dumpspecs(GSList * dumpspecs,
1530 dumpfile_t * header) {
1533 if (dumpspecs == NULL)
1539 ds = (dumpspec_t *)dumpspecs->data;
1540 if (disk_match(header, ds->datestamp, ds->host,
1541 ds->disk, ds->level) != 0) {
1544 dumpspecs = dumpspecs->next;
1550 /* A wrapper around restore() above. This function does some extra
1551 checking to seek to the file in question and ensure that we really,
1552 really want to use it.
1554 The next_file argument provides instruction on what to do if the
1555 requested file does not exist on the volume: If next_file is NULL
1556 then if the requested file is missing the function will return
1557 RESTORE_STATUS_NEXT_FILE. If next_file is not NULL then the first
1558 extant file whose number is equal to or greater than file_num will
1559 be attempted. *next_file will be filled in with the number of the
1560 file following the one that was attempted. */
1561 static RestoreFileStatus
1562 try_restore_single_file(Device * device, int file_num, int* next_file,
1564 rst_flags_t * flags,
1565 am_feature_t * their_features,
1566 dumpfile_t * first_restored_file,
1568 seentapes_t * tape_seen) {
1569 RestoreSource source;
1570 source.u.device = device;
1571 source.restore_mode = DEVICE_MODE;
1573 source.header = device_seek_file(device, file_num);
1575 if (source.header == NULL) {
1576 /* This definitely indicates an error. */
1577 send_message(prompt_out, flags, their_features,
1578 "Could not seek device %s to file %d: %s.",
1579 device->device_name, file_num,
1580 device_error(device));
1581 return RESTORE_STATUS_NEXT_TAPE;
1582 } else if (source.header->type == F_TAPEEND) {
1583 amfree(source.header);
1584 return RESTORE_STATUS_NEXT_TAPE;
1585 } else if (device->file != file_num) {
1586 if (next_file == NULL) {
1587 send_message(prompt_out, flags, their_features,
1588 "Requested file %d does not exist.",
1590 return RESTORE_STATUS_NEXT_FILE;
1592 send_message(prompt_out, flags, their_features,
1593 "Skipped from file %d to file %d.",
1594 file_num, device->file);
1595 file_num = device->file;
1598 if (!am_has_feature(their_features, fe_amrecover_dle_in_header)) {
1599 source.header->dle_str = NULL;
1602 if (next_file != NULL) {
1603 *next_file = file_num + 1;
1606 g_return_val_if_fail(source.header->type == F_DUMPFILE ||
1607 source.header->type == F_CONT_DUMPFILE ||
1608 source.header->type == F_SPLIT_DUMPFILE,
1609 RESTORE_STATUS_NEXT_FILE);
1612 if (!run_dumpspecs(dumpspecs, source.header)) {
1613 if(!flags->amidxtaped) {
1614 g_fprintf(prompt_out, "%s: %d: skipping ",
1615 get_pname(), file_num);
1616 print_header(prompt_out, source.header);
1618 return RESTORE_STATUS_NEXT_FILE;
1621 if (first_restored_file != NULL &&
1622 first_restored_file->type != F_UNKNOWN &&
1623 first_restored_file->type != F_EMPTY &&
1624 !headers_equal(first_restored_file, source.header, 1) &&
1625 (flags->pipe_to_fd == fileno(stdout))) {
1626 return RESTORE_STATUS_STOP;
1629 if (!flags->amidxtaped) {
1630 g_fprintf(stderr, "%s: %d: restoring ",
1631 get_pname(), file_num);
1632 print_header(stderr, source.header);
1634 record_seen_dump(tape_seen, source.header);
1635 restore(&source, flags);
1636 if (first_restored_file) {
1637 memcpy(first_restored_file, source.header, sizeof(dumpfile_t));
1639 return RESTORE_STATUS_NEXT_FILE;
1642 /* This function handles processing of a particular tape or holding
1643 disk file. It returns TRUE if it is useful to load another tape.*/
1646 search_a_tape(Device * device,
1647 FILE *prompt_out, /* Where to send any prompts */
1648 rst_flags_t *flags, /* Restore options. */
1649 am_feature_t *their_features,
1650 tapelist_t *desired_tape, /* A list of desired tape files */
1651 GSList *dumpspecs, /* What disks to restore. */
1652 seentapes_t **tape_seen, /* Where to record data on
1654 /* May be NULL. If zeroed, will be filled in with the
1655 first restored file. If already filled in, then we
1656 may only restore other files from the same dump. */
1657 dumpfile_t * first_restored_file,
1660 seentapes_t * tape_seen_head = NULL;
1661 RestoreSource source;
1664 int tapefile_idx = -1;
1666 RestoreFileStatus restore_status = RESTORE_STATUS_NEXT_TAPE;
1668 /* if we're doing an inventory (logstream != NULL), then we need
1669 * somewhere to keep track of our seen tapes */
1670 g_assert(tape_seen != NULL || logstream == NULL);
1672 source.restore_mode = DEVICE_MODE;
1673 source.u.device = device;
1676 if(desired_tape && desired_tape->numfiles > 0)
1680 dbprintf(_("search_a_tape: desired_tape=%p label=%s\n"),
1681 desired_tape, desired_tape->label);
1682 dbprintf(_("tape: numfiles = %d\n"), desired_tape->numfiles);
1683 for (i=0; i < desired_tape->numfiles; i++) {
1684 dbprintf(_("tape: files[%d] = %lld\n"),
1685 i, (long long)desired_tape->files[i]);
1688 dbprintf(_("search_a_tape: no desired_tape\n"));
1690 dbprintf(_("current tapefile_idx = %d\n"), tapefile_idx);
1693 if (check_volume_seen(*tape_seen, device->volume_label)) {
1694 send_message(prompt_out, flags, their_features,
1695 "Skipping repeat tape %s in slot %s",
1696 device->volume_label, curslot);
1699 record_seen_volume(tape_seen, device->volume_label, curslot);
1700 tape_seen_head = *tape_seen;
1703 if (desired_tape && desired_tape->numfiles > 0) {
1704 /* Iterate the tape list, handle each file in order. */
1706 for (file_index = 0; file_index < desired_tape->numfiles;
1708 int file_num = desired_tape->files[file_index];
1709 restore_status = try_restore_single_file(device, file_num, NULL,
1712 first_restored_file,
1713 NULL, tape_seen_head);
1714 if (restore_status != RESTORE_STATUS_NEXT_FILE)
1717 } else if(flags->fsf && flags->amidxtaped) {
1718 /* Restore a single file, then quit. */
1720 try_restore_single_file(device, flags->fsf, NULL, prompt_out, flags,
1721 their_features, first_restored_file,
1722 dumpspecs, tape_seen_head);
1724 /* Search the tape from beginning to end. */
1727 if (flags->fsf > 0) {
1728 file_num = flags->fsf;
1733 if (!flags->amidxtaped) {
1734 g_fprintf(prompt_out, "Restoring from tape %s starting with file %d.\n",
1735 device->volume_label, file_num);
1741 try_restore_single_file(device, file_num, &file_num,
1743 their_features, first_restored_file,
1744 dumpspecs, tape_seen_head);
1745 if (restore_status != RESTORE_STATUS_NEXT_FILE)
1750 /* spit out our accumulated list of dumps, if we're inventorying */
1751 if (logstream != NULL) {
1752 print_tape_inventory(logstream, tape_seen_head, device->volume_time,
1753 device->volume_label, tape_count);
1755 return (restore_status != RESTORE_STATUS_STOP);
1758 static void free_seen_tapes(seentapes_t * seentapes) {
1759 while (seentapes != NULL) {
1760 seentapes_t *tape_seen = seentapes;
1761 seentapes = seentapes->next;
1762 while(tape_seen->files != NULL) {
1763 dumplist_t *temp_dump = tape_seen->files;
1764 tape_seen->files = temp_dump->next;
1765 amfree(temp_dump->file);
1768 amfree(tape_seen->label);
1769 amfree(tape_seen->slotstr);
1775 /* Spit out a list of expected tapes, so people with manual changers know
1777 static void print_expected_tape_list(FILE* prompt_out, FILE* prompt_in,
1778 tapelist_t *tapelist,
1779 rst_flags_t * flags) {
1780 tapelist_t * cur_volume;
1782 g_fprintf(prompt_out, "The following tapes are needed:");
1783 for(cur_volume = tapelist; cur_volume != NULL;
1784 cur_volume = cur_volume->next){
1785 g_fprintf(prompt_out, " %s", cur_volume->label);
1787 g_fprintf(prompt_out, "\n");
1789 if(flags->wait_tape_prompt){
1791 g_fprintf(prompt_out,"Press enter when ready\n");
1793 input = agets(prompt_in);
1795 g_fprintf(prompt_out, "\n");
1800 /* Restore a single holding-disk file. We will fill in this_header
1801 with the header from this restore (if it is not null), and in the
1802 stdout-pipe case, we abort according to last_header. Returns TRUE
1803 if the restore should continue, FALSE if we are done. */
1804 gboolean restore_holding_disk(FILE * prompt_out,
1805 rst_flags_t * flags,
1806 am_feature_t * features,
1808 seentapes_t ** seen,
1810 dumpfile_t * this_header,
1811 dumpfile_t * last_header) {
1812 RestoreSource source;
1813 gboolean read_result;
1816 source.header = &header;
1817 source.restore_mode = HOLDING_MODE;
1818 source.u.holding_fd = robust_open(file->label, 0, 0);
1819 if (source.u.holding_fd < 0) {
1820 send_message(prompt_out, flags, features,
1821 "could not open %s: %s",
1822 file->label, strerror(errno));
1826 g_fprintf(stderr, "Reading %s from fd %d\n",
1827 file->label, source.u.holding_fd);
1829 read_result = read_holding_disk_header(source.header,
1830 source.u.holding_fd, flags);
1832 send_message(prompt_out, flags, features,
1833 "Invalid header reading %s.",
1835 aclose(source.u.holding_fd);
1839 if (!run_dumpspecs(dumpspecs, source.header)) {
1843 if (last_header != NULL && !flags->amidxtaped &&
1844 flags->pipe_to_fd == STDOUT_FILENO &&
1845 last_header->type != F_UNKNOWN &&
1846 !headers_equal(last_header, source.header, 1)) {
1848 } else if (this_header != NULL) {
1849 memcpy(this_header, source.header, sizeof(*this_header));
1853 record_seen_volume(seen, file->label, "<none>");
1854 record_seen_dump(*seen, source.header);
1857 print_header(stderr, source.header);
1859 restore(&source, flags);
1860 aclose(source.u.holding_fd);
1864 /* Ask for a specific manual tape. If we find the right one, then open it
1865 * and return a Device handle. If not, return NULL. Pass a device name, but
1866 * it might be overridden. */
1867 static Device* manual_find_tape(char ** cur_tapedev, tapelist_t * cur_volume,
1868 FILE * prompt_out, FILE * prompt_in,
1869 rst_flags_t * flags,
1870 am_feature_t * features) {
1871 LoadStatus status = LOAD_NEXT;
1875 status = load_manual_tape(cur_tapedev, prompt_out, prompt_in,
1876 flags, features, cur_volume);
1878 if (status == LOAD_STOP)
1881 rval = conditional_device_open(*cur_tapedev, prompt_out, flags,
1882 features, cur_volume);
1888 /* If we have a tapelist, then we mandate restoring in tapelist
1889 order. The logic is simple: Get the next tape, and deal with it,
1890 then move on to the next one. */
1892 restore_from_tapelist(FILE * prompt_out,
1894 tapelist_t * tapelist,
1896 rst_flags_t * flags,
1897 am_feature_t * features,
1899 gboolean use_changer,
1901 tapelist_t * cur_volume;
1902 dumpfile_t first_restored_file;
1903 seentapes_t * seentapes = NULL;
1905 fh_init(&first_restored_file);
1907 for(cur_volume = tapelist; cur_volume != NULL;
1908 cur_volume = cur_volume->next){
1909 if (cur_volume->isafile) {
1910 /* Restore from holding disk; just go. */
1911 if (first_restored_file.type == F_UNKNOWN) {
1912 if (!restore_holding_disk(prompt_out, flags,
1913 features, cur_volume, &seentapes,
1914 NULL, NULL, &first_restored_file)) {
1918 restore_holding_disk(prompt_out, flags, features,
1919 cur_volume, &seentapes,
1920 NULL, &first_restored_file, NULL);
1922 if (flags->pipe_to_fd == fileno(stdout)) {
1926 Device * device = NULL;
1928 char * tapedev = NULL;
1929 loadlabel_data data;
1930 data.cur_tapedev = &tapedev;
1931 data.searchlabel = cur_volume->label;
1933 changer_find(&data, scan_init, loadlabel_slot,
1935 device = conditional_device_open(tapedev, prompt_out,
1942 device = manual_find_tape(&cur_tapedev, cur_volume, prompt_out,
1943 prompt_in, flags, features);
1949 g_fprintf(stderr, "Scanning volume %s (slot %s)\n",
1950 device->volume_label,
1953 g_fprintf(stderr, "Scanning volume %s\n",
1954 device->volume_label);
1957 if (!search_a_tape(device, prompt_out, flags, features,
1958 cur_volume, dumpspecs, &seentapes,
1959 &first_restored_file, 0, logstream)) {
1960 g_object_unref(device);
1963 g_object_unref(device);
1967 free_seen_tapes(seentapes);
1970 /* This function works when we are operating without a tapelist
1971 (regardless of whether or not we have a changer). This only happens
1972 when we are using amfetchdump without dump logs, but in the future
1973 may include amrestore as well. The philosophy is to keep loading
1974 tapes until we run out. */
1976 restore_without_tapelist(FILE * prompt_out,
1979 rst_flags_t * flags,
1980 am_feature_t * features,
1982 /* -1 if no changer. */
1986 seentapes_t * seentapes;
1988 dumpfile_t first_restored_file;
1990 fh_init(&first_restored_file);
1992 /* This loop also aborts if we run out of manual tapes, or
1993 encounter a changer error. */
1995 Device * device = NULL;
1996 if (slot_count > 0) {
1997 while (cur_slot < slot_count && device == NULL) {
1999 changer_loadslot("next", &curslot, &cur_tapedev);
2000 device = conditional_device_open(cur_tapedev, prompt_out,
2003 amfree(cur_tapedev);
2006 if (cur_slot >= slot_count)
2009 device = manual_find_tape(&cur_tapedev, NULL, prompt_out,
2010 prompt_in, flags, features);
2016 g_fprintf(stderr, "Scanning %s (slot %s)\n", device->volume_label,
2019 if (!search_a_tape(device, prompt_out, flags, features,
2020 NULL, dumpspecs, &seentapes, &first_restored_file,
2021 tape_count, logstream)) {
2022 g_object_unref(device);
2025 g_object_unref(device);
2029 free_seen_tapes(seentapes);
2033 * Take a pattern of dumps and restore it blind, a la amrestore. In addition,
2034 * be smart enough to change tapes and continue with minimal operator
2035 * intervention, and write out a record of what was found on tapes in the
2036 * the regular logging format. Can take a tapelist with a specific set of
2037 * tapes to search (rather than "everything I can find"), which in turn can
2038 * optionally list specific files to restore.
2045 tapelist_t * tapelist,
2047 rst_flags_t * flags,
2048 am_feature_t * their_features)
2052 FILE *logstream = NULL;
2053 tapelist_t *desired_tape = NULL;
2054 struct sigaction act, oact;
2058 if(!prompt_out) prompt_out = stderr;
2060 /* Don't die when child closes pipe */
2061 signal(SIGPIPE, SIG_IGN);
2063 /* catch SIGINT with something that'll flush unmerged splits */
2064 act.sa_handler = handle_sigint;
2065 sigemptyset(&act.sa_mask);
2067 if(sigaction(SIGINT, &act, &oact) != 0){
2068 error(_("error setting SIGINT handler: %s"), strerror(errno));
2071 if(flags->delay_assemble || flags->inline_assemble) exitassemble = 1;
2072 else exitassemble = 0;
2074 /* if given a log file, print an inventory of stuff found */
2075 if(flags->inventory_log) {
2076 if(!strcmp(flags->inventory_log, "-")) logstream = stdout;
2077 else if((logstream = fopen(flags->inventory_log, "w+")) == NULL) {
2078 error(_("Couldn't open log file %s for writing: %s"),
2079 flags->inventory_log, strerror(errno));
2084 /* Suss what tape device we're using, whether there's a changer, etc. */
2086 use_changer = changer_init();
2090 if (flags->alt_tapedev) {
2091 cur_tapedev = stralloc(flags->alt_tapedev);
2092 } else if(!cur_tapedev) {
2093 cur_tapedev = getconf_str(CNF_TAPEDEV);
2094 if (cur_tapedev == NULL) {
2095 error(_("No tapedev specified"));
2098 /* XXX oughta complain if no config is loaded */
2099 g_fprintf(stderr, _("%s: Using tapedev %s\n"), get_pname(), cur_tapedev);
2101 else{ /* good, the changer works, see what it can do */
2103 changer_info(&slots, &curslot, &backwards);
2106 if (tapelist && !flags->amidxtaped) {
2107 print_expected_tape_list(prompt_out, prompt_in, tapelist, flags);
2109 desired_tape = tapelist;
2111 if (use_changer) { /* load current slot */
2114 changer_loadslot("current", &curslot, &cur_tapedev);
2118 * If we're not given a tapelist, iterate over everything our changer can
2119 * find. If there's no changer, we'll prompt to be handfed tapes.
2121 * If we *are* given a tapelist, restore from those tapes in the order in
2122 * which they're listed. Unless the changer (if we have one) can't go
2123 * backwards, in which case check every tape we see and restore from it if
2126 * (obnoxious, isn't this?)
2130 restore_from_tapelist(prompt_out, prompt_in, tapelist, dumpspecs,
2131 flags, their_features, cur_tapedev, use_changer,
2134 restore_without_tapelist(prompt_out, prompt_in, dumpspecs, flags,
2135 their_features, cur_tapedev,
2136 (use_changer ? slots : -1),
2140 if(logstream && logstream != stderr && logstream != stdout){
2143 if(flags->delay_assemble || flags->inline_assemble){
2144 flush_open_outputs(1, NULL);
2146 else flush_open_outputs(0, NULL);
2150 * Create a new, clean set of restore flags with some sane default values.
2155 rst_flags_t *flags = alloc(SIZEOF(rst_flags_t));
2157 memset(flags, 0, SIZEOF(rst_flags_t));
2160 flags->comp_type = COMPRESS_FAST_OPT;
2161 flags->inline_assemble = 1;
2162 flags->pipe_to_fd = -1;
2163 flags->check_labels = 1;
2169 * Make sure the set of restore options given is sane. Print errors for
2170 * things that're odd, and return -1 for fatal errors.
2174 rst_flags_t * flags)
2178 if(!flags) return(-1);
2180 if(flags->compress && flags->leave_comp){
2181 g_fprintf(stderr, _("Cannot specify 'compress output' and 'leave compression alone' together\n"));
2185 if(flags->restore_dir != NULL){
2186 struct stat statinfo;
2188 if(flags->pipe_to_fd != -1){
2189 g_fprintf(stderr, _("Specifying output directory and piping output are mutually exclusive\n"));
2192 if(stat(flags->restore_dir, &statinfo) < 0){
2193 g_fprintf(stderr, _("Cannot stat restore target dir '%s': %s\n"),
2194 flags->restore_dir, strerror(errno));
2197 if((statinfo.st_mode & S_IFMT) != S_IFDIR){
2198 g_fprintf(stderr, _("'%s' is not a directory\n"), flags->restore_dir);
2203 if((flags->pipe_to_fd != -1 || flags->compress) &&
2204 (flags->delay_assemble || !flags->inline_assemble)){
2205 g_fprintf(stderr, _("Split dumps *must* be automatically reassembled when piping output or compressing/uncompressing\n"));
2209 if(flags->delay_assemble && flags->inline_assemble){
2210 g_fprintf(stderr, _("Inline split assembling and delayed assembling are mutually exclusive\n"));
2218 * Clean up after a rst_flags_t
2222 rst_flags_t * flags)
2226 amfree(flags->restore_dir);
2227 amfree(flags->alt_tapedev);
2228 amfree(flags->inventory_log);
2234 printf_arglist_function3(
2237 rst_flags_t *, flags,
2238 am_feature_t *, their_features,
2242 char linebuf[STR_SIZE];
2244 arglist_start(argp, format);
2245 g_vsnprintf(linebuf, SIZEOF(linebuf)-1, format, argp);
2248 g_fprintf(stderr,"%s\n", linebuf);
2249 if (flags->amidxtaped && their_features &&
2250 am_has_feature(their_features, fe_amrecover_message)) {
2251 g_fprintf(prompt_out, "MESSAGE %s\r\n", linebuf);