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