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