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.43.2.13.4.6.2.19 2003/03/04 21:13:58 martinea Exp $
29 * implements the "extract" command in amrecover
34 #include "amrecover.h"
35 #include "fileheader.h"
42 #if defined(KRB4_SECURITY)
43 #include "krb4-security.h"
47 typedef struct EXTRACT_LIST_ITEM
51 struct EXTRACT_LIST_ITEM *next;
55 typedef struct EXTRACT_LIST
57 char date[11]; /* date tape created */
58 int level; /* level of dump */
59 char tape[256]; /* tape label */
60 int fileno; /* fileno on tape */
61 EXTRACT_LIST_ITEM *files; /* files to get off tape */
63 struct EXTRACT_LIST *next;
70 char *dump_device_name = NULL;
72 extern char *localhost;
74 /* global pid storage for interrupt handler */
75 pid_t extract_restore_child_pid = -1;
78 static EXTRACT_LIST *extract_list = NULL;
81 unsigned short samba_extract_method = SAMBA_TAR;
82 #endif /* SAMBA_CLIENT */
84 #define READ_TIMEOUT 240*60
86 static int okay_to_continue P((int, int, int));
88 ssize_t read_buffer(datafd, buffer, buflen)
93 int maxfd, nfound = 0;
95 fd_set readset, selectset;
96 struct timeval timeout;
101 if(datafd < 0 || datafd >= FD_SETSIZE) {
102 errno = EMFILE; /* out of range */
113 FD_SET(datafd, &readset);
117 timeout.tv_sec = READ_TIMEOUT;
119 memcpy(&selectset, &readset, sizeof(fd_set));
121 nfound = select(maxfd, (SELECT_ARG_TYPE *)(&selectset), NULL, NULL, &timeout);
123 /* check for errors or timeout */
127 fprintf(stderr,"timeout waiting for amrestore\n");
128 fprintf(stderr,"increase READ_TIMEOUT in recover-src/extract_list.c if your tape is slow\n");
132 fprintf(stderr,"nfound == -1\n");
137 if(FD_ISSET(datafd, &selectset)) {
138 size = read(datafd, dataptr, spaceleft);
146 "EOF, check amidxtaped.<timestamp>.debug file on %s.\n",
155 } while (spaceleft>0 && size>0);
160 return (ssize_t)(buflen-spaceleft);
163 EXTRACT_LIST *first_tape_list P((void))
168 EXTRACT_LIST *next_tape_list(list)
176 static void clear_tape_list(tape_list)
177 EXTRACT_LIST *tape_list;
179 EXTRACT_LIST_ITEM *this, *next;
181 this = tape_list->files;
188 tape_list->files = NULL;
192 /* remove a tape list from the extract list, clearing the tape list
193 beforehand if necessary */
194 void delete_tape_list(tape_list)
195 EXTRACT_LIST *tape_list;
197 EXTRACT_LIST *this, *prev;
199 /* is it first on the list? */
200 if (tape_list == extract_list)
202 clear_tape_list(tape_list);
203 extract_list = tape_list->next;
208 /* so not first on list - find it and delete */
210 this = extract_list->next;
213 if (this == tape_list)
215 clear_tape_list(tape_list);
216 prev->next = tape_list->next;
227 /* return the number of files on a tape's list */
228 int length_of_tape_list(tape_list)
229 EXTRACT_LIST *tape_list;
231 EXTRACT_LIST_ITEM *fn;
235 for (fn = tape_list->files; fn != NULL; fn = fn->next)
242 void clear_extract_list P((void))
244 while (extract_list != NULL)
245 delete_tape_list(extract_list);
249 /* returns -1 if error */
250 /* returns 0 on succes */
251 /* returns 1 if already added */
252 static int add_extract_item(ditem)
255 EXTRACT_LIST *this, *this1;
256 EXTRACT_LIST_ITEM *that, *curr;
257 char *ditem_path = NULL;
259 ditem_path = stralloc(ditem->path);
260 clean_pathname(ditem_path);
262 for (this = extract_list; this != NULL; this = this->next)
264 /* see if this is the list for the tape */
265 if (this->level == ditem->level && strcmp(this->tape, ditem->tape) == 0)
267 /* yes, so add to list */
271 if (strcmp(curr->path,ditem_path) == 0) {
277 that = (EXTRACT_LIST_ITEM *)alloc(sizeof(EXTRACT_LIST_ITEM));
278 strncpy(that->path, ditem_path, sizeof(that->path)-1);
279 that->path[sizeof(that->path)-1] = '\0';
280 that->next = this->files;
281 this->files = that; /* add at front since easiest */
287 /* so this is the first time we have seen this tape */
288 this = (EXTRACT_LIST *)alloc(sizeof(EXTRACT_LIST));
289 strncpy(this->tape, ditem->tape, sizeof(this->tape)-1);
290 this->tape[sizeof(this->tape)-1] ='\0';
291 this->level = ditem->level;
292 this->fileno = ditem->fileno;
293 strncpy(this->date, ditem->date, sizeof(this->date)-1);
294 this->date[sizeof(this->date)-1] = '\0';
295 that = (EXTRACT_LIST_ITEM *)alloc(sizeof(EXTRACT_LIST_ITEM));
296 strncpy(that->path, ditem_path, sizeof(that->path)-1);
297 that->path[sizeof(that->path)-1] = '\0';
301 /* add this in date increasing order */
302 /* because restore must be done in this order */
303 /* add at begining */
304 if(extract_list==NULL || strcmp(this->date,extract_list->date) < 0)
306 this->next = extract_list;
311 for (this1 = extract_list; this1->next != NULL; this1 = this1->next)
313 /* add in the middle */
314 if(strcmp(this->date,this1->next->date) < 0)
316 this->next = this1->next;
330 /* returns -1 if error */
331 /* returns 0 on deletion */
332 /* returns 1 if not there */
333 static int delete_extract_item(ditem)
337 EXTRACT_LIST_ITEM *that, *prev;
338 char *ditem_path = NULL;
340 ditem_path = stralloc(ditem->path);
341 clean_pathname(ditem_path);
343 for (this = extract_list; this != NULL; this = this->next)
345 /* see if this is the list for the tape */
346 if (this->level == ditem->level && strcmp(this->tape, ditem->tape) == 0)
348 /* yes, so find file on list */
350 if (strcmp(that->path, ditem_path) == 0)
353 this->files = that->next;
355 /* if list empty delete it */
356 if (this->files == NULL)
357 delete_tape_list(this);
365 if (strcmp(that->path, ditem_path) == 0)
367 prev->next = that->next;
392 regex = glob_to_regex(glob);
393 dbprintf(("add_glob (%s) -> %s\n", glob, regex));
394 if ((s = validate_regexp(regex)) != NULL) {
395 printf("\"%s\" is not a valid shell wildcard pattern: ", glob);
400 * glob_to_regex() anchors the beginning of the pattern with ^,
401 * but we will be tacking it onto the end of the current directory
402 * in add_file, so strip that off. Also, it anchors the end with
403 * $, but we need to match an optional trailing /, so tack that on
406 regex_path = stralloc(regex + 1);
408 regex_path[strlen(regex_path) - 1] = '\0';
409 strappend(regex_path, "[/]*$");
410 add_file(glob, regex_path);
414 void add_regex(regex)
419 if ((s = validate_regexp(regex)) != NULL) {
420 printf("\"%s\" is not a valid regular expression: ", regex);
424 add_file(regex, regex);
427 void add_file(path, regex)
431 DIR_ITEM *ditem, lditem;
432 char *path_on_disk = NULL;
433 char *path_on_disk_slash = NULL;
438 char *dir, *dir_undo, dir_undo_ch = '\0';
439 char *ditem_path = NULL;
446 if (disk_path == NULL) {
447 printf("Must select directory before adding files\n");
451 dbprintf(("add_file: Looking for \"%s\"\n", regex));
453 /* remove "/" at end of path */
455 while(j >= 0 && regex[j] == '/') regex[j--] = '\0';
457 /* convert path (assumed in cwd) to one on disk */
458 if (strcmp(disk_path, "/") == 0)
459 path_on_disk = stralloc2("/", regex);
461 char *clean_disk_path = clean_regex(disk_path);
462 path_on_disk = vstralloc(clean_disk_path, "/", regex, NULL);
463 amfree(clean_disk_path);
466 path_on_disk_slash = stralloc2(path_on_disk, "/");
468 dbprintf(("add_file: Converted path=\"%s\" to path_on_disk=\"%s\"\n",
469 regex, path_on_disk));
472 for (ditem=get_dir_list(); ditem!=NULL; ditem=get_next_dir_item(ditem))
474 dbprintf(("add_file: Pondering ditem->path=\"%s\"\n", ditem->path));
475 if (match(path_on_disk, ditem->path)
476 || match(path_on_disk_slash, ditem->path))
479 j = strlen(ditem->path);
480 if((j > 0 && ditem->path[j-1] == '/')
481 || (j > 1 && ditem->path[j-2] == '/' && ditem->path[j-1] == '.'))
482 { /* It is a directory */
484 ditem_path = newstralloc(ditem_path, ditem->path);
485 clean_pathname(ditem_path);
487 cmd = stralloc2("ORLD ", ditem_path);
488 if(send_command(cmd) == -1) {
491 amfree(path_on_disk);
492 amfree(path_on_disk_slash);
497 if ((i = get_reply_line()) == -1) {
499 amfree(path_on_disk);
500 amfree(path_on_disk_slash);
503 if(i==0) /* assume something wrong */
506 amfree(path_on_disk);
507 amfree(path_on_disk_slash);
515 strncpy(lditem.path, ditem_path, sizeof(lditem.path)-1);
516 lditem.path[sizeof(lditem.path)-1] = '\0';
517 /* skip the last line -- duplicate of the preamble */
518 while ((i = get_reply_line()) != 0)
522 amfree(path_on_disk);
523 amfree(path_on_disk_slash);
528 if(dir_undo) *dir_undo = dir_undo_ch;
530 cmd = stralloc(l); /* save for error report */
532 continue; /* throw the rest of the lines away */
535 if (!server_happy()) {
540 if(strncmp(l, sc, sizeof(sc)-1) != 0) {
541 err = "bad reply: not 201-";
545 s = l + sizeof(sc)-1;
548 skip_whitespace(s, ch);
550 err = "bad reply: missing date field";
553 copy_string(s, ch, lditem.date, sizeof(lditem.date), fp);
555 err = "bad reply: date field too large";
559 skip_whitespace(s, ch);
560 if(ch == '\0' || sscanf(s - 1, "%d", &lditem.level) != 1) {
561 err = "bad reply: cannot parse level field";
566 skip_whitespace(s, ch);
568 err = "bad reply: missing tape field";
571 copy_string(s, ch, lditem.tape, sizeof(lditem.tape), fp);
573 err = "bad reply: tape field too large";
577 if(am_has_feature(their_features, fe_amindexd_fileno_in_ORLD)) {
578 skip_whitespace(s, ch);
579 if(ch == '\0' || sscanf(s - 1, "%d", &lditem.fileno) != 1) {
580 err = "bad reply: cannot parse fileno field";
586 skip_whitespace(s, ch);
588 err = "bad reply: missing directory field";
592 skip_non_whitespace(s, ch);
594 dir_undo_ch = *dir_undo;
597 switch(add_extract_item(&lditem)) {
599 printf("System error\n");
600 dbprintf(("add_file: (Failed) System error\n"));
603 printf("Added dir %s at date %s\n",
604 ditem_path, lditem.date);
605 dbprintf(("add_file: (Successful) Added dir %s at date %s\n",
606 ditem_path,lditem.date));
613 if(!server_happy()) {
620 } else if(added == 0) {
621 printf("dir %s already added\n", ditem_path);
622 dbprintf(("add_file: dir %s already added\n", ditem_path));
625 else /* It is a file */
627 switch(add_extract_item(ditem)) {
629 printf("System error\n");
630 dbprintf(("add_file: (Failed) System error\n"));
633 printf("Added %s\n", ditem->path);
634 dbprintf(("add_file: (Successful) Added %s\n",
638 printf("File %s already added\n", ditem->path);
639 dbprintf(("add_file: file %s already added\n",
648 amfree(path_on_disk);
649 amfree(path_on_disk_slash);
652 printf("File %s doesn't exist in directory\n", path);
653 dbprintf(("add_file: (Failed) File %s doesn't exist in directory\n",
659 void delete_glob(glob)
666 regex = glob_to_regex(glob);
667 dbprintf(("delete_glob (%s) -> %s\n", glob, regex));
668 if ((s = validate_regexp(regex)) != NULL) {
669 printf("\"%s\" is not a valid shell wildcard pattern: ", glob);
674 * glob_to_regex() anchors the beginning of the pattern with ^,
675 * but we will be tacking it onto the end of the current directory
676 * in add_file, so strip that off. Also, it anchors the end with
677 * $, but we need to match an optional trailing /, so tack that on
680 regex_path = stralloc(regex + 1);
682 regex_path[strlen(regex_path) - 1] = '\0';
683 strappend(regex_path, "[/]*$");
684 delete_file(glob, regex_path);
688 void delete_regex(regex)
693 if ((s = validate_regexp(regex)) != NULL) {
694 printf("\"%s\" is not a valid regular expression: ", regex);
698 delete_file(regex, regex);
701 void delete_file(path, regex)
705 DIR_ITEM *ditem, lditem;
706 char *path_on_disk = NULL;
707 char *path_on_disk_slash = NULL;
712 char *date, *date_undo, date_undo_ch = '\0';
713 char *tape, *tape_undo, tape_undo_ch = '\0';
714 char *dir, *dir_undo, dir_undo_ch = '\0';
716 char *ditem_path = NULL;
723 if (disk_path == NULL) {
724 printf("Must select directory before deleting files\n");
728 dbprintf(("delete_file: Looking for \"%s\"\n", path));
729 /* remove "/" at the end of the path */
731 while(j >= 0 && regex[j] == '/') regex[j--] = '\0';
733 /* convert path (assumed in cwd) to one on disk */
734 if (strcmp(disk_path, "/") == 0)
735 path_on_disk = stralloc2("/", regex);
737 char *clean_disk_path = clean_regex(disk_path);
738 path_on_disk = vstralloc(clean_disk_path, "/", regex, NULL);
739 amfree(clean_disk_path);
742 path_on_disk_slash = stralloc2(path_on_disk, "/");
744 dbprintf(("delete_file: Converted path=\"%s\" to path_on_disk=\"%s\"\n",
745 regex, path_on_disk));
747 for (ditem=get_dir_list(); ditem!=NULL; ditem=get_next_dir_item(ditem))
749 dbprintf(("delete_file: Pondering ditem->path=\"%s\"\n", ditem->path));
750 if (match(path_on_disk, ditem->path)
751 || match(path_on_disk_slash, ditem->path))
754 j = strlen(ditem->path);
755 if((j > 0 && ditem->path[j-1] == '/')
756 || (j > 1 && ditem->path[j-2] == '/' && ditem->path[j-1] == '.'))
757 { /* It is a directory */
758 ditem_path = newstralloc(ditem_path, ditem->path);
759 clean_pathname(ditem_path);
761 cmd = stralloc2("ORLD ", ditem_path);
762 if(send_command(cmd) == -1) {
765 amfree(path_on_disk);
766 amfree(path_on_disk_slash);
771 if ((i = get_reply_line()) == -1) {
773 amfree(path_on_disk);
774 amfree(path_on_disk_slash);
777 if(i==0) /* assume something wrong */
780 amfree(path_on_disk);
781 amfree(path_on_disk_slash);
787 strncpy(lditem.path, ditem->path, sizeof(lditem.path)-1);
788 lditem.path[sizeof(lditem.path)-1] = '\0';
791 date_undo = tape_undo = dir_undo = NULL;
792 /* skip the last line -- duplicate of the preamble */
793 while ((i = get_reply_line()) != 0)
797 amfree(path_on_disk);
798 amfree(path_on_disk_slash);
803 if(tape_undo) *tape_undo = tape_undo_ch;
804 if(dir_undo) *dir_undo = dir_undo_ch;
805 date_undo = tape_undo = dir_undo = NULL;
806 cmd = stralloc(l); /* save for the error report */
808 continue; /* throw the rest of the lines away */
811 if (!server_happy()) {
816 if(strncmp(l, sc, sizeof(sc)-1) != 0) {
817 err = "bad reply: not 201-";
820 s = l + sizeof(sc)-1;
823 skip_whitespace(s, ch);
825 err = "bad reply: missing date field";
829 skip_non_whitespace(s, ch);
831 date_undo_ch = *date_undo;
834 skip_whitespace(s, ch);
835 if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
836 err = "bad reply: cannot parse level field";
841 skip_whitespace(s, ch);
843 err = "bad reply: missing tape field";
847 skip_non_whitespace(s, ch);
849 tape_undo_ch = *tape_undo;
852 if(am_has_feature(their_features, fe_amindexd_fileno_in_ORLD)) {
853 skip_whitespace(s, ch);
854 if(ch == '\0' || sscanf(s - 1, "%d", &fileno) != 1) {
855 err = "bad reply: cannot parse fileno field";
861 skip_whitespace(s, ch);
863 err = "bad reply: missing directory field";
867 skip_non_whitespace(s, ch);
869 dir_undo_ch = *dir_undo;
872 strncpy(lditem.date, date, sizeof(lditem.date)-1);
873 lditem.date[sizeof(lditem.date)-1] = '\0';
875 strncpy(lditem.tape, tape, sizeof(lditem.tape)-1);
876 lditem.tape[sizeof(lditem.tape)-1] = '\0';
877 switch(delete_extract_item(&lditem)) {
879 printf("System error\n");
880 dbprintf(("delete_file: (Failed) System error\n"));
883 printf("Deleted dir %s at date %s\n", ditem_path, date);
884 dbprintf(("delete_file: (Successful) Deleted dir %s at date %s\n",
892 if(!server_happy()) {
899 } else if(deleted == 0) {
900 printf("Warning - dir '%s' not on tape list\n",
902 dbprintf(("delete_file: dir '%s' not on tape list\n",
908 switch(delete_extract_item(ditem)) {
910 printf("System error\n");
911 dbprintf(("delete_file: (Failed) System error\n"));
914 printf("Deleted %s\n", ditem->path);
915 dbprintf(("delete_file: (Successful) Deleted %s\n",
919 printf("Warning - file '%s' not on tape list\n",
921 dbprintf(("delete_file: file '%s' not on tape list\n",
930 amfree(path_on_disk);
931 amfree(path_on_disk_slash);
934 printf("File %s doesn't exist in directory\n", path);
935 dbprintf(("delete_file: (Failed) File %s doesn't exist in directory\n",
941 /* print extract list into file. If NULL ptr passed print to screen */
942 void display_extract_list(file)
946 EXTRACT_LIST_ITEM *that;
953 if ((pager = getenv("PAGER")) == NULL)
958 * Set up the pager command so if the pager is terminated, we do
959 * not get a SIGPIPE back.
961 pager_command = stralloc2(pager, " ; /bin/cat > /dev/null");
962 if ((fp = popen(pager_command, "w")) == NULL)
964 printf("Warning - can't pipe through %s\n", pager);
967 amfree(pager_command);
971 if ((fp = fopen(file, "w")) == NULL)
973 printf("Can't open file '%s' to print extract list into\n", file);
978 for (this = extract_list; this != NULL; this = this->next)
980 fprintf(fp, "TAPE %s LEVEL %d DATE %s\n",
981 this->tape, this->level, this->date);
982 for (that = this->files; that != NULL; that = that->next)
983 fprintf(fp, "\t%s\n", that->path);
989 printf("Extract list written to file %s\n", file);
995 /* returns 0 if extract list empty and 1 if it isn't */
996 int is_extract_list_nonempty P((void))
998 return (extract_list != NULL);
1002 /* prints continue prompt and waits for response,
1003 returns 0 if don't, non-0 if do */
1004 static int okay_to_continue(allow_tape, allow_skip, allow_retry)
1019 prompt = "New tape device [?]: ";
1020 } else if (allow_tape && allow_skip) {
1021 prompt = "Continue [?/Y/n/s/t]? ";
1022 } else if (allow_tape && !allow_skip) {
1023 prompt = "Continue [?/Y/n/t]? ";
1024 } else if (allow_retry) {
1025 prompt = "Continue [?/Y/n/r]? ";
1027 prompt = "Continue [?/Y/n]? ";
1029 fputs(prompt, stdout);
1030 fflush(stdout); fflush(stderr);
1032 if ((line = agets(stdin)) == NULL) {
1043 while ((ch = *s++) != '\0' && isspace(ch)) {}
1046 printf("Enter a new device ([host:]device) or \"default\"\n");
1048 printf("Enter \"y\"es to continue, \"n\"o to stop");
1050 printf(", \"s\"kip this tape");
1053 printf(" or \"r\"etry this tape");
1056 printf(" or \"t\"ape to change tape drives");
1060 } else if (get_tape) {
1063 } else if (ch == '\0' || ch == 'Y' || ch == 'y') {
1065 } else if (allow_tape && (ch == 'T' || ch == 't')) {
1067 } else if (ch == 'N' || ch == 'n') {
1069 } else if (allow_retry && (ch == 'R' || ch == 'r')) {
1071 } else if (allow_skip && (ch == 'S' || ch == 's')) {
1079 static void send_to_tape_server(tss, cmd)
1087 for (l = 0, n = strlen(cmd); l < n; l += s)
1088 if ((s = write(tss, cmd + l, n - l)) < 0)
1090 perror("Error writing to tape server");
1094 for (l = 0, n = strlen(end); l < n; l += s)
1095 if ((s = write(tss, end + l, n - l)) < 0)
1097 perror("Error writing to tape server");
1103 /* start up connection to tape server and set commands to initiate
1104 transfer of dump image.
1105 Return tape server socket on success, -1 on error. */
1106 static int extract_files_setup(label, fsf)
1112 int tape_server_socket;
1113 char *disk_regex = NULL;
1114 char *host_regex = NULL;
1115 char *service_name = NULL;
1117 char *clean_datestamp, *ch, *ch1;
1119 service_name = stralloc2("amidxtape", SERVICE_SUFFIX);
1121 /* get tape server details */
1122 if ((sp = getservbyname(service_name, "tcp")) == NULL)
1124 printf("%s/tcp unknown protocol - config error?\n", service_name);
1125 amfree(service_name);
1128 amfree(service_name);
1129 seteuid(0); /* it either works ... */
1131 tape_server_socket = stream_client_privileged(tape_server_name,
1136 if (tape_server_socket < 0)
1138 printf("cannot connect to %s: %s\n", tape_server_name, strerror(errno));
1141 if (my_port >= IPPORT_RESERVED) {
1142 aclose(tape_server_socket);
1143 printf("did not get a reserved port: %d\n", my_port);
1147 seteuid(getuid()); /* put it back */
1149 /* do the security thing */
1150 #if defined(KRB4_SECURITY)
1151 #if 0 /* not yet implemented */
1154 line = get_krb_security();
1159 line = get_bsd_security();
1161 send_to_tape_server(tape_server_socket, line);
1162 memset(line, '\0', strlen(line));
1165 disk_regex = alloc(strlen(disk_name) * 2 + 3);
1170 /* we want to force amrestore to only match disk_name exactly */
1173 /* We need to escape some characters first... NT compatibilty crap */
1174 for (; *ch != 0; ch++, ch1++) {
1175 switch (*ch) { /* done this way in case there are more */
1178 /* no break; we do want to fall through... */
1184 /* we want to force amrestore to only match disk_name exactly */
1189 host_regex = alloc(strlen(dump_hostname) * 2 + 3);
1194 /* we want to force amrestore to only match dump_hostname exactly */
1197 /* We need to escape some characters first... NT compatibilty crap */
1198 for (; *ch != 0; ch++, ch1++) {
1199 switch (*ch) { /* done this way in case there are more */
1202 /* no break; we do want to fall through... */
1208 /* we want to force amrestore to only match dump_hostname exactly */
1213 clean_datestamp = stralloc(dump_datestamp);
1214 for(ch=ch1=clean_datestamp;*ch1 != '\0';ch1++) {
1222 if(am_has_feature(their_features, fe_amidxtaped_header) &&
1223 am_has_feature(their_features, fe_amidxtaped_device) &&
1224 am_has_feature(their_features, fe_amidxtaped_host) &&
1225 am_has_feature(their_features, fe_amidxtaped_disk) &&
1226 am_has_feature(their_features, fe_amidxtaped_datestamp)) {
1230 if(am_has_feature(their_features, fe_amidxtaped_config)) {
1231 tt = newstralloc2(tt, "CONFIG=", config);
1232 send_to_tape_server(tape_server_socket, tt);
1234 if(am_has_feature(their_features, fe_amidxtaped_label) &&
1235 label && label[0] != '/') {
1236 tt = newstralloc2(tt,"LABEL=",label);
1237 send_to_tape_server(tape_server_socket, tt);
1239 if(am_has_feature(their_features, fe_amidxtaped_fsf)) {
1241 ap_snprintf(v_fsf, 99, "%d", fsf);
1242 tt = newstralloc2(tt, "FSF=",v_fsf);
1243 send_to_tape_server(tape_server_socket, tt);
1245 send_to_tape_server(tape_server_socket, "HEADER");
1246 tt = newstralloc2(tt, "DEVICE=", dump_device_name);
1247 send_to_tape_server(tape_server_socket, tt);
1248 tt = newstralloc2(tt, "HOST=", host_regex);
1249 send_to_tape_server(tape_server_socket, tt);
1250 tt = newstralloc2(tt, "DISK=", disk_regex);
1251 send_to_tape_server(tape_server_socket, tt);
1252 tt = newstralloc2(tt, "DATESTAMP=", clean_datestamp);
1253 send_to_tape_server(tape_server_socket, tt);
1254 send_to_tape_server(tape_server_socket, "END");
1257 else if(1 /* am_has_feature(their_features, fe_amidxtaped_nargs) */) {
1258 /* 2.4.3 doesn't set fe_amidxtaped_nargs but support it */
1259 /* must be supported without test until 2005 */
1261 /* send to the tape server what tape file we want */
1270 send_to_tape_server(tape_server_socket, "6");
1271 send_to_tape_server(tape_server_socket, "-h");
1272 send_to_tape_server(tape_server_socket, "-p");
1273 send_to_tape_server(tape_server_socket, dump_device_name);
1274 send_to_tape_server(tape_server_socket, host_regex);
1275 send_to_tape_server(tape_server_socket, disk_regex);
1276 send_to_tape_server(tape_server_socket, clean_datestamp);
1278 dbprintf(("Started amidxtaped with arguments \"6 -h -p %s %s %s %s\"\n",
1279 dump_device_name, host_regex, disk_regex, clean_datestamp));
1284 amfree(clean_datestamp);
1286 return tape_server_socket;
1290 size_t read_file_header(buffer, file, buflen, tapedev)
1296 * Reads the first block of a tape file.
1300 bytes_read=read_buffer(tapedev,buffer,buflen);
1301 if(bytes_read < 0) {
1302 error("error reading tape: %s", strerror(errno));
1304 else if((size_t)bytes_read < buflen) {
1305 fprintf(stderr, "%s: short block %d byte%s\n",
1306 get_pname(), (int)bytes_read, (bytes_read == 1) ? "" : "s");
1307 print_header(stdout, file);
1308 error("Can't read file header");
1310 else { /* bytes_read == buflen */
1311 parse_file_header(buffer, file, bytes_read);
1313 return((size_t)bytes_read);
1316 enum dumptypes {IS_UNKNOWN, IS_DUMP, IS_GNUTAR, IS_TAR, IS_SAMBA, IS_SAMBA_TAR};
1318 /* exec restore to do the actual restoration */
1319 static void extract_files_child(in_fd, elist)
1321 EXTRACT_LIST *elist;
1324 int extra_params = 0;
1326 char **restore_args = NULL;
1328 EXTRACT_LIST_ITEM *fn;
1329 enum dumptypes dumptype = IS_UNKNOWN;
1330 char buffer[DISK_BLOCK_BYTES];
1335 int passwd_field = -1;
1337 char *domain = NULL, *smbpass = NULL;
1340 /* code executed by child to do extraction */
1343 /* make in_fd be our stdin */
1344 if (dup2(in_fd, STDIN_FILENO) == -1)
1346 perror("extract_list - extract files client");
1350 /* read the file header */
1352 buflen=read_file_header(buffer, &file, sizeof(buffer), STDIN_FILENO);
1354 if(buflen == 0 || file.type != F_DUMPFILE) {
1355 print_header(stdout, &file);
1356 error("bad header");
1359 if (file.program != NULL) {
1361 if (strcmp(file.program, GNUTAR) == 0)
1362 dumptype = IS_GNUTAR;
1365 if (dumptype == IS_UNKNOWN) {
1366 len_program = strlen(file.program);
1367 if(len_program >= 3 &&
1368 strcmp(&file.program[len_program-3],"tar") == 0)
1373 if (dumptype == IS_UNKNOWN && strcmp(file.program, SAMBA_CLIENT) ==0) {
1374 if (samba_extract_method == SAMBA_TAR)
1375 dumptype = IS_SAMBA_TAR;
1377 dumptype = IS_SAMBA;
1382 /* form the arguments to restore */
1383 files_off_tape = length_of_tape_list(elist);
1400 #if defined(XFSDUMP)
1401 if (strcmp(file.program, XFSDUMP) == 0) {
1402 extra_params = 4 + files_off_tape;
1412 restore_args = (char **)alloc((extra_params + files_off_tape + 1)
1417 restore_args[j++] = stralloc("smbclient");
1418 smbpass = findpass(file.disk, &domain);
1420 restore_args[j++] = stralloc(file.disk);
1422 restore_args[j++] = stralloc("-U");
1423 restore_args[j++] = smbpass;
1425 restore_args[j++] = stralloc("-W");
1426 restore_args[j++] = stralloc(domain);
1431 restore_args[j++] = stralloc("-d0");
1432 restore_args[j++] = stralloc("-Tx");
1433 restore_args[j++] = stralloc("-"); /* data on stdin */
1438 restore_args[j++] = stralloc("tar");
1439 restore_args[j++] = stralloc("-xpGvf");
1440 restore_args[j++] = stralloc("-"); /* data on stdin */
1443 restore_args[j++] = stralloc("tar");
1444 restore_args[j++] = stralloc("-xpvf");
1445 restore_args[j++] = stralloc("-"); /* data on stdin */
1449 restore_args[j++] = stralloc("restore");
1451 restore_args[j++] = stralloc("-xB");
1453 #if defined(XFSDUMP)
1454 if (strcmp(file.program, XFSDUMP) == 0) {
1455 restore_args[j++] = stralloc("-v");
1456 restore_args[j++] = stralloc("silent");
1460 if (strcmp(file.program, VDUMP) == 0) {
1461 restore_args[j++] = stralloc("xf");
1462 restore_args[j++] = stralloc("-"); /* data on stdin */
1466 restore_args[j++] = stralloc("xbf");
1467 restore_args[j++] = stralloc("2"); /* read in units of 1K */
1468 restore_args[j++] = stralloc("-"); /* data on stdin */
1473 for (i = 0, fn = elist->files; i < files_off_tape; i++, fn = fn->next)
1480 restore_args[j++] = stralloc2(".", fn->path);
1484 #if defined(XFSDUMP)
1485 if (strcmp(file.program, XFSDUMP) == 0) {
1487 * xfsrestore needs a -s option before each file to be
1488 * restored, and also wants them to be relative paths.
1490 restore_args[j++] = stralloc("-s");
1491 restore_args[j++] = stralloc(fn->path + 1);
1495 restore_args[j++] = stralloc(fn->path);
1499 #if defined(XFSDUMP)
1500 if (strcmp(file.program, XFSDUMP) == 0) {
1501 restore_args[j++] = stralloc("-");
1502 restore_args[j++] = stralloc(".");
1505 restore_args[j] = NULL;
1510 cmd = stralloc(SAMBA_CLIENT);
1513 /* fall through to ... */
1519 fprintf(stderr, "warning: GNUTAR program not available.\n");
1520 cmd = stralloc("tar");
1522 cmd = stralloc(GNUTAR);
1529 if (strcmp(file.program, DUMP) == 0) {
1530 cmd = stralloc(RESTORE);
1534 if (strcmp(file.program, VDUMP) == 0) {
1535 cmd = stralloc(VRESTORE);
1539 if (strcmp(file.program, VXDUMP) == 0) {
1540 cmd = stralloc(VXRESTORE);
1543 #if defined(XFSDUMP)
1544 if (strcmp(file.program, XFSDUMP) == 0) {
1545 cmd = stralloc(XFSRESTORE);
1549 fprintf(stderr, "warning: restore program for %s not available.\n",
1551 cmd = stralloc("restore");
1555 dbprintf(("Exec'ing %s with arguments:\n", cmd));
1556 for (i = 0; i < j; i++) {
1557 if( i == passwd_field)
1558 dbprintf(("\tXXXXX\n"));
1560 dbprintf(("\t%s\n", restore_args[i]));
1562 (void)execv(cmd, restore_args);
1563 /* only get here if exec failed */
1565 for (i = 0; i < j; i++) {
1566 amfree(restore_args[i]);
1568 amfree(restore_args);
1570 perror("amrecover couldn't exec");
1571 fprintf(stderr, " problem executing %s\n", cmd);
1579 /* does the actual extraction of files */
1580 /* The original design had the dump image being returned exactly as it
1581 appears on the tape, and this routine getting from the index server
1582 whether or not it is compressed, on the assumption that the tape
1583 server may not know how to uncompress it. But
1584 - Amrestore can't do that. It returns either compressed or uncompressed
1585 (always). Amrestore assumes it can uncompress files. It is thus a good
1586 idea to run the tape server on a machine with gzip.
1587 - The information about compression in the disklist is really only
1588 for future dumps. It is possible to change compression on a drive
1589 so the information in the disklist may not necessarily relate to
1590 the dump image on the tape.
1591 Consequently the design was changed to assuming that amrestore can
1592 uncompress any dump image and have it return an uncompressed file
1594 void extract_files P((void))
1596 EXTRACT_LIST *elist;
1598 amwait_t child_stat;
1601 int tape_server_socket;
1605 if (!is_extract_list_nonempty())
1607 printf("Extract list empty - No files to extract!\n");
1611 /* get tape device name from index server if none specified */
1612 if (tape_server_name == NULL) {
1613 tape_server_name = newstralloc(tape_server_name, server_name);
1615 if (tape_device_name == NULL) {
1616 if (send_command("TAPE") == -1)
1618 if (get_reply_line() == -1)
1621 if (!server_happy())
1626 /* skip reply number */
1627 tape_device_name = newstralloc(tape_device_name, l+4);
1630 if (strcmp(tape_device_name, "/dev/null") == 0)
1632 printf("amrecover: warning: using %s as the tape device will not work\n",
1637 for (elist = first_tape_list(); elist != NULL; elist = next_tape_list(elist))
1638 if(elist->tape[0]!='/') {
1640 printf("\nExtracting files using tape drive %s on host %s.\n",
1641 tape_device_name, tape_server_name);
1642 printf("The following tapes are needed:");
1647 printf(" %s\n", elist->tape);
1650 for (elist = first_tape_list(); elist != NULL; elist = next_tape_list(elist))
1651 if(elist->tape[0]=='/') {
1653 printf("\nExtracting files from holding disk on host %s.\n",
1655 printf("The following files are needed:");
1660 printf(" %s\n", elist->tape);
1663 getcwd(buf, sizeof(buf));
1664 printf("Restoring files into directory %s\n", buf);
1666 if (samba_extract_method == SAMBA_SMBCLIENT)
1667 printf("(unless it is a Samba backup, that will go through to the SMB server)\n");
1669 if (!okay_to_continue(0,0,0))
1673 while ((elist = first_tape_list()) != NULL)
1675 if(elist->tape[0]=='/') {
1676 dump_device_name = newstralloc(dump_device_name, elist->tape);
1677 printf("Extracting from file %s\n",dump_device_name);
1680 printf("Extracting files using tape drive %s on host %s.\n",
1681 tape_device_name, tape_server_name);
1682 printf("Load tape %s now\n", elist->tape);
1683 otc = okay_to_continue(1,1,0);
1686 else if (otc == SKIP_TAPE) {
1687 delete_tape_list(elist); /* skip this tape */
1690 dump_device_name = newstralloc(dump_device_name, tape_device_name);
1692 dump_datestamp = newstralloc(dump_datestamp, elist->date);
1694 /* connect to the tape handler daemon on the tape drive server */
1695 if ((tape_server_socket = extract_files_setup(elist->tape, elist->fileno)) == -1)
1697 fprintf(stderr, "amrecover - can't talk to tape server\n");
1701 /* okay, ready to extract. fork a child to do the actual work */
1702 if ((pid = fork()) == 0)
1704 /* this is the child process */
1705 /* never gets out of this clause */
1706 extract_files_child(tape_server_socket, elist);
1709 /* this is the parent */
1712 perror("extract_list - error forking child");
1716 /* store the child pid globally so that it can be killed on intr */
1717 extract_restore_child_pid = pid;
1719 aclose(tape_server_socket);
1721 /* wait for the child process to finish */
1722 if ((pid = waitpid(-1, &child_stat, 0)) == (pid_t)-1)
1724 perror("extract_list - error waiting for child");
1727 if (pid == extract_restore_child_pid)
1729 extract_restore_child_pid = -1;
1733 fprintf(stderr, "extract list - unknown child terminated?\n");
1736 if ((WIFEXITED(child_stat) != 0) && (WEXITSTATUS(child_stat) != 0))
1739 "extract_list - child returned non-zero status: %d\n",
1740 WEXITSTATUS(child_stat));
1741 otc = okay_to_continue(0,0,1);
1745 delete_tape_list(elist); /* tape failed so delete from list */
1747 else { /* RETRY_TAPE */
1751 delete_tape_list(elist); /* tape done so delete from list */