2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1998, 2000 University of Maryland at College Park
4 * Copyright (c) 2007-2012 Zmanda, Inc. All Rights Reserved.
7 * Permission to use, copy, modify, distribute, and sell this software and its
8 * documentation for any purpose is hereby granted without fee, provided that
9 * the above copyright notice appear in all copies and that both that
10 * copyright notice and this permission notice appear in supporting
11 * documentation, and that the name of U.M. not be used in advertising or
12 * publicity pertaining to distribution of the software without specific,
13 * written prior permission. U.M. makes no representations about the
14 * suitability of this software for any purpose. It is provided "as is"
15 * without express or implied warranty.
17 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
19 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
21 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
22 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24 * Authors: the Amanda Development Team. Its members are listed in a
25 * file named AUTHORS, in the root directory of this distribution.
30 * implements the "extract" command in amrecover
36 #include "amrecover.h"
37 #include "fileheader.h"
46 typedef struct EXTRACT_LIST_ITEM {
49 struct EXTRACT_LIST_ITEM *next;
53 typedef struct EXTRACT_LIST {
54 char *date; /* date tape created */
55 int level; /* level of dump */
56 char *tape; /* tape label */
57 off_t fileno; /* fileno on tape */
58 EXTRACT_LIST_ITEM *files; /* files to get off tape */
60 struct EXTRACT_LIST *next;
67 char *dump_device_name = NULL;
69 extern char *localhost;
71 /* global pid storage for interrupt handler */
72 pid_t extract_restore_child_pid = -1;
74 static EXTRACT_LIST *extract_list = NULL;
75 static int tape_control_sock = -1;
76 static int tape_data_sock = -1;
79 unsigned short samba_extract_method = SAMBA_TAR;
80 #endif /* SAMBA_CLIENT */
82 #define READ_TIMEOUT 240*60
84 EXTRACT_LIST *first_tape_list(void);
85 EXTRACT_LIST *next_tape_list(EXTRACT_LIST *list);
86 int is_extract_list_nonempty(void);
87 int length_of_tape_list(EXTRACT_LIST *tape_list);
88 void add_file(char *path, char *regex);
89 void add_glob(char *glob);
90 void add_regex(char *regex);
91 void clear_extract_list(void);
92 void clean_tape_list(EXTRACT_LIST *tape_list);
93 void clean_extract_list(void);
94 void delete_file(char *path, char *regex);
95 void delete_glob(char *glob);
96 void delete_regex(char *regex);
97 void delete_tape_list(EXTRACT_LIST *tape_list);
98 void display_extract_list(char *file);
99 void extract_files(void);
100 void read_file_header(char *buffer,
104 void writer_intermediary(int ctl_fd, int data_fd, EXTRACT_LIST *elist);
105 void writer_intermediary(int ctl_fd, int data_fd, EXTRACT_LIST *elist);
107 static int add_extract_item(DIR_ITEM *ditem);
108 static int delete_extract_item(DIR_ITEM *ditem);
109 static int extract_files_setup(char *label, off_t fsf);
110 static int okay_to_continue(int allow_tape,
113 static int okay_to_continue(int, int, int);
114 static ssize_t read_buffer(int datafd,
118 static void clear_tape_list(EXTRACT_LIST *tape_list);
119 static void extract_files_child(int in_fd, EXTRACT_LIST *elist);
120 static void send_to_tape_server(int tss, char *cmd);
124 * Function: ssize_t read_buffer(datafd, buffer, buflen, timeout_s)
127 * read data from input file desciptor waiting up to timeout_s
128 * seconds before returning data.
131 * datafd - File descriptor to read from.
132 * buffer - Buffer to read into.
133 * buflen - Maximum number of bytes to read into buffer.
134 * timeout_s - Seconds to wait before returning what was already read.
137 * >0 - Number of data bytes in buffer.
139 * -1 - errno == ETIMEDOUT if no data available in specified time.
140 * errno == ENFILE if datafd is invalid.
141 * otherwise errno is set by select or read..
153 struct timeval timeout;
158 if(datafd < 0 || datafd >= (int)FD_SETSIZE) {
159 errno = EMFILE; /* out of range */
164 spaceleft = (ssize_t)buflen;
168 FD_SET(datafd, &readset);
169 timeout.tv_sec = timeout_s;
171 nfound = select(datafd+1, &readset, NULL, NULL, &timeout);
173 /* Select returned an error. */
174 g_fprintf(stderr,_("select error: %s\n"), strerror(errno));
180 /* Select timed out. */
181 if (timeout_s != 0) {
182 /* Not polling: a real read timeout */
183 g_fprintf(stderr,_("timeout waiting for restore\n"));
184 g_fprintf(stderr,_("increase READ_TIMEOUT in recover-src/extract_list.c if your tape is slow\n"));
191 if(!FD_ISSET(datafd, &readset))
194 /* Select says data is available, so read it. */
195 size = read(datafd, dataptr, (size_t)spaceleft);
197 if ((errno == EINTR) || (errno == EAGAIN)) {
200 if (errno != EPIPE) {
201 g_fprintf(stderr, _("read_buffer: read error - %s"),
209 } while ((size > 0) && (spaceleft > 0));
211 return ((((ssize_t)buflen-spaceleft) > 0) ? ((ssize_t)buflen-spaceleft) : size);
216 first_tape_list(void)
223 /*@keep@*/ EXTRACT_LIST *list)
232 EXTRACT_LIST * tape_list)
234 EXTRACT_LIST_ITEM *this, *next;
237 this = tape_list->files;
245 tape_list->files = NULL;
249 /* remove a tape list from the extract list, clearing the tape list
250 beforehand if necessary */
253 EXTRACT_LIST * tape_list)
255 EXTRACT_LIST *this, *prev;
257 if (tape_list == NULL)
260 /* is it first on the list? */
261 if (tape_list == extract_list)
263 extract_list = tape_list->next;
264 clear_tape_list(tape_list);
265 amfree(tape_list->date);
266 amfree(tape_list->tape);
271 /* so not first on list - find it and delete */
273 this = extract_list->next;
276 if (this == tape_list)
278 prev->next = tape_list->next;
279 clear_tape_list(tape_list);
280 amfree(tape_list->date);
281 amfree(tape_list->tape);
292 /* return the number of files on a tape's list */
295 EXTRACT_LIST * tape_list)
297 EXTRACT_LIST_ITEM *fn;
301 for (fn = tape_list->files; fn != NULL; fn = fn->next)
309 clear_extract_list(void)
311 while (extract_list != NULL)
312 delete_tape_list(extract_list);
318 EXTRACT_LIST *tape_list)
320 EXTRACT_LIST_ITEM *fn1, *pfn1, *ofn1;
321 EXTRACT_LIST_ITEM *fn2, *pfn2, *ofn2;
326 fn1 = tape_list->files;
327 while (fn1 != NULL) {
332 while (fn2 != NULL && remove_fn1 == 0) {
334 if(strcmp(fn1->path, fn2->path) == 0) {
336 } else if (strncmp(fn1->path, fn2->path, strlen(fn1->path)) == 0 &&
337 ((strlen(fn2->path) > strlen(fn1->path) &&
338 fn2->path[strlen(fn1->path)] == '/') ||
339 (fn1->path[strlen(fn1->path)-1] == '/'))) {
341 } else if (strncmp(fn2->path, fn1->path, strlen(fn2->path)) == 0 &&
342 ((strlen(fn1->path) > strlen(fn2->path) &&
343 fn1->path[strlen(fn2->path)] == '/') ||
344 (fn2->path[strlen(fn2->path)-1] == '/'))) {
350 dbprintf(_("removing path %s, it is included in %s\n"),
351 fn2->path, fn1->path);
357 } else if (remove_fn1 == 0) {
363 if(remove_fn1 != 0) {
364 /* fn2->path is always valid */
365 /*@i@*/ dbprintf(_("removing path %s, it is included in %s\n"),
366 /*@i@*/ fn1->path, fn2->path);
371 amfree(tape_list->files);
372 tape_list->files = fn1;
386 clean_extract_list(void)
390 for (this = extract_list; this != NULL; this = this->next)
391 clean_tape_list(this);
395 /* returns -1 if error */
396 /* returns 0 on succes */
397 /* returns 1 if already added */
402 EXTRACT_LIST *this, *this1;
403 EXTRACT_LIST_ITEM *that, *curr;
404 char *ditem_path = NULL;
406 ditem_path = stralloc(ditem->path);
407 clean_pathname(ditem_path);
409 for (this = extract_list; this != NULL; this = this->next)
411 /* see if this is the list for the tape */
412 if (this->level == ditem->level && strcmp(this->tape, ditem->tape) == 0)
414 /* yes, so add to list */
418 if (strcmp(curr->path, ditem_path) == 0) {
424 that = (EXTRACT_LIST_ITEM *)alloc(sizeof(EXTRACT_LIST_ITEM));
425 that->path = stralloc(ditem_path);
426 that->next = this->files;
427 this->files = that; /* add at front since easiest */
433 /* so this is the first time we have seen this tape */
434 this = (EXTRACT_LIST *)alloc(sizeof(EXTRACT_LIST));
435 this->tape = stralloc(ditem->tape);
436 this->level = ditem->level;
437 this->fileno = ditem->fileno;
438 this->date = stralloc(ditem->date);
439 that = (EXTRACT_LIST_ITEM *)alloc(sizeof(EXTRACT_LIST_ITEM));
440 that->path = stralloc(ditem_path);
444 /* add this in date increasing order */
445 /* because restore must be done in this order */
446 /* add at begining */
447 if(extract_list==NULL || strcmp(this->date,extract_list->date) < 0)
449 this->next = extract_list;
454 for (this1 = extract_list; this1->next != NULL; this1 = this1->next)
456 /* add in the middle */
457 if(strcmp(this->date,this1->next->date) < 0)
459 this->next = this1->next;
473 /* returns -1 if error */
474 /* returns 0 on deletion */
475 /* returns 1 if not there */
481 EXTRACT_LIST_ITEM *that, *prev;
482 char *ditem_path = NULL;
484 ditem_path = stralloc(ditem->path);
485 clean_pathname(ditem_path);
487 for (this = extract_list; this != NULL; this = this->next)
489 /* see if this is the list for the tape */
490 if (this->level == ditem->level && strcmp(this->tape, ditem->tape) == 0)
492 /* yes, so find file on list */
494 if (strcmp(that->path, ditem_path) == 0)
497 this->files = that->next;
500 /* if list empty delete it */
501 if (this->files == NULL)
502 delete_tape_list(this);
510 if (strcmp(that->path, ditem_path) == 0)
512 prev->next = that->next;
537 char *uqglob = unquote_string(glob);
539 regex = glob_to_regex(uqglob);
540 dbprintf(_("add_glob (%s) -> %s\n"), uqglob, regex);
541 if ((s = validate_regexp(regex)) != NULL) {
542 g_printf(_("%s is not a valid shell wildcard pattern: "), glob);
546 * glob_to_regex() anchors the beginning of the pattern with ^,
547 * but we will be tacking it onto the end of the current directory
548 * in add_file, so strip that off. Also, it anchors the end with
549 * $, but we need to match an optional trailing /, so tack that on
552 regex_path = stralloc(regex + 1);
553 regex_path[strlen(regex_path) - 1] = '\0';
554 strappend(regex_path, "[/]*$");
555 add_file(uqglob, regex_path);
567 char *uqregex = unquote_string(regex);
569 if ((s = validate_regexp(uqregex)) != NULL) {
570 g_printf(_("%s is not a valid regular expression: "), regex);
573 add_file(uqregex, regex);
582 DIR_ITEM *ditem, lditem;
583 char *path_on_disk = NULL;
584 char *path_on_disk_slash = NULL;
589 char *dir_undo, dir_undo_ch = '\0';
590 char *ditem_path = NULL;
593 char *s, *fp, *quoted;
598 if (disk_path == NULL) {
599 g_printf(_("Must select directory before adding files\n"));
602 memset(&lditem, 0, sizeof(lditem)); /* Prevent use of bogus data... */
604 dbprintf(_("add_file: Looking for \"%s\"\n"), regex);
606 if(strcmp(regex, "/[/]*$") == 0) { /* "/" behave like "." */
609 else if(strcmp(regex, "[^/]*[/]*$") == 0) { /* "*" */
610 regex = "([^/.]|\\.[^/]+|[^/.][^/]*)[/]*$";
612 /* remove "/" at end of path */
613 j = (ssize_t)(strlen(regex) - 1);
614 while(j >= 0 && regex[j] == '/')
618 /* convert path (assumed in cwd) to one on disk */
619 if (strcmp(disk_path, "/") == 0) {
621 /* No mods needed if already starts with '/' */
622 path_on_disk = stralloc(regex);
625 path_on_disk = stralloc2("/", regex);
628 char *clean_disk_path = clean_regex(disk_path, 0);
629 path_on_disk = vstralloc(clean_disk_path, "/", regex, NULL);
630 amfree(clean_disk_path);
633 path_on_disk_slash = stralloc2(path_on_disk, "/");
635 dbprintf(_("add_file: Converted path=\"%s\" to path_on_disk=\"%s\"\n"),
636 regex, path_on_disk);
640 for (ditem=get_dir_list(); ditem!=NULL; ditem=get_next_dir_item(ditem))
643 quoted = quote_string(ditem->path);
644 dbprintf(_("add_file: Pondering ditem->path=%s\n"), quoted);
646 if (match(path_on_disk, ditem->path)
647 || match(path_on_disk_slash, ditem->path))
650 j = (ssize_t)strlen(ditem->path);
651 if((j > 0 && ditem->path[j-1] == '/')
652 || (j > 1 && ditem->path[j-2] == '/' && ditem->path[j-1] == '.'))
653 { /* It is a directory */
654 ditem_path = newstralloc(ditem_path, ditem->path);
655 clean_pathname(ditem_path);
657 cmd = newstralloc2(cmd, "ORLD ", ditem_path);
658 if(send_command(cmd) == -1) {
661 amfree(path_on_disk);
662 amfree(path_on_disk_slash);
668 if ((i = get_reply_line()) == -1) {
670 amfree(path_on_disk);
671 amfree(path_on_disk_slash);
674 if(i==0) { /* assume something wrong */
676 amfree(path_on_disk);
677 amfree(path_on_disk_slash);
679 g_printf(_("%s\n"), l);
684 lditem.path = newstralloc(lditem.path, ditem->path);
685 /* skip the last line -- duplicate of the preamble */
687 while ((i = get_reply_line()) != 0) {
690 amfree(path_on_disk);
691 amfree(path_on_disk_slash);
696 if(dir_undo) *dir_undo = dir_undo_ch;
698 cmd = stralloc(l); /* save for error report */
700 continue; /* throw the rest of the lines away */
703 if (!server_happy()) {
709 if(strncmp_const_skip(l, "201-", s, ch) != 0) {
710 err = _("bad reply: not 201-");
715 skip_whitespace(s, ch);
717 err = _("bad reply: missing date field");
721 skip_non_whitespace(s, ch);
723 lditem.date = newstralloc(lditem.date, fp);
726 skip_whitespace(s, ch);
727 if(ch == '\0' || sscanf(s - 1, "%d", &lditem.level) != 1) {
728 err = _("bad reply: cannot parse level field");
733 skip_whitespace(s, ch);
735 err = _("bad reply: missing tape field");
739 skip_non_whitespace(s, ch);
741 lditem.tape = newstralloc(lditem.tape, fp);
744 if(am_has_feature(indexsrv_features, fe_amindexd_fileno_in_ORLD)) {
745 long long fileno_ = (long long)0;
746 skip_whitespace(s, ch);
748 sscanf(s - 1, "%lld", &fileno_) != 1) {
749 err = _("bad reply: cannot parse fileno field");
752 lditem.fileno = (off_t)fileno_;
756 skip_whitespace(s, ch);
758 err = _("bad reply: missing directory field");
761 skip_quoted_string(s, ch);
763 dir_undo_ch = *dir_undo;
766 switch(add_extract_item(&lditem)) {
768 g_printf(_("System error\n"));
769 dbprintf(_("add_file: (Failed) System error\n"));
773 quoted = quote_string(lditem.path);
774 g_printf(_("Added dir %s at date %s\n"),
775 quoted, lditem.date);
776 dbprintf(_("add_file: (Successful) Added dir %s at date %s\n"),
777 quoted, lditem.date);
786 if(!server_happy()) {
793 } else if(added == 0) {
794 quoted = quote_string(ditem_path);
795 g_printf(_("dir %s already added\n"), quoted);
796 dbprintf(_("add_file: dir %s already added\n"), quoted);
800 else /* It is a file */
802 switch(add_extract_item(ditem)) {
804 g_printf(_("System error\n"));
805 dbprintf(_("add_file: (Failed) System error\n"));
809 quoted = quote_string(ditem->path);
810 g_printf(_("Added file %s\n"), quoted);
811 dbprintf(_("add_file: (Successful) Added %s\n"), quoted);
816 quoted = quote_string(ditem->path);
817 g_printf(_("File %s already added\n"), quoted);
818 dbprintf(_("add_file: file %s already added\n"), quoted);
828 amfree(path_on_disk);
829 amfree(path_on_disk_slash);
832 quoted = quote_string(path);
833 g_printf(_("File %s doesn't exist in directory\n"), quoted);
834 dbprintf(_("add_file: (Failed) File %s doesn't exist in directory\n"),
848 char *uqglob = unquote_string(glob);
850 regex = glob_to_regex(uqglob);
851 dbprintf(_("delete_glob (%s) -> %s\n"), uqglob, regex);
852 if ((s = validate_regexp(regex)) != NULL) {
853 g_printf(_("\"%s\" is not a valid shell wildcard pattern: "), glob);
857 * glob_to_regex() anchors the beginning of the pattern with ^,
858 * but we will be tacking it onto the end of the current directory
859 * in add_file, so strip that off. Also, it anchors the end with
860 * $, but we need to match an optional trailing /, so tack that on
863 regex_path = stralloc(regex + 1);
864 regex_path[strlen(regex_path) - 1] = '\0';
865 strappend(regex_path, "[/]*$");
866 delete_file(uqglob, regex_path);
878 char *uqregex = unquote_string(regex);
880 if ((s = validate_regexp(regex)) != NULL) {
881 g_printf(_("\"%s\" is not a valid regular expression: "), regex);
884 delete_file(uqregex, uqregex);
894 DIR_ITEM *ditem, lditem;
895 char *path_on_disk = NULL;
896 char *path_on_disk_slash = NULL;
902 char *tape, *tape_undo, tape_undo_ch = '\0';
903 char *dir_undo, dir_undo_ch = '\0';
905 char *ditem_path = NULL;
913 if (disk_path == NULL) {
914 g_printf(_("Must select directory before deleting files\n"));
917 memset(&lditem, 0, sizeof(lditem)); /* Prevent use of bogus data... */
919 dbprintf(_("delete_file: Looking for \"%s\"\n"), path);
921 if (strcmp(regex, "[^/]*[/]*$") == 0) {
922 /* Looking for * find everything but single . */
923 regex = "([^/.]|\\.[^/]+|[^/.][^/]*)[/]*$";
925 /* remove "/" at end of path */
926 j = (ssize_t)(strlen(regex) - 1);
927 while(j >= 0 && regex[j] == '/') regex[j--] = '\0';
930 /* convert path (assumed in cwd) to one on disk */
931 if (strcmp(disk_path, "/") == 0) {
933 if (strcmp(regex, "/[/]*$") == 0) {
934 /* We want "/" to match the directory itself: "/." */
935 path_on_disk = stralloc("/\\.[/]*$");
937 /* No mods needed if already starts with '/' */
938 path_on_disk = stralloc(regex);
942 path_on_disk = stralloc2("/", regex);
945 char *clean_disk_path = clean_regex(disk_path, 0);
946 path_on_disk = vstralloc(clean_disk_path, "/", regex, NULL);
947 amfree(clean_disk_path);
950 path_on_disk_slash = stralloc2(path_on_disk, "/");
952 dbprintf(_("delete_file: Converted path=\"%s\" to path_on_disk=\"%s\"\n"),
953 regex, path_on_disk);
955 for (ditem=get_dir_list(); ditem!=NULL; ditem=get_next_dir_item(ditem))
957 quoted = quote_string(ditem->path);
958 dbprintf(_("delete_file: Pondering ditem->path=%s\n"), quoted);
960 if (match(path_on_disk, ditem->path)
961 || match(path_on_disk_slash, ditem->path))
964 j = (ssize_t)strlen(ditem->path);
965 if((j > 0 && ditem->path[j-1] == '/')
966 || (j > 1 && ditem->path[j-2] == '/' && ditem->path[j-1] == '.'))
967 { /* It is a directory */
968 ditem_path = newstralloc(ditem_path, ditem->path);
969 clean_pathname(ditem_path);
971 cmd = newstralloc2(cmd, "ORLD ", ditem_path);
972 if(send_command(cmd) == -1) {
975 amfree(path_on_disk);
976 amfree(path_on_disk_slash);
981 if ((i = get_reply_line()) == -1) {
983 amfree(path_on_disk);
984 amfree(path_on_disk_slash);
987 if(i==0) /* assume something wrong */
990 amfree(path_on_disk);
991 amfree(path_on_disk_slash);
997 lditem.path = newstralloc(lditem.path, ditem->path);
999 tape_undo = dir_undo = NULL;
1000 /* skip the last line -- duplicate of the preamble */
1001 while ((i = get_reply_line()) != 0)
1005 amfree(path_on_disk);
1006 amfree(path_on_disk_slash);
1011 if(tape_undo) *tape_undo = tape_undo_ch;
1012 if(dir_undo) *dir_undo = dir_undo_ch;
1013 tape_undo = dir_undo = NULL;
1014 cmd = stralloc(l); /* save for the error report */
1016 continue; /* throw the rest of the lines away */
1019 if (!server_happy()) {
1025 if(strncmp_const_skip(l, "201-", s, ch) != 0) {
1026 err = _("bad reply: not 201-");
1031 skip_whitespace(s, ch);
1033 err = _("bad reply: missing date field");
1037 skip_non_whitespace(s, ch);
1040 skip_whitespace(s, ch);
1041 if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
1042 err = _("bad reply: cannot parse level field");
1045 skip_integer(s, ch);
1047 skip_whitespace(s, ch);
1049 err = _("bad reply: missing tape field");
1053 skip_non_whitespace(s, ch);
1055 tape_undo_ch = *tape_undo;
1058 if(am_has_feature(indexsrv_features, fe_amindexd_fileno_in_ORLD)) {
1059 long long fileno_ = (long long)0;
1060 skip_whitespace(s, ch);
1062 sscanf(s - 1, "%lld", &fileno_) != 1) {
1063 err = _("bad reply: cannot parse fileno field");
1066 skip_integer(s, ch);
1069 skip_whitespace(s, ch);
1071 err = _("bad reply: missing directory field");
1074 skip_non_whitespace(s, ch);
1076 dir_undo_ch = *dir_undo;
1079 lditem.date = newstralloc(lditem.date, date);
1081 lditem.tape = newstralloc(lditem.tape, tape);
1082 switch(delete_extract_item(&lditem)) {
1084 g_printf(_("System error\n"));
1085 dbprintf(_("delete_file: (Failed) System error\n"));
1088 g_printf(_("Deleted dir %s at date %s\n"), ditem_path, date);
1089 dbprintf(_("delete_file: (Successful) Deleted dir %s at date %s\n"),
1097 if(!server_happy()) {
1104 } else if(deleted == 0) {
1105 g_printf(_("Warning - dir '%s' not on tape list\n"),
1107 dbprintf(_("delete_file: dir '%s' not on tape list\n"),
1113 switch(delete_extract_item(ditem)) {
1115 g_printf(_("System error\n"));
1116 dbprintf(_("delete_file: (Failed) System error\n"));
1119 g_printf(_("Deleted %s\n"), ditem->path);
1120 dbprintf(_("delete_file: (Successful) Deleted %s\n"),
1124 g_printf(_("Warning - file '%s' not on tape list\n"),
1126 dbprintf(_("delete_file: file '%s' not on tape list\n"),
1135 amfree(path_on_disk);
1136 amfree(path_on_disk_slash);
1139 g_printf(_("File %s doesn't exist in directory\n"), path);
1140 dbprintf(_("delete_file: (Failed) File %s doesn't exist in directory\n"),
1146 /* print extract list into file. If NULL ptr passed print to screen */
1148 display_extract_list(
1152 EXTRACT_LIST_ITEM *that;
1155 char *pager_command;
1160 if ((pager = getenv("PAGER")) == NULL)
1165 * Set up the pager command so if the pager is terminated, we do
1166 * not get a SIGPIPE back.
1168 pager_command = stralloc2(pager, " ; /bin/cat > /dev/null");
1169 if ((fp = popen(pager_command, "w")) == NULL)
1171 g_printf(_("Warning - can't pipe through %s\n"), pager);
1174 amfree(pager_command);
1178 uqfile = unquote_string(file);
1179 if ((fp = fopen(uqfile, "w")) == NULL)
1181 g_printf(_("Can't open file %s to print extract list into\n"), file);
1188 for (this = extract_list; this != NULL; this = this->next)
1190 g_fprintf(fp, _("TAPE %s LEVEL %d DATE %s\n"),
1191 this->tape, this->level, this->date);
1192 for (that = this->files; that != NULL; that = that->next)
1193 g_fprintf(fp, "\t%s\n", that->path);
1199 g_printf(_("Extract list written to file %s\n"), file);
1205 /* returns 0 if extract list empty and 1 if it isn't */
1207 is_extract_list_nonempty(void)
1209 return (extract_list != NULL);
1213 /* prints continue prompt and waits for response,
1214 returns 0 if don't, non-0 if do */
1231 prompt = _("New tape device [?]: ");
1232 } else if (allow_tape && allow_skip) {
1233 prompt = _("Continue [?/Y/n/s/t]? ");
1234 } else if (allow_tape && !allow_skip) {
1235 prompt = _("Continue [?/Y/n/t]? ");
1236 } else if (allow_retry) {
1237 prompt = _("Continue [?/Y/n/r]? ");
1239 prompt = _("Continue [?/Y/n]? ");
1241 fputs(prompt, stdout);
1242 fflush(stdout); fflush(stderr);
1244 if ((line = agets(stdin)) == NULL) {
1255 while ((ch = *s++) != '\0' && g_ascii_isspace(ch)) {
1256 (void)ch; /* Quiet empty loop body warning */
1260 g_printf(_("Enter a new device ([host:]device) or \"default\"\n"));
1262 g_printf(_("Enter \"y\"es to continue, \"n\"o to stop"));
1264 g_printf(_(", \"s\"kip this tape"));
1267 g_printf(_(" or \"r\"etry this tape"));
1270 g_printf(_(" or \"t\"ape to change tape drives"));
1274 } else if (get_tape) {
1277 } else if (ch == '\0' || ch == 'Y' || ch == 'y') {
1279 } else if (allow_tape && (ch == 'T' || ch == 't')) {
1281 } else if (ch == 'N' || ch == 'n') {
1283 } else if (allow_retry && (ch == 'R' || ch == 'r')) {
1285 } else if (allow_skip && (ch == 'S' || ch == 's')) {
1296 send_to_tape_server(
1300 char *msg = stralloc2(cmd, "\r\n");
1302 if (full_write(tss, msg, strlen(msg)) < strlen(msg))
1304 error(_("Error writing to tape server: %s"), strerror(errno));
1311 /* start up connection to tape server and set commands to initiate
1312 transfer of dump image.
1313 Return tape server socket on success, -1 on error. */
1315 extract_files_setup(
1320 in_port_t my_port, my_data_port;
1321 char *disk_regex = NULL;
1322 char *host_regex = NULL;
1323 char *service_name = NULL;
1325 char *clean_datestamp, *ch, *ch1;
1326 char *our_feature_string = NULL;
1329 service_name = stralloc2("amidxtape", SERVICE_SUFFIX);
1331 /* get tape server details */
1332 if ((sp = getservbyname(service_name, "tcp")) == NULL)
1334 g_printf(_("%s/tcp unknown protocol - config error?\n"), service_name);
1335 amfree(service_name);
1338 amfree(service_name);
1339 seteuid(0); /* it either works ... */
1341 tape_control_sock = stream_client_privileged(tape_server_name,
1342 (in_port_t)ntohs((in_port_t)sp->s_port),
1347 if (tape_control_sock < 0)
1349 g_printf(_("cannot connect to %s: %s\n"), tape_server_name, strerror(errno));
1352 if (my_port >= IPPORT_RESERVED) {
1353 aclose(tape_control_sock);
1354 g_printf(_("did not get a reserved port: %u\n"), (unsigned)my_port);
1359 seteuid(getuid()); /* put it back */
1361 /* do the security thing */
1362 line = get_security();
1363 send_to_tape_server(tape_control_sock, line);
1364 memset(line, '\0', strlen(line));
1367 disk_regex = alloc(strlen(disk_name) * 2 + 3);
1372 /* we want to force amrestore to only match disk_name exactly */
1375 /* We need to escape some characters first... NT compatibilty crap */
1376 for (; *ch != 0; ch++, ch1++) {
1377 switch (*ch) { /* done this way in case there are more */
1380 /* no break; we do want to fall through... */
1386 /* we want to force amrestore to only match disk_name exactly */
1391 host_regex = alloc(strlen(dump_hostname) * 2 + 3);
1396 /* we want to force amrestore to only match dump_hostname exactly */
1399 /* We need to escape some characters first... NT compatibilty crap */
1400 for (; *ch != 0; ch++, ch1++) {
1401 switch (*ch) { /* done this way in case there are more */
1404 /* no break; we do want to fall through... */
1410 /* we want to force amrestore to only match dump_hostname exactly */
1415 clean_datestamp = stralloc(dump_datestamp);
1416 for(ch=ch1=clean_datestamp;*ch1 != '\0';ch1++) {
1424 /* push our feature list off to the tape server */
1425 /* XXX assumes that index server and tape server are equivalent, ew */
1426 if(am_has_feature(indexsrv_features, fe_amidxtaped_exchange_features)){
1427 char buffer[32768] = "\0";
1429 our_feature_string = am_feature_to_string(our_features);
1430 tt = newstralloc2(tt, "FEATURES=", our_feature_string);
1431 send_to_tape_server(tape_control_sock, tt);
1432 if (read(tape_control_sock, buffer, sizeof(buffer)) <= 0) {
1433 error(_("Could not read features from control socket\n"));
1436 tapesrv_features = am_string_to_feature(buffer);
1437 amfree(our_feature_string);
1441 if(am_has_feature(indexsrv_features, fe_amidxtaped_header) &&
1442 am_has_feature(indexsrv_features, fe_amidxtaped_device) &&
1443 am_has_feature(indexsrv_features, fe_amidxtaped_host) &&
1444 am_has_feature(indexsrv_features, fe_amidxtaped_disk) &&
1445 am_has_feature(indexsrv_features, fe_amidxtaped_datestamp)) {
1447 if(am_has_feature(indexsrv_features, fe_amidxtaped_config)) {
1448 tt = newstralloc2(tt, "CONFIG=", config);
1449 send_to_tape_server(tape_control_sock, tt);
1451 if(am_has_feature(indexsrv_features, fe_amidxtaped_label) &&
1452 label && label[0] != '/') {
1453 tt = newstralloc2(tt,"LABEL=",label);
1454 send_to_tape_server(tape_control_sock, tt);
1456 if(am_has_feature(indexsrv_features, fe_amidxtaped_fsf)) {
1458 g_snprintf(v_fsf, 99, "%lld", (long long)fsf);
1459 tt = newstralloc2(tt, "FSF=",v_fsf);
1460 send_to_tape_server(tape_control_sock, tt);
1462 send_to_tape_server(tape_control_sock, "HEADER");
1463 tt = newstralloc2(tt, "DEVICE=", dump_device_name);
1464 send_to_tape_server(tape_control_sock, tt);
1465 tt = newstralloc2(tt, "HOST=", host_regex);
1466 send_to_tape_server(tape_control_sock, tt);
1467 tt = newstralloc2(tt, "DISK=", disk_regex);
1468 send_to_tape_server(tape_control_sock, tt);
1469 tt = newstralloc2(tt, "DATESTAMP=", clean_datestamp);
1470 send_to_tape_server(tape_control_sock, tt);
1471 send_to_tape_server(tape_control_sock, "END");
1474 else if(am_has_feature(indexsrv_features, fe_amidxtaped_nargs)) {
1475 /* send to the tape server what tape file we want */
1484 send_to_tape_server(tape_control_sock, "6");
1485 send_to_tape_server(tape_control_sock, "-h");
1486 send_to_tape_server(tape_control_sock, "-p");
1487 send_to_tape_server(tape_control_sock, dump_device_name);
1488 send_to_tape_server(tape_control_sock, host_regex);
1489 send_to_tape_server(tape_control_sock, disk_regex);
1490 send_to_tape_server(tape_control_sock, clean_datestamp);
1492 dbprintf(_("Started amidxtaped with arguments \"6 -h -p %s %s %s %s\"\n"),
1493 dump_device_name, host_regex, disk_regex, clean_datestamp);
1497 * split-restoring amidxtaped versions will expect to set up a data
1498 * connection for dumpfile data, distinct from the socket we're already
1499 * using for control data
1502 if(am_has_feature(tapesrv_features, fe_recover_splits)){
1504 in_port_t data_port = (in_port_t)-1;
1507 nread = read(tape_control_sock, buffer, sizeof(buffer));
1510 error(_("Could not read from control socket: %s\n"),
1515 buffer[nread] = '\0';
1516 if (sscanf(buffer, "CONNECT %hu\n",
1517 (unsigned short *)&data_port) != 1) {
1518 error(_("Recieved invalid port number message from control socket: %s\n"),
1523 tape_data_sock = stream_client_privileged(server_name,
1529 if(tape_data_sock == -1){
1530 error(_("Unable to make data connection to server: %s\n"),
1535 amfree(our_feature_string);
1537 line = get_security();
1539 send_to_tape_server(tape_data_sock, line);
1540 memset(line, '\0', strlen(line));
1546 amfree(clean_datestamp);
1548 return tape_control_sock;
1553 * Reads the first block of a tape file.
1565 bytes_read = read_buffer(tapedev, buffer, buflen, READ_TIMEOUT);
1566 if(bytes_read < 0) {
1567 error(_("error reading header (%s), check amidxtaped.*.debug on server"),
1572 if((size_t)bytes_read < buflen) {
1573 g_fprintf(stderr, plural(_("%s: short block %d byte\n"),
1574 _("%s: short block %d bytes\n"), bytes_read),
1575 get_pname(), (int)bytes_read);
1576 print_header(stdout, file);
1577 error(_("Can't read file header"));
1581 /* bytes_read == buflen */
1582 parse_file_header(buffer, file, (size_t)bytes_read);
1595 extract_files_child(
1597 EXTRACT_LIST * elist)
1602 GPtrArray *argv_ptr = g_ptr_array_new();
1604 EXTRACT_LIST_ITEM *fn;
1605 enum dumptypes dumptype = IS_UNKNOWN;
1606 char buffer[DISK_BLOCK_BYTES];
1610 guint passwd_field = 999999999;
1612 char *domain = NULL, *smbpass = NULL;
1615 /* code executed by child to do extraction */
1618 /* make in_fd be our stdin */
1619 if (dup2(in_fd, STDIN_FILENO) == -1)
1621 error(_("dup2 failed in extract_files_child: %s"), strerror(errno));
1625 /* read the file header */
1627 read_file_header(buffer, &file, sizeof(buffer), STDIN_FILENO);
1629 if(file.type != F_DUMPFILE) {
1630 print_header(stdout, &file);
1631 error(_("bad header"));
1635 if (file.program != NULL) {
1637 if (strcmp(file.program, GNUTAR) == 0)
1638 dumptype = IS_GNUTAR;
1641 if (dumptype == IS_UNKNOWN) {
1642 len_program = strlen(file.program);
1643 if(len_program >= 3 &&
1644 strcmp(&file.program[len_program-3],"tar") == 0)
1649 if (dumptype == IS_UNKNOWN && strcmp(file.program, SAMBA_CLIENT) ==0) {
1650 if (samba_extract_method == SAMBA_TAR)
1651 dumptype = IS_SAMBA_TAR;
1653 dumptype = IS_SAMBA;
1658 /* form the arguments to restore */
1659 files_off_tape = length_of_tape_list(elist);
1663 g_ptr_array_add(argv_ptr, stralloc("smbclient"));
1664 smbpass = findpass(file.disk, &domain);
1666 g_ptr_array_add(argv_ptr, stralloc(file.disk));
1667 g_ptr_array_add(argv_ptr, stralloc("-U"));
1668 passwd_field = argv_ptr->len;
1669 g_ptr_array_add(argv_ptr, stralloc(smbpass));
1671 g_ptr_array_add(argv_ptr, stralloc("-W"));
1672 g_ptr_array_add(argv_ptr, stralloc(domain));
1675 g_ptr_array_add(argv_ptr, stralloc("-d0"));
1676 g_ptr_array_add(argv_ptr, stralloc("-Tx"));
1677 g_ptr_array_add(argv_ptr, stralloc("-")); /* data on stdin */
1682 g_ptr_array_add(argv_ptr, stralloc("tar"));
1683 g_ptr_array_add(argv_ptr, stralloc("--numeric-owner"));
1684 g_ptr_array_add(argv_ptr, stralloc("-xpGvf"));
1685 g_ptr_array_add(argv_ptr, stralloc("-")); /* data on stdin */
1688 g_ptr_array_add(argv_ptr, stralloc("tar"));
1689 g_ptr_array_add(argv_ptr, stralloc("-xpvf"));
1690 g_ptr_array_add(argv_ptr, stralloc("-")); /* data on stdin */
1694 g_ptr_array_add(argv_ptr, stralloc("restore"));
1696 g_ptr_array_add(argv_ptr, stralloc("-xB"));
1698 #if defined(XFSDUMP)
1699 if (strcmp(file.program, XFSDUMP) == 0) {
1700 g_ptr_array_add(argv_ptr, stralloc("-v"));
1701 g_ptr_array_add(argv_ptr, stralloc("silent"));
1705 if (strcmp(file.program, VDUMP) == 0) {
1706 g_ptr_array_add(argv_ptr, stralloc("xf"));
1707 g_ptr_array_add(argv_ptr, stralloc("-")); /* data on stdin */
1711 g_ptr_array_add(argv_ptr, stralloc("xbf"));
1712 g_ptr_array_add(argv_ptr, stralloc("2")); /* read in units of 1K */
1713 g_ptr_array_add(argv_ptr, stralloc("-")); /* data on stdin */
1718 for (i = 0, fn = elist->files; i < files_off_tape; i++, fn = fn->next)
1725 if (strcmp(fn->path, "/") == 0)
1726 g_ptr_array_add(argv_ptr, stralloc("."));
1728 g_ptr_array_add(argv_ptr, stralloc2(".", fn->path));
1732 #if defined(XFSDUMP)
1733 if (strcmp(file.program, XFSDUMP) == 0) {
1735 * xfsrestore needs a -s option before each file to be
1736 * restored, and also wants them to be relative paths.
1738 g_ptr_array_add(argv_ptr, stralloc("-s"));
1739 g_ptr_array_add(argv_ptr, stralloc(fn->path + 1));
1743 g_ptr_array_add(argv_ptr, stralloc(fn->path));
1747 #if defined(XFSDUMP)
1748 if (strcmp(file.program, XFSDUMP) == 0) {
1749 g_ptr_array_add(argv_ptr, stralloc("-"));
1750 g_ptr_array_add(argv_ptr, stralloc("."));
1753 g_ptr_array_add(argv_ptr, NULL);
1758 cmd = stralloc(SAMBA_CLIENT);
1761 /* fall through to ... */
1767 g_fprintf(stderr, _("warning: GNUTAR program not available.\n"));
1768 cmd = stralloc("tar");
1770 cmd = stralloc(GNUTAR);
1777 if (strcmp(file.program, DUMP) == 0) {
1778 cmd = stralloc(RESTORE);
1782 if (strcmp(file.program, VDUMP) == 0) {
1783 cmd = stralloc(VRESTORE);
1787 if (strcmp(file.program, VXDUMP) == 0) {
1788 cmd = stralloc(VXRESTORE);
1791 #if defined(XFSDUMP)
1792 if (strcmp(file.program, XFSDUMP) == 0) {
1793 cmd = stralloc(XFSRESTORE);
1797 g_fprintf(stderr, _("warning: restore program for %s not available.\n"),
1799 cmd = stralloc("restore");
1803 dbprintf(_("Exec'ing %s with arguments:\n"), cmd);
1804 for (j = 0; j < argv_ptr->len - 1; j++) {
1805 if( j == passwd_field)
1806 dbprintf("\tXXXXX\n");
1808 dbprintf("\t%s\n", (char *)g_ptr_array_index(argv_ptr, j));
1811 (void)execv(cmd, (char **)argv_ptr->pdata);
1812 /* only get here if exec failed */
1814 g_ptr_array_free_full(argv_ptr);
1816 perror(_("amrecover couldn't exec"));
1817 g_fprintf(stderr, _(" problem executing %s\n"), cmd);
1825 * Interpose something between the process writing out the dump (writing it to
1826 * some extraction program, really) and the socket from which we're reading, so
1827 * that we can do things like prompt for human interaction for multiple tapes.
1830 writer_intermediary(
1833 EXTRACT_LIST * elist)
1837 char buffer[DISK_BLOCK_BYTES];
1839 amwait_t extractor_status;
1841 SELECT_ARG_TYPE readset, selectset;
1842 struct timeval timeout;
1845 * If there's no distinct data channel (such as if we're talking to an
1846 * older server), don't bother doing anything complicated. Just run the
1850 extract_files_child(ctl_fd, elist);
1854 if(pipe(child_pipe) == -1) {
1855 error(_("extract_list - error setting up pipe to extractor: %s\n"),
1860 /* okay, ready to extract. fork a child to do the actual work */
1861 if ((pid = fork()) == 0) {
1862 /* this is the child process */
1863 /* never gets out of this clause */
1864 aclose(child_pipe[1]);
1865 extract_files_child(child_pipe[0], elist);
1869 /* This is the parent */
1871 error(_("writer_intermediary - error forking child"));
1875 aclose(child_pipe[0]);
1877 if(data_fd > ctl_fd) max_fd = data_fd+1;
1878 else max_fd = ctl_fd+1;
1880 FD_SET(data_fd, &readset);
1881 FD_SET(ctl_fd, &readset);
1884 timeout.tv_sec = READ_TIMEOUT;
1885 timeout.tv_usec = 0;
1886 FD_COPY(&readset, &selectset);
1888 nfound = select(max_fd, &selectset, NULL, NULL,
1891 g_fprintf(stderr,_("select error: %s\n"), strerror(errno));
1895 if (nfound == 0) { /* timeout */
1896 g_fprintf(stderr, _("timeout waiting %d seconds for restore\n"),
1898 g_fprintf(stderr, _("increase READ_TIMEOUT in recover-src/extract_list.c if your tape is slow\n"));
1902 if(FD_ISSET(ctl_fd, &selectset)) {
1903 bytes_read = read(ctl_fd, buffer, sizeof(buffer)-1);
1904 switch(bytes_read) {
1906 if ((errno != EINTR) && (errno != EAGAIN)) {
1907 if (errno != EPIPE) {
1908 g_fprintf(stderr,_("writer ctl fd read error: %s"),
1911 FD_CLR(ctl_fd, &readset);
1916 FD_CLR(ctl_fd, &readset);
1920 char desired_tape[MAX_TAPE_LABEL_BUF];
1922 buffer[bytes_read] = '\0';
1923 /* if prompted for a tape, relay said prompt to the user */
1924 if(sscanf(buffer, "FEEDME %132s\n", desired_tape) == 1) {
1928 g_printf(_("Please insert tape %s. Continue? [Y|n]: "),
1932 input = agets(stdin); /* strips \n */
1933 if (strcasecmp("", input) == 0||
1934 strcasecmp("y", input) == 0||
1935 strcasecmp("yes", input) == 0) {
1936 send_to_tape_server(tape_control_sock, "OK");
1938 } else if (strcasecmp("n", input) == 0||
1939 strcasecmp("no", input) == 0) {
1940 send_to_tape_server(tape_control_sock, "ERROR");
1942 We are the middle process, so just die. */
1948 g_fprintf(stderr, _("Strange message from tape server: %s"), buffer);
1955 /* now read some dump data */
1956 if(FD_ISSET(data_fd, &selectset)) {
1957 bytes_read = read(data_fd, buffer, sizeof(buffer)-1);
1958 switch(bytes_read) {
1960 if ((errno != EINTR) && (errno != EAGAIN)) {
1961 if (errno != EPIPE) {
1962 g_fprintf(stderr,_("writer data fd read error: %s"),
1965 FD_CLR(data_fd, &readset);
1970 FD_CLR(data_fd, &readset);
1975 * spit what we got from the server to the child
1976 * process handling actual dumpfile extraction
1978 if(full_write(child_pipe[1], buffer, bytes_read) < bytes_read) {
1979 if(errno == EPIPE) {
1980 error(_("pipe data reader has quit: %s\n"),
1984 error(_("Write error to extract child: %s\n"),
1991 } while(FD_ISSET(ctl_fd, &readset) || FD_ISSET(data_fd, &readset));
1993 aclose(child_pipe[1]);
1995 waitpid(pid, &extractor_status, 0);
1996 if(WEXITSTATUS(extractor_status) != 0){
1997 int ret = WEXITSTATUS(extractor_status);
1998 if(ret == 255) ret = -1;
1999 error(_("Extractor child exited with status %d\n"), ret);
2006 /* exec restore to do the actual restoration */
2008 /* does the actual extraction of files */
2010 * The original design had the dump image being returned exactly as it
2011 * appears on the tape, and this routine getting from the index server
2012 * whether or not it is compressed, on the assumption that the tape
2013 * server may not know how to uncompress it. But
2014 * - Amrestore can't do that. It returns either compressed or uncompressed
2015 * (always). Amrestore assumes it can uncompress files. It is thus a good
2016 * idea to run the tape server on a machine with gzip.
2017 * - The information about compression in the disklist is really only
2018 * for future dumps. It is possible to change compression on a drive
2019 * so the information in the disklist may not necessarily relate to
2020 * the dump image on the tape.
2021 * Consequently the design was changed to assuming that amrestore can
2022 * uncompress any dump image and have it return an uncompressed file
2028 EXTRACT_LIST *elist;
2030 amwait_t child_stat;
2035 tapelist_t *tlist = NULL;
2037 if (!is_extract_list_nonempty())
2039 g_printf(_("Extract list empty - No files to extract!\n"));
2043 clean_extract_list();
2045 /* get tape device name from index server if none specified */
2046 if (tape_server_name == NULL) {
2047 tape_server_name = newstralloc(tape_server_name, server_name);
2049 if (tape_device_name == NULL) {
2050 if (send_command("TAPE") == -1)
2052 if (get_reply_line() == -1)
2055 if (!server_happy())
2057 g_printf("%s\n", l);
2060 /* skip reply number */
2061 tape_device_name = newstralloc(tape_device_name, l+4);
2064 if (strcmp(tape_device_name, "/dev/null") == 0)
2066 g_printf(_("amrecover: warning: using %s as the tape device will not work\n"),
2071 for (elist = first_tape_list(); elist != NULL; elist = next_tape_list(elist))
2072 if(elist->tape[0]!='/') {
2074 g_printf(_("\nExtracting files using tape drive %s on host %s.\n"),
2075 tape_device_name, tape_server_name);
2076 g_printf(_("The following tapes are needed:"));
2081 tlist = unmarshal_tapelist_str(elist->tape);
2082 for( ; tlist != NULL; tlist = tlist->next)
2083 g_printf(" %s", tlist->label);
2088 for (elist = first_tape_list(); elist != NULL; elist = next_tape_list(elist))
2090 if(elist->tape[0]=='/') {
2092 g_printf(_("\nExtracting files from holding disk on host %s.\n"),
2094 g_printf(_("The following files are needed:"));
2099 tlist = unmarshal_tapelist_str(elist->tape);
2100 for( ; tlist != NULL; tlist = tlist->next)
2101 g_printf(" %s", tlist->label);
2108 if (getcwd(buf, sizeof(buf)) == NULL) {
2109 perror(_("extract_list: Cannot determine current working directory"));
2113 g_printf(_("Restoring files into directory %s\n"), buf);
2115 if (samba_extract_method == SAMBA_SMBCLIENT)
2116 g_printf(_("(unless it is a Samba backup, that will go through to the SMB server)\n"));
2118 if (!okay_to_continue(0,0,0))
2122 while ((elist = first_tape_list()) != NULL)
2124 if(elist->tape[0]=='/') {
2125 dump_device_name = newstralloc(dump_device_name, elist->tape);
2126 g_printf(_("Extracting from file "));
2127 tlist = unmarshal_tapelist_str(dump_device_name);
2128 for( ; tlist != NULL; tlist = tlist->next)
2129 g_printf(" %s", tlist->label);
2134 g_printf(_("Extracting files using tape drive %s on host %s.\n"),
2135 tape_device_name, tape_server_name);
2136 tlist = unmarshal_tapelist_str(elist->tape);
2137 g_printf(_("Load tape %s now\n"), tlist->label);
2139 otc = okay_to_continue(1,1,0);
2142 else if (otc == SKIP_TAPE) {
2143 delete_tape_list(elist); /* skip this tape */
2146 dump_device_name = newstralloc(dump_device_name, tape_device_name);
2148 dump_datestamp = newstralloc(dump_datestamp, elist->date);
2150 /* connect to the tape handler daemon on the tape drive server */
2151 if ((tape_control_sock = extract_files_setup(elist->tape, elist->fileno)) == -1)
2153 g_fprintf(stderr, _("amrecover - can't talk to tape server\n"));
2157 /* okay, ready to extract. fork a child to do the actual work */
2158 if ((pid = fork()) == 0)
2160 /* this is the child process */
2161 /* never gets out of this clause */
2162 writer_intermediary(tape_control_sock, tape_data_sock, elist);
2165 /* this is the parent */
2168 perror(_("extract_list - error forking child"));
2169 aclose(tape_control_sock);
2173 /* store the child pid globally so that it can be killed on intr */
2174 extract_restore_child_pid = pid;
2176 /* wait for the child process to finish */
2177 if ((pid = waitpid(-1, &child_stat, 0)) == (pid_t)-1)
2179 perror(_("extract_list - error waiting for child"));
2183 if(tape_data_sock != -1) {
2184 aclose(tape_data_sock);
2187 if (pid == extract_restore_child_pid)
2189 extract_restore_child_pid = -1;
2193 g_fprintf(stderr, _("extract list - unknown child terminated?\n"));
2196 if ((WIFEXITED(child_stat) != 0) && (WEXITSTATUS(child_stat) != 0))
2199 _("extract_list - child returned non-zero status: %d\n"),
2200 WEXITSTATUS(child_stat));
2201 otc = okay_to_continue(0,0,1);
2206 delete_tape_list(elist); /* tape failed so delete from list */
2210 delete_tape_list(elist); /* tape done so delete from list */