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