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,v 1.28 2006/03/14 13:12:01 martinea Exp $
29 * retrieves files from an amanda tape
39 #include "fileheader.h"
44 /* stuff we're stuck having global */
45 static long blocksize = -1;
46 static char *cur_tapedev = NULL;
47 static char *searchlabel = NULL;
49 static int exitassemble = 0;
50 static int tapefd, nslots;
52 char *rst_conf_logdir = NULL;
53 char *rst_conf_logfile = NULL;
56 typedef struct open_output_s {
57 struct open_output_s *next;
65 typedef struct dumplist_s {
66 struct dumplist_s *next;
70 static open_output_t *open_outputs = NULL;
71 static dumplist_t *alldumps_list = NULL;
73 static ssize_t get_block P((int tapefd, char *buffer, int isafile));
74 static void append_file_to_fd P((char *filename, int fd));
75 static int headers_equal P((dumpfile_t *file1, dumpfile_t *file2, int ignore_partnums));
76 static int already_have_dump P((dumpfile_t *file));
80 static void handle_sigint(sig)
83 * We might want to flush any open dumps and unmerged splits before exiting
84 * on SIGINT, so do so.
87 flush_open_outputs(exitassemble, NULL);
88 if(rst_conf_logfile) unlink(rst_conf_logfile);
94 rst_conf_logdir = getconf_str(CNF_LOGDIR);
95 if (*rst_conf_logdir == '/') {
96 rst_conf_logdir = stralloc(rst_conf_logdir);
98 rst_conf_logdir = stralloc2(config_dir, rst_conf_logdir);
100 rst_conf_logfile = vstralloc(rst_conf_logdir, "/log", NULL);
101 if (access(rst_conf_logfile, F_OK) == 0) {
102 error("%s exists: amdump or amflush is already running, or you must run amcleanup", rst_conf_logfile);
104 log_add(L_INFO, get_pname());
109 * Return 1 if the two fileheaders match in name, disk, type, split chunk part
110 * number, and datestamp, and 0 if not. The part number can be optionally
113 int headers_equal (file1, file2, ignore_partnums)
114 dumpfile_t *file1, *file2;
117 if(!file1 || !file2) return(0);
119 if(file1->dumplevel == file2->dumplevel &&
120 file1->type == file2->type &&
121 !strcmp(file1->datestamp, file2->datestamp) &&
122 !strcmp(file1->name, file2->name) &&
123 !strcmp(file1->disk, file2->disk) &&
124 (ignore_partnums || file1->partnum == file2->partnum)){
132 * See whether we're already pulled an exact copy of the given file (chunk
133 * number and all). Returns 0 if not, 1 if so.
135 int already_have_dump(file)
138 dumplist_t *fileentry = NULL;
141 for(fileentry=alldumps_list;fileentry;fileentry=fileentry->next){
142 if(headers_equal(file, fileentry->file, 0)) return(1);
148 * Open the named file and append its contents to the (hopefully open) file
149 * descriptor supplies.
151 static void append_file_to_fd(filename, fd)
161 blocksize = DISK_BLOCK_BYTES;
162 buffer = alloc(blocksize);
164 if((tapefd = open(filename, O_RDONLY)) == -1) {
165 error("can't open %s: %s", filename, strerror(errno));
170 bytes_read = get_block(tapefd, buffer, 1); /* same as isafile = 1 */
172 error("read error: %s", strerror(errno));
179 s = fullwrite(fd, buffer, bytes_read);
180 if (s < bytes_read) {
181 fprintf(stderr,"Error %d (%s) offset " OFF_T_FMT "+" AM64_FMT ", wrote " AM64_FMT "\n",
182 errno, strerror(errno), wc, (am64_t)bytes_read, (am64_t)s);
184 if((errno == EPIPE) || (errno == ECONNRESET)) {
185 error("%s: pipe reader has quit in middle of file.\n",
189 error("restore: write error = %s", strerror(errno));
192 error("Short write: wrote %d bytes expected %d\n", s, bytes_read);
203 * Tape changer support routines, stolen brazenly from amtape
206 scan_init(ud, rc, ns, bk, s)
211 error("could not get changer info: %s", changer_resultstr);
218 int loadlabel_slot(ud, rc, slotstr, device)
225 char *datestamp = NULL;
230 error("could not load slot %s: %s", slotstr, changer_resultstr);
232 fprintf(stderr, "%s: slot %s: %s\n",
233 get_pname(), slotstr, changer_resultstr);
234 else if((errstr = tape_rdlabel(device, &datestamp, &label)) != NULL)
235 fprintf(stderr, "%s: slot %s: %s\n", get_pname(), slotstr, errstr);
237 fprintf(stderr, "%s: slot %s: date %-8s label %s",
238 get_pname(), slotstr, datestamp, label);
239 if(strcmp(label, FAKE_LABEL) != 0
240 && strcmp(label, searchlabel) != 0)
241 fprintf(stderr, " (wrong tape)\n");
243 fprintf(stderr, " (exact label match)\n");
244 if((errstr = tape_rewind(device)) != NULL) {
246 "%s: could not rewind %s: %s",
247 get_pname(), device, errstr);
251 curslot = stralloc(slotstr);
255 cur_tapedev = stralloc(device);
262 if(cur_tapedev) amfree(cur_tapedev);
263 curslot = stralloc(slotstr);
264 if(!device) return(1);
265 cur_tapedev = stralloc(device);
271 /* non-local functions follow */
276 * Check whether we've read all of the preceding parts of a given split dump,
277 * generally used to see if we're done and can close the thing.
279 int have_all_parts (file, upto)
284 int *foundparts = NULL;
285 dumplist_t *fileentry = NULL;
287 if(!file || file->partnum < 1) return(0);
289 if(upto < 1) upto = file->totalparts;
291 foundparts = alloc(sizeof(int) * upto);
292 for(c = 0 ; c< upto; c++) foundparts[c] = 0;
294 for(fileentry=alldumps_list;fileentry; fileentry=fileentry->next){
295 dumpfile_t *cur_file = fileentry->file;
296 if(headers_equal(file, cur_file, 1)){
297 if(cur_file->partnum > upto){
302 foundparts[cur_file->partnum - 1] = 1;
306 for(c = 0 ; c< upto; c++){
318 * Free up the open filehandles and memory we were using to track in-progress
319 * dumpfiles (generally for split ones we're putting back together). If
320 * applicable, also find the ones that are continuations of one another and
321 * string them together. If given an optional file header argument, flush
322 * only that dump and do not flush/free any others.
324 void flush_open_outputs(reassemble, only_file)
326 dumpfile_t *only_file;
328 open_output_t *cur_out = NULL, *prev = NULL;
329 find_result_t *sorted_files = NULL;
330 amwait_t compress_status;
333 fprintf(stderr, "\n");
337 * Deal with any split dumps we've been working on, appending pieces
338 * that haven't yet been appended and closing filehandles we've been
342 find_result_t *cur_find_res = NULL;
343 int outfd = -1, lastpartnum = -1;
344 dumpfile_t *main_file = NULL;
345 cur_out = open_outputs;
347 /* stick the dumpfile_t's into a list find_result_t's so that we can
348 abuse existing sort functionality */
349 for(cur_out=open_outputs; cur_out; cur_out=cur_out->next){
350 find_result_t *cur_find_res = NULL;
351 dumpfile_t *cur_file = cur_out->file;
352 /* if we requested a particular file, do only that one */
353 if(only_file && !headers_equal(cur_file, only_file, 1)){
356 cur_find_res = alloc(sizeof(find_result_t));
357 memset(cur_find_res, '\0', sizeof(find_result_t));
358 cur_find_res->datestamp = atoi(cur_file->datestamp);
359 cur_find_res->hostname = stralloc(cur_file->name);
360 cur_find_res->diskname = stralloc(cur_file->disk);
361 cur_find_res->level = cur_file->dumplevel;
362 if(cur_file->partnum < 1) cur_find_res->partnum = stralloc("--");
364 char part_str[NUM_STR_SIZE];
365 snprintf(part_str, sizeof(part_str), "%d", cur_file->partnum);
366 cur_find_res->partnum = stralloc(part_str);
368 cur_find_res->user_ptr = (void*)cur_out;
370 cur_find_res->next = sorted_files;
371 sorted_files = cur_find_res;
373 sort_find_result("hkdlp", &sorted_files);
375 /* now we have an in-order list of the files we need to concatenate */
376 cur_find_res = sorted_files;
377 for(cur_find_res=sorted_files;
379 cur_find_res=cur_find_res->next){
380 dumpfile_t *cur_file = NULL;
381 cur_out = (open_output_t*)cur_find_res->user_ptr;
382 cur_file = cur_out->file;
384 /* if we requested a particular file, do only that one */
385 if(only_file && !headers_equal(cur_file, only_file, 1)){
389 if(cur_file->type == F_SPLIT_DUMPFILE) {
390 /* is it a continuation of one we've been writing? */
391 if(main_file && cur_file->partnum > lastpartnum &&
392 headers_equal(cur_file, main_file, 1)){
394 /* effectively changing filehandles */
395 aclose(cur_out->outfd);
396 cur_out->outfd = outfd;
398 fprintf(stderr, "Merging %s with %s\n",
399 make_filename(cur_file), make_filename(main_file));
400 append_file_to_fd(make_filename(cur_file), outfd);
401 if(unlink(make_filename(cur_file)) < 0){
402 fprintf(stderr, "Failed to unlink %s: %s\n",
403 make_filename(cur_file), strerror(errno));
408 if(outfd >= 0) aclose(outfd);
409 if(main_file) amfree(main_file);
410 main_file = alloc(sizeof(dumpfile_t));
411 memcpy(main_file, cur_file, sizeof(dumpfile_t));
412 outfd = cur_out->outfd;
414 if((outfd = open(make_filename(cur_file), O_RDWR|O_APPEND)) < 0){
415 error("Couldn't open %s for appending: %s\n",
416 make_filename(cur_file), strerror(errno));
420 lastpartnum = cur_file->partnum;
423 aclose(cur_out->outfd);
431 free_find_result(&sorted_files);
435 * Now that the split dump closure is done, free up resources we don't
438 for(cur_out=open_outputs; cur_out; cur_out=cur_out->next){
439 dumpfile_t *cur_file = NULL;
440 if(prev) amfree(prev);
441 cur_file = cur_out->file;
442 /* if we requested a particular file, do only that one */
443 if(only_file && !headers_equal(cur_file, only_file, 1)){
447 aclose(cur_out->outfd);
450 if(cur_out->comp_enc_pid > 0){
451 waitpid(cur_out->comp_enc_pid, &compress_status, 0);
453 amfree(cur_out->file);
461 * Turn a fileheader into a string suited for use on the filesystem.
463 char *make_filename(file)
466 char number[NUM_STR_SIZE];
467 char part[NUM_STR_SIZE];
468 char totalparts[NUM_STR_SIZE];
474 snprintf(number, sizeof(number), "%d", file->dumplevel);
475 snprintf(part, sizeof(part), "%d", file->partnum);
477 if(file->totalparts < 0){
478 snprintf(totalparts, sizeof(totalparts), "UNKNOWN");
481 snprintf(totalparts, sizeof(totalparts), "%d", file->totalparts);
483 padlen = strlen(totalparts) + 1 - strlen(part);
485 memset(pad, '0', padlen);
486 pad[padlen - 1] = '\0';
488 snprintf(part, sizeof(part), "%s%d", pad, file->partnum);
490 sfn = sanitise_filename(file->disk);
491 fn = vstralloc(file->name,
499 if(file->partnum > 0){
500 fn = vstralloc(fn, ".", part, NULL);
509 XXX Making this thing a lib functiong broke a lot of assumptions everywhere,
510 but I think I've found them all. Maybe. Damn globals all over the place.
512 static ssize_t get_block(tapefd, buffer, isafile)
517 return (fullread(tapefd, buffer, blocksize));
519 return(tapefd_read(tapefd, buffer, blocksize));
522 int disk_match(file, datestamp, hostname, diskname, level)
524 char *datestamp, *hostname, *diskname, *level;
526 * Returns 1 if the current dump file matches the hostname and diskname
527 * regular expressions given on the command line, 0 otherwise. As a
528 * special case, empty regexs are considered equivalent to ".*": they
532 char level_str[NUM_STR_SIZE];
533 snprintf(level_str, sizeof(level_str), "%d", file->dumplevel);
535 if(file->type != F_DUMPFILE && file->type != F_SPLIT_DUMPFILE) return 0;
537 if((*hostname == '\0' || match_host(hostname, file->name)) &&
538 (*diskname == '\0' || match_disk(diskname, file->disk)) &&
539 (*datestamp == '\0' || match_datestamp(datestamp, file->datestamp)) &&
540 (*level == '\0' || match_level(level, level_str)))
547 void read_file_header(file, tapefd, isafile, flags)
553 * Reads the first block of a tape file.
559 if(flags->blocksize > 0)
560 blocksize = flags->blocksize;
561 else if(blocksize == -1)
562 blocksize = DISK_BLOCK_BYTES;
563 buffer = alloc(blocksize);
565 bytes_read = get_block(tapefd, buffer, isafile);
567 error("error reading file header: %s", strerror(errno));
571 if(bytes_read < blocksize) {
572 if(bytes_read == 0) {
573 fprintf(stderr, "%s: missing file header block\n", get_pname());
575 fprintf(stderr, "%s: short file header block: " AM64_FMT " byte%s\n",
576 get_pname(), (am64_t)bytes_read, (bytes_read == 1) ? "" : "s");
578 file->type = F_UNKNOWN;
580 parse_file_header(buffer, file, bytes_read);
586 void drain_file(tapefd, flags)
594 blocksize = flags->blocksize;
595 else if(blocksize == -1)
596 blocksize = DISK_BLOCK_BYTES;
597 buffer = alloc(blocksize);
600 bytes_read = get_block(tapefd, buffer, 0);
602 error("drain read error: %s", strerror(errno));
604 } while (bytes_read > 0);
609 ssize_t restore(file, filename, tapefd, isafile, flags)
616 * Restore the current file from tape. Depending on the settings of
617 * the command line flags, the file might need to be compressed or
618 * uncompressed. If so, a pipe through compress or uncompress is set
619 * up. The final output usually goes to a file named host.disk.date.lev,
620 * but with the -p flag the output goes to stdout (and presumably is
626 int file_is_compressed;
627 int is_continuation = 0;
628 int check_for_aborted = 0;
629 char *tmp_filename = NULL, *final_filename = NULL;
630 struct stat statinfo;
631 open_output_t *myout = NULL, *oldout = NULL;
632 dumplist_t *tempdump = NULL, *fileentry = NULL;
634 int need_compress=0, need_uncompress=0, need_decrypt=0;
642 blocksize = flags->blocksize;
643 else if(blocksize == -1)
644 blocksize = DISK_BLOCK_BYTES;
646 if(already_have_dump(file)){
647 fprintf(stderr, " *** Duplicate file %s, one is probably an aborted write\n", make_filename(file));
648 check_for_aborted = 1;
651 /* store a shorthand record of this dump */
652 tempdump = alloc(sizeof(dumplist_t));
653 tempdump->file = alloc(sizeof(dumpfile_t));
654 tempdump->next = NULL;
655 memcpy(tempdump->file, file, sizeof(dumpfile_t));
658 * If we're appending chunked files to one another, and if this is a
659 * continuation of a file we just restored, and we've still got the
660 * output handle from that previous restore, we're golden. Phew.
662 if(flags->inline_assemble && file->type == F_SPLIT_DUMPFILE){
663 myout = open_outputs;
664 while(myout != NULL){
665 if(myout->file->type == F_SPLIT_DUMPFILE &&
666 headers_equal(file, myout->file, 1)){
667 if(file->partnum == myout->lastpartnum + 1){
674 if(myout != NULL) myout->lastpartnum = file->partnum;
675 else if(file->partnum != 1){
676 fprintf(stderr, "%s: Chunk out of order, will save to disk and append to output.\n", get_pname());
677 flags->pipe_to_fd = -1;
679 flags->leave_comp = 1;
682 myout = alloc(sizeof(open_output_t));
683 memset(myout, 0, sizeof(open_output_t));
687 myout = alloc(sizeof(open_output_t));
688 memset(myout, 0, sizeof(open_output_t));
692 if(is_continuation && flags->pipe_to_fd == -1){
693 fprintf(stderr, "%s: appending to %s\n", get_pname(),
694 make_filename(myout->file));
697 /* adjust compression flag */
698 file_is_compressed = file->compressed;
699 if(!flags->compress && file_is_compressed && !known_compress_type(file)) {
701 "%s: unknown compression suffix %s, can't uncompress\n",
702 get_pname(), file->comp_suffix);
706 /* set up final destination file */
708 if(is_continuation && myout != NULL) {
711 if(flags->pipe_to_fd != -1) {
712 dest = flags->pipe_to_fd; /* standard output */
714 char *filename_ext = NULL;
716 if(flags->compress) {
717 filename_ext = file_is_compressed ? file->comp_suffix
719 } else if(flags->raw) {
720 filename_ext = ".RAW";
724 filename_ext = stralloc2(filename, filename_ext);
725 tmp_filename = stralloc(filename_ext);
726 if(flags->restore_dir != NULL) {
727 char *tmpstr = vstralloc(flags->restore_dir, "/",
729 amfree(tmp_filename);
730 tmp_filename = tmpstr;
732 final_filename = stralloc(tmp_filename);
733 tmp_filename = newvstralloc(tmp_filename, ".tmp", NULL);
734 if((dest = creat(tmp_filename, CREAT_MODE)) < 0) {
735 error("could not create output file %s: %s",
736 tmp_filename, strerror(errno));
739 amfree(filename_ext);
746 * If -r or -h, write the header before compress or uncompress pipe.
747 * Only write DISK_BLOCK_BYTES, regardless of how much was read.
748 * This makes the output look like a holding disk image, and also
749 * makes it easier to remove the header (e.g. in amrecover) since
750 * it has a fixed size.
752 if(flags->raw || (flags->headers && !is_continuation)) {
757 if(flags->compress && !file_is_compressed) {
758 file->compressed = 1;
759 snprintf(file->uncompress_cmd, sizeof(file->uncompress_cmd),
760 " %s %s |", UNCOMPRESS_PATH,
761 #ifdef UNCOMPRESS_OPT
767 strncpy(file->comp_suffix,
769 sizeof(file->comp_suffix)-1);
770 file->comp_suffix[sizeof(file->comp_suffix)-1] = '\0';
773 memcpy(&tmp_hdr, file, sizeof(dumpfile_t));
775 /* remove CONT_FILENAME from header */
776 cont_filename = stralloc(file->cont_filename);
777 memset(file->cont_filename,'\0',sizeof(file->cont_filename));
778 file->blocksize = DISK_BLOCK_BYTES;
781 * Dumb down split file headers as well, so that older versions of
782 * things like amrecover won't gag on them.
784 if(file->type == F_SPLIT_DUMPFILE && flags->mask_splits){
785 file->type = F_DUMPFILE;
788 buffer = alloc(DISK_BLOCK_BYTES);
789 build_header(buffer, file, DISK_BLOCK_BYTES);
791 if((w = fullwrite(out, buffer, DISK_BLOCK_BYTES)) != DISK_BLOCK_BYTES) {
793 error("write error: %s", strerror(errno));
795 error("write error: %d instead of %d", w, DISK_BLOCK_BYTES);
799 /* add CONT_FILENAME to header */
801 // strncpy(file->cont_filename, cont_filename, sizeof(file->cont_filename));
803 amfree(cont_filename);
804 memcpy(file, &tmp_hdr, sizeof(dumpfile_t));
807 /* find out if compression or uncompression is needed here */
808 if(flags->compress && !file_is_compressed && !is_continuation
809 && !flags->leave_comp
810 && (flags->inline_assemble || file->type != F_SPLIT_DUMPFILE))
813 if(!flags->raw && !flags->compress && file_is_compressed
814 && !is_continuation && !flags->leave_comp && (flags->inline_assemble
815 || file->type != F_SPLIT_DUMPFILE))
818 if(!flags->raw && file->encrypted)
821 /* Setup pipes for decryption / compression / uncompression */
824 if (pipe(&pipes[stage].pipe[0]) < 0)
825 error("error [pipe[%d]: %s]", stage, strerror(errno));
829 if (need_compress || need_uncompress) {
830 if (pipe(&pipes[stage].pipe[0]) < 0)
831 error("error [pipe[%d]: %s]", stage, strerror(errno));
834 pipes[stage].pipe[0] = -1;
835 pipes[stage].pipe[1] = out;
839 /* decrypt first if it's encrypted and no -r */
841 switch(myout->comp_enc_pid = fork()) {
843 error("could not fork for decrypt: %s", strerror(errno));
845 aclose(pipes[stage].pipe[0]);
846 aclose(pipes[stage+1].pipe[1]);
850 if(dup2(pipes[stage].pipe[0], 0) == -1)
851 error("error decrypt stdin [dup2 %d %d: %s]", stage,
852 pipes[stage].pipe[0], strerror(errno));
854 if(dup2(pipes[stage+1].pipe[1], 1) == -1)
855 error("error decrypt stdout [dup2 %d %d: %s]", stage + 1,
856 pipes[stage+1].pipe[1], strerror(errno));
859 if (*file->srv_encrypt) {
860 (void) execlp(file->srv_encrypt, file->srv_encrypt,
861 file->srv_decrypt_opt, NULL);
862 error("could not exec %s: %s", file->srv_encrypt, strerror(errno));
863 } else if (*file->clnt_encrypt) {
864 (void) execlp(file->clnt_encrypt, file->clnt_encrypt,
865 file->clnt_decrypt_opt, NULL);
866 error("could not exec %s: %s", file->clnt_encrypt, strerror(errno));
873 * Insert a compress pipe
875 switch(myout->comp_enc_pid = fork()) {
876 case -1: error("could not fork for %s: %s",
877 COMPRESS_PATH, strerror(errno));
879 aclose(pipes[stage].pipe[0]);
880 aclose(pipes[stage+1].pipe[1]);
884 if(dup2(pipes[stage].pipe[0], 0) == -1)
885 error("error compress stdin [dup2 %d %d: %s]", stage,
886 pipes[stage].pipe[0], strerror(errno));
888 if(dup2(pipes[stage+1].pipe[1], 1) == -1)
889 error("error compress stdout [dup2 %d %d: %s]", stage + 1,
890 pipes[stage+1].pipe[1], strerror(errno));
892 if (*flags->comp_type == '\0') {
893 flags->comp_type = NULL;
897 (void) execlp(COMPRESS_PATH, COMPRESS_PATH, flags->comp_type, (char *)0);
898 error("could not exec %s: %s", COMPRESS_PATH, strerror(errno));
900 } else if(need_uncompress) {
902 * If not -r, -c, -l, and file is compressed, and split reassembly
903 * options are sane, insert uncompress pipe
907 * XXX for now we know that for the two compression types we
908 * understand, .Z and optionally .gz, UNCOMPRESS_PATH will take
909 * care of both. Later, we may need to reference a table of
910 * possible uncompress programs.
912 switch(myout->comp_enc_pid = fork()) {
914 error("could not fork for %s: %s",
915 UNCOMPRESS_PATH, strerror(errno));
917 aclose(pipes[stage].pipe[0]);
918 aclose(pipes[stage+1].pipe[1]);
922 if(dup2(pipes[stage].pipe[0], 0) == -1)
923 error("error uncompress stdin [dup2 %d %d: %s]", stage,
924 pipes[stage].pipe[0], strerror(errno));
926 if(dup2(pipes[stage+1].pipe[1], 1) == -1)
927 error("error uncompress stdout [dup2 %d %d: %s]", stage + 1,
928 pipes[stage+1].pipe[1], strerror(errno));
931 if (*file->srvcompprog) {
932 (void) execlp(file->srvcompprog, file->srvcompprog, "-d", NULL);
933 error("could not exec %s: %s", file->srvcompprog, strerror(errno));
934 } else if (*file->clntcompprog) {
935 (void) execlp(file->clntcompprog, file->clntcompprog, "-d", NULL);
936 error("could not exec %s: %s", file->clntcompprog, strerror(errno));
938 (void) execlp(UNCOMPRESS_PATH, UNCOMPRESS_PATH,
939 #ifdef UNCOMPRESS_OPT
943 error("could not exec %s: %s", UNCOMPRESS_PATH, strerror(errno));
948 /* copy the rest of the file from tape to the output */
949 if(flags->blocksize > 0)
950 blocksize = flags->blocksize;
951 else if(blocksize == -1)
952 blocksize = DISK_BLOCK_BYTES;
953 buffer = alloc(blocksize);
956 bytes_read = get_block(tapefd, buffer, isafile);
958 error("restore read error: %s", strerror(errno));
963 if((s = fullwrite(pipes[0].pipe[1], buffer, bytes_read)) < 0) {
964 if ((errno == EPIPE) || (errno == ECONNRESET)) {
966 * reading program has ended early
967 * e.g: bzip2 closes pipe when it
968 * trailing garbage after EOF
972 perror("restore: write error");
978 * See if we need to switch to the next file in a holding restore
980 if(file->cont_filename[0] == '\0') {
981 break; /* no more files */
984 if((tapefd = open(file->cont_filename, O_RDONLY)) == -1) {
985 char *cont_filename = strrchr(file->cont_filename,'/');
988 if((tapefd = open(cont_filename,O_RDONLY)) == -1) {
989 error("can't open %s: %s", file->cont_filename,
993 fprintf(stderr, "cannot open %s: %s\n",
994 file->cont_filename, strerror(errno));
995 fprintf(stderr, "using %s\n",
1000 error("can't open %s: %s", file->cont_filename,
1004 read_file_header(file, tapefd, isafile, flags);
1005 if(file->type != F_DUMPFILE && file->type != F_CONT_DUMPFILE
1006 && file->type != F_SPLIT_DUMPFILE) {
1007 fprintf(stderr, "unexpected header type: ");
1008 print_header(stderr, file);
1012 } while (bytes_read > 0);
1016 if(!flags->inline_assemble) {
1020 if(!is_continuation){
1021 if(tmp_filename && stat(tmp_filename, &statinfo) < 0){
1022 error("Can't stat the file I just created (%s)!\n", tmp_filename);
1024 if(check_for_aborted){
1025 char *old_dump = final_filename;
1026 struct stat oldstat;
1027 if(stat(old_dump, &oldstat) >= 0){
1028 if(oldstat.st_size <= statinfo.st_size){
1029 dumplist_t *prev_fileentry = NULL;
1030 open_output_t *prev_out = NULL;
1031 fprintf(stderr, "Newer restore is larger, using that\n");
1032 /* nuke the old dump's entry in alldump_list */
1033 for(fileentry=alldumps_list;
1035 fileentry=fileentry->next){
1036 if(headers_equal(file, fileentry->file, 0)){
1038 prev_fileentry->next = fileentry->next;
1041 alldumps_list = fileentry->next;
1046 prev_fileentry = fileentry;
1048 myout = open_outputs;
1049 while(myout != NULL){
1050 if(headers_equal(file, myout->file, 0)){
1051 if(myout->outfd >= 0)
1052 aclose(myout->outfd);
1054 prev_out->next = myout->next;
1056 else open_outputs = myout->next;
1061 myout = myout->next;
1065 fprintf(stderr, "Older restore is larger, using that\n");
1066 unlink(tmp_filename);
1067 amfree(tempdump->file);
1069 amfree(tmp_filename);
1070 amfree(final_filename);
1071 return (bytes_read);
1075 if(tmp_filename && final_filename &&
1076 rename(tmp_filename, final_filename) < 0){
1077 error("Can't rename %s to %s: %s\n", tmp_filename, final_filename,
1081 if(tmp_filename) amfree(tmp_filename);
1082 if(final_filename) amfree(final_filename);
1086 * actually insert tracking data for this file into our various
1087 * structures (we waited in case we needed to give up)
1089 if(!is_continuation){
1090 oldout = alloc(sizeof(open_output_t));
1091 oldout->file = alloc(sizeof(dumpfile_t));
1092 memcpy(oldout->file, file, sizeof(dumpfile_t));
1093 if(flags->inline_assemble) oldout->outfd = pipes[0].pipe[1];
1094 else oldout->outfd = -1;
1095 oldout->comp_enc_pid = -1;
1096 oldout->lastpartnum = file->partnum;
1097 oldout->next = open_outputs;
1098 open_outputs = oldout;
1101 for(fileentry=alldumps_list;fileentry->next;fileentry=fileentry->next);
1102 fileentry->next = tempdump;
1105 alldumps_list = tempdump;
1108 return (bytes_read);
1114 * Take a pattern of dumps and restore it blind, a la amrestore. In addition,
1115 * be smart enough to change tapes and continue with minimal operator
1116 * intervention, and write out a record of what was found on tapes in the
1117 * the regular logging format. Can take a tapelist with a specific set of
1118 * tapes to search (rather than "everything I can find"), which in turn can
1119 * optionally list specific files to restore.
1121 void search_tapes(prompt_out, use_changer, tapelist, match_list, flags, their_features)
1124 tapelist_t *tapelist;
1125 match_list_t *match_list;
1127 am_feature_t *their_features;
1129 struct stat stat_tape;
1131 int have_changer = 1;
1135 FILE *logstream = NULL;
1136 dumplist_t *fileentry = NULL;
1137 tapelist_t *desired_tape = NULL;
1138 struct sigaction act, oact;
1140 ssize_t bytes_read = 0;
1143 struct seentapes *next;
1147 } *seentapes = NULL;
1149 if(!prompt_out) prompt_out = stderr;
1151 if(flags->blocksize) blocksize = flags->blocksize;
1152 else if(blocksize == -1) blocksize = DISK_BLOCK_BYTES;
1154 /* Don't die when child closes pipe */
1155 signal(SIGPIPE, SIG_IGN);
1157 /* catch SIGINT with something that'll flush unmerged splits */
1158 act.sa_handler = handle_sigint;
1159 sigemptyset(&act.sa_mask);
1161 if(sigaction(SIGINT, &act, &oact) != 0){
1162 error("error setting SIGINT handler: %s", strerror(errno));
1164 if(flags->delay_assemble || flags->inline_assemble) exitassemble = 1;
1165 else exitassemble = 0;
1167 /* if given a log file, print an inventory of stuff found */
1168 if(flags->inventory_log){
1169 if(!strcmp(flags->inventory_log, "-")) logstream = stdout;
1170 else if((logstream = fopen(flags->inventory_log, "w+")) == NULL){
1171 error("Couldn't open log file %s for writing: %s\n",
1172 flags->inventory_log, strerror(errno));
1176 /* Suss what tape device we're using, whether there's a changer, etc. */
1177 if(!use_changer || (have_changer = changer_init()) == 0) {
1178 if(flags->alt_tapedev) cur_tapedev = stralloc(flags->alt_tapedev);
1179 else if(!cur_tapedev) cur_tapedev = getconf_str(CNF_TAPEDEV);
1180 /* XXX oughta complain if no config is loaded */
1181 fprintf(stderr, "%s: Using tapedev %s\n", get_pname(), cur_tapedev);
1183 } else if (have_changer != 1) {
1184 error("changer initialization failed: %s", strerror(errno));
1186 else{ /* good, the changer works, see what it can do */
1187 changer_info(&slots, &curslot, &backwards);
1190 if(tapelist && !flags->amidxtaped){
1191 slots = num_entries(tapelist);
1193 Spit out a list of expected tapes, so people with manual changers know
1196 fprintf(prompt_out, "The following tapes are needed:");
1197 for(desired_tape = tapelist;
1198 desired_tape != NULL;
1199 desired_tape = desired_tape->next){
1200 fprintf(prompt_out, " %s", desired_tape->label);
1202 fprintf(prompt_out, "\n");
1204 if(flags->wait_tape_prompt){
1206 fprintf(prompt_out,"Press enter when ready\n");
1208 input = agets(stdin);
1210 fprintf(prompt_out, "\n");
1214 desired_tape = tapelist;
1217 * If we're not given a tapelist, iterate over everything our changer can
1218 * find. If there's no changer, we'll prompt to be handfed tapes.
1220 * If we *are* given a tapelist, restore from those tapes in the order in
1221 * which they're listed. Unless the changer (if we have one) can't go
1222 * backwards, in which case check every tape we see and restore from it if
1225 * (obnoxious, isn't this?)
1228 curslot = stralloc("<none>");
1229 while(desired_tape || ((slot_num < slots || !have_changer) && !tapelist)){
1231 struct seentapes *tape_seen = NULL;
1232 dumpfile_t file, tapestart, prev_rst_file;
1233 char *logline = NULL;
1234 int tapefile_idx = -1;
1239 * Deal with instances where we're being asked to restore from a file
1241 if(desired_tape && desired_tape->isafile){
1243 if ((tapefd = open(desired_tape->label, 0)) == -1){
1244 fprintf(stderr, "could not open %s: %s\n",
1245 desired_tape->label, strerror(errno));
1248 fprintf(stderr, "Reading %s to fd %d\n", desired_tape->label, tapefd);
1250 read_file_header(&file, tapefd, 1, flags);
1251 label = stralloc(desired_tape->label);
1254 * Make sure we can read whatever tape is loaded, then grab the label.
1256 else if(cur_tapedev && newtape){
1257 if(tape_stat(cur_tapedev,&stat_tape)!=0) {
1258 error("could not stat %s: %s", cur_tapedev, strerror(errno));
1261 if((err = tape_rewind(cur_tapedev)) != NULL) {
1262 fprintf(stderr, "Could not rewind device '%s': %s\n",
1266 if((tapefd = tape_open(cur_tapedev, 0)) < 0){
1267 fprintf(stderr, "could not open tape device %s: %s\n",
1268 cur_tapedev, strerror(errno));
1273 read_file_header(&file, tapefd, 0, flags);
1274 if (file.type != F_TAPESTART) {
1275 fprintf(stderr, "Not an amanda tape\n");
1276 tapefd_close(tapefd);
1279 memcpy(&tapestart, &file, sizeof(dumpfile_t));
1280 label = stralloc(file.name);
1283 } else if(newtape) {
1284 wrongtape = 1; /* nothing loaded */
1289 * Skip this tape if we did it already. Note that this would let
1290 * duplicate labels through, so long as they were in the same slot.
1291 * I'm over it, are you?
1293 if(label && newtape && !isafile && !wrongtape){
1294 for(tape_seen = seentapes; tape_seen; tape_seen = tape_seen->next){
1295 if(!strcmp(tape_seen->label, label) &&
1296 !strcmp(tape_seen->slotstr, curslot)){
1297 fprintf(stderr, "Saw repeat tape %s in slot %s\n", label, curslot);
1306 * See if we've got the tape we were looking for, if we were looking
1307 * for something specific.
1309 if((desired_tape || !cur_tapedev) && newtape && !isafile && !wrongtape){
1310 if(!label || (flags->check_labels &&
1311 desired_tape && strcmp(label, desired_tape->label) != 0)){
1313 fprintf(stderr, "Label mismatch, got %s and expected %s\n", label, desired_tape->label);
1314 if(have_changer && !backwards){
1315 fprintf(stderr, "Changer can't go backwards, restoring anyway\n");
1319 else fprintf(stderr, "No tape device initialized yet\n");
1325 * If we have an incorrect tape loaded, go try to find the right one
1326 * (or just see what the next available one is).
1328 if((wrongtape || !newtape) && !isafile){
1330 tapefd_close(tapefd);
1332 fprintf(stderr,"Looking for tape %s...\n", desired_tape->label);
1334 searchlabel = desired_tape->label;
1335 changer_find(NULL, scan_init, loadlabel_slot, desired_tape->label);
1338 changer_loadslot("next", &curslot, &cur_tapedev);
1340 while(have_changer && !cur_tapedev){
1341 fprintf(stderr, "Changer did not set the tape device (slot empty or changer misconfigured?)\n");
1342 changer_loadslot("next", &curslot, &cur_tapedev);
1348 if (!flags->amidxtaped) {
1350 "Insert tape labeled %s in device %s "
1351 "and press return\n",
1352 desired_tape->label, cur_tapedev);
1354 input = agets(stdin);
1356 } else if (their_features &&
1357 am_has_feature(their_features,
1358 fe_amrecover_FEEDME)) {
1359 fprintf(prompt_out, "FEEDME %s\n",
1360 desired_tape->label);
1362 input = agets(stdin); /* Strips \n but not \r */
1363 if (strcmp("OK\r", input) != 0) {
1364 error("Got bad response from amrecover: %s",
1369 error("Client doesn't support fe_amrecover_FEEDME");
1374 assert(!flags->amidxtaped);
1377 changer_loadslot("first", &curslot, &cur_tapedev);
1379 changer_loadslot("next", &curslot, &cur_tapedev);
1380 if(have_changer && !cur_tapedev)
1381 error("Changer did not set the tape device, probably misconfigured");
1384 /* XXX need a condition for ending processing? */
1386 fprintf(prompt_out,"Insert a tape to search and press enter, ^D to finish reading tapes\n");
1388 if((input = agets(stdin)) == NULL) break;
1402 fprintf(stderr, "Scanning %s (slot %s)\n", label, curslot);
1406 tape_seen = alloc(sizeof(struct seentapes));
1407 memset(tape_seen, '\0', sizeof(struct seentapes));
1409 tape_seen->label = label;
1410 tape_seen->slotstr = stralloc(curslot);
1411 tape_seen->next = seentapes;
1412 tape_seen->files = NULL;
1413 seentapes = tape_seen;
1416 * Start slogging through the tape itself. If our tapelist (if we
1417 * have one) contains a list of files to restore, obey that instead
1418 * of checking for matching headers on all files.
1421 if(desired_tape && desired_tape->numfiles > 0) tapefile_idx = 0;
1423 /* if we know where we're going, fastforward there */
1424 if(flags->fsf && !isafile){
1427 /* If we have a tapelist entry, filenums will be store there */
1428 if(tapefile_idx >= 0)
1429 fsf_by = desired_tape->files[tapefile_idx];
1431 * older semantics assume we're restoring one file, with the fsf
1432 * flag being the filenum on tape for said file
1434 else fsf_by = flags->fsf;
1437 if(tapefd_rewind(tapefd) < 0) {
1438 error("Could not rewind device %s: %s", cur_tapedev,
1442 if(tapefd_fsf(tapefd, fsf_by) < 0) {
1443 error("Could not fsf device %s by %d: %s", cur_tapedev, fsf_by,
1449 read_file_header(&file, tapefd, isafile, flags);
1453 while((file.type == F_TAPESTART || file.type == F_DUMPFILE ||
1454 file.type == F_SPLIT_DUMPFILE) &&
1455 (tapefile_idx < 0 || tapefile_idx < desired_tape->numfiles)) {
1456 int found_match = 0;
1458 dumplist_t *tempdump = NULL;
1460 /* store record of this dump for inventorying purposes */
1461 tempdump = alloc(sizeof(dumplist_t));
1462 tempdump->file = alloc(sizeof(dumpfile_t));
1463 tempdump->next = NULL;
1464 memcpy(tempdump->file, &file, sizeof(dumpfile_t));
1465 if(tape_seen->files){
1466 for(fileentry=tape_seen->files;
1468 fileentry=fileentry->next);
1469 fileentry->next = tempdump;
1471 else tape_seen->files = tempdump;
1473 /* see if we need to restore the thing */
1474 if(isafile) found_match = 1;
1475 else if(tapefile_idx >= 0){ /* do it by explicit file #s */
1476 if(filenum == desired_tape->files[tapefile_idx]){
1481 else{ /* search and match headers */
1482 for(me = match_list; me; me = me->next) {
1483 if(disk_match(&file, me->datestamp, me->hostname,
1484 me->diskname, me->level) != 0){
1492 char *filename = make_filename(&file);
1493 fprintf(stderr, "%s: %3d: restoring ", get_pname(), filenum);
1494 print_header(stderr, &file);
1495 bytes_read = restore(&file, filename, tapefd, isafile, flags);
1500 /* advance to the next file, fast-forwarding where reasonable */
1501 if(bytes_read == 0 && !isafile) {
1502 tapefd_close(tapefd);
1503 if((tapefd = tape_open(cur_tapedev, 0)) < 0) {
1504 error("could not open %s: %s",
1505 cur_tapedev, strerror(errno));
1507 } else if(!isafile){
1508 /* cheat and jump ahead to where we're going if we can */
1509 if (!found_match && flags->fsf) {
1510 drain_file(tapefd, flags);
1512 } else if(tapefile_idx >= 0 &&
1513 tapefile_idx < desired_tape->numfiles &&
1515 int fsf_by = desired_tape->files[tapefile_idx] - filenum;
1517 if(tapefd_fsf(tapefd, fsf_by) < 0) {
1518 error("Could not fsf device %s by %d: %s", cur_tapedev, fsf_by,
1521 else filenum = desired_tape->files[tapefile_idx];
1523 } else if (!found_match && flags->fsf) {
1524 /* ... or fsf by 1, whatever */
1525 if(tapefd_fsf(tapefd, 1) < 0) {
1526 error("could not fsf device %s: %s",
1527 cur_tapedev, strerror(errno));
1535 memcpy(&prev_rst_file, &file, sizeof(dumpfile_t));
1540 read_file_header(&file, tapefd, isafile, flags);
1542 /* only restore a single dump, if piping to stdout */
1543 if(!headers_equal(&prev_rst_file, &file, 1) &&
1544 flags->pipe_to_fd == fileno(stdout)) break;
1545 } /* while we keep seeing headers */
1548 if(bytes_read == 0) {
1549 /* XXX is this dain-bramaged? */
1551 if((tapefd = tape_open(cur_tapedev, 0)) < 0) {
1552 error("could not open %s: %s",
1553 cur_tapedev, strerror(errno));
1556 if(tapefd_fsf(tapefd, 1) < 0) {
1557 error("could not fsf %s: %s",
1558 cur_tapedev, strerror(errno));
1562 tapefd_close(tapefd);
1564 /* spit out our accumulated list of dumps, if we're inventorying */
1566 logline = log_genstring(L_START, "taper",
1567 "datestamp %s label %s tape %d",
1568 tapestart.datestamp, tapestart.name, slot_num);
1569 fprintf(logstream, logline);
1570 for(fileentry=tape_seen->files; fileentry; fileentry=fileentry->next){
1572 switch(fileentry->file->type){
1574 logline = log_genstring(L_SUCCESS, "taper",
1575 "%s %s %s %d [faked log entry]",
1576 fileentry->file->name,
1577 fileentry->file->disk,
1578 fileentry->file->datestamp,
1579 fileentry->file->dumplevel);
1581 case F_SPLIT_DUMPFILE:
1582 logline = log_genstring(L_CHUNK, "taper",
1583 "%s %s %s %d %d [faked log entry]",
1584 fileentry->file->name,
1585 fileentry->file->disk,
1586 fileentry->file->datestamp,
1587 fileentry->file->partnum,
1588 fileentry->file->dumplevel);
1594 fprintf(logstream, logline);
1600 fprintf(stderr, "%s: Search of %s complete\n",
1601 get_pname(), tape_seen->label);
1602 if(desired_tape) desired_tape = desired_tape->next;
1604 /* only restore a single dump, if piping to stdout */
1605 if(!headers_equal(&prev_rst_file, &file, 1) &&
1606 flags->pipe_to_fd == fileno(stdout)) break;
1609 while(seentapes != NULL) {
1610 struct seentapes *tape_seen = seentapes;
1611 seentapes = seentapes->next;
1612 while(tape_seen->files != NULL) {
1613 dumplist_t *temp_dump = tape_seen->files;
1614 tape_seen->files = temp_dump->next;
1615 amfree(temp_dump->file);
1618 amfree(tape_seen->label);
1619 amfree(tape_seen->slotstr);
1624 if(logstream && logstream != stderr && logstream != stdout){
1627 if(flags->delay_assemble || flags->inline_assemble){
1628 flush_open_outputs(1, NULL);
1630 else flush_open_outputs(0, NULL);
1634 * Create a new, clean set of restore flags with some sane default values.
1636 rst_flags_t *new_rst_flags()
1638 rst_flags_t *flags = alloc(sizeof(rst_flags_t));
1640 memset(flags, 0, sizeof(rst_flags_t));
1643 flags->comp_type = COMPRESS_FAST_OPT;
1644 flags->inline_assemble = 1;
1645 flags->pipe_to_fd = -1;
1646 flags->check_labels = 1;
1652 * Make sure the set of restore options given is sane. Print errors for
1653 * things that're odd, and return -1 for fatal errors.
1655 int check_rst_flags(rst_flags_t *flags)
1659 if(!flags) return(-1);
1661 if(flags->compress && flags->leave_comp){
1662 fprintf(stderr, "Cannot specify 'compress output' and 'leave compression alone' together\n");
1666 if(flags->restore_dir != NULL){
1667 struct stat statinfo;
1669 if(flags->pipe_to_fd != -1){
1670 fprintf(stderr, "Specifying output directory and piping output are mutually exclusive\n");
1673 if(stat(flags->restore_dir, &statinfo) < 0){
1674 fprintf(stderr, "Cannot stat restore target dir '%s': %s\n",
1675 flags->restore_dir, strerror(errno));
1678 if((statinfo.st_mode & S_IFMT) != S_IFDIR){
1679 fprintf(stderr, "'%s' is not a directory\n", flags->restore_dir);
1684 if((flags->pipe_to_fd != -1 || flags->compress) &&
1685 (flags->delay_assemble || !flags->inline_assemble)){
1686 fprintf(stderr, "Split dumps *must* be automatically reassembled when piping output or compressing/uncompressing\n");
1690 if(flags->delay_assemble && flags->inline_assemble){
1691 fprintf(stderr, "Inline split assembling and delayed assembling are mutually exclusive\n");
1699 * Clean up after a rst_flags_t
1701 void free_rst_flags(flags)
1706 if(flags->restore_dir) amfree(flags->restore_dir);
1707 if(flags->alt_tapedev) amfree(flags->alt_tapedev);
1708 if(flags->inventory_log) amfree(flags->inventory_log);
1715 * Clean up after a match_list_t
1717 void free_match_list(match_list)
1718 match_list_t *match_list;
1721 match_list_t *prev = NULL;
1723 for(me = match_list; me; me = me->next){
1724 /* XXX freeing these is broken? can't work out why */
1725 /* if(me->hostname) amfree(me->hostname);
1726 if(me->diskname) amfree(me->diskname);
1727 if(me->datestamp) amfree(me->datestamp);
1728 if(me->level) amfree(me->level); */
1729 if(prev) amfree(prev);
1732 if(prev) amfree(prev);