2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1998, 2000 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: extract_list.c,v 1.117 2006/08/24 01:57:15 paddy_s Exp $
29 * implements the "extract" command in amrecover
34 #include "amrecover.h"
35 #include "fileheader.h"
48 typedef struct EXTRACT_LIST_ITEM {
50 struct EXTRACT_LIST_ITEM *next;
54 typedef struct EXTRACT_LIST {
55 char *date; /* date tape created */
56 int level; /* level of dump */
57 char *tape; /* tape label */
58 off_t fileno; /* fileno on tape */
59 EXTRACT_LIST_ITEM *files; /* files to get off tape */
61 struct EXTRACT_LIST *next;
70 security_stream_t *fd;
71 } amidxtaped_streams[] = {
77 #define NSTREAMS (int)(sizeof(amidxtaped_streams) / sizeof(amidxtaped_streams[0]))
80 static void amidxtaped_response(void *, pkt_t *, security_handle_t *);
81 static void stop_amidxtaped(void);
82 char *amidxtaped_client_get_security_conf(char *, void *);
83 static char *dump_device_name = NULL;
85 static char *amidxtaped_line = NULL;
87 extern char *localhost;
89 /* global pid storage for interrupt handler */
90 pid_t extract_restore_child_pid = -1;
92 static EXTRACT_LIST *extract_list = NULL;
93 static const security_driver_t *amidxtaped_secdrv;
96 unsigned short samba_extract_method = SAMBA_TAR;
97 #endif /* SAMBA_CLIENT */
99 #define READ_TIMEOUT 240*60
101 EXTRACT_LIST *first_tape_list(void);
102 EXTRACT_LIST *next_tape_list(EXTRACT_LIST *list);
103 static int is_empty_dir(char *fname);
104 int is_extract_list_nonempty(void);
105 int length_of_tape_list(EXTRACT_LIST *tape_list);
106 void add_file(char *path, char *regex);
107 void add_glob(char *glob);
108 void add_regex(char *regex);
109 void clear_extract_list(void);
110 void clean_tape_list(EXTRACT_LIST *tape_list);
111 void clean_extract_list(void);
112 void check_file_overwrite(char *filename);
113 void delete_file(char *path, char *regex);
114 void delete_glob(char *glob);
115 void delete_regex(char *regex);
116 void delete_tape_list(EXTRACT_LIST *tape_list);
117 void display_extract_list(char *file);
118 void extract_files(void);
119 void read_file_header(char *buffer,
123 static int add_extract_item(DIR_ITEM *ditem);
124 static int delete_extract_item(DIR_ITEM *ditem);
125 static int extract_files_setup(char *label, off_t fsf);
126 static int okay_to_continue(int allow_tape,
129 static ssize_t read_buffer(int datafd,
133 static void clear_tape_list(EXTRACT_LIST *tape_list);
134 static void extract_files_child(int in_fd, EXTRACT_LIST *elist);
135 static void send_to_tape_server(security_stream_t *stream, char *cmd);
136 int writer_intermediary(EXTRACT_LIST *elist);
137 int get_amidxtaped_line(void);
138 static void read_amidxtaped_data(void *, void *, ssize_t);
141 * Function: ssize_t read_buffer(datafd, buffer, buflen, timeout_s)
144 * read data from input file desciptor waiting up to timeout_s
145 * seconds before returning data.
148 * datafd - File descriptor to read from.
149 * buffer - Buffer to read into.
150 * buflen - Maximum number of bytes to read into buffer.
151 * timeout_s - Seconds to wait before returning what was already read.
154 * >0 - Number of data bytes in buffer.
156 * -1 - errno == ETIMEDOUT if no data available in specified time.
157 * errno == ENFILE if datafd is invalid.
158 * otherwise errno is set by select or read..
169 SELECT_ARG_TYPE readset;
170 struct timeval timeout;
175 if(datafd < 0 || datafd >= (int)FD_SETSIZE) {
176 errno = EMFILE; /* out of range */
181 spaceleft = (ssize_t)buflen;
185 FD_SET(datafd, &readset);
186 timeout.tv_sec = timeout_s;
188 nfound = select(datafd+1, &readset, NULL, NULL, &timeout);
190 /* Select returned an error. */
191 g_fprintf(stderr,_("select error: %s\n"), strerror(errno));
197 /* Select timed out. */
198 if (timeout_s != 0) {
199 /* Not polling: a real read timeout */
200 g_fprintf(stderr,_("timeout waiting for restore\n"));
201 g_fprintf(stderr,_("increase READ_TIMEOUT in recover-src/extract_list.c if your tape is slow\n"));
208 if(!FD_ISSET(datafd, &readset))
211 /* Select says data is available, so read it. */
212 size = read(datafd, dataptr, (size_t)spaceleft);
214 if ((errno == EINTR) || (errno == EAGAIN)) {
217 if (errno != EPIPE) {
218 g_fprintf(stderr, _("read_buffer: read error - %s"),
226 } while ((size > 0) && (spaceleft > 0));
228 return ((((ssize_t)buflen-spaceleft) > 0) ? ((ssize_t)buflen-spaceleft) : size);
233 first_tape_list(void)
240 /*@keep@*/EXTRACT_LIST *list)
249 EXTRACT_LIST * tape_list)
251 EXTRACT_LIST_ITEM *this, *next;
254 this = tape_list->files;
262 tape_list->files = NULL;
266 /* remove a tape list from the extract list, clearing the tape list
267 beforehand if necessary */
270 EXTRACT_LIST *tape_list)
272 EXTRACT_LIST *this, *prev;
274 if (tape_list == NULL)
277 /* is it first on the list? */
278 if (tape_list == extract_list)
280 extract_list = tape_list->next;
281 clear_tape_list(tape_list);
282 amfree(tape_list->date);
283 amfree(tape_list->tape);
288 /* so not first on list - find it and delete */
290 this = extract_list->next;
293 if (this == tape_list)
295 prev->next = tape_list->next;
296 clear_tape_list(tape_list);
297 amfree(tape_list->date);
298 amfree(tape_list->tape);
309 /* return the number of files on a tape's list */
312 EXTRACT_LIST *tape_list)
314 EXTRACT_LIST_ITEM *fn;
318 for (fn = tape_list->files; fn != NULL; fn = fn->next)
326 clear_extract_list(void)
328 while (extract_list != NULL)
329 delete_tape_list(extract_list);
335 EXTRACT_LIST *tape_list)
337 EXTRACT_LIST_ITEM *fn1, *pfn1, *ofn1;
338 EXTRACT_LIST_ITEM *fn2, *pfn2, *ofn2;
343 fn1 = tape_list->files;
344 while (fn1 != NULL) {
349 while (fn2 != NULL && remove_fn1 == 0) {
351 if(strcmp(fn1->path, fn2->path) == 0) {
353 } else if (strncmp(fn1->path, fn2->path, strlen(fn1->path)) == 0 &&
354 ((strlen(fn2->path) > strlen(fn1->path) &&
355 fn2->path[strlen(fn1->path)] == '/') ||
356 (fn1->path[strlen(fn1->path)-1] == '/'))) {
358 } else if (strncmp(fn2->path, fn1->path, strlen(fn2->path)) == 0 &&
359 ((strlen(fn1->path) > strlen(fn2->path) &&
360 fn1->path[strlen(fn2->path)] == '/') ||
361 (fn2->path[strlen(fn2->path)-1] == '/'))) {
367 dbprintf(_("removing path %s, it is included in %s\n"),
368 fn2->path, fn1->path);
374 } else if (remove_fn1 == 0) {
380 if(remove_fn1 != 0) {
381 /* fn2->path is always valid */
382 /*@i@*/ dbprintf(_("removing path %s, it is included in %s\n"),
383 /*@i@*/ fn1->path, fn2->path);
388 amfree(tape_list->files);
389 tape_list->files = fn1;
403 clean_extract_list(void)
407 for (this = extract_list; this != NULL; this = this->next)
408 clean_tape_list(this);
412 int add_to_unlink_list(char *path);
413 int do_unlink_list(void);
414 void free_unlink_list(void);
416 typedef struct s_unlink_list {
418 struct s_unlink_list *next;
420 t_unlink_list *unlink_list = NULL;
429 unlink_list = alloc(SIZEOF(*unlink_list));
430 unlink_list->path = stralloc(path);
431 unlink_list->next = NULL;
433 for (ul = unlink_list; ul != NULL; ul = ul->next) {
434 if (strcmp(ul->path, path) == 0)
437 ul = alloc(SIZEOF(*ul));
438 ul->path = stralloc(path);
439 ul->next = unlink_list;
451 for (ul = unlink_list; ul != NULL; ul = ul->next) {
452 if (unlink(ul->path) < 0) {
453 g_fprintf(stderr,_("Can't unlink %s: %s\n"), ul->path, strerror(errno));
462 free_unlink_list(void)
464 t_unlink_list *ul, *ul1;
466 for (ul = unlink_list; ul != NULL; ul = ul1) {
478 check_file_overwrite(
482 EXTRACT_LIST_ITEM *fn;
483 struct stat stat_buf;
487 for (this = extract_list; this != NULL; this = this->next) {
488 for (fn = this->files; fn != NULL ; fn = fn->next) {
490 /* Check path component of fn->path */
492 path = stralloc2(dir, fn->path);
493 if (path[strlen(path)-1] == '/') {
494 path[strlen(path)-1] = '\0';
497 s = path + strlen(dir) + 1;
498 while((s = strchr(s, '/'))) {
500 if (lstat(path, &stat_buf) == 0) {
501 if(!S_ISDIR(stat_buf.st_mode)) {
502 if (add_to_unlink_list(path)) {
503 g_printf(_("WARNING: %s is not a directory, "
504 "it will be deleted.\n"),
509 else if (errno != ENOENT) {
510 g_printf(_("Can't stat %s: %s\n"), path, strerror(errno));
519 filename = stralloc2(dir, fn->path);
520 if (filename[strlen(filename)-1] == '/') {
521 filename[strlen(filename)-1] = '\0';
524 if (lstat(filename, &stat_buf) == 0) {
525 if(S_ISDIR(stat_buf.st_mode)) {
526 if(!is_empty_dir(filename)) {
527 g_printf(_("WARNING: All existing files in %s "
528 "will be deleted.\n"), filename);
530 } else if(S_ISREG(stat_buf.st_mode)) {
531 g_printf(_("WARNING: Existing file %s will be overwritten\n"),
534 if (add_to_unlink_list(filename)) {
535 g_printf(_("WARNING: Existing entry %s will be deleted\n"),
539 } else if (errno != ENOENT) {
540 g_printf(_("Can't stat %s: %s\n"), filename, strerror(errno));
548 /* returns -1 if error */
549 /* returns 0 on succes */
550 /* returns 1 if already added */
555 EXTRACT_LIST *this, *this1;
556 EXTRACT_LIST_ITEM *that, *curr;
557 char *ditem_path = NULL;
559 ditem_path = stralloc(ditem->path);
560 clean_pathname(ditem_path);
562 for (this = extract_list; this != NULL; this = this->next)
564 /* see if this is the list for the tape */
565 if (this->level == ditem->level && strcmp(this->tape, ditem->tape) == 0)
567 /* yes, so add to list */
571 if (strcmp(curr->path,ditem_path) == 0) {
577 that = (EXTRACT_LIST_ITEM *)alloc(sizeof(EXTRACT_LIST_ITEM));
578 that->path = stralloc(ditem_path);
579 that->next = this->files;
580 this->files = that; /* add at front since easiest */
586 /* so this is the first time we have seen this tape */
587 this = (EXTRACT_LIST *)alloc(sizeof(EXTRACT_LIST));
588 this->tape = stralloc(ditem->tape);
589 this->level = ditem->level;
590 this->fileno = ditem->fileno;
591 this->date = stralloc(ditem->date);
592 that = (EXTRACT_LIST_ITEM *)alloc(sizeof(EXTRACT_LIST_ITEM));
593 that->path = stralloc(ditem_path);
597 /* add this in date increasing order */
598 /* because restore must be done in this order */
599 /* add at begining */
600 if(extract_list==NULL || strcmp(this->date,extract_list->date) < 0)
602 this->next = extract_list;
607 for (this1 = extract_list; this1->next != NULL; this1 = this1->next)
609 /* add in the middle */
610 if(strcmp(this->date,this1->next->date) < 0)
612 this->next = this1->next;
626 /* returns -1 if error */
627 /* returns 0 on deletion */
628 /* returns 1 if not there */
634 EXTRACT_LIST_ITEM *that, *prev;
635 char *ditem_path = NULL;
637 ditem_path = stralloc(ditem->path);
638 clean_pathname(ditem_path);
640 for (this = extract_list; this != NULL; this = this->next)
642 /* see if this is the list for the tape */
643 if (this->level == ditem->level && strcmp(this->tape, ditem->tape) == 0)
645 /* yes, so find file on list */
647 if (strcmp(that->path, ditem_path) == 0)
650 this->files = that->next;
653 /* if list empty delete it */
654 if (this->files == NULL)
655 delete_tape_list(this);
663 if (strcmp(that->path, ditem_path) == 0)
665 prev->next = that->next;
691 char *uqglob = unquote_string(glob);
693 regex = glob_to_regex(uqglob);
694 dbprintf(_("add_glob (%s) -> %s\n"), uqglob, regex);
695 if ((s = validate_regexp(regex)) != NULL) {
696 g_printf(_("%s is not a valid shell wildcard pattern: "), glob);
700 * glob_to_regex() anchors the beginning of the pattern with ^,
701 * but we will be tacking it onto the end of the current directory
702 * in add_file, so strip that off. Also, it anchors the end with
703 * $, but we need to match an optional trailing /, so tack that on
706 regex_path = stralloc(regex + 1);
707 regex_path[strlen(regex_path) - 1] = '\0';
708 strappend(regex_path, "[/]*$");
709 add_file(uqglob, regex_path);
721 char *uqregex = unquote_string(regex);
723 if ((s = validate_regexp(uqregex)) != NULL) {
724 g_printf(_("\"%s\" is not a valid regular expression: "), regex);
727 add_file(uqregex, regex);
737 DIR_ITEM *ditem, lditem;
738 char *path_on_disk = NULL;
743 char *dir, *dir_undo, dir_undo_ch = '\0';
744 char *ditem_path = NULL;
745 char *qditem_path = NULL;
748 char *s, *fp, *quoted;
753 if (disk_path == NULL) {
754 g_printf(_("Must select directory before adding files\n"));
757 memset(&lditem, 0, sizeof(lditem)); /* Prevent use of bogus data... */
759 dbprintf(_("add_file: Looking for \"%s\"\n"), regex);
761 if(strcmp(regex, "/[/]*$") == 0) { /* "/" behave like "." */
764 else if(strcmp(regex, "[^/]*[/]*$") == 0) { /* "*" */
765 regex = "([^/.]|\\.[^/]+|[^/.][^/]*)[/]*$";
767 /* remove "/" at end of path */
768 j = (ssize_t)(strlen(regex) - 1);
769 while(j >= 0 && regex[j] == '/')
773 /* convert path (assumed in cwd) to one on disk */
774 if (strcmp(disk_path, "/") == 0) {
776 /* No mods needed if already starts with '/' */
777 path_on_disk = stralloc(regex);
780 path_on_disk = stralloc2("/", regex);
783 char *clean_disk_path = clean_regex(disk_path);
784 path_on_disk = vstralloc(clean_disk_path, "/", regex, NULL);
785 amfree(clean_disk_path);
788 dbprintf(_("add_file: Converted path=\"%s\" to path_on_disk=\"%s\"\n"),
789 regex, path_on_disk);
793 for (ditem=get_dir_list(); ditem!=NULL; ditem=get_next_dir_item(ditem))
796 quoted = quote_string(ditem->path);
797 dbprintf(_("add_file: Pondering ditem->path=%s\n"), quoted);
799 if (match(path_on_disk, ditem->path))
802 j = (ssize_t)strlen(ditem->path);
803 if((j > 0 && ditem->path[j-1] == '/')
804 || (j > 1 && ditem->path[j-2] == '/' && ditem->path[j-1] == '.'))
805 { /* It is a directory */
806 ditem_path = newstralloc(ditem_path, ditem->path);
807 clean_pathname(ditem_path);
809 qditem_path = quote_string(ditem_path);
810 cmd = newstralloc2(cmd, "ORLD ", qditem_path);
812 if(send_command(cmd) == -1) {
815 amfree(path_on_disk);
821 if ((i = get_reply_line()) == -1) {
823 amfree(path_on_disk);
826 if(i==0) { /* assume something wrong */
828 amfree(path_on_disk);
835 lditem.path = newstralloc(lditem.path, ditem->path);
836 /* skip the last line -- duplicate of the preamble */
838 while ((i = get_reply_line()) != 0) {
841 amfree(path_on_disk);
846 if(dir_undo) *dir_undo = dir_undo_ch;
848 cmd = stralloc(l); /* save for error report */
850 continue; /* throw the rest of the lines away */
853 if (!server_happy()) {
859 if(strncmp_const_skip(l, "201-", s, ch) != 0) {
860 err = _("bad reply: not 201-");
865 skip_whitespace(s, ch);
867 err = _("bad reply: missing date field");
871 skip_non_whitespace(s, ch);
873 lditem.date = newstralloc(lditem.date, fp);
876 skip_whitespace(s, ch);
877 if(ch == '\0' || sscanf(s - 1, "%d", &lditem.level) != 1) {
878 err = _("bad reply: cannot parse level field");
883 skip_whitespace(s, ch);
885 err = _("bad reply: missing tape field");
889 skip_non_whitespace(s, ch);
891 lditem.tape = newstralloc(lditem.tape, fp);
894 if(am_has_feature(indexsrv_features, fe_amindexd_fileno_in_ORLD)) {
895 long long fileno_ = (long long)0;
896 skip_whitespace(s, ch);
898 sscanf(s - 1, "%lld", &fileno_) != 1) {
899 err = _("bad reply: cannot parse fileno field");
902 lditem.fileno = (off_t)fileno_;
906 skip_whitespace(s, ch);
908 err = _("bad reply: missing directory field");
912 skip_quoted_string(s, ch);
914 dir_undo_ch = *dir_undo;
917 switch(add_extract_item(&lditem)) {
919 g_printf(_("System error\n"));
920 dbprintf(_("add_file: (Failed) System error\n"));
924 quoted = quote_string(lditem.path);
925 g_printf(_("Added dir %s at date %s\n"),
926 quoted, lditem.date);
927 dbprintf(_("add_file: (Successful) Added dir %s at date %s\n"),
928 quoted, lditem.date);
937 if(!server_happy()) {
944 } else if(added == 0) {
945 quoted = quote_string(ditem_path);
946 g_printf(_("dir %s already added\n"), quoted);
947 dbprintf(_("add_file: dir %s already added\n"), quoted);
951 else /* It is a file */
953 switch(add_extract_item(ditem)) {
955 g_printf(_("System error\n"));
956 dbprintf(_("add_file: (Failed) System error\n"));
960 quoted = quote_string(ditem->path);
961 g_printf(_("Added file %s\n"), quoted);
962 dbprintf(_("add_file: (Successful) Added %s\n"), quoted);
967 quoted = quote_string(ditem->path);
968 g_printf(_("File %s already added\n"), quoted);
969 dbprintf(_("add_file: file %s already added\n"), quoted);
978 amfree(path_on_disk);
985 quoted = quote_string(path);
986 g_printf(_("File %s doesn't exist in directory\n"), quoted);
987 dbprintf(_("add_file: (Failed) File %s doesn't exist in directory\n"),
1001 char *uqglob = unquote_string(glob);
1003 regex = glob_to_regex(uqglob);
1004 dbprintf(_("delete_glob (%s) -> %s\n"), uqglob, regex);
1005 if ((s = validate_regexp(regex)) != NULL) {
1006 g_printf(_("\"%s\" is not a valid shell wildcard pattern: "), glob);
1010 * glob_to_regex() anchors the beginning of the pattern with ^,
1011 * but we will be tacking it onto the end of the current directory
1012 * in add_file, so strip that off. Also, it anchors the end with
1013 * $, but we need to match an optional trailing /, so tack that on
1016 regex_path = stralloc(regex + 1);
1017 regex_path[strlen(regex_path) - 1] = '\0';
1018 strappend(regex_path, "[/]*$");
1019 delete_file(uqglob, regex_path);
1031 char *uqregex = unquote_string(regex);
1033 if ((s = validate_regexp(regex)) != NULL) {
1034 g_printf(_("\"%s\" is not a valid regular expression: "), regex);
1037 delete_file(uqregex, uqregex);
1047 DIR_ITEM *ditem, lditem;
1048 char *path_on_disk = NULL;
1054 char *tape, *tape_undo, tape_undo_ch = '\0';
1055 char *dir_undo, dir_undo_ch = '\0';
1058 char *ditem_path = NULL;
1067 if (disk_path == NULL) {
1068 g_printf(_("Must select directory before deleting files\n"));
1071 memset(&lditem, 0, sizeof(lditem)); /* Prevent use of bogus data... */
1073 dbprintf(_("delete_file: Looking for \"%s\"\n"), path);
1075 if (strcmp(regex, "[^/]*[/]*$") == 0) {
1076 /* Looking for * find everything but single . */
1077 regex = "([^/.]|\\.[^/]+|[^/.][^/]*)[/]*$";
1079 /* remove "/" at end of path */
1080 j = (ssize_t)(strlen(regex) - 1);
1081 while(j >= 0 && regex[j] == '/') regex[j--] = '\0';
1084 /* convert path (assumed in cwd) to one on disk */
1085 if (strcmp(disk_path, "/") == 0) {
1086 if (*regex == '/') {
1087 if (strcmp(regex, "/[/]*$") == 0) {
1088 /* We want "/" to match the directory itself: "/." */
1089 path_on_disk = stralloc("/\\.[/]*$");
1091 /* No mods needed if already starts with '/' */
1092 path_on_disk = stralloc(regex);
1096 path_on_disk = stralloc2("/", regex);
1099 char *clean_disk_path = clean_regex(disk_path);
1100 path_on_disk = vstralloc(clean_disk_path, "/", regex, NULL);
1101 amfree(clean_disk_path);
1104 dbprintf(_("delete_file: Converted path=\"%s\" to path_on_disk=\"%s\"\n"),
1105 regex, path_on_disk);
1107 for (ditem=get_dir_list(); ditem!=NULL; ditem=get_next_dir_item(ditem))
1109 quoted = quote_string(ditem->path);
1110 dbprintf(_("delete_file: Pondering ditem->path=%s\n"), quoted);
1112 if (match(path_on_disk, ditem->path))
1115 j = (ssize_t)strlen(ditem->path);
1116 if((j > 0 && ditem->path[j-1] == '/')
1117 || (j > 1 && ditem->path[j-2] == '/' && ditem->path[j-1] == '.'))
1118 { /* It is a directory */
1119 ditem_path = newstralloc(ditem_path, ditem->path);
1120 clean_pathname(ditem_path);
1122 qditem_path = quote_string(ditem_path);
1123 cmd = newstralloc2(cmd, "ORLD ", qditem_path);
1124 amfree(qditem_path);
1125 if(send_command(cmd) == -1) {
1128 amfree(path_on_disk);
1133 if ((i = get_reply_line()) == -1) {
1135 amfree(path_on_disk);
1138 if(i==0) /* assume something wrong */
1141 amfree(path_on_disk);
1143 g_printf("%s\n", l);
1147 lditem.path = newstralloc(lditem.path, ditem->path);
1149 tape_undo = dir_undo = NULL;
1150 /* skip the last line -- duplicate of the preamble */
1151 while ((i = get_reply_line()) != 0)
1155 amfree(path_on_disk);
1160 if(tape_undo) *tape_undo = tape_undo_ch;
1161 if(dir_undo) *dir_undo = dir_undo_ch;
1162 tape_undo = dir_undo = NULL;
1163 cmd = stralloc(l); /* save for the error report */
1165 continue; /* throw the rest of the lines away */
1168 if (!server_happy()) {
1174 if(strncmp_const_skip(l, "201-", s, ch) != 0) {
1175 err = _("bad reply: not 201-");
1180 skip_whitespace(s, ch);
1182 err = _("bad reply: missing date field");
1186 skip_non_whitespace(s, ch);
1189 skip_whitespace(s, ch);
1190 if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
1191 err = _("bad reply: cannot parse level field");
1194 skip_integer(s, ch);
1196 skip_whitespace(s, ch);
1198 err = _("bad reply: missing tape field");
1202 skip_non_whitespace(s, ch);
1204 tape_undo_ch = *tape_undo;
1207 if(am_has_feature(indexsrv_features, fe_amindexd_fileno_in_ORLD)) {
1208 long long fileno_ = (long long)0;
1209 skip_whitespace(s, ch);
1211 sscanf(s - 1, "%lld", &fileno_) != 1) {
1212 err = _("bad reply: cannot parse fileno field");
1215 fileno = (off_t)fileno_;
1216 skip_integer(s, ch);
1219 skip_whitespace(s, ch);
1221 err = _("bad reply: missing directory field");
1224 skip_non_whitespace(s, ch);
1226 dir_undo_ch = *dir_undo;
1229 lditem.date = newstralloc(lditem.date, date);
1231 lditem.tape = newstralloc(lditem.tape, tape);
1232 switch(delete_extract_item(&lditem)) {
1234 g_printf(_("System error\n"));
1235 dbprintf(_("delete_file: (Failed) System error\n"));
1238 g_printf(_("Deleted dir %s at date %s\n"), ditem_path, date);
1239 dbprintf(_("delete_file: (Successful) Deleted dir %s at date %s\n"),
1247 if(!server_happy()) {
1254 } else if(deleted == 0) {
1255 g_printf(_("Warning - dir '%s' not on tape list\n"),
1257 dbprintf(_("delete_file: dir '%s' not on tape list\n"),
1263 switch(delete_extract_item(ditem)) {
1265 g_printf(_("System error\n"));
1266 dbprintf(_("delete_file: (Failed) System error\n"));
1269 g_printf(_("Deleted %s\n"), ditem->path);
1270 dbprintf(_("delete_file: (Successful) Deleted %s\n"),
1274 g_printf(_("Warning - file '%s' not on tape list\n"),
1276 dbprintf(_("delete_file: file '%s' not on tape list\n"),
1285 amfree(path_on_disk);
1288 g_printf(_("File %s doesn't exist in directory\n"), path);
1289 dbprintf(_("delete_file: (Failed) File %s doesn't exist in directory\n"),
1295 /* print extract list into file. If NULL ptr passed print to screen */
1297 display_extract_list(
1301 EXTRACT_LIST_ITEM *that;
1304 char *pager_command;
1309 if ((pager = getenv("PAGER")) == NULL)
1314 * Set up the pager command so if the pager is terminated, we do
1315 * not get a SIGPIPE back.
1317 pager_command = stralloc2(pager, " ; /bin/cat > /dev/null");
1318 if ((fp = popen(pager_command, "w")) == NULL)
1320 g_printf(_("Warning - can't pipe through %s\n"), pager);
1323 amfree(pager_command);
1327 uqfile = unquote_string(file);
1328 if ((fp = fopen(uqfile, "w")) == NULL)
1330 g_printf(_("Can't open file %s to print extract list into\n"), file);
1337 for (this = extract_list; this != NULL; this = this->next)
1339 g_fprintf(fp, _("TAPE %s LEVEL %d DATE %s\n"),
1340 this->tape, this->level, this->date);
1341 for (that = this->files; that != NULL; that = that->next)
1342 g_fprintf(fp, "\t%s\n", that->path);
1348 g_printf(_("Extract list written to file %s\n"), file);
1359 struct dirent *entry;
1362 if((dir = opendir(fname)) == NULL)
1366 while(!gotentry && (entry = readdir(dir)) != NULL) {
1367 gotentry = !is_dot_or_dotdot(entry->d_name);
1375 /* returns 0 if extract list empty and 1 if it isn't */
1377 is_extract_list_nonempty(void)
1379 return (extract_list != NULL);
1383 /* prints continue prompt and waits for response,
1384 returns 0 if don't, non-0 if do */
1401 prompt = _("New device name [?]: ");
1402 } else if (allow_tape && allow_skip) {
1403 prompt = _("Continue [?/Y/n/s/d]? ");
1404 } else if (allow_tape && !allow_skip) {
1405 prompt = _("Continue [?/Y/n/d]? ");
1406 } else if (allow_retry) {
1407 prompt = _("Continue [?/Y/n/r]? ");
1409 prompt = _("Continue [?/Y/n]? ");
1411 fputs(prompt, stdout);
1412 fflush(stdout); fflush(stderr);
1414 if ((line = agets(stdin)) == NULL) {
1424 dbprintf("User prompt: '%s'; response: '%s'\n", prompt, line);
1427 while ((ch = *s++) != '\0' && isspace(ch)) {
1428 (void)ch; /* Quiet empty loop compiler warning */
1432 g_printf(_("Enter a new device name or \"default\"\n"));
1434 g_printf(_("Enter \"y\"es to continue, \"n\"o to stop"));
1436 g_printf(_(", \"s\"kip this tape"));
1439 g_printf(_(" or \"r\"etry this tape"));
1442 g_printf(_(" or \"d\" to change to a new device"));
1446 } else if (get_device) {
1447 char *tmp = stralloc(tape_server_name);
1449 if (strncmp_const(s - 1, "default") == 0) {
1450 set_device(tmp, NULL); /* default device, existing host */
1451 } else if (s[-1] != '\0') {
1452 set_device(tmp, s - 1); /* specified device, existing host */
1454 g_printf(_("No change.\n"));
1460 } else if (ch == '\0' || ch == 'Y' || ch == 'y') {
1462 } else if (allow_tape && (ch == 'D' || ch == 'd' || ch == 'T' || ch == 't')) {
1463 get_device = 1; /* ('T' and 't' are for backward-compatibility) */
1464 } else if (ch == 'N' || ch == 'n') {
1466 } else if (allow_retry && (ch == 'R' || ch == 'r')) {
1468 } else if (allow_skip && (ch == 'S' || ch == 's')) {
1479 send_to_tape_server(
1480 security_stream_t * stream,
1483 char *msg = stralloc2(cmd, "\r\n");
1485 if (security_stream_write(stream, msg, strlen(msg)) < 0)
1487 error(_("Error writing to tape server"));
1495 /* start up connection to tape server and set commands to initiate
1496 transfer of dump image.
1497 Return tape server socket on success, -1 on error. */
1499 extract_files_setup(
1503 char *disk_regex = NULL;
1504 char *host_regex = NULL;
1505 char *clean_datestamp, *ch, *ch1;
1510 amidxtaped_secdrv = security_getdriver(authopt);
1511 if (amidxtaped_secdrv == NULL) {
1512 error(_("no '%s' security driver available for host '%s'"),
1513 authopt, tape_server_name);
1516 /* We assume that amidxtaped support fe_amidxtaped_options_features */
1517 /* and fe_amidxtaped_options_auth */
1518 /* We should send a noop to really know */
1519 req = vstralloc("SERVICE amidxtaped\n",
1520 "OPTIONS ", "features=", our_features_string, ";",
1521 "auth=", authopt, ";",
1523 protocol_sendreq(tape_server_name, amidxtaped_secdrv,
1524 generic_client_get_security_conf, req, STARTUP_TIMEOUT,
1525 amidxtaped_response, &response_error);
1528 if(response_error != 0) {
1532 disk_regex = alloc(strlen(disk_name) * 2 + 3);
1537 /* we want to force amrestore to only match disk_name exactly */
1540 /* We need to escape some characters first... NT compatibilty crap */
1541 for (; *ch != 0; ch++, ch1++) {
1542 switch (*ch) { /* done this way in case there are more */
1545 /* no break; we do want to fall through... */
1551 /* we want to force amrestore to only match disk_name exactly */
1556 host_regex = alloc(strlen(dump_hostname) * 2 + 3);
1561 /* we want to force amrestore to only match dump_hostname exactly */
1564 /* We need to escape some characters first... NT compatibilty crap */
1565 for (; *ch != 0; ch++, ch1++) {
1566 switch (*ch) { /* done this way in case there are more */
1569 /* no break; we do want to fall through... */
1575 /* we want to force amrestore to only match dump_hostname exactly */
1580 clean_datestamp = stralloc(dump_datestamp);
1581 for(ch=ch1=clean_datestamp;*ch1 != '\0';ch1++) {
1588 /* push our feature list off to the tape server */
1589 /* XXX assumes that index server and tape server are equivalent, ew */
1591 if(am_has_feature(indexsrv_features, fe_amidxtaped_exchange_features)){
1592 tt = newstralloc2(tt, "FEATURES=", our_features_string);
1593 send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt);
1594 get_amidxtaped_line();
1595 if(strncmp_const(amidxtaped_line,"FEATURES=") == 0) {
1596 tapesrv_features = am_string_to_feature(amidxtaped_line+9);
1598 g_fprintf(stderr, _("amrecover - expecting FEATURES line from amidxtaped\n"));
1602 amfree(clean_datestamp);
1605 am_release_feature_set(tapesrv_features);
1609 if(am_has_feature(indexsrv_features, fe_amidxtaped_header) &&
1610 am_has_feature(indexsrv_features, fe_amidxtaped_device) &&
1611 am_has_feature(indexsrv_features, fe_amidxtaped_host) &&
1612 am_has_feature(indexsrv_features, fe_amidxtaped_disk) &&
1613 am_has_feature(indexsrv_features, fe_amidxtaped_datestamp)) {
1615 if(am_has_feature(indexsrv_features, fe_amidxtaped_config)) {
1616 tt = newstralloc2(tt, "CONFIG=", config_name);
1617 send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt);
1619 if(am_has_feature(indexsrv_features, fe_amidxtaped_label) &&
1620 label && label[0] != '/') {
1621 tt = newstralloc2(tt,"LABEL=",label);
1622 send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt);
1624 if(am_has_feature(indexsrv_features, fe_amidxtaped_fsf)) {
1626 g_snprintf(v_fsf, 99, "%lld", (long long)fsf);
1627 tt = newstralloc2(tt, "FSF=",v_fsf);
1628 send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt);
1630 send_to_tape_server(amidxtaped_streams[CTLFD].fd, "HEADER");
1631 tt = newstralloc2(tt, "DEVICE=", dump_device_name);
1632 send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt);
1633 tt = newstralloc2(tt, "HOST=", host_regex);
1634 send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt);
1635 tt = newstralloc2(tt, "DISK=", disk_regex);
1636 send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt);
1637 tt = newstralloc2(tt, "DATESTAMP=", clean_datestamp);
1638 send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt);
1639 send_to_tape_server(amidxtaped_streams[CTLFD].fd, "END");
1642 else if(am_has_feature(indexsrv_features, fe_amidxtaped_nargs)) {
1643 /* send to the tape server what tape file we want */
1652 send_to_tape_server(amidxtaped_streams[CTLFD].fd, "6");
1653 send_to_tape_server(amidxtaped_streams[CTLFD].fd, "-h");
1654 send_to_tape_server(amidxtaped_streams[CTLFD].fd, "-p");
1655 send_to_tape_server(amidxtaped_streams[CTLFD].fd, dump_device_name);
1656 send_to_tape_server(amidxtaped_streams[CTLFD].fd, host_regex);
1657 send_to_tape_server(amidxtaped_streams[CTLFD].fd, disk_regex);
1658 send_to_tape_server(amidxtaped_streams[CTLFD].fd, clean_datestamp);
1660 dbprintf(_("Started amidxtaped with arguments \"6 -h -p %s %s %s %s\"\n"),
1661 dump_device_name, host_regex, disk_regex, clean_datestamp);
1666 amfree(clean_datestamp);
1673 * Reads the first block of a tape file.
1684 bytes_read = read_buffer(tapedev, buffer, buflen, READ_TIMEOUT);
1685 if(bytes_read < 0) {
1686 error(_("error reading header (%s), check amidxtaped.*.debug on server"),
1691 if((size_t)bytes_read < buflen) {
1692 g_fprintf(stderr, plural(_("%s: short block %d byte\n"),
1693 _("%s: short block %d bytes\n"), bytes_read),
1694 get_pname(), (int)bytes_read);
1695 print_header(stdout, file);
1696 error(_("Can't read file header"));
1700 /* bytes_read == buflen */
1701 parse_file_header(buffer, file, (size_t)bytes_read);
1715 extract_files_child(
1717 EXTRACT_LIST * elist)
1720 int extra_params = 0;
1722 char **restore_args = NULL;
1724 EXTRACT_LIST_ITEM *fn;
1725 enum dumptypes dumptype = IS_UNKNOWN;
1726 char buffer[DISK_BLOCK_BYTES];
1730 int passwd_field = -1;
1732 char *domain = NULL, *smbpass = NULL;
1735 /* code executed by child to do extraction */
1738 /* make in_fd be our stdin */
1739 if (dup2(in_fd, STDIN_FILENO) == -1)
1741 error(_("dup2 failed in extract_files_child: %s"), strerror(errno));
1745 /* read the file header */
1747 read_file_header(buffer, &file, sizeof(buffer), STDIN_FILENO);
1749 if(file.type != F_DUMPFILE) {
1750 print_header(stdout, &file);
1751 error(_("bad header"));
1755 if (file.program != NULL) {
1756 if (strcmp(file.program, "BACKUP") == 0)
1757 dumptype = IS_BACKUP_API;
1759 if (strcmp(file.program, GNUTAR) == 0)
1760 dumptype = IS_GNUTAR;
1763 if (dumptype == IS_UNKNOWN) {
1764 len_program = strlen(file.program);
1765 if(len_program >= 3 &&
1766 strcmp(&file.program[len_program-3],"tar") == 0)
1771 if (dumptype == IS_UNKNOWN && strcmp(file.program, SAMBA_CLIENT) ==0) {
1772 if (samba_extract_method == SAMBA_TAR)
1773 dumptype = IS_SAMBA_TAR;
1775 dumptype = IS_SAMBA;
1780 /* form the arguments to restore */
1781 files_off_tape = length_of_tape_list(elist);
1800 #if defined(XFSDUMP)
1801 if (strcmp(file.program, XFSDUMP) == 0) {
1802 extra_params = 4 + files_off_tape;
1814 restore_args = (char **)alloc((size_t)((extra_params + files_off_tape + 1)
1819 restore_args[j++] = stralloc("smbclient");
1820 smbpass = findpass(file.disk, &domain);
1822 restore_args[j++] = stralloc(file.disk);
1824 restore_args[j++] = stralloc("-U");
1825 restore_args[j++] = smbpass;
1827 restore_args[j++] = stralloc("-W");
1828 restore_args[j++] = stralloc(domain);
1833 restore_args[j++] = stralloc("-d0");
1834 restore_args[j++] = stralloc("-Tx");
1835 restore_args[j++] = stralloc("-"); /* data on stdin */
1840 restore_args[j++] = stralloc("tar");
1841 restore_args[j++] = stralloc("--numeric-owner");
1842 restore_args[j++] = stralloc("-xpGvf");
1843 restore_args[j++] = stralloc("-"); /* data on stdin */
1846 restore_args[j++] = stralloc("tar");
1847 restore_args[j++] = stralloc("-xpvf");
1848 restore_args[j++] = stralloc("-"); /* data on stdin */
1852 restore_args[j++] = stralloc("restore");
1854 restore_args[j++] = stralloc("-xB");
1856 #if defined(XFSDUMP)
1857 if (strcmp(file.program, XFSDUMP) == 0) {
1858 restore_args[j++] = stralloc("-v");
1859 restore_args[j++] = stralloc("silent");
1863 if (strcmp(file.program, VDUMP) == 0) {
1864 restore_args[j++] = stralloc("xf");
1865 restore_args[j++] = stralloc("-"); /* data on stdin */
1869 restore_args[j++] = stralloc("xbf");
1870 restore_args[j++] = stralloc("2"); /* read in units of 1K */
1871 restore_args[j++] = stralloc("-"); /* data on stdin */
1876 restore_args[j++] = stralloc(file.dumper);
1877 restore_args[j++] = stralloc("restore");
1878 restore_args[j++] = stralloc("--config");
1879 restore_args[j++] = stralloc(config_name);
1880 restore_args[j++] = stralloc("--disk");
1881 restore_args[j++] = stralloc(file.disk);
1885 for (i = 0, fn = elist->files; i < files_off_tape; i++, fn = fn->next)
1893 if (strcmp(fn->path, "/") == 0)
1894 restore_args[j++] = stralloc(".");
1896 restore_args[j++] = stralloc2(".", fn->path);
1900 #if defined(XFSDUMP)
1901 if (strcmp(file.program, XFSDUMP) == 0) {
1903 * xfsrestore needs a -s option before each file to be
1904 * restored, and also wants them to be relative paths.
1906 restore_args[j++] = stralloc("-s");
1907 restore_args[j++] = stralloc(fn->path + 1);
1911 restore_args[j++] = stralloc(fn->path);
1916 #if defined(XFSDUMP)
1917 if (strcmp(file.program, XFSDUMP) == 0) {
1918 restore_args[j++] = stralloc("-");
1919 restore_args[j++] = stralloc(".");
1922 restore_args[j] = NULL;
1927 cmd = stralloc(SAMBA_CLIENT);
1930 /* fall through to ... */
1936 g_fprintf(stderr, _("warning: GNUTAR program not available.\n"));
1937 cmd = stralloc("tar");
1939 cmd = stralloc(GNUTAR);
1946 if (strcmp(file.program, DUMP) == 0) {
1947 cmd = stralloc(RESTORE);
1951 if (strcmp(file.program, VDUMP) == 0) {
1952 cmd = stralloc(VRESTORE);
1956 if (strcmp(file.program, VXDUMP) == 0) {
1957 cmd = stralloc(VXRESTORE);
1960 #if defined(XFSDUMP)
1961 if (strcmp(file.program, XFSDUMP) == 0) {
1962 cmd = stralloc(XFSRESTORE);
1966 g_fprintf(stderr, _("warning: restore program for %s not available.\n"),
1968 cmd = stralloc("restore");
1972 cmd = vstralloc(DUMPER_DIR, "/", file.dumper, NULL);
1976 dbprintf(_("Exec'ing %s with arguments:\n"), cmd);
1977 for (i = 0; i < j; i++) {
1978 if( i == passwd_field)
1979 dbprintf("\tXXXXX\n");
1981 dbprintf(_("\t%s\n"), restore_args[i]);
1984 (void)execv(cmd, restore_args);
1985 /* only get here if exec failed */
1987 for (i = 0; i < j; i++) {
1988 amfree(restore_args[i]);
1990 amfree(restore_args);
1992 perror(_("amrecover couldn't exec"));
1993 g_fprintf(stderr, _(" problem executing %s\n"), cmd);
2001 * Interpose something between the process writing out the dump (writing it to
2002 * some extraction program, really) and the socket from which we're reading, so
2003 * that we can do things like prompt for human interaction for multiple tapes.
2006 writer_intermediary(
2007 EXTRACT_LIST * elist)
2011 amwait_t extractor_status;
2013 if(pipe(child_pipe) == -1) {
2014 error(_("extract_list - error setting up pipe to extractor: %s\n"),
2019 /* okay, ready to extract. fork a child to do the actual work */
2020 if ((pid = fork()) == 0) {
2021 /* this is the child process */
2022 /* never gets out of this clause */
2023 aclose(child_pipe[1]);
2024 extract_files_child(child_pipe[0], elist);
2028 /* This is the parent */
2030 g_printf(_("writer_intermediary - error forking child"));
2034 aclose(child_pipe[0]);
2036 security_stream_read(amidxtaped_streams[DATAFD].fd,
2037 read_amidxtaped_data, &(child_pipe[1]));
2039 while(get_amidxtaped_line() >= 0) {
2040 char desired_tape[MAX_TAPE_LABEL_BUF];
2042 /* if prompted for a tape, relay said prompt to the user */
2043 if(sscanf(amidxtaped_line, "FEEDME %132s\n", desired_tape) == 1) {
2045 g_printf(_("Load tape %s now\n"), desired_tape);
2046 dbprintf(_("Requesting tape %s from user\n"), desired_tape);
2047 done = okay_to_continue(am_has_feature(indexsrv_features,
2048 fe_amrecover_feedme_tape),
2051 if (am_has_feature(indexsrv_features,
2052 fe_amrecover_feedme_tape)) {
2053 char *reply = stralloc2("TAPE ", tape_device_name);
2054 send_to_tape_server(amidxtaped_streams[CTLFD].fd, reply);
2057 send_to_tape_server(amidxtaped_streams[CTLFD].fd, "OK");
2060 send_to_tape_server(amidxtaped_streams[CTLFD].fd, "ERROR");
2063 } else if(strncmp_const(amidxtaped_line, "MESSAGE ") == 0) {
2064 g_printf("%s\n",&amidxtaped_line[8]);
2066 g_fprintf(stderr, _("Strange message from tape server: %s"),
2072 /* CTL might be close before DATA */
2074 aclose(child_pipe[1]);
2076 waitpid(pid, &extractor_status, 0);
2077 if(WEXITSTATUS(extractor_status) != 0){
2078 int ret = WEXITSTATUS(extractor_status);
2079 if(ret == 255) ret = -1;
2080 g_printf(_("Extractor child exited with status %d\n"), ret);
2086 /* exec restore to do the actual restoration */
2088 /* does the actual extraction of files */
2090 * The original design had the dump image being returned exactly as it
2091 * appears on the tape, and this routine getting from the index server
2092 * whether or not it is compressed, on the assumption that the tape
2093 * server may not know how to uncompress it. But
2094 * - Amrestore can't do that. It returns either compressed or uncompressed
2095 * (always). Amrestore assumes it can uncompress files. It is thus a good
2096 * idea to run the tape server on a machine with gzip.
2097 * - The information about compression in the disklist is really only
2098 * for future dumps. It is possible to change compression on a drive
2099 * so the information in the disklist may not necessarily relate to
2100 * the dump image on the tape.
2101 * Consequently the design was changed to assuming that amrestore can
2102 * uncompress any dump image and have it return an uncompressed file
2108 EXTRACT_LIST *elist;
2113 tapelist_t *tlist = NULL, *a_tlist;
2115 if (!is_extract_list_nonempty())
2117 g_printf(_("Extract list empty - No files to extract!\n"));
2121 clean_extract_list();
2123 /* get tape device name from index server if none specified */
2124 if (tape_server_name == NULL) {
2125 tape_server_name = newstralloc(tape_server_name, server_name);
2127 if (tape_device_name == NULL) {
2128 if (send_command("TAPE") == -1)
2130 if (get_reply_line() == -1)
2133 if (!server_happy())
2135 g_printf("%s\n", l);
2138 /* skip reply number */
2139 tape_device_name = newstralloc(tape_device_name, l+4);
2142 if (strcmp(tape_device_name, "/dev/null") == 0)
2144 g_printf(_("amrecover: warning: using %s as the tape device will not work\n"),
2149 for (elist = first_tape_list(); elist != NULL; elist = next_tape_list(elist)) {
2150 if(elist->tape[0]!='/') {
2152 g_printf(_("\nExtracting files using tape drive %s on host %s.\n"),
2153 tape_device_name, tape_server_name);
2154 g_printf(_("The following tapes are needed:"));
2159 tlist = unmarshal_tapelist_str(elist->tape);
2160 for(a_tlist = tlist ; a_tlist != NULL; a_tlist = a_tlist->next)
2161 g_printf(" %s", a_tlist->label);
2163 free_tapelist(tlist);
2167 for (elist = first_tape_list(); elist != NULL; elist = next_tape_list(elist)) {
2168 if(elist->tape[0]=='/') {
2170 g_printf(_("\nExtracting files from holding disk on host %s.\n"),
2172 g_printf(_("The following files are needed:"));
2177 tlist = unmarshal_tapelist_str(elist->tape);
2178 for(a_tlist = tlist; a_tlist != NULL; a_tlist = a_tlist->next)
2179 g_printf(" %s", a_tlist->label);
2181 free_tapelist(tlist);
2186 cwd = g_get_current_dir();
2188 perror(_("extract_list: Current working directory unavailable"));
2192 g_printf(_("Restoring files into directory %s\n"), cwd);
2193 check_file_overwrite(cwd);
2196 if (samba_extract_method == SAMBA_SMBCLIENT)
2197 g_printf(_("(unless it is a Samba backup, that will go through to the SMB server)\n"));
2199 dbprintf(_("Checking with user before restoring into directory %s\n"), cwd);
2200 if (!okay_to_continue(0,0,0)) {
2206 if (!do_unlink_list()) {
2207 g_fprintf(stderr, _("Can't recover because I can't cleanup the cwd (%s)\n"),
2214 while ((elist = first_tape_list()) != NULL)
2216 if(elist->tape[0]=='/') {
2217 dump_device_name = newstralloc(dump_device_name, elist->tape);
2218 g_printf(_("Extracting from file "));
2219 tlist = unmarshal_tapelist_str(dump_device_name);
2220 for(a_tlist = tlist; a_tlist != NULL; a_tlist = a_tlist->next)
2221 g_printf(" %s", a_tlist->label);
2223 free_tapelist(tlist);
2226 g_printf(_("Extracting files using tape drive %s on host %s.\n"),
2227 tape_device_name, tape_server_name);
2228 tlist = unmarshal_tapelist_str(elist->tape);
2229 g_printf(_("Load tape %s now\n"), tlist->label);
2230 dbprintf(_("Requesting tape %s from user\n"), tlist->label);
2231 free_tapelist(tlist);
2232 otc = okay_to_continue(1,1,0);
2235 else if (otc == SKIP_TAPE) {
2236 delete_tape_list(elist); /* skip this tape */
2239 dump_device_name = newstralloc(dump_device_name, tape_device_name);
2241 dump_datestamp = newstralloc(dump_datestamp, elist->date);
2243 /* connect to the tape handler daemon on the tape drive server */
2244 if ((extract_files_setup(elist->tape, elist->fileno)) == -1)
2246 g_fprintf(stderr, _("amrecover - can't talk to tape server: %s\n"),
2251 /* if the server have fe_amrecover_feedme_tape, it has asked for
2252 * the tape itself, even if the restore didn't succeed, we should
2255 if(writer_intermediary(elist) == 0 ||
2256 am_has_feature(indexsrv_features, fe_amrecover_feedme_tape))
2257 delete_tape_list(elist); /* tape done so delete from list */
2264 amidxtaped_response(
2267 security_handle_t * sech)
2269 int ports[NSTREAMS], *response_error = datap, i;
2274 assert(response_error != NULL);
2275 assert(sech != NULL);
2276 memset(ports, -1, SIZEOF(ports));
2279 errstr = newvstrallocf(errstr, _("[request failed: %s]"), security_geterror(sech));
2280 *response_error = 1;
2283 security_close_connection(sech, dump_hostname);
2285 if (pkt->type == P_NAK) {
2286 #if defined(PACKET_DEBUG)
2287 g_fprintf(stderr, _("got nak response:\n----\n%s\n----\n\n"), pkt->body);
2290 tok = strtok(pkt->body, " ");
2291 if (tok == NULL || strcmp(tok, "ERROR") != 0)
2294 tok = strtok(NULL, "\n");
2296 errstr = newvstralloc(errstr, "NAK: ", tok, NULL);
2297 *response_error = 1;
2300 errstr = newstralloc(errstr, "request NAK");
2301 *response_error = 2;
2306 if (pkt->type != P_REP) {
2307 errstr = newvstrallocf(errstr, _("received strange packet type %s: %s"),
2308 pkt_type2str(pkt->type), pkt->body);
2309 *response_error = 1;
2313 #if defined(PACKET_DEBUG)
2314 g_fprintf(stderr, _("got response:\n----\n%s\n----\n\n"), pkt->body);
2317 for(i = 0; i < NSTREAMS; i++) {
2319 amidxtaped_streams[i].fd = NULL;
2323 while((tok = strtok(p, " \n")) != NULL) {
2327 * Error response packets have "ERROR" followed by the error message
2328 * followed by a newline.
2330 if (strcmp(tok, "ERROR") == 0) {
2331 tok = strtok(NULL, "\n");
2333 tok = _("[bogus error packet]");
2334 errstr = newstralloc(errstr, tok);
2335 *response_error = 2;
2341 * Regular packets have CONNECT followed by three streams
2343 if (strcmp(tok, "CONNECT") == 0) {
2346 * Parse the three stream specifiers out of the packet.
2348 for (i = 0; i < NSTREAMS; i++) {
2349 tok = strtok(NULL, " ");
2350 if (tok == NULL || strcmp(tok, amidxtaped_streams[i].name) != 0) {
2351 extra = vstrallocf(_("CONNECT token is \"%s\": expected \"%s\""),
2352 tok ? tok : "(null)",
2353 amidxtaped_streams[i].name);
2356 tok = strtok(NULL, " \n");
2357 if (tok == NULL || sscanf(tok, "%d", &ports[i]) != 1) {
2358 extra = vstrallocf(_("CONNECT %s token is \"%s\": expected a port number"),
2359 amidxtaped_streams[i].name,
2360 tok ? tok : "(null)");
2368 * OPTIONS [options string] '\n'
2370 if (strcmp(tok, "OPTIONS") == 0) {
2371 tok = strtok(NULL, "\n");
2373 extra = stralloc(_("OPTIONS token is missing"));
2377 while((p = strchr(tok, ';')) != NULL) {
2379 if(strncmp_const(tok, "features=") == 0) {
2380 tok += sizeof("features=") - 1;
2381 am_release_feature_set(their_features);
2382 if((their_features = am_string_to_feature(tok)) == NULL) {
2383 errstr = newvstralloc(errstr,
2384 _("OPTIONS: bad features value: "),
2396 extra = vstrallocf("next token is \"%s\": expected \"CONNECT\", \"ERROR\" or \"OPTIONS\""),
2397 tok ? tok : _("(null)"));
2403 * Connect the streams to their remote ports
2405 for (i = 0; i < NSTREAMS; i++) {
2408 amidxtaped_streams[i].fd = security_stream_client(sech, ports[i]);
2409 dbprintf(_("amidxtaped_streams[%d].fd = %p\n"),i, amidxtaped_streams[i].fd);
2410 if (amidxtaped_streams[i].fd == NULL) {
2411 errstr = newvstrallocf(errstr,\
2412 _("[could not connect %s stream: %s]"),
2413 amidxtaped_streams[i].name,
2414 security_geterror(sech));
2419 * Authenticate the streams
2421 for (i = 0; i < NSTREAMS; i++) {
2422 if (amidxtaped_streams[i].fd == NULL)
2424 if (security_stream_auth(amidxtaped_streams[i].fd) < 0) {
2425 errstr = newvstrallocf(errstr,
2426 _("[could not authenticate %s stream: %s]"),
2427 amidxtaped_streams[i].name,
2428 security_stream_geterror(amidxtaped_streams[i].fd));
2434 * The CTLFD and DATAFD streams are mandatory. If we didn't get
2437 if (amidxtaped_streams[CTLFD].fd == NULL) {
2438 errstr = newvstrallocf(errstr, _("[couldn't open CTL streams]"));
2441 if (amidxtaped_streams[DATAFD].fd == NULL) {
2442 errstr = newvstrallocf(errstr, _("[couldn't open DATA streams]"));
2446 /* everything worked */
2447 *response_error = 0;
2452 errstr = newvstrallocf(errstr,
2453 _("[parse of reply message failed: %s]"), extra);
2455 errstr = newvstrallocf(errstr,
2456 _("[parse of reply message failed: (no additional information)"));
2459 *response_error = 2;
2464 *response_error = 1;
2468 * This is called when everything needs to shut down so event_loop()
2472 stop_amidxtaped(void)
2476 for (i = 0; i < NSTREAMS; i++) {
2477 if (amidxtaped_streams[i].fd != NULL) {
2478 security_stream_close(amidxtaped_streams[i].fd);
2479 amidxtaped_streams[i].fd = NULL;
2484 static char* ctl_buffer = NULL;
2485 /* gets a "line" from server and put in server_line */
2486 /* server_line is terminated with \0, \r\n is striped */
2487 /* returns -1 if error */
2490 get_amidxtaped_line(void)
2496 amfree(amidxtaped_line);
2498 ctl_buffer = stralloc("");
2500 while (!strstr(ctl_buffer,"\r\n")) {
2501 size = security_stream_read_sync(amidxtaped_streams[CTLFD].fd, &buf);
2505 else if(size == 0) {
2508 newbuf = alloc(strlen(ctl_buffer)+size+1);
2509 strncpy(newbuf, ctl_buffer, (size_t)(strlen(ctl_buffer) + size + 1));
2510 memcpy(newbuf+strlen(ctl_buffer), buf, (size_t)size);
2511 newbuf[strlen(ctl_buffer)+size] = '\0';
2513 ctl_buffer = newbuf;
2516 s = strstr(ctl_buffer,"\r\n");
2518 newbuf = stralloc(s+2);
2519 amidxtaped_line = stralloc(ctl_buffer);
2521 ctl_buffer = newbuf;
2527 read_amidxtaped_data(
2534 assert(cookie != NULL);
2536 fd = *(int *)cookie;
2538 errstr = newstralloc2(errstr, _("amidxtaped read: "),
2539 security_stream_geterror(amidxtaped_streams[DATAFD].fd));
2544 * EOF. Stop and return.
2547 security_stream_close(amidxtaped_streams[DATAFD].fd);
2548 amidxtaped_streams[DATAFD].fd = NULL;
2550 * If the mesg fd has also shut down, then we're done.
2555 assert(buf != NULL);
2558 * We ignore errors while writing to the index file.
2560 (void)fullwrite(fd, buf, (size_t)size);
2561 security_stream_read(amidxtaped_streams[DATAFD].fd, read_amidxtaped_data, cookie);
2565 amidxtaped_client_get_security_conf(
2569 (void)arg; /* Quiet unused parameter warning */
2571 if(!string || !*string)
2574 if(strcmp(string, "auth")==0) {
2575 return(getconf_str(CNF_AUTH));
2577 if(strcmp(string, "ssh_keys")==0) {
2578 return(getconf_str(CNF_SSH_KEYS));