d254022ed573a72b3efe060ef171ffec3fa746ab
[debian/amanda] / recover-src / extract_list.c
1 /*
2  * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3  * Copyright (c) 1991-1998, 2000 University of Maryland at College Park
4  * All Rights Reserved.
5  *
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.
15  *
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.
22  *
23  * Authors: the Amanda Development Team.  Its members are listed in a
24  * file named AUTHORS, in the root directory of this distribution.
25  */
26 /*
27  * $Id$
28  *
29  * implements the "extract" command in amrecover
30  */
31
32 #include "amanda.h"
33 #include "match.h"
34 #include "amrecover.h"
35 #include "fileheader.h"
36 #include "dgram.h"
37 #include "stream.h"
38 #include "tapelist.h"
39 #ifdef SAMBA_CLIENT
40 #include "findpass.h"
41 #endif
42 #include "util.h"
43 #include "conffile.h"
44 #include "protocol.h"
45 #include "event.h"
46 #include "client_util.h"
47 #include "security.h"
48
49 typedef struct EXTRACT_LIST_ITEM {
50     char *path;
51     struct EXTRACT_LIST_ITEM *next;
52 }
53 EXTRACT_LIST_ITEM;
54
55 typedef struct EXTRACT_LIST {
56     char *date;                 /* date tape created */
57     int  level;                 /* level of dump */
58     char *tape;                 /* tape label */
59     off_t fileno;               /* fileno on tape */
60     EXTRACT_LIST_ITEM *files;   /* files to get off tape */
61
62     struct EXTRACT_LIST *next;
63 }
64 EXTRACT_LIST;
65
66 typedef struct ctl_data_s {
67   int                      header_done;
68   int                      child_pipe[2];
69   int                      pid;
70   EXTRACT_LIST            *elist;
71   dumpfile_t               file;
72   data_path_t              data_path;
73   char                    *addrs;
74   backup_support_option_t *bsu;
75 } ctl_data_t;
76
77 #define SKIP_TAPE 2
78 #define RETRY_TAPE 3
79
80 static struct {
81     const char *name;
82     security_stream_t *fd;
83 } amidxtaped_streams[] = {
84 #define CTLFD  0
85     { "CTL", NULL },
86 #define DATAFD  1
87     { "DATA", NULL },
88 };
89 #define NSTREAMS  (int)(sizeof(amidxtaped_streams) / sizeof(amidxtaped_streams[0]))
90
91
92 static void amidxtaped_response(void *, pkt_t *, security_handle_t *);
93 static void stop_amidxtaped(void);
94 static char *dump_device_name = NULL;
95 static char *errstr;
96 static char *amidxtaped_line = NULL;
97 extern char *localhost;
98
99 /* global pid storage for interrupt handler */
100 pid_t extract_restore_child_pid = -1;
101
102 static EXTRACT_LIST *extract_list = NULL;
103 static const security_driver_t *amidxtaped_secdrv;
104
105 unsigned short samba_extract_method = SAMBA_TAR;
106
107 #define READ_TIMEOUT    240*60
108
109 EXTRACT_LIST *first_tape_list(void);
110 EXTRACT_LIST *next_tape_list(EXTRACT_LIST *list);
111 static int is_empty_dir(char *fname);
112 int is_extract_list_nonempty(void);
113 int length_of_tape_list(EXTRACT_LIST *tape_list);
114 void add_file(char *path, char *regex);
115 void add_glob(char *glob);
116 void add_regex(char *regex);
117 void clear_extract_list(void);
118 void clean_tape_list(EXTRACT_LIST *tape_list);
119 void clean_extract_list(void);
120 void check_file_overwrite(char *filename);
121 void delete_file(char *path, char *regex);
122 void delete_glob(char *glob);
123 void delete_regex(char *regex);
124 void delete_tape_list(EXTRACT_LIST *tape_list);
125 void display_extract_list(char *file);
126 void extract_files(void);
127 void read_file_header(char *buffer,
128                         dumpfile_t *file,
129                         size_t buflen,
130                         int tapedev);
131 static int add_extract_item(DIR_ITEM *ditem);
132 static int delete_extract_item(DIR_ITEM *ditem);
133 static int extract_files_setup(char *label, off_t fsf);
134 static int okay_to_continue(int allow_tape,
135                         int allow_skip,
136                         int allow_retry);
137 static ssize_t read_buffer(int datafd,
138                         char *buffer,
139                         size_t buflen,
140                         long timeout_s);
141 static void clear_tape_list(EXTRACT_LIST *tape_list);
142 static void extract_files_child(ctl_data_t *ctl_data);
143 static void send_to_tape_server(security_stream_t *stream, char *cmd);
144 int writer_intermediary(EXTRACT_LIST *elist);
145 int get_amidxtaped_line(void);
146 static void read_amidxtaped_data(void *, void *, ssize_t);
147 static char *merge_path(char *path1, char *path2);
148 static gboolean ask_file_overwrite(ctl_data_t *ctl_data);
149 static void start_processing_data(ctl_data_t *ctl_data);
150
151 /*
152  * Function:  ssize_t read_buffer(datafd, buffer, buflen, timeout_s)
153  *
154  * Description:
155  *      read data from input file desciptor waiting up to timeout_s
156  *      seconds before returning data.
157  *
158  * Inputs:
159  *      datafd    - File descriptor to read from.
160  *      buffer    - Buffer to read into.
161  *      buflen    - Maximum number of bytes to read into buffer.
162  *      timeout_s - Seconds to wait before returning what was already read.
163  *
164  * Returns:
165  *      >0        - Number of data bytes in buffer.
166  *       0        - EOF
167  *      -1        - errno == ETIMEDOUT if no data available in specified time.
168  *                  errno == ENFILE if datafd is invalid.
169  *                  otherwise errno is set by select or read..
170  */
171
172 static ssize_t
173 read_buffer(
174     int         datafd,
175     char *      buffer,
176     size_t      buflen,
177     long        timeout_s)
178 {
179     ssize_t size = 0;
180     SELECT_ARG_TYPE readset;
181     struct timeval timeout;
182     char *dataptr;
183     ssize_t spaceleft;
184     int nfound;
185
186     if(datafd < 0 || datafd >= (int)FD_SETSIZE) {
187         errno = EMFILE;                                 /* out of range */
188         return -1;
189     }
190
191     dataptr = buffer;
192     spaceleft = (ssize_t)buflen;
193
194     do {
195         FD_ZERO(&readset);
196         FD_SET(datafd, &readset);
197         timeout.tv_sec = timeout_s;
198         timeout.tv_usec = 0;
199         nfound = select(datafd+1, &readset, NULL, NULL, &timeout);
200         if(nfound < 0 ) {
201             /* Select returned an error. */
202             g_fprintf(stderr,_("select error: %s\n"), strerror(errno));
203             size = -1;
204             break;
205         }
206
207         if (nfound == 0) {
208             /* Select timed out. */
209             if (timeout_s != 0)  {
210                 /* Not polling: a real read timeout */
211                 g_fprintf(stderr,_("timeout waiting for restore\n"));
212                 g_fprintf(stderr,_("increase READ_TIMEOUT in recover-src/extract_list.c if your tape is slow\n"));
213             }
214             errno = ETIMEDOUT;
215             size = -1;
216             break;
217         }
218
219         if(!FD_ISSET(datafd, &readset))
220             continue;
221
222         /* Select says data is available, so read it.  */
223         size = read(datafd, dataptr, (size_t)spaceleft);
224         if (size < 0) {
225             if ((errno == EINTR) || (errno == EAGAIN)) {
226                 continue;
227             }
228             if (errno != EPIPE) {
229                 g_fprintf(stderr, _("read_buffer: read error - %s"),
230                     strerror(errno));
231                 break;
232             }
233             size = 0;
234         }
235         spaceleft -= size;
236         dataptr += size;
237     } while ((size > 0) && (spaceleft > 0));
238
239     return ((((ssize_t)buflen-spaceleft) > 0) ? ((ssize_t)buflen-spaceleft) : size);
240 }
241
242
243 EXTRACT_LIST *
244 first_tape_list(void)
245 {
246     return extract_list;
247 }
248
249 EXTRACT_LIST *
250 next_tape_list(
251     /*@keep@*/EXTRACT_LIST *list)
252 {
253     if (list == NULL)
254         return NULL;
255     return list->next;
256 }
257
258 static void
259 clear_tape_list(
260     EXTRACT_LIST *      tape_list)
261 {
262     EXTRACT_LIST_ITEM *this, *next;
263
264
265     this = tape_list->files;
266     while (this != NULL)
267     {
268         next = this->next;
269         amfree(this->path);
270         amfree(this);
271         this = next;
272     }
273     tape_list->files = NULL;
274 }
275
276
277 /* remove a tape list from the extract list, clearing the tape list
278    beforehand if necessary */
279 void
280 delete_tape_list(
281     EXTRACT_LIST *tape_list)
282 {
283     EXTRACT_LIST *this, *prev;
284
285     if (tape_list == NULL)
286         return;
287
288     /* is it first on the list? */
289     if (tape_list == extract_list)
290     {
291         extract_list = tape_list->next;
292         clear_tape_list(tape_list);
293         amfree(tape_list->date);
294         amfree(tape_list->tape);
295         amfree(tape_list);
296         return;
297     }
298
299     /* so not first on list - find it and delete */
300     prev = extract_list;
301     this = extract_list->next;
302     while (this != NULL)
303     {
304         if (this == tape_list)
305         {
306             prev->next = tape_list->next;
307             clear_tape_list(tape_list);
308             amfree(tape_list->date);
309             amfree(tape_list->tape);
310             amfree(tape_list);
311             return;
312         }
313         prev = this;
314         this = this->next;
315     }
316     /*NOTREACHED*/
317 }
318
319
320 /* return the number of files on a tape's list */
321 int
322 length_of_tape_list(
323     EXTRACT_LIST *tape_list)
324 {
325     EXTRACT_LIST_ITEM *fn;
326     int n;
327
328     n = 0;
329     for (fn = tape_list->files; fn != NULL; fn = fn->next)
330         n++;
331
332     return n;
333 }
334
335
336 void
337 clear_extract_list(void)
338 {
339     while (extract_list != NULL)
340         delete_tape_list(extract_list);
341 }
342
343
344 void
345 clean_tape_list(
346     EXTRACT_LIST *tape_list)
347 {
348     EXTRACT_LIST_ITEM *fn1, *pfn1, *ofn1;
349     EXTRACT_LIST_ITEM *fn2, *pfn2, *ofn2;
350     int remove_fn1;
351     int remove_fn2;
352
353     pfn1 = NULL;
354     fn1 = tape_list->files;
355     while (fn1 != NULL) {
356         remove_fn1 = 0;
357
358         pfn2 = fn1;
359         fn2 = fn1->next;
360         while (fn2 != NULL && remove_fn1 == 0) {
361             remove_fn2 = 0;
362             if(strcmp(fn1->path, fn2->path) == 0) {
363                 remove_fn2 = 1;
364             } else if (strncmp(fn1->path, fn2->path, strlen(fn1->path)) == 0 &&
365                        ((strlen(fn2->path) > strlen(fn1->path) &&
366                          fn2->path[strlen(fn1->path)] == '/') ||
367                        (fn1->path[strlen(fn1->path)-1] == '/'))) {
368                 remove_fn2 = 1;
369             } else if (strncmp(fn2->path, fn1->path, strlen(fn2->path)) == 0 &&
370                        ((strlen(fn1->path) > strlen(fn2->path) &&
371                          fn1->path[strlen(fn2->path)] == '/')  ||
372                        (fn2->path[strlen(fn2->path)-1] == '/'))) {
373                 remove_fn1 = 1;
374                 break;
375             }
376
377             if (remove_fn2) {
378                 dbprintf(_("removing path %s, it is included in %s\n"),
379                           fn2->path, fn1->path);
380                 ofn2 = fn2;
381                 fn2 = fn2->next;
382                 amfree(ofn2->path);
383                 amfree(ofn2);
384                 pfn2->next = fn2;
385             } else if (remove_fn1 == 0) {
386                 pfn2 = fn2;
387                 fn2 = fn2->next;
388             }
389         }
390
391         if(remove_fn1 != 0) {
392             /* fn2->path is always valid */
393             /*@i@*/ dbprintf(_("removing path %s, it is included in %s\n"),
394             /*@i@*/           fn1->path, fn2->path);
395             ofn1 = fn1;
396             fn1 = fn1->next;
397             amfree(ofn1->path);
398             if(pfn1 == NULL) {
399                 amfree(tape_list->files);
400                 tape_list->files = fn1;
401             } else {
402                 amfree(pfn1->next);
403                 pfn1->next = fn1;
404             }
405         } else {
406             pfn1 = fn1;
407             fn1 = fn1->next;
408         }
409     }
410 }
411
412
413 static char *
414 file_of_path(
415     char *path,
416     char **dir)
417 {
418     char *npath = g_path_get_basename(path);
419     *dir = g_path_get_dirname(path);
420     if (strcmp(*dir, ".") == 0) {
421         amfree(*dir);
422     }
423     return npath;
424 }
425
426 void
427 clean_extract_list(void)
428 {
429     EXTRACT_LIST *this;
430
431     for (this = extract_list; this != NULL; this = this->next)
432         clean_tape_list(this);
433 }
434
435
436 int add_to_unlink_list(char *path);
437 int do_unlink_list(void);
438 void free_unlink_list(void);
439
440 typedef struct s_unlink_list {
441     char *path;
442     struct s_unlink_list *next;
443 } t_unlink_list;
444 t_unlink_list *unlink_list = NULL;
445
446 int
447 add_to_unlink_list(
448     char *path)
449 {
450     t_unlink_list *ul;
451
452     if (!unlink_list) {
453         unlink_list = alloc(SIZEOF(*unlink_list));
454         unlink_list->path = stralloc(path);
455         unlink_list->next = NULL;
456     } else {
457         for (ul = unlink_list; ul != NULL; ul = ul->next) {
458             if (strcmp(ul->path, path) == 0)
459                 return 0;
460         }
461         ul = alloc(SIZEOF(*ul));
462         ul->path = stralloc(path);
463         ul->next = unlink_list;
464         unlink_list = ul;
465     }
466     return 1;
467 }
468
469 int
470 do_unlink_list(void)
471 {
472     t_unlink_list *ul;
473     int ret = 1;
474
475     for (ul = unlink_list; ul != NULL; ul = ul->next) {
476         if (unlink(ul->path) < 0) {
477             g_fprintf(stderr,_("Can't unlink %s: %s\n"), ul->path, strerror(errno));
478             ret = 0;
479         }
480     }
481     return ret;
482 }
483
484
485 void
486 free_unlink_list(void)
487 {
488     t_unlink_list *ul, *ul1;
489
490     for (ul = unlink_list; ul != NULL; ul = ul1) {
491         amfree(ul->path);
492         ul1 = ul->next;
493         amfree(ul);
494     }
495
496     unlink_list = NULL;
497 }
498
499
500
501 void
502 check_file_overwrite(
503     char *dir)
504 {
505     EXTRACT_LIST      *this;
506     EXTRACT_LIST_ITEM *fn;
507     struct stat        stat_buf;
508     char              *filename;
509     char              *path, *s;
510
511     for (this = extract_list; this != NULL; this = this->next) {
512         for (fn = this->files; fn != NULL ; fn = fn->next) {
513
514             /* Check path component of fn->path */
515
516             path = stralloc2(dir, fn->path);
517             if (path[strlen(path)-1] == '/') {
518                 path[strlen(path)-1] = '\0';
519             }
520
521             s = path + strlen(dir) + 1;
522             while((s = strchr(s, '/'))) {
523                 *s = '\0';
524                 if (lstat(path, &stat_buf) == 0) {
525                     if(!S_ISDIR(stat_buf.st_mode)) {
526                         if (add_to_unlink_list(path)) {
527                             g_printf(_("WARNING: %s is not a directory, "
528                                    "it will be deleted.\n"),
529                                    path);
530                         }
531                     }
532                 }
533                 else if (errno != ENOENT) {
534                     g_printf(_("Can't stat %s: %s\n"), path, strerror(errno));
535                 }
536                 *s = '/';
537                 s++;
538             }
539             amfree(path);
540
541             /* Check fn->path */
542
543             filename = stralloc2(dir, fn->path);
544             if (filename[strlen(filename)-1] == '/') {
545                 filename[strlen(filename)-1] = '\0';
546             }
547
548             if (lstat(filename, &stat_buf) == 0) {
549                 if(S_ISDIR(stat_buf.st_mode)) {
550                     if(!is_empty_dir(filename)) {
551                         g_printf(_("WARNING: All existing files in %s "
552                                "will be deleted.\n"), filename);
553                     }
554                 } else if(S_ISREG(stat_buf.st_mode)) {
555                     g_printf(_("WARNING: Existing file %s will be overwritten\n"),
556                            filename);
557                 } else {
558                     if (add_to_unlink_list(filename)) {
559                         g_printf(_("WARNING: Existing entry %s will be deleted\n"),
560                                filename);
561                     }
562                 }
563             } else if (errno != ENOENT) {
564                 g_printf(_("Can't stat %s: %s\n"), filename, strerror(errno));
565             }
566             amfree(filename);
567         }
568     }
569 }
570
571
572 /* returns -1 if error */
573 /* returns  0 on succes */
574 /* returns  1 if already added */
575 static int
576 add_extract_item(
577     DIR_ITEM *ditem)
578 {
579     EXTRACT_LIST *this, *this1;
580     EXTRACT_LIST_ITEM *that, *curr;
581     char *ditem_path = NULL;
582
583     ditem_path = stralloc(ditem->path);
584     clean_pathname(ditem_path);
585
586     for (this = extract_list; this != NULL; this = this->next)
587     {
588         /* see if this is the list for the tape */      
589         if (this->level == ditem->level && strcmp(this->tape, ditem->tape) == 0)
590         {
591             /* yes, so add to list */
592             curr=this->files;
593             while(curr!=NULL)
594             {
595                 if (strcmp(curr->path,ditem_path) == 0) {
596                     amfree(ditem_path);
597                     return 1;
598                 }
599                 curr=curr->next;
600             }
601             that = (EXTRACT_LIST_ITEM *)alloc(sizeof(EXTRACT_LIST_ITEM));
602             that->path = stralloc(ditem_path);
603             that->next = this->files;
604             this->files = that;         /* add at front since easiest */
605             amfree(ditem_path);
606             return 0;
607         }
608     }
609
610     /* so this is the first time we have seen this tape */
611     this = (EXTRACT_LIST *)alloc(sizeof(EXTRACT_LIST));
612     this->tape = stralloc(ditem->tape);
613     this->level = ditem->level;
614     this->fileno = ditem->fileno;
615     this->date = stralloc(ditem->date);
616     that = (EXTRACT_LIST_ITEM *)alloc(sizeof(EXTRACT_LIST_ITEM));
617     that->path = stralloc(ditem_path);
618     that->next = NULL;
619     this->files = that;
620
621     /* add this in date increasing order          */
622     /* because restore must be done in this order */
623     /* add at begining */
624     if(extract_list==NULL || strcmp(this->date,extract_list->date) < 0)
625     {
626         this->next = extract_list;
627         extract_list = this;
628         amfree(ditem_path);
629         return 0;
630     }
631     for (this1 = extract_list; this1->next != NULL; this1 = this1->next)
632     {
633         /* add in the middle */
634         if(strcmp(this->date,this1->next->date) < 0)
635         {
636             this->next = this1->next;
637             this1->next = this;
638             amfree(ditem_path);
639             return 0;
640         }
641     }
642     /* add at end */
643     this->next = NULL;
644     this1->next = this;
645     amfree(ditem_path);
646     return 0;
647 }
648
649
650 /* returns -1 if error */
651 /* returns  0 on deletion */
652 /* returns  1 if not there */
653 static int
654 delete_extract_item(
655     DIR_ITEM *ditem)
656 {
657     EXTRACT_LIST *this;
658     EXTRACT_LIST_ITEM *that, *prev;
659     char *ditem_path = NULL;
660
661     ditem_path = stralloc(ditem->path);
662     clean_pathname(ditem_path);
663
664     for (this = extract_list; this != NULL; this = this->next)
665     {
666         /* see if this is the list for the tape */      
667         if (this->level == ditem->level && strcmp(this->tape, ditem->tape) == 0)
668         {
669             /* yes, so find file on list */
670             that = this->files;
671             if (strcmp(that->path, ditem_path) == 0)
672             {
673                 /* first on list */
674                 this->files = that->next;
675                 amfree(that->path);
676                 amfree(that);
677                 /* if list empty delete it */
678                 if (this->files == NULL)
679                     delete_tape_list(this);
680                 amfree(ditem_path);
681                 return 0;
682             }
683             prev = that;
684             that = that->next;
685             while (that != NULL)
686             {
687                 if (strcmp(that->path, ditem_path) == 0)
688                 {
689                     prev->next = that->next;
690                     amfree(that->path);
691                     amfree(that);
692                     amfree(ditem_path);
693                     return 0;
694                 }
695                 prev = that;
696                 that = that->next;
697             }
698             amfree(ditem_path);
699             return 1;
700         }
701     }
702
703     amfree(ditem_path);
704     return 1;
705 }
706
707 static char *
708 merge_path(
709     char *path1,
710     char *path2)
711 {
712     char *result;
713     int len = strlen(path1);
714     if (path1[len-1] == '/' && path2[0] == '/') {
715         result = stralloc2(path1, path2+1);
716     } else if (path1[len-1] != '/' && path2[0] != '/') {
717         result = vstralloc(path1, "/", path2, NULL);
718     } else {
719         result = stralloc2(path1, path2);
720     }
721     return result;
722 }
723
724 void
725 add_glob(
726     char *      glob)
727 {
728     char *regex;
729     char *regex_path;
730     char *s;
731     char *uqglob;
732     char *dir;
733     char *sdir = NULL;
734     int   result = 1;
735
736     if (disk_path == NULL) {
737         g_printf(_("Must select directory before adding files\n"));
738         return;
739     }
740
741     uqglob = unquote_string(glob);
742     glob = file_of_path(uqglob, &dir);
743     if (dir) {
744         sdir = merge_path(mount_point, disk_path);
745         result = cd_glob(dir, 0);
746         amfree(dir);
747     }
748     if (result) {
749         regex = glob_to_regex(glob);
750         dbprintf(_("add_glob (%s) -> %s\n"), uqglob, regex);
751         if ((s = validate_regexp(regex)) != NULL) {
752             g_printf(_("%s is not a valid shell wildcard pattern: "), glob);
753             puts(s);
754         } else {
755             /*
756              * glob_to_regex() anchors the beginning of the pattern with ^,
757              * but we will be tacking it onto the end of the current directory
758              * in add_file, so strip that off.  Also, it anchors the end with
759              * $, but we need to match an optional trailing /, so tack that on
760              * the end.
761              */
762             regex_path = stralloc(regex + 1);
763             regex_path[strlen(regex_path) - 1] = '\0';
764             strappend(regex_path, "[/]*$");
765             add_file(uqglob, regex_path);
766             amfree(regex_path);
767         }
768         if (sdir) {
769             set_directory(sdir, 0);
770         }
771         amfree(regex);
772     }
773     amfree(sdir);
774     amfree(uqglob);
775     amfree(glob);
776 }
777
778 void
779 add_regex(
780     char *      regex)
781 {
782     char *s;
783     char *dir;
784     char *sdir = NULL;
785     char *uqregex;
786     char *newregex;
787     int   result = 1;
788
789     if (disk_path == NULL) {
790         g_printf(_("Must select directory before adding files\n"));
791         return;
792     }
793
794     uqregex = unquote_string(regex);
795     newregex = file_of_path(uqregex, &dir);
796     if (dir) {
797         sdir = merge_path(mount_point, disk_path);
798         result = cd_regex(dir, 0);
799         amfree(dir);
800     }
801
802     if (result) { 
803         if ((s = validate_regexp(newregex)) != NULL) {
804             g_printf(_("\"%s\" is not a valid regular expression: "), newregex);
805             puts(s);
806         } else {
807             add_file(uqregex, newregex);
808         }
809         if (sdir) {
810             set_directory(sdir, 0);
811         }
812     }
813     amfree(sdir);
814     amfree(uqregex);
815     amfree(newregex);
816 }
817
818 void
819 add_file(
820     char *      path,
821     char *      regex)
822 {
823     DIR_ITEM *ditem, lditem;
824     char *path_on_disk = NULL;
825     char *cmd = NULL;
826     char *err = NULL;
827     int i;
828     ssize_t j;
829     char *dir, *dir_undo, dir_undo_ch = '\0';
830     char *ditem_path = NULL;
831     char *qditem_path = NULL;
832     char *l = NULL;
833     int  added;
834     char *s, *fp, *quoted;
835     int ch;
836     int found_one;
837     int dir_entries;
838
839     if (disk_path == NULL) {
840         g_printf(_("Must select directory before adding files\n"));
841         return;
842     }
843     memset(&lditem, 0, sizeof(lditem)); /* Prevent use of bogus data... */
844
845     dbprintf(_("add_file: Looking for \"%s\"\n"), regex);
846
847     if(strcmp(regex, "/[/]*$") == 0) {  /* "/" behave like "." */
848         regex = "\\.[/]*$";
849     }
850     else if(strcmp(regex, "[^/]*[/]*$") == 0) {         /* "*" */
851         regex = "([^/.]|\\.[^/]+|[^/.][^/]*)[/]*$";
852     } else {
853         /* remove "/" at end of path */
854         j = (ssize_t)(strlen(regex) - 1);
855         while(j >= 0 && regex[j] == '/')
856             regex[j--] = '\0';
857     }
858
859     /* convert path (assumed in cwd) to one on disk */
860     if (strcmp(disk_path, "/") == 0) {
861         if (*regex == '/') {
862             /* No mods needed if already starts with '/' */
863             path_on_disk = stralloc(regex);
864         } else {
865             /* Prepend '/' */
866             path_on_disk = stralloc2("/", regex);
867         }
868     } else {
869         char *clean_disk_path = clean_regex(disk_path, 0);
870         path_on_disk = vstralloc(clean_disk_path, "/", regex, NULL);
871         amfree(clean_disk_path);
872     }
873
874     dbprintf(_("add_file: Converted path=\"%s\" to path_on_disk=\"%s\"\n"),
875               regex, path_on_disk);
876
877     found_one = 0;
878     dir_entries = 0;
879     for (ditem=get_dir_list(); ditem!=NULL; ditem=get_next_dir_item(ditem))
880     {
881         dir_entries++;
882         quoted = quote_string(ditem->path);
883         dbprintf(_("add_file: Pondering ditem->path=%s\n"), quoted);
884         amfree(quoted);
885         if (match(path_on_disk, ditem->path))
886         {
887             found_one = 1;
888             j = (ssize_t)strlen(ditem->path);
889             if((j > 0 && ditem->path[j-1] == '/')
890                || (j > 1 && ditem->path[j-2] == '/' && ditem->path[j-1] == '.'))
891             {   /* It is a directory */
892                 ditem_path = newstralloc(ditem_path, ditem->path);
893                 clean_pathname(ditem_path);
894
895                 qditem_path = quote_string(ditem_path);
896                 cmd = newstralloc2(cmd, "ORLD ", qditem_path);
897                 amfree(qditem_path);
898                 if(send_command(cmd) == -1) {
899                     amfree(cmd);
900                     amfree(ditem_path);
901                     amfree(path_on_disk);
902                     exit(1);
903                 }
904                 amfree(cmd);
905                 cmd = NULL;
906                 /* skip preamble */
907                 if ((i = get_reply_line()) == -1) {
908                     amfree(ditem_path);
909                     amfree(path_on_disk);
910                     exit(1);
911                 }
912                 if(i==0) {              /* assume something wrong */
913                     amfree(ditem_path);
914                     amfree(path_on_disk);
915                     l = reply_line();
916                     g_printf("%s\n", l);
917                     return;
918                 }
919                 dir_undo = NULL;
920                 added=0;
921                 lditem.path = newstralloc(lditem.path, ditem->path);
922                 /* skip the last line -- duplicate of the preamble */
923
924                 while ((i = get_reply_line()) != 0) {
925                     if (i == -1) {
926                         amfree(ditem_path);
927                         amfree(path_on_disk);
928                         exit(1);
929                     }
930                     if(err) {
931                         if(cmd == NULL) {
932                             if(dir_undo) *dir_undo = dir_undo_ch;
933                             dir_undo = NULL;
934                             cmd = stralloc(l);  /* save for error report */
935                         }
936                         continue;       /* throw the rest of the lines away */
937                     }
938                     l=reply_line();
939                     if (!server_happy()) {
940                         puts(l);
941                         continue;
942                     }
943
944                     s = l;
945                     if(strncmp_const_skip(l, "201-", s, ch) != 0) {
946                         err = _("bad reply: not 201-");
947                         continue;
948                     }
949                     ch = *s++;
950
951                     skip_whitespace(s, ch);
952                     if(ch == '\0') {
953                         err = _("bad reply: missing date field");
954                         continue;
955                     }
956                     fp = s-1;
957                     skip_non_whitespace(s, ch);
958                     s[-1] = '\0';
959                     lditem.date = newstralloc(lditem.date, fp);
960                     s[-1] = (char)ch;
961
962                     skip_whitespace(s, ch);
963                     if(ch == '\0' || sscanf(s - 1, "%d", &lditem.level) != 1) {
964                         err = _("bad reply: cannot parse level field");
965                         continue;
966                     }
967                     skip_integer(s, ch);
968
969                     skip_whitespace(s, ch);
970                     if(ch == '\0') {
971                         err = _("bad reply: missing tape field");
972                         continue;
973                     }
974                     fp = s-1;
975                     skip_non_whitespace(s, ch);
976                     s[-1] = '\0';
977                     lditem.tape = newstralloc(lditem.tape, fp);
978                     s[-1] = (char)ch;
979
980                     if(am_has_feature(indexsrv_features, fe_amindexd_fileno_in_ORLD)) {
981                         long long fileno_ = (long long)0;
982                         skip_whitespace(s, ch);
983                         if(ch == '\0' ||
984                            sscanf(s - 1, "%lld", &fileno_) != 1) {
985                             err = _("bad reply: cannot parse fileno field");
986                             continue;
987                         }
988                         lditem.fileno = (off_t)fileno_;
989                         skip_integer(s, ch);
990                     }
991
992                     skip_whitespace(s, ch);
993                     if(ch == '\0') {
994                         err = _("bad reply: missing directory field");
995                         continue;
996                     }
997                     dir = s - 1;
998                     skip_quoted_string(s, ch);
999                     dir_undo = s - 1;
1000                     dir_undo_ch = *dir_undo;
1001                     *dir_undo = '\0';
1002
1003                     switch(add_extract_item(&lditem)) {
1004                     case -1:
1005                         g_printf(_("System error\n"));
1006                         dbprintf(_("add_file: (Failed) System error\n"));
1007                         break;
1008
1009                     case  0:
1010                         quoted = quote_string(lditem.path);
1011                         g_printf(_("Added dir %s at date %s\n"),
1012                                quoted, lditem.date);
1013                         dbprintf(_("add_file: (Successful) Added dir %s at date %s\n"),
1014                                   quoted, lditem.date);
1015                         amfree(quoted);
1016                         added=1;
1017                         break;
1018
1019                     case  1:
1020                         break;
1021                     }
1022                 }
1023                 if(!server_happy()) {
1024                     puts(reply_line());
1025                 } else if(err) {
1026                     if (*err)
1027                         puts(err);
1028                     if (cmd)
1029                         puts(cmd);
1030                 } else if(added == 0) {
1031                     quoted = quote_string(ditem_path);
1032                     g_printf(_("dir %s already added\n"), quoted);
1033                     dbprintf(_("add_file: dir %s already added\n"), quoted);
1034                     amfree(quoted);
1035                 }
1036             }
1037             else /* It is a file */
1038             {
1039                 switch(add_extract_item(ditem)) {
1040                 case -1:
1041                     g_printf(_("System error\n"));
1042                     dbprintf(_("add_file: (Failed) System error\n"));
1043                     break;
1044
1045                 case  0:
1046                     quoted = quote_string(ditem->path);
1047                     g_printf(_("Added file %s\n"), quoted);
1048                     dbprintf(_("add_file: (Successful) Added %s\n"), quoted);
1049                     amfree(quoted);
1050                     break;
1051
1052                 case  1:
1053                     quoted = quote_string(ditem->path);
1054                     g_printf(_("File %s already added\n"), quoted);
1055                     dbprintf(_("add_file: file %s already added\n"), quoted);
1056                     amfree(quoted);
1057                 }
1058             }
1059         }
1060     }
1061
1062     amfree(cmd);
1063     amfree(ditem_path);
1064     amfree(path_on_disk);
1065
1066     amfree(lditem.path);
1067     amfree(lditem.date);
1068     amfree(lditem.tape);
1069
1070     if(! found_one) {
1071         quoted = quote_string(path);
1072         g_printf(_("File %s doesn't exist in directory\n"), quoted);
1073         dbprintf(_("add_file: (Failed) File %s doesn't exist in directory\n"),
1074                   quoted);
1075         amfree(quoted);
1076     }
1077 }
1078
1079
1080 void
1081 delete_glob(
1082     char *      glob)
1083 {
1084     char *regex;
1085     char *regex_path;
1086     char *s;
1087     char *uqglob;
1088     char *newglob;
1089     char *dir;
1090     char *sdir = NULL;
1091     int   result = 1;
1092
1093     if (disk_path == NULL) {
1094         g_printf(_("Must select directory before adding files\n"));
1095         return;
1096     }
1097
1098     uqglob = unquote_string(glob);
1099     newglob = file_of_path(uqglob, &dir);
1100     if (dir) {
1101         sdir = merge_path(mount_point, disk_path);
1102         result = cd_glob(dir, 0);
1103         amfree(dir);
1104     }
1105     if (result) {
1106         regex = glob_to_regex(newglob);
1107         dbprintf(_("delete_glob (%s) -> %s\n"), newglob, regex);
1108         if ((s = validate_regexp(regex)) != NULL) {
1109             g_printf(_("\"%s\" is not a valid shell wildcard pattern: "),
1110                      newglob);
1111             puts(s);
1112 } else {
1113             /*
1114              * glob_to_regex() anchors the beginning of the pattern with ^,
1115              * but we will be tacking it onto the end of the current directory
1116              * in add_file, so strip that off.  Also, it anchors the end with
1117              * $, but we need to match an optional trailing /, so tack that on
1118              * the end.
1119              */
1120             regex_path = stralloc(regex + 1);
1121             regex_path[strlen(regex_path) - 1] = '\0';
1122             strappend(regex_path, "[/]*$");
1123             delete_file(uqglob, regex_path);
1124             amfree(regex_path);
1125         }
1126         if (sdir) {
1127             set_directory(sdir, 0);
1128         }
1129         amfree(regex);
1130     }
1131     amfree(sdir);
1132     amfree(uqglob);
1133     amfree(newglob);
1134 }
1135
1136 void
1137 delete_regex(
1138     char *      regex)
1139 {
1140     char *s;
1141     char *dir;
1142     char *sdir = NULL;
1143     char *uqregex;
1144     char *newregex;
1145     int   result = 1;
1146
1147     if (disk_path == NULL) {
1148         g_printf(_("Must select directory before adding files\n"));
1149         return;
1150     }
1151
1152     uqregex = unquote_string(regex);
1153     newregex = file_of_path(uqregex, &dir);
1154     if (dir) {
1155         sdir = merge_path(mount_point, disk_path);
1156         result = cd_regex(dir, 0);
1157         amfree(dir);
1158     }
1159
1160     if (result == 1) {
1161         if ((s = validate_regexp(newregex)) != NULL) {
1162             g_printf(_("\"%s\" is not a valid regular expression: "), newregex);
1163             puts(s);
1164         } else {
1165             delete_file(newregex, regex);
1166         }
1167         if (sdir) {
1168             set_directory(sdir, 0);
1169         }
1170     }
1171     amfree(sdir);
1172     amfree(uqregex);
1173     amfree(newregex);
1174 }
1175
1176 void
1177 delete_file(
1178     char *      path,
1179     char *      regex)
1180 {
1181     DIR_ITEM *ditem, lditem;
1182     char *path_on_disk = NULL;
1183     char *cmd = NULL;
1184     char *err = NULL;
1185     int i;
1186     ssize_t j;
1187     char *date;
1188     char *tape, *tape_undo, tape_undo_ch = '\0';
1189     char *dir_undo, dir_undo_ch = '\0';
1190     int  level = 0;
1191     off_t fileno;
1192     char *ditem_path = NULL;
1193     char *qditem_path;
1194     char *l = NULL;
1195     int  deleted;
1196     char *s;
1197     int ch;
1198     int found_one;
1199     char *quoted;
1200
1201     if (disk_path == NULL) {
1202         g_printf(_("Must select directory before deleting files\n"));
1203         return;
1204     }
1205     memset(&lditem, 0, sizeof(lditem)); /* Prevent use of bogus data... */
1206
1207     dbprintf(_("delete_file: Looking for \"%s\"\n"), path);
1208
1209     if (strcmp(regex, "[^/]*[/]*$") == 0) {
1210         /* Looking for * find everything but single . */
1211         regex = "([^/.]|\\.[^/]+|[^/.][^/]*)[/]*$";
1212     } else {
1213         /* remove "/" at end of path */
1214         j = (ssize_t)(strlen(regex) - 1);
1215         while(j >= 0 && regex[j] == '/') regex[j--] = '\0';
1216     }
1217
1218     /* convert path (assumed in cwd) to one on disk */
1219     if (strcmp(disk_path, "/") == 0) {
1220         if (*regex == '/') {
1221             if (strcmp(regex, "/[/]*$") == 0) {
1222                 /* We want "/" to match the directory itself: "/." */
1223                 path_on_disk = stralloc("/\\.[/]*$");
1224             } else {
1225                 /* No mods needed if already starts with '/' */
1226                 path_on_disk = stralloc(regex);
1227             }
1228         } else {
1229             /* Prepend '/' */
1230             path_on_disk = stralloc2("/", regex);
1231         }
1232     } else {
1233         char *clean_disk_path = clean_regex(disk_path, 0);
1234         path_on_disk = vstralloc(clean_disk_path, "/", regex, NULL);
1235         amfree(clean_disk_path);
1236     }
1237
1238     dbprintf(_("delete_file: Converted path=\"%s\" to path_on_disk=\"%s\"\n"),
1239               regex, path_on_disk);
1240     found_one = 0;
1241     for (ditem=get_dir_list(); ditem!=NULL; ditem=get_next_dir_item(ditem))
1242     {
1243         quoted = quote_string(ditem->path);
1244         dbprintf(_("delete_file: Pondering ditem->path=%s\n"), quoted);
1245         amfree(quoted);
1246         if (match(path_on_disk, ditem->path))
1247         {
1248             found_one = 1;
1249             j = (ssize_t)strlen(ditem->path);
1250             if((j > 0 && ditem->path[j-1] == '/')
1251                || (j > 1 && ditem->path[j-2] == '/' && ditem->path[j-1] == '.'))
1252             {   /* It is a directory */
1253                 ditem_path = newstralloc(ditem_path, ditem->path);
1254                 clean_pathname(ditem_path);
1255
1256                 qditem_path = quote_string(ditem_path);
1257                 cmd = newstralloc2(cmd, "ORLD ", qditem_path);
1258                 amfree(qditem_path);
1259                 if(send_command(cmd) == -1) {
1260                     amfree(cmd);
1261                     amfree(ditem_path);
1262                     amfree(path_on_disk);
1263                     exit(1);
1264                 }
1265                 amfree(cmd);
1266                 /* skip preamble */
1267                 if ((i = get_reply_line()) == -1) {
1268                     amfree(ditem_path);
1269                     amfree(path_on_disk);
1270                     exit(1);
1271                 }
1272                 if(i==0)                /* assume something wrong */
1273                 {
1274                     amfree(ditem_path);
1275                     amfree(path_on_disk);
1276                     l = reply_line();
1277                     g_printf("%s\n", l);
1278                     return;
1279                 }
1280                 deleted=0;
1281                 lditem.path = newstralloc(lditem.path, ditem->path);
1282                 amfree(cmd);
1283                 tape_undo = dir_undo = NULL;
1284                 /* skip the last line -- duplicate of the preamble */
1285                 while ((i = get_reply_line()) != 0)
1286                 {
1287                     if (i == -1) {
1288                         amfree(ditem_path);
1289                         amfree(path_on_disk);
1290                         exit(1);
1291                     }
1292                     if(err) {
1293                         if(cmd == NULL) {
1294                             if(tape_undo) *tape_undo = tape_undo_ch;
1295                             if(dir_undo) *dir_undo = dir_undo_ch;
1296                             tape_undo = dir_undo = NULL;
1297                             cmd = stralloc(l);  /* save for the error report */
1298                         }
1299                         continue;       /* throw the rest of the lines away */
1300                     }
1301                     l=reply_line();
1302                     if (!server_happy()) {
1303                         puts(l);
1304                         continue;
1305                     }
1306
1307                     s = l;
1308                     if(strncmp_const_skip(l, "201-", s, ch) != 0) {
1309                         err = _("bad reply: not 201-");
1310                         continue;
1311                     }
1312                     ch = *s++;
1313
1314                     skip_whitespace(s, ch);
1315                     if(ch == '\0') {
1316                         err = _("bad reply: missing date field");
1317                         continue;
1318                     }
1319                     date = s - 1;
1320                     skip_non_whitespace(s, ch);
1321                     *(s - 1) = '\0';
1322
1323                     skip_whitespace(s, ch);
1324                     if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
1325                         err = _("bad reply: cannot parse level field");
1326                         continue;
1327                     }
1328                     skip_integer(s, ch);
1329
1330                     skip_whitespace(s, ch);
1331                     if(ch == '\0') {
1332                         err = _("bad reply: missing tape field");
1333                         continue;
1334                     }
1335                     tape = s - 1;
1336                     skip_non_whitespace(s, ch);
1337                     tape_undo = s - 1;
1338                     tape_undo_ch = *tape_undo;
1339                     *tape_undo = '\0';
1340
1341                     if(am_has_feature(indexsrv_features, fe_amindexd_fileno_in_ORLD)) {
1342                         long long fileno_ = (long long)0;
1343                         skip_whitespace(s, ch);
1344                         if(ch == '\0' ||
1345                            sscanf(s - 1, "%lld", &fileno_) != 1) {
1346                             err = _("bad reply: cannot parse fileno field");
1347                             continue;
1348                         }
1349                         fileno = (off_t)fileno_;
1350                         skip_integer(s, ch);
1351                     }
1352
1353                     skip_whitespace(s, ch);
1354                     if(ch == '\0') {
1355                         err = _("bad reply: missing directory field");
1356                         continue;
1357                     }
1358                     skip_non_whitespace(s, ch);
1359                     dir_undo = s - 1;
1360                     dir_undo_ch = *dir_undo;
1361                     *dir_undo = '\0';
1362
1363                     lditem.date = newstralloc(lditem.date, date);
1364                     lditem.level=level;
1365                     lditem.tape = newstralloc(lditem.tape, tape);
1366                     switch(delete_extract_item(&lditem)) {
1367                     case -1:
1368                         g_printf(_("System error\n"));
1369                         dbprintf(_("delete_file: (Failed) System error\n"));
1370                         break;
1371                     case  0:
1372                         g_printf(_("Deleted dir %s at date %s\n"), ditem_path, date);
1373                         dbprintf(_("delete_file: (Successful) Deleted dir %s at date %s\n"),
1374                                   ditem_path, date);
1375                         deleted=1;
1376                         break;
1377                     case  1:
1378                         break;
1379                     }
1380                 }
1381                 if(!server_happy()) {
1382                     puts(reply_line());
1383                 } else if(err) {
1384                     if (*err)
1385                         puts(err);
1386                     if (cmd)
1387                         puts(cmd);
1388                 } else if(deleted == 0) {
1389                     g_printf(_("Warning - dir '%s' not on tape list\n"),
1390                            ditem_path);
1391                     dbprintf(_("delete_file: dir '%s' not on tape list\n"),
1392                               ditem_path);
1393                 }
1394             }
1395             else
1396             {
1397                 switch(delete_extract_item(ditem)) {
1398                 case -1:
1399                     g_printf(_("System error\n"));
1400                     dbprintf(_("delete_file: (Failed) System error\n"));
1401                     break;
1402                 case  0:
1403                     g_printf(_("Deleted %s\n"), ditem->path);
1404                     dbprintf(_("delete_file: (Successful) Deleted %s\n"),
1405                               ditem->path);
1406                     break;
1407                 case  1:
1408                     g_printf(_("Warning - file '%s' not on tape list\n"),
1409                            ditem->path);
1410                     dbprintf(_("delete_file: file '%s' not on tape list\n"),
1411                               ditem->path);
1412                     break;
1413                 }
1414             }
1415         }
1416     }
1417     amfree(cmd);
1418     amfree(ditem_path);
1419     amfree(path_on_disk);
1420
1421     if(! found_one) {
1422         g_printf(_("File %s doesn't exist in directory\n"), path);
1423         dbprintf(_("delete_file: (Failed) File %s doesn't exist in directory\n"),
1424                   path);
1425     }
1426 }
1427
1428
1429 /* print extract list into file. If NULL ptr passed print to screen */
1430 void
1431 display_extract_list(
1432     char *      file)
1433 {
1434     EXTRACT_LIST *this;
1435     EXTRACT_LIST_ITEM *that;
1436     FILE *fp;
1437     char *pager;
1438     char *pager_command;
1439     char *uqfile;
1440
1441     if (file == NULL)
1442     {
1443         if ((pager = getenv("PAGER")) == NULL)
1444         {
1445             pager = "more";
1446         }
1447         /*
1448          * Set up the pager command so if the pager is terminated, we do
1449          * not get a SIGPIPE back.
1450          */
1451         pager_command = stralloc2(pager, " ; /bin/cat > /dev/null");
1452         if ((fp = popen(pager_command, "w")) == NULL)
1453         {
1454             g_printf(_("Warning - can't pipe through %s\n"), pager);
1455             fp = stdout;
1456         }
1457         amfree(pager_command);
1458     }
1459     else
1460     {
1461         uqfile = unquote_string(file);
1462         if ((fp = fopen(uqfile, "w")) == NULL)
1463         {
1464             g_printf(_("Can't open file %s to print extract list into\n"), file);
1465             amfree(uqfile);
1466             return;
1467         }
1468         amfree(uqfile);
1469     }
1470
1471     for (this = extract_list; this != NULL; this = this->next)
1472     {
1473         g_fprintf(fp, _("TAPE %s LEVEL %d DATE %s\n"),
1474                 this->tape, this->level, this->date);
1475         for (that = this->files; that != NULL; that = that->next)
1476             g_fprintf(fp, "\t%s\n", that->path);
1477     }
1478
1479     if (file == NULL) {
1480         apclose(fp);
1481     } else {
1482         g_printf(_("Extract list written to file %s\n"), file);
1483         afclose(fp);
1484     }
1485 }
1486
1487
1488 static int
1489 is_empty_dir(
1490     char *fname)
1491 {
1492     DIR *dir;
1493     struct dirent *entry;
1494     int gotentry;
1495
1496     if((dir = opendir(fname)) == NULL)
1497         return 1;
1498
1499     gotentry = 0;
1500     while(!gotentry && (entry = readdir(dir)) != NULL) {
1501         gotentry = !is_dot_or_dotdot(entry->d_name);
1502     }
1503
1504     closedir(dir);
1505     return !gotentry;
1506
1507 }
1508
1509 /* returns 0 if extract list empty and 1 if it isn't */
1510 int
1511 is_extract_list_nonempty(void)
1512 {
1513     return (extract_list != NULL);
1514 }
1515
1516
1517 /* prints continue prompt and waits for response,
1518    returns 0 if don't, non-0 if do */
1519 static int
1520 okay_to_continue(
1521     int allow_tape,
1522     int allow_skip,
1523     int allow_retry)
1524 {
1525     int ch;
1526     int ret = -1;
1527     char *line = NULL;
1528     char *s;
1529     char *prompt;
1530     int get_device;
1531
1532     get_device = 0;
1533     while (ret < 0) {
1534         if (get_device) {
1535             prompt = _("New device name [?]: ");
1536         } else if (allow_tape && allow_skip) {
1537             prompt = _("Continue [?/Y/n/s/d]? ");
1538         } else if (allow_tape && !allow_skip) {
1539             prompt = _("Continue [?/Y/n/d]? ");
1540         } else if (allow_retry) {
1541             prompt = _("Continue [?/Y/n/r]? ");
1542         } else {
1543             prompt = _("Continue [?/Y/n]? ");
1544         }
1545         fputs(prompt, stdout);
1546         fflush(stdout); fflush(stderr);
1547         amfree(line);
1548         if ((line = agets(stdin)) == NULL) {
1549             putchar('\n');
1550             clearerr(stdin);
1551             if (get_device) {
1552                 get_device = 0;
1553                 continue;
1554             }
1555             ret = 0;
1556             break;
1557         }
1558         dbprintf("User prompt: '%s'; response: '%s'\n", prompt, line);
1559
1560         s = line;
1561         while ((ch = *s++) != '\0' && g_ascii_isspace(ch)) {
1562             (void)ch;   /* Quiet empty loop compiler warning */
1563         }
1564         if (ch == '?') {
1565             if (get_device) {
1566                 g_printf(_("Enter a new device name or \"default\"\n"));
1567             } else {
1568                 g_printf(_("Enter \"y\"es to continue, \"n\"o to stop"));
1569                 if(allow_skip) {
1570                     g_printf(_(", \"s\"kip this tape"));
1571                 }
1572                 if(allow_retry) {
1573                     g_printf(_(" or \"r\"etry this tape"));
1574                 }
1575                 if (allow_tape) {
1576                     g_printf(_(" or \"d\" to change to a new device"));
1577                 }
1578                 putchar('\n');
1579             }
1580         } else if (get_device) {
1581             char *tmp = stralloc(tape_server_name);
1582
1583             if (strncmp_const(s - 1, "default") == 0) {
1584                 set_device(tmp, NULL); /* default device, existing host */
1585             } else if (s[-1] != '\0') {
1586                 set_device(tmp, s - 1); /* specified device, existing host */
1587             } else {
1588                 g_printf(_("No change.\n"));
1589             }
1590
1591             amfree(tmp);
1592
1593             get_device = 0;
1594         } else if (ch == '\0' || ch == 'Y' || ch == 'y') {
1595             ret = 1;
1596         } else if (allow_tape && (ch == 'D' || ch == 'd' || ch == 'T' || ch == 't')) {
1597             get_device = 1; /* ('T' and 't' are for backward-compatibility) */
1598         } else if (ch == 'N' || ch == 'n') {
1599             ret = 0;
1600         } else if (allow_retry && (ch == 'R' || ch == 'r')) {
1601             ret = RETRY_TAPE;
1602         } else if (allow_skip && (ch == 'S' || ch == 's')) {
1603             ret = SKIP_TAPE;
1604         }
1605     }
1606     /*@ignore@*/
1607     amfree(line);
1608     /*@end@*/
1609     return ret;
1610 }
1611
1612 static void
1613 send_to_tape_server(
1614     security_stream_t * stream,
1615     char *              cmd)
1616 {
1617     char *msg = stralloc2(cmd, "\r\n");
1618
1619     g_debug("send_to_tape_server: %s\n", cmd);
1620     if (security_stream_write(stream, msg, strlen(msg)) < 0)
1621     {
1622         error(_("Error writing to tape server"));
1623         exit(101);
1624         /*NOTREACHED*/
1625     }
1626     amfree(msg);
1627 }
1628
1629
1630 /* start up connection to tape server and set commands to initiate
1631    transfer of dump image.
1632    Return tape server socket on success, -1 on error. */
1633 static int
1634 extract_files_setup(
1635     char *      label,
1636     off_t       fsf)
1637 {
1638     char *disk_regex = NULL;
1639     char *host_regex = NULL;
1640     char *clean_datestamp, *ch, *ch1;
1641     char *tt = NULL;
1642     char *req;
1643     int response_error;
1644
1645     amidxtaped_secdrv = security_getdriver(authopt);
1646     if (amidxtaped_secdrv == NULL) {
1647         error(_("no '%s' security driver available for host '%s'"),
1648               authopt, tape_server_name);
1649     }
1650
1651     /* We assume that amidxtaped support fe_amidxtaped_options_features */
1652     /*                               and fe_amidxtaped_options_auth     */
1653     /* We should send a noop to really know                             */
1654     req = vstralloc("SERVICE amidxtaped\n",
1655                     "OPTIONS ", "features=", our_features_string, ";",
1656                                 "auth=", authopt, ";",
1657                     "\n", NULL);
1658     protocol_sendreq(tape_server_name, amidxtaped_secdrv,
1659                      generic_client_get_security_conf, req, STARTUP_TIMEOUT,
1660                      amidxtaped_response, &response_error);
1661     amfree(req);
1662     protocol_run();
1663     if(response_error != 0) {
1664         return -1;
1665     }
1666
1667     disk_regex = make_exact_disk_expression(disk_name);
1668     host_regex = make_exact_host_expression(dump_hostname);
1669
1670     clean_datestamp = stralloc(dump_datestamp);
1671     for(ch=ch1=clean_datestamp;*ch1 != '\0';ch1++) {
1672         if(*ch1 != '-') {
1673             *ch = *ch1;
1674             ch++;
1675         }
1676     }
1677     *ch = '\0';
1678     /* push our feature list off to the tape server */
1679     /* XXX assumes that index server and tape server are equivalent, ew */
1680
1681     if(am_has_feature(indexsrv_features, fe_amidxtaped_exchange_features)){
1682         tt = newstralloc2(tt, "FEATURES=", our_features_string);
1683         send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt);
1684         get_amidxtaped_line();
1685         if(strncmp_const(amidxtaped_line,"FEATURES=") == 0) {
1686             tapesrv_features = am_string_to_feature(amidxtaped_line+9);
1687         } else {
1688             g_fprintf(stderr, _("amrecover - expecting FEATURES line from amidxtaped\n"));
1689             stop_amidxtaped();
1690             amfree(disk_regex);
1691             amfree(host_regex);
1692             amfree(clean_datestamp);
1693             return -1;
1694         }
1695     } else {
1696         *tapesrv_features = *indexsrv_features;
1697     }
1698
1699
1700     if(am_has_feature(indexsrv_features, fe_amidxtaped_header) &&
1701        am_has_feature(indexsrv_features, fe_amidxtaped_device) &&
1702        am_has_feature(indexsrv_features, fe_amidxtaped_host) &&
1703        am_has_feature(indexsrv_features, fe_amidxtaped_disk) &&
1704        am_has_feature(indexsrv_features, fe_amidxtaped_datestamp)) {
1705
1706         if(am_has_feature(indexsrv_features, fe_amidxtaped_config)) {
1707             tt = newstralloc2(tt, "CONFIG=", get_config_name());
1708             send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt);
1709         }
1710         if(am_has_feature(indexsrv_features, fe_amidxtaped_label) &&
1711            label && label[0] != '/') {
1712             tt = newstralloc2(tt,"LABEL=",label);
1713             send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt);
1714         }
1715         if(am_has_feature(indexsrv_features, fe_amidxtaped_fsf)) {
1716             char v_fsf[100];
1717             g_snprintf(v_fsf, 99, "%lld", (long long)fsf);
1718             tt = newstralloc2(tt, "FSF=",v_fsf);
1719             send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt);
1720         }
1721         send_to_tape_server(amidxtaped_streams[CTLFD].fd, "HEADER");
1722         tt = newstralloc2(tt, "DEVICE=", dump_device_name);
1723         send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt);
1724         tt = newstralloc2(tt, "HOST=", host_regex);
1725         send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt);
1726         tt = newstralloc2(tt, "DISK=", disk_regex);
1727         send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt);
1728         tt = newstralloc2(tt, "DATESTAMP=", clean_datestamp);
1729         send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt);
1730         send_to_tape_server(amidxtaped_streams[CTLFD].fd, "END");
1731         amfree(tt);
1732     }
1733     else if(am_has_feature(indexsrv_features, fe_amidxtaped_nargs)) {
1734         /* send to the tape server what tape file we want */
1735         /* 6 args:
1736          *   "-h"
1737          *   "-p"
1738          *   "tape device"
1739          *   "hostname"
1740          *   "diskname"
1741          *   "datestamp"
1742          */
1743         send_to_tape_server(amidxtaped_streams[CTLFD].fd, "6");
1744         send_to_tape_server(amidxtaped_streams[CTLFD].fd, "-h");
1745         send_to_tape_server(amidxtaped_streams[CTLFD].fd, "-p");
1746         send_to_tape_server(amidxtaped_streams[CTLFD].fd, dump_device_name);
1747         send_to_tape_server(amidxtaped_streams[CTLFD].fd, host_regex);
1748         send_to_tape_server(amidxtaped_streams[CTLFD].fd, disk_regex);
1749         send_to_tape_server(amidxtaped_streams[CTLFD].fd, clean_datestamp);
1750
1751         dbprintf(_("Started amidxtaped with arguments \"6 -h -p %s %s %s %s\"\n"),
1752                   dump_device_name, host_regex, disk_regex, clean_datestamp);
1753     }
1754
1755     amfree(disk_regex);
1756     amfree(host_regex);
1757     amfree(clean_datestamp);
1758
1759     return 0;
1760 }
1761
1762
1763 /*
1764  * Reads the first block of a tape file.
1765  */
1766
1767 void
1768 read_file_header(
1769     char *      buffer,
1770     dumpfile_t *file,
1771     size_t      buflen,
1772     int         tapedev)
1773 {
1774     ssize_t bytes_read;
1775     bytes_read = read_buffer(tapedev, buffer, buflen, READ_TIMEOUT);
1776     if(bytes_read < 0) {
1777         error(_("error reading header (%s), check amidxtaped.*.debug on server"),
1778               strerror(errno));
1779         /*NOTREACHED*/
1780     }
1781
1782     if((size_t)bytes_read < buflen) {
1783         g_fprintf(stderr, plural(_("%s: short block %d byte\n"),
1784                                _("%s: short block %d bytes\n"), bytes_read),
1785                 get_pname(), (int)bytes_read);
1786         print_header(stdout, file);
1787         error(_("Can't read file header"));
1788         /*NOTREACHED*/
1789     }
1790
1791     /* bytes_read == buflen */
1792     parse_file_header(buffer, file, (size_t)bytes_read);
1793 }
1794
1795 enum dumptypes {
1796         IS_UNKNOWN,
1797         IS_DUMP,
1798         IS_GNUTAR,
1799         IS_TAR,
1800         IS_SAMBA,
1801         IS_SAMBA_TAR,
1802         IS_APPLICATION_API
1803 };
1804
1805 static void
1806 extract_files_child(
1807     ctl_data_t         *ctl_data)
1808 {
1809     int save_errno;
1810     int   i;
1811     guint j;
1812     GPtrArray *argv_ptr = g_ptr_array_new();
1813     int files_off_tape;
1814     EXTRACT_LIST_ITEM *fn;
1815     enum dumptypes dumptype = IS_UNKNOWN;
1816     size_t len_program;
1817     char *cmd = NULL;
1818     guint passwd_field = 999999999;
1819 #ifdef SAMBA_CLIENT
1820     char *domain = NULL, *smbpass = NULL;
1821 #endif
1822
1823     /* code executed by child to do extraction */
1824     /* never returns */
1825
1826     /* make in_fd be our stdin */
1827     if (dup2(ctl_data->child_pipe[0], STDIN_FILENO) == -1)
1828     {
1829         error(_("dup2 failed in extract_files_child: %s"), strerror(errno));
1830         /*NOTREACHED*/
1831     }
1832
1833     if(ctl_data->file.type != F_DUMPFILE) {
1834         dump_dumpfile_t(&ctl_data->file);
1835         error(_("bad header"));
1836         /*NOTREACHED*/
1837     }
1838
1839     if (ctl_data->file.program != NULL) {
1840         if (strcmp(ctl_data->file.program, "APPLICATION") == 0)
1841             dumptype = IS_APPLICATION_API;
1842 #ifdef GNUTAR
1843         if (strcmp(ctl_data->file.program, GNUTAR) == 0)
1844             dumptype = IS_GNUTAR;
1845 #endif
1846
1847         if (dumptype == IS_UNKNOWN) {
1848             len_program = strlen(ctl_data->file.program);
1849             if(len_program >= 3 &&
1850                strcmp(&ctl_data->file.program[len_program-3],"tar") == 0)
1851                 dumptype = IS_TAR;
1852         }
1853
1854 #ifdef SAMBA_CLIENT
1855         if (dumptype == IS_UNKNOWN && strcmp(ctl_data->file.program, SAMBA_CLIENT) ==0) {
1856             if (samba_extract_method == SAMBA_TAR)
1857               dumptype = IS_SAMBA_TAR;
1858             else
1859               dumptype = IS_SAMBA;
1860         }
1861 #endif
1862     }
1863
1864     /* form the arguments to restore */
1865     files_off_tape = length_of_tape_list(ctl_data->elist);
1866     switch(dumptype) {
1867     case IS_SAMBA:
1868 #ifdef SAMBA_CLIENT
1869         g_ptr_array_add(argv_ptr, stralloc("smbclient"));
1870         smbpass = findpass(ctl_data->file.disk, &domain);
1871         if (smbpass) {
1872             g_ptr_array_add(argv_ptr, stralloc(ctl_data->file.disk));
1873             g_ptr_array_add(argv_ptr, stralloc("-U"));
1874             passwd_field = argv_ptr->len;
1875             g_ptr_array_add(argv_ptr, stralloc(smbpass));
1876             if (domain) {
1877                 g_ptr_array_add(argv_ptr, stralloc("-W"));
1878                 g_ptr_array_add(argv_ptr, stralloc(domain));
1879             }
1880         }
1881         g_ptr_array_add(argv_ptr, stralloc("-d0"));
1882         g_ptr_array_add(argv_ptr, stralloc("-Tx"));
1883         g_ptr_array_add(argv_ptr, stralloc("-"));       /* data on stdin */
1884         break;
1885 #endif
1886     case IS_TAR:
1887     case IS_GNUTAR:
1888         g_ptr_array_add(argv_ptr, stralloc("tar"));
1889         g_ptr_array_add(argv_ptr, stralloc("--numeric-owner"));
1890         g_ptr_array_add(argv_ptr, stralloc("-xpGvf"));
1891         g_ptr_array_add(argv_ptr, stralloc("-"));       /* data on stdin */
1892         break;
1893     case IS_SAMBA_TAR:
1894         g_ptr_array_add(argv_ptr, stralloc("tar"));
1895         g_ptr_array_add(argv_ptr, stralloc("-xpvf"));
1896         g_ptr_array_add(argv_ptr, stralloc("-"));       /* data on stdin */
1897         break;
1898     case IS_UNKNOWN:
1899     case IS_DUMP:
1900         g_ptr_array_add(argv_ptr, stralloc("restore"));
1901 #ifdef AIX_BACKUP
1902         restore_args[j++] = stralloc("-xB");
1903         g_ptr_array_add(argv_ptr, stralloc("-xB"));
1904 #else
1905 #if defined(XFSDUMP)
1906         if (strcmp(ctl_data->file.program, XFSDUMP) == 0) {
1907             g_ptr_array_add(argv_ptr, stralloc("-v"));
1908             g_ptr_array_add(argv_ptr, stralloc("silent"));
1909         } else
1910 #endif
1911 #if defined(VDUMP)
1912         if (strcmp(ctl_data->file.program, VDUMP) == 0) {
1913             g_ptr_array_add(argv_ptr, stralloc("xf"));
1914             g_ptr_array_add(argv_ptr, stralloc("-"));   /* data on stdin */
1915         } else
1916 #endif
1917         {
1918         g_ptr_array_add(argv_ptr, stralloc("xbf"));
1919         g_ptr_array_add(argv_ptr, stralloc("2")); /* read in units of 1K */
1920         g_ptr_array_add(argv_ptr, stralloc("-"));       /* data on stdin */
1921         }
1922 #endif
1923         break;
1924     case IS_APPLICATION_API:
1925         g_ptr_array_add(argv_ptr, stralloc(ctl_data->file.application));
1926         g_ptr_array_add(argv_ptr, stralloc("restore"));
1927         g_ptr_array_add(argv_ptr, stralloc("--config"));
1928         g_ptr_array_add(argv_ptr, stralloc(get_config_name()));
1929         g_ptr_array_add(argv_ptr, stralloc("--disk"));
1930         g_ptr_array_add(argv_ptr, stralloc(ctl_data->file.disk));
1931         if (dump_dle && dump_dle->device) {
1932             g_ptr_array_add(argv_ptr, stralloc("--device"));
1933             g_ptr_array_add(argv_ptr, stralloc(dump_dle->device));
1934         }
1935         if (ctl_data->data_path == DATA_PATH_DIRECTTCP) {
1936             g_ptr_array_add(argv_ptr, stralloc("--data-path"));
1937             g_ptr_array_add(argv_ptr, stralloc("DIRECTTCP"));
1938             g_ptr_array_add(argv_ptr, stralloc("--direct-tcp"));
1939             g_ptr_array_add(argv_ptr, stralloc(ctl_data->addrs));
1940         }
1941         if (ctl_data->bsu && ctl_data->bsu->smb_recover_mode &&
1942             samba_extract_method == SAMBA_SMBCLIENT){
1943             g_ptr_array_add(argv_ptr, stralloc("--recover-mode"));
1944             g_ptr_array_add(argv_ptr, stralloc("smb"));
1945         }
1946         g_ptr_array_add(argv_ptr, stralloc("--level"));
1947         g_ptr_array_add(argv_ptr, g_strdup_printf("%d", ctl_data->elist->level));
1948         if (dump_dle) {
1949             GSList   *scriptlist;
1950             script_t *script;
1951
1952             merge_properties(dump_dle->application_property, proplist);
1953             application_property_add_to_argv(argv_ptr, dump_dle, NULL,
1954                                              tapesrv_features);
1955             for (scriptlist = dump_dle->scriptlist; scriptlist != NULL;
1956                  scriptlist = scriptlist->next) {
1957                 script = (script_t *)scriptlist->data;
1958                 if (script->result && script->result->proplist) {
1959                     property_add_to_argv(argv_ptr, script->result->proplist);
1960                 }
1961             }
1962
1963         } else if (proplist) {
1964             g_hash_table_foreach(proplist, &proplist_add_to_argv, argv_ptr);
1965         }
1966         break;
1967     }
1968
1969     for (i = 0, fn = ctl_data->elist->files; i < files_off_tape;
1970                                              i++, fn = fn->next)
1971     {
1972         switch (dumptype) {
1973         case IS_APPLICATION_API:
1974         case IS_TAR:
1975         case IS_GNUTAR:
1976         case IS_SAMBA_TAR:
1977         case IS_SAMBA:
1978             if (strcmp(fn->path, "/") == 0)
1979                 g_ptr_array_add(argv_ptr, stralloc("."));
1980             else
1981                 g_ptr_array_add(argv_ptr, stralloc2(".", fn->path));
1982             break;
1983         case IS_UNKNOWN:
1984         case IS_DUMP:
1985 #if defined(XFSDUMP)
1986             if (strcmp(ctl_data->file.program, XFSDUMP) == 0) {
1987                 /*
1988                  * xfsrestore needs a -s option before each file to be
1989                  * restored, and also wants them to be relative paths.
1990                  */
1991                 g_ptr_array_add(argv_ptr, stralloc("-s"));
1992                 g_ptr_array_add(argv_ptr, stralloc(fn->path + 1));
1993             } else
1994 #endif
1995             {
1996             g_ptr_array_add(argv_ptr, stralloc(fn->path));
1997             }
1998             break;
1999         }
2000     }
2001 #if defined(XFSDUMP)
2002     if (strcmp(ctl_data->file.program, XFSDUMP) == 0) {
2003         g_ptr_array_add(argv_ptr, stralloc("-"));
2004         g_ptr_array_add(argv_ptr, stralloc("."));
2005     }
2006 #endif
2007     g_ptr_array_add(argv_ptr, NULL);
2008
2009     switch (dumptype) {
2010     case IS_SAMBA:
2011 #ifdef SAMBA_CLIENT
2012         cmd = stralloc(SAMBA_CLIENT);
2013         break;
2014 #else
2015         /* fall through to ... */
2016 #endif
2017     case IS_TAR:
2018     case IS_GNUTAR:
2019     case IS_SAMBA_TAR:
2020 #ifndef GNUTAR
2021         g_fprintf(stderr, _("warning: GNUTAR program not available.\n"));
2022         cmd = stralloc("tar");
2023 #else
2024         cmd = stralloc(GNUTAR);
2025 #endif
2026         break;
2027     case IS_UNKNOWN:
2028     case IS_DUMP:
2029         cmd = NULL;
2030 #if defined(DUMP)
2031         if (strcmp(ctl_data->file.program, DUMP) == 0) {
2032             cmd = stralloc(RESTORE);
2033         }
2034 #endif
2035 #if defined(VDUMP)
2036         if (strcmp(ctl_data->file.program, VDUMP) == 0) {
2037             cmd = stralloc(VRESTORE);
2038         }
2039 #endif
2040 #if defined(VXDUMP)
2041         if (strcmp(ctl_data->file.program, VXDUMP) == 0) {
2042             cmd = stralloc(VXRESTORE);
2043         }
2044 #endif
2045 #if defined(XFSDUMP)
2046         if (strcmp(ctl_data->file.program, XFSDUMP) == 0) {
2047             cmd = stralloc(XFSRESTORE);
2048         }
2049 #endif
2050         if (cmd == NULL) {
2051             g_fprintf(stderr, _("warning: restore program for %s not available.\n"),
2052                     ctl_data->file.program);
2053             cmd = stralloc("restore");
2054         }
2055         break;
2056     case IS_APPLICATION_API:
2057         cmd = vstralloc(APPLICATION_DIR, "/", ctl_data->file.application, NULL);
2058         break;
2059     }
2060     if (cmd) {
2061         dbprintf(_("Exec'ing %s with arguments:\n"), cmd);
2062         for (j = 0; j < argv_ptr->len - 1; j++) {
2063             if (j == passwd_field)
2064                 dbprintf("\tXXXXX\n");
2065             else
2066                 dbprintf(_("\t%s\n"), (char *)g_ptr_array_index(argv_ptr, j));
2067         }
2068         safe_fd(-1, 0);
2069         (void)execv(cmd, (char **)argv_ptr->pdata);
2070         /* only get here if exec failed */
2071         save_errno = errno;
2072         g_ptr_array_free_full(argv_ptr);
2073         errno = save_errno;
2074         perror(_("amrecover couldn't exec"));
2075         g_fprintf(stderr, _(" problem executing %s\n"), cmd);
2076         amfree(cmd);
2077     }
2078     exit(1);
2079     /*NOT REACHED */
2080 }
2081
2082 /*
2083  * Interpose something between the process writing out the dump (writing it to
2084  * some extraction program, really) and the socket from which we're reading, so
2085  * that we can do things like prompt for human interaction for multiple tapes.
2086  */
2087 int
2088 writer_intermediary(
2089     EXTRACT_LIST *      elist)
2090 {
2091     ctl_data_t ctl_data;
2092     amwait_t   extractor_status;
2093
2094     ctl_data.header_done   = 0;
2095     ctl_data.child_pipe[0] = -1;
2096     ctl_data.child_pipe[1] = -1;
2097     ctl_data.pid           = -1;
2098     ctl_data.elist         = elist;
2099     fh_init(&ctl_data.file);
2100     ctl_data.data_path     = DATA_PATH_AMANDA;
2101     ctl_data.addrs         = NULL;
2102     ctl_data.bsu           = NULL;
2103
2104     security_stream_read(amidxtaped_streams[DATAFD].fd,
2105                          read_amidxtaped_data, &ctl_data);
2106
2107     while(get_amidxtaped_line() >= 0) {
2108         char desired_tape[MAX_TAPE_LABEL_BUF];
2109         g_debug("get amidxtaped line: %s", amidxtaped_line);
2110
2111         /* if prompted for a tape, relay said prompt to the user */
2112         if(sscanf(amidxtaped_line, "FEEDME %132s\n", desired_tape) == 1) {
2113             int done;
2114             g_printf(_("Load tape %s now\n"), desired_tape);
2115             dbprintf(_("Requesting tape %s from user\n"), desired_tape);
2116             done = okay_to_continue(am_has_feature(indexsrv_features,
2117                                                    fe_amrecover_feedme_tape),
2118                                     0, 0);
2119             if (done == 1) {
2120                 if (am_has_feature(indexsrv_features,
2121                                    fe_amrecover_feedme_tape)) {
2122                     char *reply = stralloc2("TAPE ", tape_device_name);
2123                     send_to_tape_server(amidxtaped_streams[CTLFD].fd, reply);
2124                     amfree(reply);
2125                 } else {
2126                     send_to_tape_server(amidxtaped_streams[CTLFD].fd, "OK");
2127                 }
2128             } else {
2129                 send_to_tape_server(amidxtaped_streams[CTLFD].fd, "ERROR");
2130                 break;
2131             }
2132         } else if (strncmp_const(amidxtaped_line, "USE-DATAPATH ") == 0) {
2133             if (strncmp_const(amidxtaped_line+13, "AMANDA") == 0) {
2134                 ctl_data.data_path = DATA_PATH_AMANDA;
2135                 g_debug("Using AMANDA data-path");
2136             } else if (strncmp_const(amidxtaped_line+13, "DIRECT-TCP") == 0) {
2137                 ctl_data.data_path = DATA_PATH_DIRECTTCP;
2138                 ctl_data.addrs = stralloc(amidxtaped_line+24);
2139                 g_debug("Using DIRECT-TCP data-path with %s", ctl_data.addrs);
2140             }
2141             start_processing_data(&ctl_data);
2142         } else if(strncmp_const(amidxtaped_line, "MESSAGE ") == 0) {
2143             g_printf("%s\n",&amidxtaped_line[8]);
2144         } else {
2145             g_fprintf(stderr, _("Strange message from tape server: %s"),
2146                     amidxtaped_line);
2147             break;
2148         }
2149     }
2150
2151     /* CTL might be close before DATA */
2152     event_loop(0);
2153     dumpfile_free_data(&ctl_data.file);
2154     amfree(ctl_data.addrs);
2155     amfree(ctl_data.bsu);
2156     if (ctl_data.child_pipe[1] != -1)
2157         aclose(ctl_data.child_pipe[1]);
2158
2159     if (ctl_data.header_done == 0) {
2160         g_printf(_("Got no header and data from server, check in amidxtaped.*.debug and amandad.*.debug files on server\n"));
2161     }
2162
2163     if (ctl_data.pid != -1) {
2164         waitpid(ctl_data.pid, &extractor_status, 0);
2165         if(WEXITSTATUS(extractor_status) != 0){
2166             int ret = WEXITSTATUS(extractor_status);
2167             if(ret == 255) ret = -1;
2168             g_printf(_("Extractor child exited with status %d\n"), ret);
2169             return -1;
2170         }
2171     }
2172     return(0);
2173 }
2174
2175 /* exec restore to do the actual restoration */
2176
2177 /* does the actual extraction of files */
2178 /*
2179  * The original design had the dump image being returned exactly as it
2180  * appears on the tape, and this routine getting from the index server
2181  * whether or not it is compressed, on the assumption that the tape
2182  * server may not know how to uncompress it. But
2183  * - Amrestore can't do that. It returns either compressed or uncompressed
2184  * (always). Amrestore assumes it can uncompress files. It is thus a good
2185  * idea to run the tape server on a machine with gzip.
2186  * - The information about compression in the disklist is really only
2187  * for future dumps. It is possible to change compression on a drive
2188  * so the information in the disklist may not necessarily relate to
2189  * the dump image on the tape.
2190  *   Consequently the design was changed to assuming that amrestore can
2191  * uncompress any dump image and have it return an uncompressed file
2192  * always.
2193  */
2194 void
2195 extract_files(void)
2196 {
2197     EXTRACT_LIST *elist;
2198     char *l;
2199     int first;
2200     int otc;
2201     tapelist_t *tlist = NULL, *a_tlist;
2202     g_option_t g_options;
2203     levellist_t all_level = NULL;
2204     int last_level;
2205
2206     if (!is_extract_list_nonempty())
2207     {
2208         g_printf(_("Extract list empty - No files to extract!\n"));
2209         return;
2210     }
2211
2212     clean_extract_list();
2213
2214     /* get tape device name from index server if none specified */
2215     if (tape_server_name == NULL) {
2216         tape_server_name = newstralloc(tape_server_name, server_name);
2217     }
2218     if (tape_device_name == NULL) {
2219         if (send_command("TAPE") == -1)
2220             exit(1);
2221         if (get_reply_line() == -1)
2222             exit(1);
2223         l = reply_line();
2224         if (!server_happy())
2225         {
2226             g_printf("%s\n", l);
2227             exit(1);
2228         }
2229         /* skip reply number */
2230         tape_device_name = newstralloc(tape_device_name, l+4);
2231     }
2232
2233     if (strcmp(tape_device_name, "/dev/null") == 0)
2234     {
2235         g_printf(_("amrecover: warning: using %s as the tape device will not work\n"),
2236                tape_device_name);
2237     }
2238
2239     first=1;
2240     for (elist = first_tape_list(); elist != NULL; elist = next_tape_list(elist)) {
2241         if(elist->tape[0]!='/') {
2242             if(first) {
2243                 g_printf(_("\nExtracting files using tape drive %s on host %s.\n"),
2244                         tape_device_name, tape_server_name);
2245                 g_printf(_("The following tapes are needed:"));
2246                 first=0;
2247             }
2248             else
2249                 g_printf("                               ");
2250             tlist = unmarshal_tapelist_str(elist->tape);
2251             for(a_tlist = tlist ; a_tlist != NULL; a_tlist = a_tlist->next)
2252                 g_printf(" %s", a_tlist->label);
2253             g_printf("\n");
2254             free_tapelist(tlist);
2255         }
2256     }
2257     first=1;
2258     for (elist = first_tape_list(); elist != NULL; elist = next_tape_list(elist)) {
2259         if(elist->tape[0]=='/') {
2260             if(first) {
2261                 g_printf(_("\nExtracting files from holding disk on host %s.\n"),
2262                         tape_server_name);
2263                 g_printf(_("The following files are needed:"));
2264                 first=0;
2265             }
2266             else
2267                 g_printf("                               ");
2268             tlist = unmarshal_tapelist_str(elist->tape);
2269             for(a_tlist = tlist; a_tlist != NULL; a_tlist = a_tlist->next)
2270                 g_printf(" %s", a_tlist->label);
2271             g_printf("\n");
2272             free_tapelist(tlist);
2273         }
2274     }
2275     g_printf("\n");
2276
2277     g_options.config = get_config_name();
2278     g_options.hostname = dump_hostname;
2279     for (elist = first_tape_list(); elist != NULL;
2280          elist = next_tape_list(elist)) {
2281         level_t *level = g_new0(level_t, 1);
2282         level->level = elist->level;
2283         all_level = g_slist_append(all_level, level);
2284     }
2285     if (dump_dle) {
2286         g_slist_free_full(dump_dle->levellist);
2287         dump_dle->levellist = all_level;
2288         run_client_scripts(EXECUTE_ON_PRE_RECOVER, &g_options, dump_dle,
2289                            stderr);
2290         dump_dle->levellist = NULL;
2291     }
2292     last_level = -1;
2293     while ((elist = first_tape_list()) != NULL)
2294     {
2295         if(elist->tape[0]=='/') {
2296             dump_device_name = newstralloc(dump_device_name, elist->tape);
2297             g_printf(_("Extracting from file "));
2298             tlist = unmarshal_tapelist_str(dump_device_name);
2299             for(a_tlist = tlist; a_tlist != NULL; a_tlist = a_tlist->next)
2300                 g_printf(" %s", a_tlist->label);
2301             g_printf("\n");
2302             free_tapelist(tlist);
2303         }
2304         else {
2305             g_printf(_("Extracting files using tape drive %s on host %s.\n"),
2306                    tape_device_name, tape_server_name);
2307             tlist = unmarshal_tapelist_str(elist->tape);
2308             g_printf(_("Load tape %s now\n"), tlist->label);
2309             dbprintf(_("Requesting tape %s from user\n"), tlist->label);
2310             free_tapelist(tlist);
2311             otc = okay_to_continue(1,1,0);
2312             if (otc == 0)
2313                 return;
2314             else if (otc == SKIP_TAPE) {
2315                 delete_tape_list(elist); /* skip this tape */
2316                 continue;
2317             }
2318             dump_device_name = newstralloc(dump_device_name, tape_device_name);
2319         }
2320         dump_datestamp = newstralloc(dump_datestamp, elist->date);
2321
2322         if (last_level != -1 && dump_dle) {
2323             level_t *level;
2324
2325             level = g_new0(level_t, 1);
2326             level->level = last_level;
2327             dump_dle->levellist = g_slist_append(dump_dle->levellist, level);
2328
2329             level = g_new0(level_t, 1);
2330             level->level = elist->level;
2331             dump_dle->levellist = g_slist_append(dump_dle->levellist, level);
2332             run_client_scripts(EXECUTE_ON_INTER_LEVEL_RECOVER, &g_options,
2333                                dump_dle, stderr);
2334             g_slist_free_full(dump_dle->levellist);
2335             dump_dle->levellist = NULL;
2336         }
2337
2338         /* connect to the tape handler daemon on the tape drive server */
2339         if ((extract_files_setup(elist->tape, elist->fileno)) == -1)
2340         {
2341             g_fprintf(stderr, _("amrecover - can't talk to tape server: %s\n"),
2342                     errstr);
2343             return;
2344         }
2345         if (dump_dle) {
2346             level_t *level;
2347
2348             level = g_new0(level_t, 1);
2349             level->level = elist->level;
2350             dump_dle->levellist = g_slist_append(dump_dle->levellist, level);
2351             run_client_scripts(EXECUTE_ON_PRE_LEVEL_RECOVER, &g_options,
2352                                dump_dle, stderr);
2353         }
2354         last_level = elist->level;
2355
2356         /* if the server have fe_amrecover_feedme_tape, it has asked for
2357          * the tape itself, even if the restore didn't succeed, we should
2358          * remove it.
2359          */
2360         if(writer_intermediary(elist) == 0 ||
2361            am_has_feature(indexsrv_features, fe_amrecover_feedme_tape))
2362             delete_tape_list(elist);    /* tape done so delete from list */
2363
2364         am_release_feature_set(tapesrv_features);
2365         stop_amidxtaped();
2366
2367         if (dump_dle) {
2368             run_client_scripts(EXECUTE_ON_POST_LEVEL_RECOVER, &g_options,
2369                                dump_dle, stderr);
2370             g_slist_free_full(dump_dle->levellist);
2371             dump_dle->levellist = NULL;
2372         }
2373     }
2374     if (dump_dle) {
2375         dump_dle->levellist = all_level;
2376         run_client_scripts(EXECUTE_ON_POST_RECOVER, &g_options, dump_dle,
2377                            stderr);
2378         g_slist_free_full(dump_dle->levellist);
2379         all_level = NULL;
2380         dump_dle->levellist = NULL;
2381     }
2382 }
2383
2384 static void
2385 amidxtaped_response(
2386     void *              datap,
2387     pkt_t *             pkt,
2388     security_handle_t * sech)
2389 {
2390     int ports[NSTREAMS], *response_error = datap, i;
2391     char *p;
2392     char *tok;
2393     char *extra = NULL;
2394
2395     assert(response_error != NULL);
2396     assert(sech != NULL);
2397     memset(ports, -1, SIZEOF(ports));
2398
2399     if (pkt == NULL) {
2400         errstr = newvstrallocf(errstr, _("[request failed: %s]"), security_geterror(sech));
2401         *response_error = 1;
2402         return;
2403     }
2404     security_close_connection(sech, dump_hostname);
2405
2406     if (pkt->type == P_NAK) {
2407 #if defined(PACKET_DEBUG)
2408         g_fprintf(stderr, _("got nak response:\n----\n%s\n----\n\n"), pkt->body);
2409 #endif
2410
2411         tok = strtok(pkt->body, " ");
2412         if (tok == NULL || strcmp(tok, "ERROR") != 0)
2413             goto bad_nak;
2414
2415         tok = strtok(NULL, "\n");
2416         if (tok != NULL) {
2417             errstr = newvstralloc(errstr, "NAK: ", tok, NULL);
2418             *response_error = 1;
2419         } else {
2420 bad_nak:
2421             errstr = newstralloc(errstr, "request NAK");
2422             *response_error = 2;
2423         }
2424         return;
2425     }
2426
2427     if (pkt->type != P_REP) {
2428         errstr = newvstrallocf(errstr, _("received strange packet type %s: %s"),
2429                               pkt_type2str(pkt->type), pkt->body);
2430         *response_error = 1;
2431         return;
2432     }
2433
2434 #if defined(PACKET_DEBUG)
2435     g_fprintf(stderr, _("got response:\n----\n%s\n----\n\n"), pkt->body);
2436 #endif
2437
2438     for(i = 0; i < NSTREAMS; i++) {
2439         ports[i] = -1;
2440         amidxtaped_streams[i].fd = NULL;
2441     }
2442
2443     p = pkt->body;
2444     while((tok = strtok(p, " \n")) != NULL) {
2445         p = NULL;
2446
2447         /*
2448          * Error response packets have "ERROR" followed by the error message
2449          * followed by a newline.
2450          */
2451         if (strcmp(tok, "ERROR") == 0) {
2452             tok = strtok(NULL, "\n");
2453             if (tok == NULL)
2454                 tok = _("[bogus error packet]");
2455             errstr = newstralloc(errstr, tok);
2456             *response_error = 2;
2457             return;
2458         }
2459
2460
2461         /*
2462          * Regular packets have CONNECT followed by three streams
2463          */
2464         if (strcmp(tok, "CONNECT") == 0) {
2465
2466             /*
2467              * Parse the three stream specifiers out of the packet.
2468              */
2469             for (i = 0; i < NSTREAMS; i++) {
2470                 tok = strtok(NULL, " ");
2471                 if (tok == NULL || strcmp(tok, amidxtaped_streams[i].name) != 0) {
2472                     extra = vstrallocf(_("CONNECT token is \"%s\": expected \"%s\""),
2473                                       tok ? tok : "(null)",
2474                                       amidxtaped_streams[i].name);
2475                     goto parse_error;
2476                 }
2477                 tok = strtok(NULL, " \n");
2478                 if (tok == NULL || sscanf(tok, "%d", &ports[i]) != 1) {
2479                     extra = vstrallocf(_("CONNECT %s token is \"%s\": expected a port number"),
2480                                       amidxtaped_streams[i].name,
2481                                       tok ? tok : "(null)");
2482                     goto parse_error;
2483                 }
2484             }
2485             continue;
2486         }
2487
2488         /*
2489          * OPTIONS [options string] '\n'
2490          */
2491         if (strcmp(tok, "OPTIONS") == 0) {
2492             tok = strtok(NULL, "\n");
2493             if (tok == NULL) {
2494                 extra = stralloc(_("OPTIONS token is missing"));
2495                 goto parse_error;
2496             }
2497 /*
2498             while((p = strchr(tok, ';')) != NULL) {
2499                 *p++ = '\0';
2500                 if(strncmp_const(tok, "features=") == 0) {
2501                     tok += sizeof("features=") - 1;
2502                     am_release_feature_set(their_features);
2503                     if((their_features = am_string_to_feature(tok)) == NULL) {
2504                         errstr = newvstralloc(errstr,
2505                                               _("OPTIONS: bad features value: "),
2506                                               tok,
2507                                               NULL);
2508                         goto parse_error;
2509                     }
2510                 }
2511                 tok = p;
2512             }
2513 */
2514             continue;
2515         }
2516 /*
2517         extra = vstrallocf("next token is \"%s\": expected \"CONNECT\", \"ERROR\" or \"OPTIONS\""),
2518                           tok ? tok : _("(null)"));
2519         goto parse_error;
2520 */
2521     }
2522
2523     /*
2524      * Connect the streams to their remote ports
2525      */
2526     for (i = 0; i < NSTREAMS; i++) {
2527         if (ports[i] == -1)
2528             continue;
2529         amidxtaped_streams[i].fd = security_stream_client(sech, ports[i]);
2530         dbprintf(_("amidxtaped_streams[%d].fd = %p\n"),i, amidxtaped_streams[i].fd);
2531         if (amidxtaped_streams[i].fd == NULL) {
2532             errstr = newvstrallocf(errstr,\
2533                         _("[could not connect %s stream: %s]"),
2534                         amidxtaped_streams[i].name,
2535                         security_geterror(sech));
2536             goto connect_error;
2537         }
2538     }
2539     /*
2540      * Authenticate the streams
2541      */
2542     for (i = 0; i < NSTREAMS; i++) {
2543         if (amidxtaped_streams[i].fd == NULL)
2544             continue;
2545         if (security_stream_auth(amidxtaped_streams[i].fd) < 0) {
2546             errstr = newvstrallocf(errstr,
2547                 _("[could not authenticate %s stream: %s]"),
2548                 amidxtaped_streams[i].name,
2549                 security_stream_geterror(amidxtaped_streams[i].fd));
2550             goto connect_error;
2551         }
2552     }
2553
2554     /*
2555      * The CTLFD and DATAFD streams are mandatory.  If we didn't get
2556      * them, complain.
2557      */
2558     if (amidxtaped_streams[CTLFD].fd == NULL) {
2559         errstr = newvstrallocf(errstr, _("[couldn't open CTL streams]"));
2560         goto connect_error;
2561     }
2562     if (amidxtaped_streams[DATAFD].fd == NULL) {
2563         errstr = newvstrallocf(errstr, _("[couldn't open DATA streams]"));
2564         goto connect_error;
2565     }
2566
2567     /* everything worked */
2568     *response_error = 0;
2569     return;
2570
2571 parse_error:
2572     if (extra) {
2573         errstr = newvstrallocf(errstr,
2574                           _("[parse of reply message failed: %s]"), extra);
2575     } else {
2576         errstr = newvstrallocf(errstr,
2577                           _("[parse of reply message failed: (no additional information)"));
2578     }
2579     amfree(extra);
2580     *response_error = 2;
2581     return;
2582
2583 connect_error:
2584     stop_amidxtaped();
2585     *response_error = 1;
2586 }
2587
2588 /*
2589  * This is called when everything needs to shut down so event_loop()
2590  * will exit.
2591  */
2592 static void
2593 stop_amidxtaped(void)
2594 {
2595     int i;
2596
2597     for (i = 0; i < NSTREAMS; i++) {
2598         if (amidxtaped_streams[i].fd != NULL) {
2599             security_stream_close(amidxtaped_streams[i].fd);
2600             amidxtaped_streams[i].fd = NULL;
2601         }
2602     }
2603 }
2604
2605 static char* ctl_buffer = NULL;
2606 /* gets a "line" from server and put in server_line */
2607 /* server_line is terminated with \0, \r\n is striped */
2608 /* returns -1 if error */
2609
2610 int
2611 get_amidxtaped_line(void)
2612 {
2613     ssize_t size;
2614     char *newbuf, *s;
2615     void *buf;
2616
2617     amfree(amidxtaped_line);
2618     if (!ctl_buffer)
2619         ctl_buffer = stralloc("");
2620
2621     while (!strstr(ctl_buffer,"\r\n")) {
2622         if (amidxtaped_streams[CTLFD].fd == NULL)
2623             return -1;
2624
2625         size = security_stream_read_sync(amidxtaped_streams[CTLFD].fd, &buf);
2626         if(size < 0) {
2627             return -1;
2628         }
2629         else if(size == 0) {
2630             return -1;
2631         }
2632         newbuf = alloc(strlen(ctl_buffer)+size+1);
2633         strncpy(newbuf, ctl_buffer, (size_t)(strlen(ctl_buffer) + size + 1));
2634         memcpy(newbuf+strlen(ctl_buffer), buf, (size_t)size);
2635         newbuf[strlen(ctl_buffer)+size] = '\0';
2636         amfree(ctl_buffer);
2637         ctl_buffer = newbuf;
2638         amfree(buf);
2639     }
2640
2641     s = strstr(ctl_buffer,"\r\n");
2642     *s = '\0';
2643     newbuf = stralloc(s+2);
2644     amidxtaped_line = stralloc(ctl_buffer);
2645     amfree(ctl_buffer);
2646     ctl_buffer = newbuf;
2647     return 0;
2648 }
2649
2650
2651 static void
2652 read_amidxtaped_data(
2653     void *      cookie,
2654     void *      buf,
2655     ssize_t     size)
2656 {
2657     ctl_data_t *ctl_data = (ctl_data_t *)cookie;
2658     assert(cookie != NULL);
2659
2660     if (size < 0) {
2661         errstr = newstralloc2(errstr, _("amidxtaped read: "),
2662                  security_stream_geterror(amidxtaped_streams[DATAFD].fd));
2663         return;
2664     }
2665
2666     /*
2667      * EOF.  Stop and return.
2668      */
2669     if (size == 0) {
2670         security_stream_close(amidxtaped_streams[DATAFD].fd);
2671         amidxtaped_streams[DATAFD].fd = NULL;
2672         /*
2673          * If the mesg fd has also shut down, then we're done.
2674          */
2675         return;
2676     }
2677
2678     assert(buf != NULL);
2679
2680     if (ctl_data->header_done == 0) {
2681         GPtrArray  *errarray;
2682         g_option_t  g_options;
2683         data_path_t data_path_set = DATA_PATH_AMANDA;
2684
2685         /* parse the file header */
2686         fh_init(&ctl_data->file);
2687         parse_file_header(buf, &ctl_data->file, (size_t)size);
2688
2689         /* call backup_support_option */
2690         g_options.config = get_config_name();
2691         g_options.hostname = dump_hostname;
2692         if (strcmp(ctl_data->file.program, "APPLICATION") == 0) {
2693             if (dump_dle) {
2694                 ctl_data->bsu = backup_support_option(ctl_data->file.application,
2695                                                       &g_options,
2696                                                       ctl_data->file.disk,
2697                                                       dump_dle->device,
2698                                                       &errarray);
2699             } else {
2700                 ctl_data->bsu = backup_support_option(ctl_data->file.application,
2701                                                       &g_options,
2702                                                       ctl_data->file.disk, NULL,
2703                                                       &errarray);
2704             }
2705             if (!ctl_data->bsu) {
2706                 guint  i;
2707                 for (i=0; i < errarray->len; i++) {
2708                     char *line;
2709                     line = g_ptr_array_index(errarray, i);
2710                     g_fprintf(stderr, "%s\n", line);
2711                 }
2712                 g_ptr_array_free_full(errarray);
2713                 exit(1);
2714             }
2715             data_path_set = ctl_data->bsu->data_path_set;
2716         }
2717         /* handle backup_support_option failure */
2718
2719         ctl_data->header_done = 1;
2720         if (!ask_file_overwrite(ctl_data)) {
2721             if (am_has_feature(tapesrv_features, fe_amidxtaped_abort)) {
2722                 send_to_tape_server(amidxtaped_streams[CTLFD].fd, "ABORT");
2723             }
2724             stop_amidxtaped();
2725             return;
2726         }
2727
2728         if (am_has_feature(tapesrv_features, fe_amidxtaped_datapath)) {
2729             char       *msg;
2730             /* send DATA-PATH request */
2731             msg = stralloc("AVAIL-DATAPATH");
2732             if (data_path_set & DATA_PATH_AMANDA)
2733                 vstrextend(&msg, " AMANDA", NULL);
2734             if (data_path_set & DATA_PATH_DIRECTTCP)
2735                 vstrextend(&msg, " DIRECT-TCP", NULL);
2736             send_to_tape_server(amidxtaped_streams[CTLFD].fd, msg);
2737             amfree(msg);
2738         } else {
2739             start_processing_data(ctl_data);
2740         }
2741     } else {
2742         /* Only the data is sent to the child */
2743         /*
2744          * We ignore errors while writing to the index file.
2745          */
2746         (void)full_write(ctl_data->child_pipe[1], buf, (size_t)size);
2747         security_stream_read(amidxtaped_streams[DATAFD].fd,
2748                              read_amidxtaped_data, cookie);
2749     }
2750 }
2751
2752 static gboolean
2753 ask_file_overwrite(
2754     ctl_data_t *ctl_data)
2755 {
2756     char *restore_dir = NULL;
2757
2758     if (ctl_data->file.dumplevel == 0) {
2759         property_t *property = g_hash_table_lookup(proplist, "directory");
2760         if (property && property->values && property->values->data) {
2761             /* take first property value */
2762             restore_dir = strdup(property->values->data);
2763         }
2764         if (samba_extract_method == SAMBA_SMBCLIENT ||
2765             (ctl_data->bsu &&
2766              ctl_data->bsu->recover_path == RECOVER_PATH_REMOTE)) {
2767             if (!restore_dir) {
2768                 restore_dir = g_strdup(ctl_data->file.disk);
2769             }
2770             g_printf(_("Restoring files into target host %s\n"), restore_dir);
2771         } else {
2772             if (!restore_dir) {
2773                 restore_dir = g_get_current_dir();
2774             }
2775             g_printf(_("Restoring files into directory %s\n"), restore_dir);
2776         }
2777
2778         /* Collect files to delete befause of a bug in gnutar */
2779         if (strcmp(ctl_data->file.program, "GNUTAR") == 0 ||
2780             (strcmp(ctl_data->file.program, "APPLICATION") == 0 &&
2781              strcmp(ctl_data->file.application, "amgtar") == 0)) {
2782             check_file_overwrite(restore_dir);
2783         } else {
2784             g_printf(_("All existing files in %s can be deleted\n"),
2785                      restore_dir);
2786         }
2787
2788         if (!okay_to_continue(0,0,0)) {
2789             free_unlink_list();
2790             amfree(restore_dir);
2791             return FALSE;
2792         }
2793         g_printf("\n");
2794
2795         /* delete the files for gnutar */
2796         if (unlink_list) {
2797             if (!do_unlink_list()) {
2798                 g_fprintf(stderr, _("Can't recover because I can't cleanup the restore directory (%s)\n"),
2799                           restore_dir);
2800                 free_unlink_list();
2801                 amfree(restore_dir);
2802                 return FALSE;
2803             }
2804             free_unlink_list();
2805         }
2806         amfree(restore_dir);
2807     }
2808     return TRUE;
2809 }
2810
2811 static void
2812 start_processing_data(
2813     ctl_data_t *ctl_data)
2814 {
2815     if (pipe(ctl_data->child_pipe) == -1) {
2816         error(_("extract_list - error setting up pipe to extractor: %s\n"),
2817               strerror(errno));
2818         /*NOTREACHED*/
2819     }
2820
2821     /* okay, ready to extract. fork a child to do the actual work */
2822     if ((ctl_data->pid = fork()) == 0) {
2823         /* this is the child process */
2824         /* never gets out of this clause */
2825         aclose(ctl_data->child_pipe[1]);
2826         extract_files_child(ctl_data);
2827         /*NOTREACHED*/
2828     }
2829         
2830     if (ctl_data->pid == -1) {
2831         errstr = newstralloc(errstr, _("writer_intermediary - error forking child"));
2832         g_printf(_("writer_intermediary - error forking child"));
2833         return;
2834     }
2835     aclose(ctl_data->child_pipe[0]);
2836     security_stream_read(amidxtaped_streams[DATAFD].fd, read_amidxtaped_data,
2837                          ctl_data);
2838     if (am_has_feature(tapesrv_features, fe_amidxtaped_datapath)) {
2839         send_to_tape_server(amidxtaped_streams[CTLFD].fd, "DATAPATH-OK");
2840     }
2841 }