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.2.2 2006/12/22 15:10:26 martinea Exp $
29 * implements the "extract" command in amrecover
34 #include "amrecover.h"
35 #include "fileheader.h"
43 #include "clientconf.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..
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 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 fprintf(stderr,"timeout waiting for restore\n");
201 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 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 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 printf("WARNING: %s is not a directory, "
504 "it will be deleted.\n",
509 else if (errno != ENOENT) {
510 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 printf("WARNING: All existing files in %s "
528 "will be deleted.\n", filename);
530 } else if(S_ISREG(stat_buf.st_mode)) {
531 printf("WARNING: Existing file %s will be overwritten\n",
534 if (add_to_unlink_list(filename)) {
535 printf("WARNING: Existing entry %s will be deleted\n",
539 } else if (errno != ENOENT) {
540 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 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 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;
739 char *path_on_disk_slash = NULL;
744 char *dir, *dir_undo, dir_undo_ch = '\0';
745 char *ditem_path = NULL;
746 char *qditem_path = NULL;
749 char *s, *fp, *quoted;
754 if (disk_path == NULL) {
755 printf("Must select directory before adding files\n");
758 memset(&lditem, 0, sizeof(lditem)); /* Prevent use of bogus data... */
760 dbprintf(("add_file: Looking for \"%s\"\n", regex));
762 if(strcmp(regex, "/[/]*$") == 0) { /* "/" behave like "." */
765 else if(strcmp(regex, "[^/]*[/]*$") == 0) { /* "*" */
766 regex = "([^/.]|\\.[^/]+|[^/.][^/]*)[/]*$";
768 /* remove "/" at end of path */
769 j = (ssize_t)(strlen(regex) - 1);
770 while(j >= 0 && regex[j] == '/')
774 /* convert path (assumed in cwd) to one on disk */
775 if (strcmp(disk_path, "/") == 0) {
777 /* No mods needed if already starts with '/' */
778 path_on_disk = stralloc(regex);
781 path_on_disk = stralloc2("/", regex);
784 char *clean_disk_path = clean_regex(disk_path);
785 path_on_disk = vstralloc(clean_disk_path, "/", regex, NULL);
786 amfree(clean_disk_path);
789 path_on_disk_slash = stralloc2(path_on_disk, "/");
791 dbprintf(("add_file: Converted path=\"%s\" to path_on_disk=\"%s\"\n",
792 regex, path_on_disk));
796 for (ditem=get_dir_list(); ditem!=NULL; ditem=get_next_dir_item(ditem))
799 quoted = quote_string(ditem->path);
800 dbprintf(("add_file: Pondering ditem->path=%s\n", quoted));
802 if (match(path_on_disk, ditem->path)
803 || match(path_on_disk_slash, ditem->path))
806 j = (ssize_t)strlen(ditem->path);
807 if((j > 0 && ditem->path[j-1] == '/')
808 || (j > 1 && ditem->path[j-2] == '/' && ditem->path[j-1] == '.'))
809 { /* It is a directory */
810 ditem_path = newstralloc(ditem_path, ditem->path);
811 clean_pathname(ditem_path);
813 qditem_path = quote_string(ditem_path);
814 cmd = stralloc2("ORLD ", qditem_path);
816 if(send_command(cmd) == -1) {
819 amfree(path_on_disk);
820 amfree(path_on_disk_slash);
826 if ((i = get_reply_line()) == -1) {
828 amfree(path_on_disk);
829 amfree(path_on_disk_slash);
832 if(i==0) { /* assume something wrong */
834 amfree(path_on_disk);
835 amfree(path_on_disk_slash);
842 lditem.path = newstralloc(lditem.path, ditem->path);
843 /* skip the last line -- duplicate of the preamble */
845 while ((i = get_reply_line()) != 0) {
848 amfree(path_on_disk);
849 amfree(path_on_disk_slash);
854 if(dir_undo) *dir_undo = dir_undo_ch;
856 cmd = stralloc(l); /* save for error report */
858 continue; /* throw the rest of the lines away */
861 if (!server_happy()) {
866 if(strncmp(l, sc, sizeof(sc)-1) != 0) {
867 err = "bad reply: not 201-";
871 s = l + sizeof(sc)-1;
874 skip_whitespace(s, ch);
876 err = "bad reply: missing date field";
880 skip_non_whitespace(s, ch);
882 lditem.date = newstralloc(lditem.date, fp);
885 skip_whitespace(s, ch);
886 if(ch == '\0' || sscanf(s - 1, "%d", &lditem.level) != 1) {
887 err = "bad reply: cannot parse level field";
892 skip_whitespace(s, ch);
894 err = "bad reply: missing tape field";
898 skip_non_whitespace(s, ch);
900 lditem.tape = newstralloc(lditem.tape, fp);
903 if(am_has_feature(indexsrv_features, fe_amindexd_fileno_in_ORLD)) {
904 skip_whitespace(s, ch);
905 if(ch == '\0' || sscanf(s - 1, OFF_T_FMT,
906 (OFF_T_FMT_TYPE *)&lditem.fileno) != 1) {
907 err = "bad reply: cannot parse fileno field";
913 skip_whitespace(s, ch);
915 err = "bad reply: missing directory field";
919 skip_quoted_string(s, ch);
921 dir_undo_ch = *dir_undo;
924 switch(add_extract_item(&lditem)) {
926 printf("System error\n");
927 dbprintf(("add_file: (Failed) System error\n"));
931 quoted = quote_string(lditem.path);
932 printf("Added dir %s at date %s\n",
933 quoted, lditem.date);
934 dbprintf(("add_file: (Successful) Added dir %s at date %s\n",
935 quoted, lditem.date));
944 if(!server_happy()) {
951 } else if(added == 0) {
952 quoted = quote_string(ditem_path);
953 printf("dir %s already added\n", quoted);
954 dbprintf(("add_file: dir %s already added\n", quoted));
958 else /* It is a file */
960 switch(add_extract_item(ditem)) {
962 printf("System error\n");
963 dbprintf(("add_file: (Failed) System error\n"));
967 quoted = quote_string(ditem->path);
968 printf("Added file %s\n", quoted);
969 dbprintf(("add_file: (Successful) Added %s\n", quoted));
974 quoted = quote_string(ditem->path);
975 printf("File %s already added\n", quoted);
976 dbprintf(("add_file: file %s already added\n", quoted));
985 amfree(path_on_disk);
986 amfree(path_on_disk_slash);
993 quoted = quote_string(path);
994 printf("File %s doesn't exist in directory\n", quoted);
995 dbprintf(("add_file: (Failed) File %s doesn't exist in directory\n",
1009 char *uqglob = unquote_string(glob);
1011 regex = glob_to_regex(uqglob);
1012 dbprintf(("delete_glob (%s) -> %s\n", uqglob, regex));
1013 if ((s = validate_regexp(regex)) != NULL) {
1014 printf("\"%s\" is not a valid shell wildcard pattern: ", glob);
1018 * glob_to_regex() anchors the beginning of the pattern with ^,
1019 * but we will be tacking it onto the end of the current directory
1020 * in add_file, so strip that off. Also, it anchors the end with
1021 * $, but we need to match an optional trailing /, so tack that on
1024 regex_path = stralloc(regex + 1);
1025 regex_path[strlen(regex_path) - 1] = '\0';
1026 strappend(regex_path, "[/]*$");
1027 delete_file(uqglob, regex_path);
1039 char *uqregex = unquote_string(regex);
1041 if ((s = validate_regexp(regex)) != NULL) {
1042 printf("\"%s\" is not a valid regular expression: ", regex);
1045 delete_file(uqregex, uqregex);
1055 DIR_ITEM *ditem, lditem;
1056 char *path_on_disk = NULL;
1057 char *path_on_disk_slash = NULL;
1063 char *tape, *tape_undo, tape_undo_ch = '\0';
1064 char *dir_undo, dir_undo_ch = '\0';
1067 char *ditem_path = NULL;
1076 if (disk_path == NULL) {
1077 printf("Must select directory before deleting files\n");
1080 memset(&lditem, 0, sizeof(lditem)); /* Prevent use of bogus data... */
1082 dbprintf(("delete_file: Looking for \"%s\"\n", path));
1084 if (strcmp(regex, "[^/]*[/]*$") == 0) {
1085 /* Looking for * find everything but single . */
1086 regex = "([^/.]|\\.[^/]+|[^/.][^/]*)[/]*$";
1088 /* remove "/" at end of path */
1089 j = (ssize_t)(strlen(regex) - 1);
1090 while(j >= 0 && regex[j] == '/') regex[j--] = '\0';
1093 /* convert path (assumed in cwd) to one on disk */
1094 if (strcmp(disk_path, "/") == 0) {
1095 if (*regex == '/') {
1096 if (strcmp(regex, "/[/]*$") == 0) {
1097 /* We want "/" to match the directory itself: "/." */
1098 path_on_disk = stralloc("/\\.[/]*$");
1100 /* No mods needed if already starts with '/' */
1101 path_on_disk = stralloc(regex);
1105 path_on_disk = stralloc2("/", regex);
1108 char *clean_disk_path = clean_regex(disk_path);
1109 path_on_disk = vstralloc(clean_disk_path, "/", regex, NULL);
1110 amfree(clean_disk_path);
1113 path_on_disk_slash = stralloc2(path_on_disk, "/");
1115 dbprintf(("delete_file: Converted path=\"%s\" to path_on_disk=\"%s\"\n",
1116 regex, path_on_disk));
1118 for (ditem=get_dir_list(); ditem!=NULL; ditem=get_next_dir_item(ditem))
1120 quoted = quote_string(ditem->path);
1121 dbprintf(("delete_file: Pondering ditem->path=%s\n", quoted));
1123 if (match(path_on_disk, ditem->path)
1124 || match(path_on_disk_slash, ditem->path))
1127 j = (ssize_t)strlen(ditem->path);
1128 if((j > 0 && ditem->path[j-1] == '/')
1129 || (j > 1 && ditem->path[j-2] == '/' && ditem->path[j-1] == '.'))
1130 { /* It is a directory */
1131 ditem_path = newstralloc(ditem_path, ditem->path);
1132 clean_pathname(ditem_path);
1134 qditem_path = quote_string(ditem_path);
1135 cmd = stralloc2("ORLD ", qditem_path);
1136 amfree(qditem_path);
1137 if(send_command(cmd) == -1) {
1140 amfree(path_on_disk);
1141 amfree(path_on_disk_slash);
1146 if ((i = get_reply_line()) == -1) {
1148 amfree(path_on_disk);
1149 amfree(path_on_disk_slash);
1152 if(i==0) /* assume something wrong */
1155 amfree(path_on_disk);
1156 amfree(path_on_disk_slash);
1162 lditem.path = newstralloc(lditem.path, ditem->path);
1164 tape_undo = dir_undo = NULL;
1165 /* skip the last line -- duplicate of the preamble */
1166 while ((i = get_reply_line()) != 0)
1170 amfree(path_on_disk);
1171 amfree(path_on_disk_slash);
1176 if(tape_undo) *tape_undo = tape_undo_ch;
1177 if(dir_undo) *dir_undo = dir_undo_ch;
1178 tape_undo = dir_undo = NULL;
1179 cmd = stralloc(l); /* save for the error report */
1181 continue; /* throw the rest of the lines away */
1184 if (!server_happy()) {
1189 if(strncmp(l, sc, sizeof(sc)-1) != 0) {
1190 err = "bad reply: not 201-";
1193 s = l + sizeof(sc)-1;
1196 skip_whitespace(s, ch);
1198 err = "bad reply: missing date field";
1202 skip_non_whitespace(s, ch);
1205 skip_whitespace(s, ch);
1206 if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
1207 err = "bad reply: cannot parse level field";
1210 skip_integer(s, ch);
1212 skip_whitespace(s, ch);
1214 err = "bad reply: missing tape field";
1218 skip_non_whitespace(s, ch);
1220 tape_undo_ch = *tape_undo;
1223 if(am_has_feature(indexsrv_features, fe_amindexd_fileno_in_ORLD)) {
1224 skip_whitespace(s, ch);
1225 if(ch == '\0' || sscanf(s - 1, OFF_T_FMT,
1226 (OFF_T_FMT_TYPE *)&fileno) != 1) {
1227 err = "bad reply: cannot parse fileno field";
1230 skip_integer(s, ch);
1233 skip_whitespace(s, ch);
1235 err = "bad reply: missing directory field";
1238 skip_non_whitespace(s, ch);
1240 dir_undo_ch = *dir_undo;
1243 lditem.date = newstralloc(lditem.date, date);
1245 lditem.tape = newstralloc(lditem.tape, tape);
1246 switch(delete_extract_item(&lditem)) {
1248 printf("System error\n");
1249 dbprintf(("delete_file: (Failed) System error\n"));
1252 printf("Deleted dir %s at date %s\n", ditem_path, date);
1253 dbprintf(("delete_file: (Successful) Deleted dir %s at date %s\n",
1261 if(!server_happy()) {
1268 } else if(deleted == 0) {
1269 printf("Warning - dir '%s' not on tape list\n",
1271 dbprintf(("delete_file: dir '%s' not on tape list\n",
1277 switch(delete_extract_item(ditem)) {
1279 printf("System error\n");
1280 dbprintf(("delete_file: (Failed) System error\n"));
1283 printf("Deleted %s\n", ditem->path);
1284 dbprintf(("delete_file: (Successful) Deleted %s\n",
1288 printf("Warning - file '%s' not on tape list\n",
1290 dbprintf(("delete_file: file '%s' not on tape list\n",
1299 amfree(path_on_disk);
1300 amfree(path_on_disk_slash);
1303 printf("File %s doesn't exist in directory\n", path);
1304 dbprintf(("delete_file: (Failed) File %s doesn't exist in directory\n",
1310 /* print extract list into file. If NULL ptr passed print to screen */
1312 display_extract_list(
1316 EXTRACT_LIST_ITEM *that;
1319 char *pager_command;
1324 if ((pager = getenv("PAGER")) == NULL)
1329 * Set up the pager command so if the pager is terminated, we do
1330 * not get a SIGPIPE back.
1332 pager_command = stralloc2(pager, " ; /bin/cat > /dev/null");
1333 if ((fp = popen(pager_command, "w")) == NULL)
1335 printf("Warning - can't pipe through %s\n", pager);
1338 amfree(pager_command);
1342 uqfile = unquote_string(file);
1343 if ((fp = fopen(uqfile, "w")) == NULL)
1345 printf("Can't open file %s to print extract list into\n", file);
1352 for (this = extract_list; this != NULL; this = this->next)
1354 fprintf(fp, "TAPE %s LEVEL %d DATE %s\n",
1355 this->tape, this->level, this->date);
1356 for (that = this->files; that != NULL; that = that->next)
1357 fprintf(fp, "\t%s\n", that->path);
1363 printf("Extract list written to file %s\n", file);
1374 struct dirent *entry;
1377 if((dir = opendir(fname)) == NULL)
1381 while(!gotentry && (entry = readdir(dir)) != NULL) {
1382 gotentry = !is_dot_or_dotdot(entry->d_name);
1390 /* returns 0 if extract list empty and 1 if it isn't */
1392 is_extract_list_nonempty(void)
1394 return (extract_list != NULL);
1398 /* prints continue prompt and waits for response,
1399 returns 0 if don't, non-0 if do */
1416 prompt = "New tape device [?]: ";
1417 } else if (allow_tape && allow_skip) {
1418 prompt = "Continue [?/Y/n/s/t]? ";
1419 } else if (allow_tape && !allow_skip) {
1420 prompt = "Continue [?/Y/n/t]? ";
1421 } else if (allow_retry) {
1422 prompt = "Continue [?/Y/n/r]? ";
1424 prompt = "Continue [?/Y/n]? ";
1426 fputs(prompt, stdout);
1427 fflush(stdout); fflush(stderr);
1429 if ((line = agets(stdin)) == NULL) {
1440 while ((ch = *s++) != '\0' && isspace(ch)) {
1441 (void)ch; /* Quiet empty loop compiler warning */
1445 printf("Enter a new device ([host:]device) or \"default\"\n");
1447 printf("Enter \"y\"es to continue, \"n\"o to stop");
1449 printf(", \"s\"kip this tape");
1452 printf(" or \"r\"etry this tape");
1455 printf(" or \"t\"ape to change tape drives");
1459 } else if (get_tape) {
1462 } else if (ch == '\0' || ch == 'Y' || ch == 'y') {
1464 } else if (allow_tape && (ch == 'T' || ch == 't')) {
1466 } else if (ch == 'N' || ch == 'n') {
1468 } else if (allow_retry && (ch == 'R' || ch == 'r')) {
1470 } else if (allow_skip && (ch == 'S' || ch == 's')) {
1481 send_to_tape_server(
1482 security_stream_t * stream,
1485 char *msg = stralloc2(cmd, "\r\n");
1487 if (security_stream_write(stream, msg, strlen(msg)) < 0)
1489 error("Error writing to tape server");
1497 /* start up connection to tape server and set commands to initiate
1498 transfer of dump image.
1499 Return tape server socket on success, -1 on error. */
1501 extract_files_setup(
1505 char *disk_regex = NULL;
1506 char *host_regex = NULL;
1507 char *clean_datestamp, *ch, *ch1;
1512 amidxtaped_secdrv = security_getdriver(authopt);
1513 if (amidxtaped_secdrv == NULL) {
1514 error("no '%s' security driver available for host '%s'",
1515 authopt, tape_server_name);
1518 /* We assume that amidxtaped support fe_amidxtaped_options_features */
1519 /* and fe_amidxtaped_options_auth */
1520 /* We should send a noop to really know */
1521 req = vstralloc("SERVICE amidxtaped\n",
1522 "OPTIONS ", "features=", our_features_string, ";",
1523 "auth=", authopt, ";",
1525 protocol_sendreq(tape_server_name, amidxtaped_secdrv,
1526 amidxtaped_client_get_security_conf, req, STARTUP_TIMEOUT,
1527 amidxtaped_response, &response_error);
1530 if(response_error != 0) {
1534 disk_regex = alloc(strlen(disk_name) * 2 + 3);
1539 /* we want to force amrestore to only match disk_name exactly */
1542 /* We need to escape some characters first... NT compatibilty crap */
1543 for (; *ch != 0; ch++, ch1++) {
1544 switch (*ch) { /* done this way in case there are more */
1547 /* no break; we do want to fall through... */
1553 /* we want to force amrestore to only match disk_name exactly */
1558 host_regex = alloc(strlen(dump_hostname) * 2 + 3);
1563 /* we want to force amrestore to only match dump_hostname exactly */
1566 /* We need to escape some characters first... NT compatibilty crap */
1567 for (; *ch != 0; ch++, ch1++) {
1568 switch (*ch) { /* done this way in case there are more */
1571 /* no break; we do want to fall through... */
1577 /* we want to force amrestore to only match dump_hostname exactly */
1582 clean_datestamp = stralloc(dump_datestamp);
1583 for(ch=ch1=clean_datestamp;*ch1 != '\0';ch1++) {
1590 /* push our feature list off to the tape server */
1591 /* XXX assumes that index server and tape server are equivalent, ew */
1593 if(am_has_feature(indexsrv_features, fe_amidxtaped_exchange_features)){
1594 tt = newstralloc2(tt, "FEATURES=", our_features_string);
1595 send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt);
1596 get_amidxtaped_line();
1597 if(strncmp(amidxtaped_line,"FEATURES=",9) == 0) {
1598 tapesrv_features = am_string_to_feature(amidxtaped_line+9);
1600 fprintf(stderr, "amrecover - expecting FEATURES line from amidxtaped\n");
1604 amfree(clean_datestamp);
1607 am_release_feature_set(tapesrv_features);
1611 if(am_has_feature(indexsrv_features, fe_amidxtaped_header) &&
1612 am_has_feature(indexsrv_features, fe_amidxtaped_device) &&
1613 am_has_feature(indexsrv_features, fe_amidxtaped_host) &&
1614 am_has_feature(indexsrv_features, fe_amidxtaped_disk) &&
1615 am_has_feature(indexsrv_features, fe_amidxtaped_datestamp)) {
1617 if(am_has_feature(indexsrv_features, fe_amidxtaped_config)) {
1618 tt = newstralloc2(tt, "CONFIG=", config);
1619 send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt);
1621 if(am_has_feature(indexsrv_features, fe_amidxtaped_label) &&
1622 label && label[0] != '/') {
1623 tt = newstralloc2(tt,"LABEL=",label);
1624 send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt);
1626 if(am_has_feature(indexsrv_features, fe_amidxtaped_fsf)) {
1628 snprintf(v_fsf, 99, OFF_T_FMT, (OFF_T_FMT_TYPE)fsf);
1629 tt = newstralloc2(tt, "FSF=",v_fsf);
1630 send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt);
1632 send_to_tape_server(amidxtaped_streams[CTLFD].fd, "HEADER");
1633 tt = newstralloc2(tt, "DEVICE=", dump_device_name);
1634 send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt);
1635 tt = newstralloc2(tt, "HOST=", host_regex);
1636 send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt);
1637 tt = newstralloc2(tt, "DISK=", disk_regex);
1638 send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt);
1639 tt = newstralloc2(tt, "DATESTAMP=", clean_datestamp);
1640 send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt);
1641 send_to_tape_server(amidxtaped_streams[CTLFD].fd, "END");
1644 else if(am_has_feature(indexsrv_features, fe_amidxtaped_nargs)) {
1645 /* send to the tape server what tape file we want */
1654 send_to_tape_server(amidxtaped_streams[CTLFD].fd, "6");
1655 send_to_tape_server(amidxtaped_streams[CTLFD].fd, "-h");
1656 send_to_tape_server(amidxtaped_streams[CTLFD].fd, "-p");
1657 send_to_tape_server(amidxtaped_streams[CTLFD].fd, dump_device_name);
1658 send_to_tape_server(amidxtaped_streams[CTLFD].fd, host_regex);
1659 send_to_tape_server(amidxtaped_streams[CTLFD].fd, disk_regex);
1660 send_to_tape_server(amidxtaped_streams[CTLFD].fd, clean_datestamp);
1662 dbprintf(("Started amidxtaped with arguments \"6 -h -p %s %s %s %s\"\n",
1663 dump_device_name, host_regex, disk_regex, clean_datestamp));
1668 amfree(clean_datestamp);
1675 * Reads the first block of a tape file.
1686 bytes_read = read_buffer(tapedev, buffer, buflen, READ_TIMEOUT);
1687 if(bytes_read < 0) {
1688 error("error reading header (%s), check amidxtaped.*.debug on server",
1693 if((size_t)bytes_read < buflen) {
1694 fprintf(stderr, "%s: short block %d byte%s\n",
1695 get_pname(), (int)bytes_read, (bytes_read == 1) ? "" : "s");
1696 print_header(stdout, file);
1697 error("Can't read file header");
1701 /* bytes_read == buflen */
1702 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) {
1757 if (strcmp(file.program, GNUTAR) == 0)
1758 dumptype = IS_GNUTAR;
1761 if (dumptype == IS_UNKNOWN) {
1762 len_program = strlen(file.program);
1763 if(len_program >= 3 &&
1764 strcmp(&file.program[len_program-3],"tar") == 0)
1769 if (dumptype == IS_UNKNOWN && strcmp(file.program, SAMBA_CLIENT) ==0) {
1770 if (samba_extract_method == SAMBA_TAR)
1771 dumptype = IS_SAMBA_TAR;
1773 dumptype = IS_SAMBA;
1778 /* form the arguments to restore */
1779 files_off_tape = length_of_tape_list(elist);
1798 #if defined(XFSDUMP)
1799 if (strcmp(file.program, XFSDUMP) == 0) {
1800 extra_params = 4 + files_off_tape;
1810 restore_args = (char **)alloc((size_t)((extra_params + files_off_tape + 1)
1815 restore_args[j++] = stralloc("smbclient");
1816 smbpass = findpass(file.disk, &domain);
1818 restore_args[j++] = stralloc(file.disk);
1820 restore_args[j++] = stralloc("-U");
1821 restore_args[j++] = smbpass;
1823 restore_args[j++] = stralloc("-W");
1824 restore_args[j++] = stralloc(domain);
1829 restore_args[j++] = stralloc("-d0");
1830 restore_args[j++] = stralloc("-Tx");
1831 restore_args[j++] = stralloc("-"); /* data on stdin */
1836 restore_args[j++] = stralloc("tar");
1837 restore_args[j++] = stralloc("--numeric-owner");
1838 restore_args[j++] = stralloc("-xpGvf");
1839 restore_args[j++] = stralloc("-"); /* data on stdin */
1842 restore_args[j++] = stralloc("tar");
1843 restore_args[j++] = stralloc("-xpvf");
1844 restore_args[j++] = stralloc("-"); /* data on stdin */
1848 restore_args[j++] = stralloc("restore");
1850 restore_args[j++] = stralloc("-xB");
1852 #if defined(XFSDUMP)
1853 if (strcmp(file.program, XFSDUMP) == 0) {
1854 restore_args[j++] = stralloc("-v");
1855 restore_args[j++] = stralloc("silent");
1859 if (strcmp(file.program, VDUMP) == 0) {
1860 restore_args[j++] = stralloc("xf");
1861 restore_args[j++] = stralloc("-"); /* data on stdin */
1865 restore_args[j++] = stralloc("xbf");
1866 restore_args[j++] = stralloc("2"); /* read in units of 1K */
1867 restore_args[j++] = stralloc("-"); /* data on stdin */
1872 for (i = 0, fn = elist->files; i < files_off_tape; i++, fn = fn->next)
1879 if (strcmp(fn->path, "/") == 0)
1880 restore_args[j++] = stralloc(".");
1882 restore_args[j++] = stralloc2(".", fn->path);
1886 #if defined(XFSDUMP)
1887 if (strcmp(file.program, XFSDUMP) == 0) {
1889 * xfsrestore needs a -s option before each file to be
1890 * restored, and also wants them to be relative paths.
1892 restore_args[j++] = stralloc("-s");
1893 restore_args[j++] = stralloc(fn->path + 1);
1897 restore_args[j++] = stralloc(fn->path);
1901 #if defined(XFSDUMP)
1902 if (strcmp(file.program, XFSDUMP) == 0) {
1903 restore_args[j++] = stralloc("-");
1904 restore_args[j++] = stralloc(".");
1907 restore_args[j] = NULL;
1912 cmd = stralloc(SAMBA_CLIENT);
1915 /* fall through to ... */
1921 fprintf(stderr, "warning: GNUTAR program not available.\n");
1922 cmd = stralloc("tar");
1924 cmd = stralloc(GNUTAR);
1931 if (strcmp(file.program, DUMP) == 0) {
1932 cmd = stralloc(RESTORE);
1936 if (strcmp(file.program, VDUMP) == 0) {
1937 cmd = stralloc(VRESTORE);
1941 if (strcmp(file.program, VXDUMP) == 0) {
1942 cmd = stralloc(VXRESTORE);
1945 #if defined(XFSDUMP)
1946 if (strcmp(file.program, XFSDUMP) == 0) {
1947 cmd = stralloc(XFSRESTORE);
1951 fprintf(stderr, "warning: restore program for %s not available.\n",
1953 cmd = stralloc("restore");
1957 dbprintf(("Exec'ing %s with arguments:\n", cmd));
1958 for (i = 0; i < j; i++) {
1959 if( i == passwd_field)
1960 dbprintf(("\tXXXXX\n"));
1962 dbprintf(("\t%s\n", restore_args[i]));
1964 (void)execv(cmd, restore_args);
1965 /* only get here if exec failed */
1967 for (i = 0; i < j; i++) {
1968 amfree(restore_args[i]);
1970 amfree(restore_args);
1972 perror("amrecover couldn't exec");
1973 fprintf(stderr, " problem executing %s\n", cmd);
1981 * Interpose something between the process writing out the dump (writing it to
1982 * some extraction program, really) and the socket from which we're reading, so
1983 * that we can do things like prompt for human interaction for multiple tapes.
1986 writer_intermediary(
1987 EXTRACT_LIST * elist)
1991 amwait_t extractor_status;
1993 if(pipe(child_pipe) == -1) {
1994 error("extract_list - error setting up pipe to extractor: %s\n",
1999 /* okay, ready to extract. fork a child to do the actual work */
2000 if ((pid = fork()) == 0) {
2001 /* this is the child process */
2002 /* never gets out of this clause */
2003 aclose(child_pipe[1]);
2004 extract_files_child(child_pipe[0], elist);
2008 /* This is the parent */
2010 printf("writer_intermediary - error forking child");
2014 aclose(child_pipe[0]);
2016 security_stream_read(amidxtaped_streams[DATAFD].fd,
2017 read_amidxtaped_data, &(child_pipe[1]));
2019 while(get_amidxtaped_line() >= 0) {
2020 char desired_tape[MAX_TAPE_LABEL_BUF];
2022 /* if prompted for a tape, relay said prompt to the user */
2023 if(sscanf(amidxtaped_line, "FEEDME %132s\n", desired_tape) == 1) {
2025 printf("Load tape %s now\n", desired_tape);
2026 done = okay_to_continue(am_has_feature(indexsrv_features,
2027 fe_amrecover_feedme_tape),
2030 if (am_has_feature(indexsrv_features,
2031 fe_amrecover_feedme_tape)) {
2032 char *reply = stralloc2("TAPE ", tape_device_name);
2033 send_to_tape_server(amidxtaped_streams[CTLFD].fd, reply);
2036 send_to_tape_server(amidxtaped_streams[CTLFD].fd, "OK");
2039 send_to_tape_server(amidxtaped_streams[CTLFD].fd, "ERROR");
2042 } else if(strncmp(amidxtaped_line, "MESSAGE ", 8) == 0) {
2043 printf("%s\n",&amidxtaped_line[8]);
2045 fprintf(stderr, "Strange message from tape server: %s",
2051 /* CTL might be close before DATA */
2053 aclose(child_pipe[1]);
2055 waitpid(pid, &extractor_status, 0);
2056 if(WEXITSTATUS(extractor_status) != 0){
2057 int ret = WEXITSTATUS(extractor_status);
2058 if(ret == 255) ret = -1;
2059 printf("Extractor child exited with status %d\n", ret);
2065 /* exec restore to do the actual restoration */
2067 /* does the actual extraction of files */
2069 * The original design had the dump image being returned exactly as it
2070 * appears on the tape, and this routine getting from the index server
2071 * whether or not it is compressed, on the assumption that the tape
2072 * server may not know how to uncompress it. But
2073 * - Amrestore can't do that. It returns either compressed or uncompressed
2074 * (always). Amrestore assumes it can uncompress files. It is thus a good
2075 * idea to run the tape server on a machine with gzip.
2076 * - The information about compression in the disklist is really only
2077 * for future dumps. It is possible to change compression on a drive
2078 * so the information in the disklist may not necessarily relate to
2079 * the dump image on the tape.
2080 * Consequently the design was changed to assuming that amrestore can
2081 * uncompress any dump image and have it return an uncompressed file
2087 EXTRACT_LIST *elist;
2092 tapelist_t *tlist = NULL, *a_tlist;
2094 if (!is_extract_list_nonempty())
2096 printf("Extract list empty - No files to extract!\n");
2100 clean_extract_list();
2102 /* get tape device name from index server if none specified */
2103 if (tape_server_name == NULL) {
2104 tape_server_name = newstralloc(tape_server_name, server_name);
2106 if (tape_device_name == NULL) {
2107 if (send_command("TAPE") == -1)
2109 if (get_reply_line() == -1)
2112 if (!server_happy())
2117 /* skip reply number */
2118 tape_device_name = newstralloc(tape_device_name, l+4);
2121 if (strcmp(tape_device_name, "/dev/null") == 0)
2123 printf("amrecover: warning: using %s as the tape device will not work\n",
2128 for (elist = first_tape_list(); elist != NULL; elist = next_tape_list(elist)) {
2129 if(elist->tape[0]!='/') {
2131 printf("\nExtracting files using tape drive %s on host %s.\n",
2132 tape_device_name, tape_server_name);
2133 printf("The following tapes are needed:");
2138 tlist = unmarshal_tapelist_str(elist->tape);
2139 for(a_tlist = tlist ; a_tlist != NULL; a_tlist = a_tlist->next)
2140 printf(" %s", a_tlist->label);
2142 free_tapelist(tlist);
2146 for (elist = first_tape_list(); elist != NULL; elist = next_tape_list(elist)) {
2147 if(elist->tape[0]=='/') {
2149 printf("\nExtracting files from holding disk on host %s.\n",
2151 printf("The following files are needed:");
2156 tlist = unmarshal_tapelist_str(elist->tape);
2157 for(a_tlist = tlist; a_tlist != NULL; a_tlist = a_tlist->next)
2158 printf(" %s", a_tlist->label);
2160 free_tapelist(tlist);
2165 if (getcwd(cwd, sizeof(cwd)) == NULL) {
2166 perror("extract_list: Current working directory unavailable");
2170 printf("Restoring files into directory %s\n", cwd);
2171 check_file_overwrite(cwd);
2174 if (samba_extract_method == SAMBA_SMBCLIENT)
2175 printf("(unless it is a Samba backup, that will go through to the SMB server)\n");
2177 if (!okay_to_continue(0,0,0))
2181 if (!do_unlink_list()) {
2182 fprintf(stderr, "Can't recover because I can't cleanup the cwd (%s)\n",
2188 while ((elist = first_tape_list()) != NULL)
2190 if(elist->tape[0]=='/') {
2191 dump_device_name = newstralloc(dump_device_name, elist->tape);
2192 printf("Extracting from file ");
2193 tlist = unmarshal_tapelist_str(dump_device_name);
2194 for(a_tlist = tlist; a_tlist != NULL; a_tlist = a_tlist->next)
2195 printf(" %s", a_tlist->label);
2197 free_tapelist(tlist);
2200 printf("Extracting files using tape drive %s on host %s.\n",
2201 tape_device_name, tape_server_name);
2202 tlist = unmarshal_tapelist_str(elist->tape);
2203 printf("Load tape %s now\n", tlist->label);
2204 free_tapelist(tlist);
2205 otc = okay_to_continue(1,1,0);
2208 else if (otc == SKIP_TAPE) {
2209 delete_tape_list(elist); /* skip this tape */
2212 dump_device_name = newstralloc(dump_device_name, tape_device_name);
2214 dump_datestamp = newstralloc(dump_datestamp, elist->date);
2216 /* connect to the tape handler daemon on the tape drive server */
2217 if ((extract_files_setup(elist->tape, elist->fileno)) == -1)
2219 fprintf(stderr, "amrecover - can't talk to tape server\n");
2223 /* if the server have fe_amrecover_feedme_tape, it has asked for
2224 * the tape itself, even if the restore didn't succeed, we should
2227 if(writer_intermediary(elist) == 0 ||
2228 am_has_feature(indexsrv_features, fe_amrecover_feedme_tape))
2229 delete_tape_list(elist); /* tape done so delete from list */
2236 amidxtaped_response(
2239 security_handle_t * sech)
2241 int ports[NSTREAMS], *response_error = datap, i;
2246 assert(response_error != NULL);
2247 assert(sech != NULL);
2248 memset(ports, -1, SIZEOF(ports));
2250 security_close_connection(sech, dump_hostname);
2252 errstr = newvstralloc(errstr, "[request failed: ",
2253 security_geterror(sech), "]", NULL);
2254 *response_error = 1;
2258 if (pkt->type == P_NAK) {
2259 #if defined(PACKET_DEBUG)
2260 fprintf(stderr, "got nak response:\n----\n%s\n----\n\n", pkt->body);
2263 tok = strtok(pkt->body, " ");
2264 if (tok == NULL || strcmp(tok, "ERROR") != 0)
2267 tok = strtok(NULL, "\n");
2269 errstr = newvstralloc(errstr, "NAK: ", tok, NULL);
2270 *response_error = 1;
2273 errstr = newstralloc(errstr, "request NAK");
2274 *response_error = 2;
2279 if (pkt->type != P_REP) {
2280 errstr = newvstralloc(errstr, "received strange packet type ",
2281 pkt_type2str(pkt->type), ": ", pkt->body, NULL);
2282 *response_error = 1;
2286 #if defined(PACKET_DEBUG)
2287 fprintf(stderr, "got response:\n----\n%s\n----\n\n", pkt->body);
2290 for(i = 0; i < NSTREAMS; i++) {
2292 amidxtaped_streams[i].fd = NULL;
2296 while((tok = strtok(p, " \n")) != NULL) {
2300 * Error response packets have "ERROR" followed by the error message
2301 * followed by a newline.
2303 if (strcmp(tok, "ERROR") == 0) {
2304 tok = strtok(NULL, "\n");
2306 tok = "[bogus error packet]";
2307 errstr = newstralloc(errstr, tok);
2308 *response_error = 2;
2314 * Regular packets have CONNECT followed by three streams
2316 if (strcmp(tok, "CONNECT") == 0) {
2319 * Parse the three stream specifiers out of the packet.
2321 for (i = 0; i < NSTREAMS; i++) {
2322 tok = strtok(NULL, " ");
2323 if (tok == NULL || strcmp(tok, amidxtaped_streams[i].name) != 0) {
2324 extra = vstralloc("CONNECT token is \"",
2325 tok ? tok : "(null)",
2327 amidxtaped_streams[i].name,
2332 tok = strtok(NULL, " \n");
2333 if (tok == NULL || sscanf(tok, "%d", &ports[i]) != 1) {
2334 extra = vstralloc("CONNECT ",
2335 amidxtaped_streams[i].name,
2337 tok ? tok : "(null)",
2338 "\": expected a port number",
2347 * OPTIONS [options string] '\n'
2349 if (strcmp(tok, "OPTIONS") == 0) {
2350 tok = strtok(NULL, "\n");
2352 extra = stralloc("OPTIONS token is missing");
2356 while((p = strchr(tok, ';')) != NULL) {
2358 #define sc "features="
2359 if(strncmp(tok, sc, sizeof(sc)-1) == 0) {
2360 tok += sizeof(sc) - 1;
2362 am_release_feature_set(their_features);
2363 if((their_features = am_string_to_feature(tok)) == NULL) {
2364 errstr = newvstralloc(errstr,
2365 "OPTIONS: bad features value: ",
2377 extra = vstralloc("next token is \"",
2378 tok ? tok : "(null)",
2379 "\": expected \"CONNECT\", \"ERROR\" or \"OPTIONS\"",
2386 * Connect the streams to their remote ports
2388 for (i = 0; i < NSTREAMS; i++) {
2391 amidxtaped_streams[i].fd = security_stream_client(sech, ports[i]);
2392 dbprintf(("amidxtaped_streams[%d].fd = %p\n",i, amidxtaped_streams[i].fd));
2393 if (amidxtaped_streams[i].fd == NULL) {
2394 errstr = newvstralloc(errstr,
2395 "[could not connect ", amidxtaped_streams[i].name, " stream: ",
2396 security_geterror(sech), "]", NULL);
2401 * Authenticate the streams
2403 for (i = 0; i < NSTREAMS; i++) {
2404 if (amidxtaped_streams[i].fd == NULL)
2406 if (security_stream_auth(amidxtaped_streams[i].fd) < 0) {
2407 errstr = newvstralloc(errstr,
2408 "[could not authenticate ", amidxtaped_streams[i].name, " stream: ",
2409 security_stream_geterror(amidxtaped_streams[i].fd), "]", NULL);
2415 * The CTLFD and DATAFD streams are mandatory. If we didn't get
2418 if (amidxtaped_streams[CTLFD].fd == NULL) {
2419 errstr = newstralloc(errstr, "[couldn't open CTL streams]");
2422 if (amidxtaped_streams[DATAFD].fd == NULL) {
2423 errstr = newstralloc(errstr, "[couldn't open DATA streams]");
2427 /* everything worked */
2428 *response_error = 0;
2432 errstr = newvstralloc(errstr,
2433 "[parse of reply message failed: ",
2434 extra ? extra : "(no additional information)",
2438 *response_error = 2;
2443 *response_error = 1;
2447 * This is called when everything needs to shut down so event_loop()
2451 stop_amidxtaped(void)
2455 for (i = 0; i < NSTREAMS; i++) {
2456 if (amidxtaped_streams[i].fd != NULL) {
2457 security_stream_close(amidxtaped_streams[i].fd);
2458 amidxtaped_streams[i].fd = NULL;
2463 static char* ctl_buffer = NULL;
2464 /* gets a "line" from server and put in server_line */
2465 /* server_line is terminated with \0, \r\n is striped */
2466 /* returns -1 if error */
2469 get_amidxtaped_line(void)
2475 amfree(amidxtaped_line);
2477 ctl_buffer = stralloc("");
2479 while (!strstr(ctl_buffer,"\r\n")) {
2480 size = security_stream_read_sync(amidxtaped_streams[CTLFD].fd, &buf);
2484 else if(size == 0) {
2487 newbuf = alloc(strlen(ctl_buffer)+size+1);
2488 strncpy(newbuf, ctl_buffer, (size_t)(strlen(ctl_buffer) + size + 1));
2489 memcpy(newbuf+strlen(ctl_buffer), buf, (size_t)size);
2490 newbuf[strlen(ctl_buffer)+size] = '\0';
2492 ctl_buffer = newbuf;
2495 s = strstr(ctl_buffer,"\r\n");
2497 newbuf = stralloc(s+2);
2498 amidxtaped_line = stralloc(ctl_buffer);
2500 ctl_buffer = newbuf;
2506 read_amidxtaped_data(
2513 assert(cookie != NULL);
2515 fd = *(int *)cookie;
2517 errstr = newstralloc2(errstr, "amidxtaped read: ",
2518 security_stream_geterror(amidxtaped_streams[DATAFD].fd));
2523 * EOF. Stop and return.
2526 security_stream_close(amidxtaped_streams[DATAFD].fd);
2527 amidxtaped_streams[DATAFD].fd = NULL;
2529 * If the mesg fd has also shut down, then we're done.
2534 assert(buf != NULL);
2537 * We ignore errors while writing to the index file.
2539 (void)fullwrite(fd, buf, (size_t)size);
2540 security_stream_read(amidxtaped_streams[DATAFD].fd, read_amidxtaped_data, cookie);
2544 amidxtaped_client_get_security_conf(
2548 (void)arg; /* Quiet unused parameter warning */
2550 if(!string || !*string)
2553 if(strcmp(string, "auth")==0) {
2554 return(client_getconf_str(CLN_AUTH));
2556 if(strcmp(string, "ssh_keys")==0) {
2557 return(client_getconf_str(CLN_SSH_KEYS));