X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=recover-src%2Fextract_list.c;h=9a453cb0fd8de01d3399efe9b7cd872d91c7659f;hb=HEAD;hp=67c02d1bd10325a8c5ee358ef6fbeb61952ee95e;hpb=cdbbeef9cde260e429854dd313bc0bf7560e1e24;p=debian%2Famanda diff --git a/recover-src/extract_list.c b/recover-src/extract_list.c index 67c02d1..9a453cb 100644 --- a/recover-src/extract_list.c +++ b/recover-src/extract_list.c @@ -1,6 +1,7 @@ /* * Amanda, The Advanced Maryland Automatic Network Disk Archiver * Copyright (c) 1991-1998, 2000 University of Maryland at College Park + * Copyright (c) 2007-2012 Zmanda, Inc. All Rights Reserved. * All Rights Reserved. * * Permission to use, copy, modify, distribute, and sell this software and its @@ -24,13 +25,13 @@ * file named AUTHORS, in the root directory of this distribution. */ /* - * $Id: extract_list.c,v 1.117 2006/08/24 01:57:15 paddy_s Exp $ + * $Id$ * * implements the "extract" command in amrecover */ #include "amanda.h" -#include "version.h" +#include "match.h" #include "amrecover.h" #include "fileheader.h" #include "dgram.h" @@ -40,13 +41,16 @@ #include "findpass.h" #endif #include "util.h" -#include "clientconf.h" +#include "conffile.h" #include "protocol.h" #include "event.h" +#include "client_util.h" #include "security.h" +#include "pipespawn.h" typedef struct EXTRACT_LIST_ITEM { char *path; + char *tpath; struct EXTRACT_LIST_ITEM *next; } EXTRACT_LIST_ITEM; @@ -62,6 +66,18 @@ typedef struct EXTRACT_LIST { } EXTRACT_LIST; +typedef struct ctl_data_s { + int header_done; + int child_pipe[2]; + int pid; + EXTRACT_LIST *elist; + dumpfile_t file; + data_path_t data_path; + char *addrs; + backup_support_option_t *bsu; + gint64 bytes_read; +} ctl_data_t; + #define SKIP_TAPE 2 #define RETRY_TAPE 3 @@ -79,12 +95,13 @@ static struct { static void amidxtaped_response(void *, pkt_t *, security_handle_t *); static void stop_amidxtaped(void); -char *amidxtaped_client_get_security_conf(char *, void *); static char *dump_device_name = NULL; static char *errstr; static char *amidxtaped_line = NULL; - extern char *localhost; +static char header_buf[32768]; +static int header_size = 0; + /* global pid storage for interrupt handler */ pid_t extract_restore_child_pid = -1; @@ -92,9 +109,7 @@ pid_t extract_restore_child_pid = -1; static EXTRACT_LIST *extract_list = NULL; static const security_driver_t *amidxtaped_secdrv; -#ifdef SAMBA_CLIENT unsigned short samba_extract_method = SAMBA_TAR; -#endif /* SAMBA_CLIENT */ #define READ_TIMEOUT 240*60 @@ -131,11 +146,14 @@ static ssize_t read_buffer(int datafd, size_t buflen, long timeout_s); static void clear_tape_list(EXTRACT_LIST *tape_list); -static void extract_files_child(int in_fd, EXTRACT_LIST *elist); +static void extract_files_child(ctl_data_t *ctl_data); static void send_to_tape_server(security_stream_t *stream, char *cmd); int writer_intermediary(EXTRACT_LIST *elist); int get_amidxtaped_line(void); static void read_amidxtaped_data(void *, void *, ssize_t); +static char *merge_path(char *path1, char *path2); +static gboolean ask_file_overwrite(ctl_data_t *ctl_data); +static void start_processing_data(ctl_data_t *ctl_data); /* * Function: ssize_t read_buffer(datafd, buffer, buflen, timeout_s) @@ -166,7 +184,7 @@ read_buffer( long timeout_s) { ssize_t size = 0; - fd_set readset; + SELECT_ARG_TYPE readset; struct timeval timeout; char *dataptr; ssize_t spaceleft; @@ -188,7 +206,7 @@ read_buffer( nfound = select(datafd+1, &readset, NULL, NULL, &timeout); if(nfound < 0 ) { /* Select returned an error. */ - fprintf(stderr,"select error: %s\n", strerror(errno)); + g_fprintf(stderr,_("select error: %s\n"), strerror(errno)); size = -1; break; } @@ -197,8 +215,8 @@ read_buffer( /* Select timed out. */ if (timeout_s != 0) { /* Not polling: a real read timeout */ - fprintf(stderr,"timeout waiting for restore\n"); - fprintf(stderr,"increase READ_TIMEOUT in recover-src/extract_list.c if your tape is slow\n"); + g_fprintf(stderr,_("timeout waiting for restore\n")); + g_fprintf(stderr,_("increase READ_TIMEOUT in recover-src/extract_list.c if your tape is slow\n")); } errno = ETIMEDOUT; size = -1; @@ -215,7 +233,7 @@ read_buffer( continue; } if (errno != EPIPE) { - fprintf(stderr, "read_buffer: read error - %s", + g_fprintf(stderr, _("read_buffer: read error - %s"), strerror(errno)); break; } @@ -249,13 +267,14 @@ clear_tape_list( EXTRACT_LIST * tape_list) { EXTRACT_LIST_ITEM *this, *next; - + this = tape_list->files; while (this != NULL) { next = this->next; amfree(this->path); + amfree(this->tpath); amfree(this); this = next; } @@ -364,11 +383,12 @@ clean_tape_list( } if (remove_fn2) { - dbprintf(("removing path %s, it is included in %s\n", - fn2->path, fn1->path)); + dbprintf(_("removing path %s, it is included in %s\n"), + fn2->path, fn1->path); ofn2 = fn2; fn2 = fn2->next; amfree(ofn2->path); + amfree(ofn2->tpath); amfree(ofn2); pfn2->next = fn2; } else if (remove_fn1 == 0) { @@ -379,11 +399,12 @@ clean_tape_list( if(remove_fn1 != 0) { /* fn2->path is always valid */ - /*@i@*/ dbprintf(("removing path %s, it is included in %s\n", - /*@i@*/ fn1->path, fn2->path)); + /*@i@*/ dbprintf(_("removing path %s, it is included in %s\n"), + /*@i@*/ fn1->tpath, fn2->tpath); ofn1 = fn1; fn1 = fn1->next; amfree(ofn1->path); + amfree(ofn1->tpath); if(pfn1 == NULL) { amfree(tape_list->files); tape_list->files = fn1; @@ -399,6 +420,19 @@ clean_tape_list( } +static char * +file_of_path( + char *path, + char **dir) +{ + char *npath = g_path_get_basename(path); + *dir = g_path_get_dirname(path); + if (strcmp(*dir, ".") == 0) { + amfree(*dir); + } + return npath; +} + void clean_extract_list(void) { @@ -450,7 +484,7 @@ do_unlink_list(void) for (ul = unlink_list; ul != NULL; ul = ul->next) { if (unlink(ul->path) < 0) { - fprintf(stderr,"Can't unlink %s: %s\n", ul->path, strerror(errno)); + g_fprintf(stderr,_("Can't unlink %s: %s\n"), ul->path, strerror(errno)); ret = 0; } } @@ -500,14 +534,14 @@ check_file_overwrite( if (lstat(path, &stat_buf) == 0) { if(!S_ISDIR(stat_buf.st_mode)) { if (add_to_unlink_list(path)) { - printf("WARNING: %s is not a directory, " - "it will be deleted.\n", + g_printf(_("WARNING: %s is not a directory, " + "it will be deleted.\n"), path); } } } else if (errno != ENOENT) { - printf("Can't stat %s: %s\n", path, strerror(errno)); + g_printf(_("Can't stat %s: %s\n"), path, strerror(errno)); } *s = '/'; s++; @@ -524,20 +558,20 @@ check_file_overwrite( if (lstat(filename, &stat_buf) == 0) { if(S_ISDIR(stat_buf.st_mode)) { if(!is_empty_dir(filename)) { - printf("WARNING: All existing files in %s " - "will be deleted.\n", filename); + g_printf(_("WARNING: All existing files in %s " + "will be deleted.\n"), filename); } } else if(S_ISREG(stat_buf.st_mode)) { - printf("WARNING: Existing file %s will be overwritten\n", + g_printf(_("WARNING: Existing file %s will be overwritten\n"), filename); } else { if (add_to_unlink_list(filename)) { - printf("WARNING: Existing entry %s will be deleted\n", + g_printf(_("WARNING: Existing entry %s will be deleted\n"), filename); } } } else if (errno != ENOENT) { - printf("Can't stat %s: %s\n", filename, strerror(errno)); + g_printf(_("Can't stat %s: %s\n"), filename, strerror(errno)); } amfree(filename); } @@ -554,7 +588,7 @@ add_extract_item( { EXTRACT_LIST *this, *this1; EXTRACT_LIST_ITEM *that, *curr; - char *ditem_path = NULL; + char *ditem_path; ditem_path = stralloc(ditem->path); clean_pathname(ditem_path); @@ -569,16 +603,16 @@ add_extract_item( while(curr!=NULL) { if (strcmp(curr->path,ditem_path) == 0) { - amfree(ditem_path); + g_free(ditem_path); return 1; } curr=curr->next; } that = (EXTRACT_LIST_ITEM *)alloc(sizeof(EXTRACT_LIST_ITEM)); - that->path = stralloc(ditem_path); + that->path = ditem_path; + that->tpath = clean_pathname(g_strdup(ditem->tpath)); that->next = this->files; this->files = that; /* add at front since easiest */ - amfree(ditem_path); return 0; } } @@ -590,18 +624,18 @@ add_extract_item( this->fileno = ditem->fileno; this->date = stralloc(ditem->date); that = (EXTRACT_LIST_ITEM *)alloc(sizeof(EXTRACT_LIST_ITEM)); - that->path = stralloc(ditem_path); + that->path = ditem_path; + that->tpath = clean_pathname(g_strdup(ditem->tpath)); that->next = NULL; this->files = that; /* add this in date increasing order */ /* because restore must be done in this order */ /* add at begining */ - if(extract_list==NULL || strcmp(this->date,extract_list->date) < 0) + if(extract_list==NULL || strcmp(this->date,extract_list->date) < 0) { this->next = extract_list; extract_list = this; - amfree(ditem_path); return 0; } for (this1 = extract_list; this1->next != NULL; this1 = this1->next) @@ -611,14 +645,12 @@ add_extract_item( { this->next = this1->next; this1->next = this; - amfree(ditem_path); return 0; } } /* add at end */ this->next = NULL; this1->next = this; - amfree(ditem_path); return 0; } @@ -649,6 +681,7 @@ delete_extract_item( /* first on list */ this->files = that->next; amfree(that->path); + amfree(that->tpath); amfree(that); /* if list empty delete it */ if (this->files == NULL) @@ -664,6 +697,7 @@ delete_extract_item( { prev->next = that->next; amfree(that->path); + amfree(that->tpath); amfree(that); amfree(ditem_path); return 0; @@ -680,6 +714,22 @@ delete_extract_item( return 1; } +static char * +merge_path( + char *path1, + char *path2) +{ + char *result; + int len = strlen(path1); + if (path1[len-1] == '/' && path2[0] == '/') { + result = stralloc2(path1, path2+1); + } else if (path1[len-1] != '/' && path2[0] != '/') { + result = vstralloc(path1, "/", path2, NULL); + } else { + result = stralloc2(path1, path2); + } + return result; +} void add_glob( @@ -688,29 +738,51 @@ add_glob( char *regex; char *regex_path; char *s; - char *uqglob = unquote_string(glob); - - regex = glob_to_regex(uqglob); - dbprintf(("add_glob (%s) -> %s\n", uqglob, regex)); - if ((s = validate_regexp(regex)) != NULL) { - printf("%s is not a valid shell wildcard pattern: ", glob); - puts(s); - } else { - /* - * glob_to_regex() anchors the beginning of the pattern with ^, - * but we will be tacking it onto the end of the current directory - * in add_file, so strip that off. Also, it anchors the end with - * $, but we need to match an optional trailing /, so tack that on - * the end. - */ - regex_path = stralloc(regex + 1); - regex_path[strlen(regex_path) - 1] = '\0'; - strappend(regex_path, "[/]*$"); - add_file(uqglob, regex_path); - amfree(regex_path); + char *uqglob; + char *dir; + char *sdir = NULL; + int result = 1; + + if (disk_path == NULL) { + g_printf(_("Must select directory before adding files\n")); + return; } - amfree(regex); + + uqglob = unquote_string(glob); + glob = file_of_path(uqglob, &dir); + if (dir) { + sdir = merge_path(mount_point, disk_path); + result = cd_glob(dir, 0); + amfree(dir); + } + if (result) { + regex = glob_to_regex(glob); + dbprintf(_("add_glob (%s) -> %s\n"), uqglob, regex); + if ((s = validate_regexp(regex)) != NULL) { + g_printf(_("%s is not a valid shell wildcard pattern: "), glob); + puts(s); + } else { + /* + * glob_to_regex() anchors the beginning of the pattern with ^, + * but we will be tacking it onto the end of the current directory + * in add_file, so strip that off. Also, it anchors the end with + * $, but we need to match an optional trailing /, so tack that on + * the end. + */ + regex_path = stralloc(regex + 1); + regex_path[strlen(regex_path) - 1] = '\0'; + strappend(regex_path, "[/]*$"); + add_file(uqglob, regex_path); + amfree(regex_path); + } + if (sdir) { + set_directory(sdir, 0); + } + amfree(regex); + } + amfree(sdir); amfree(uqglob); + amfree(glob); } void @@ -718,15 +790,39 @@ add_regex( char * regex) { char *s; - char *uqregex = unquote_string(regex); - - if ((s = validate_regexp(uqregex)) != NULL) { - printf("\"%s\" is not a valid regular expression: ", regex); - puts(s); - } else { - add_file(uqregex, regex); + char *dir; + char *sdir = NULL; + char *uqregex; + char *newregex; + int result = 1; + + if (disk_path == NULL) { + g_printf(_("Must select directory before adding files\n")); + return; + } + + uqregex = unquote_string(regex); + newregex = file_of_path(uqregex, &dir); + if (dir) { + sdir = merge_path(mount_point, disk_path); + result = cd_regex(dir, 0); + amfree(dir); } + + if (result) { + if ((s = validate_regexp(newregex)) != NULL) { + g_printf(_("\"%s\" is not a valid regular expression: "), newregex); + puts(s); + } else { + add_file(uqregex, newregex); + } + if (sdir) { + set_directory(sdir, 0); + } + } + amfree(sdir); amfree(uqregex); + amfree(newregex); } void @@ -735,14 +831,14 @@ add_file( char * regex) { DIR_ITEM *ditem, lditem; - char *path_on_disk = NULL; - char *path_on_disk_slash = NULL; + char *tpath_on_disk = NULL; char *cmd = NULL; char *err = NULL; int i; ssize_t j; - char *dir, *dir_undo, dir_undo_ch = '\0'; + char *dir_undo, dir_undo_ch = '\0'; char *ditem_path = NULL; + char *qditem_path = NULL; char *l = NULL; int added; char *s, *fp, *quoted; @@ -751,18 +847,17 @@ add_file( int dir_entries; if (disk_path == NULL) { - printf("Must select directory before adding files\n"); + g_printf(_("Must select directory before adding files\n")); return; } memset(&lditem, 0, sizeof(lditem)); /* Prevent use of bogus data... */ - dbprintf(("add_file: Looking for \"%s\"\n", regex)); + dbprintf(_("add_file: Looking for \"%s\"\n"), regex); if(strcmp(regex, "/[/]*$") == 0) { /* "/" behave like "." */ regex = "\\.[/]*$"; } else if(strcmp(regex, "[^/]*[/]*$") == 0) { /* "*" */ - //regex = regex = "([^/.]|\\.[^/]+|[^/.][^/]*)[/]*$"; } else { /* remove "/" at end of path */ @@ -775,47 +870,45 @@ add_file( if (strcmp(disk_path, "/") == 0) { if (*regex == '/') { /* No mods needed if already starts with '/' */ - path_on_disk = stralloc(regex); + tpath_on_disk = g_strdup(regex); } else { /* Prepend '/' */ - path_on_disk = stralloc2("/", regex); + tpath_on_disk = g_strconcat("/", regex, NULL); } } else { - char *clean_disk_path = clean_regex(disk_path); - path_on_disk = vstralloc(clean_disk_path, "/", regex, NULL); - amfree(clean_disk_path); + char *clean_disk_tpath = clean_regex(disk_tpath, 0); + tpath_on_disk = g_strjoin(NULL, clean_disk_tpath, "/", regex, NULL); + amfree(clean_disk_tpath); } - path_on_disk_slash = stralloc2(path_on_disk, "/"); - - dbprintf(("add_file: Converted path=\"%s\" to path_on_disk=\"%s\"\n", - regex, path_on_disk)); + dbprintf(_("add_file: Converted path=\"%s\" to tpath_on_disk=\"%s\"\n"), + regex, tpath_on_disk); found_one = 0; dir_entries = 0; for (ditem=get_dir_list(); ditem!=NULL; ditem=get_next_dir_item(ditem)) { dir_entries++; - quoted = quote_string(ditem->path); - dbprintf(("add_file: Pondering ditem->path=%s\n", quoted)); + quoted = quote_string(ditem->tpath); + dbprintf(_("add_file: Pondering ditem->path=%s\n"), quoted); amfree(quoted); - if (match(path_on_disk, ditem->path) - || match(path_on_disk_slash, ditem->path)) + if (match(tpath_on_disk, ditem->tpath)) { found_one = 1; - j = (ssize_t)strlen(ditem->path); - if((j > 0 && ditem->path[j-1] == '/') - || (j > 1 && ditem->path[j-2] == '/' && ditem->path[j-1] == '.')) + j = (ssize_t)strlen(ditem->tpath); + if((j > 0 && ditem->tpath[j-1] == '/') + || (j > 1 && ditem->tpath[j-2] == '/' && ditem->tpath[j-1] == '.')) { /* It is a directory */ ditem_path = newstralloc(ditem_path, ditem->path); clean_pathname(ditem_path); - cmd = stralloc2("ORLD ", ditem_path); + qditem_path = quote_string(ditem_path); + cmd = newstralloc2(cmd, "ORLD ", qditem_path); + amfree(qditem_path); if(send_command(cmd) == -1) { amfree(cmd); amfree(ditem_path); - amfree(path_on_disk); - amfree(path_on_disk_slash); + amfree(tpath_on_disk); exit(1); } amfree(cmd); @@ -823,28 +916,28 @@ add_file( /* skip preamble */ if ((i = get_reply_line()) == -1) { amfree(ditem_path); - amfree(path_on_disk); - amfree(path_on_disk_slash); + amfree(tpath_on_disk); exit(1); } if(i==0) { /* assume something wrong */ amfree(ditem_path); - amfree(path_on_disk); - amfree(path_on_disk_slash); + amfree(tpath_on_disk); l = reply_line(); - printf("%s\n", l); + g_printf("%s\n", l); return; } dir_undo = NULL; added=0; - lditem.path = newstralloc(lditem.path, ditem->path); + g_free(lditem.path); + g_free(lditem.tpath); + lditem.path = g_strdup(ditem->path); + lditem.tpath = g_strdup(ditem->tpath); /* skip the last line -- duplicate of the preamble */ while ((i = get_reply_line()) != 0) { if (i == -1) { amfree(ditem_path); - amfree(path_on_disk); - amfree(path_on_disk_slash); + amfree(tpath_on_disk); exit(1); } if(err) { @@ -860,18 +953,17 @@ add_file( puts(l); continue; } -#define sc "201-" - if(strncmp(l, sc, sizeof(sc)-1) != 0) { - err = "bad reply: not 201-"; + + s = l; + if(strncmp_const_skip(l, "201-", s, ch) != 0) { + err = _("bad reply: not 201-"); continue; } - - s = l + sizeof(sc)-1; ch = *s++; -#undef sc + skip_whitespace(s, ch); if(ch == '\0') { - err = "bad reply: missing date field"; + err = _("bad reply: missing date field"); continue; } fp = s-1; @@ -882,38 +974,40 @@ add_file( skip_whitespace(s, ch); if(ch == '\0' || sscanf(s - 1, "%d", &lditem.level) != 1) { - err = "bad reply: cannot parse level field"; + err = _("bad reply: cannot parse level field"); continue; } skip_integer(s, ch); skip_whitespace(s, ch); if(ch == '\0') { - err = "bad reply: missing tape field"; + err = _("bad reply: missing tape field"); continue; } fp = s-1; - skip_non_whitespace(s, ch); + skip_quoted_string(s, ch); s[-1] = '\0'; - lditem.tape = newstralloc(lditem.tape, fp); + amfree(lditem.tape); + lditem.tape = unquote_string(fp); s[-1] = (char)ch; if(am_has_feature(indexsrv_features, fe_amindexd_fileno_in_ORLD)) { + long long fileno_ = (long long)0; skip_whitespace(s, ch); - if(ch == '\0' || sscanf(s - 1, OFF_T_FMT, - (OFF_T_FMT_TYPE *)&lditem.fileno) != 1) { - err = "bad reply: cannot parse fileno field"; + if(ch == '\0' || + sscanf(s - 1, "%lld", &fileno_) != 1) { + err = _("bad reply: cannot parse fileno field"); continue; } + lditem.fileno = (off_t)fileno_; skip_integer(s, ch); } skip_whitespace(s, ch); if(ch == '\0') { - err = "bad reply: missing directory field"; + err = _("bad reply: missing directory field"); continue; } - dir = s - 1; skip_quoted_string(s, ch); dir_undo = s - 1; dir_undo_ch = *dir_undo; @@ -921,16 +1015,16 @@ add_file( switch(add_extract_item(&lditem)) { case -1: - printf("System error\n"); - dbprintf(("add_file: (Failed) System error\n")); + g_printf(_("System error\n")); + dbprintf(_("add_file: (Failed) System error\n")); break; case 0: - quoted = quote_string(lditem.path); - printf("Added dir %s at date %s\n", + quoted = quote_string(lditem.tpath); + g_printf(_("Added dir %s at date %s\n"), quoted, lditem.date); - dbprintf(("add_file: (Successful) Added dir %s at date %s\n", - quoted, lditem.date)); + dbprintf(_("add_file: (Successful) Added dir %s at date %s\n"), + quoted, lditem.date); amfree(quoted); added=1; break; @@ -948,8 +1042,8 @@ add_file( puts(cmd); } else if(added == 0) { quoted = quote_string(ditem_path); - printf("dir %s already added\n", quoted); - dbprintf(("add_file: dir %s already added\n", quoted)); + g_printf(_("dir %s already added\n"), quoted); + dbprintf(_("add_file: dir %s already added\n"), quoted); amfree(quoted); } } @@ -957,21 +1051,21 @@ add_file( { switch(add_extract_item(ditem)) { case -1: - printf("System error\n"); - dbprintf(("add_file: (Failed) System error\n")); + g_printf(_("System error\n")); + dbprintf(_("add_file: (Failed) System error\n")); break; case 0: - quoted = quote_string(ditem->path); - printf("Added file %s\n", quoted); - dbprintf(("add_file: (Successful) Added %s\n", quoted)); + quoted = quote_string(ditem->tpath); + g_printf(_("Added file %s\n"), quoted); + dbprintf(_("add_file: (Successful) Added %s\n"), quoted); amfree(quoted); break; case 1: - quoted = quote_string(ditem->path); - printf("File %s already added\n", quoted); - dbprintf(("add_file: file %s already added\n", quoted)); + quoted = quote_string(ditem->tpath); + g_printf(_("File %s already added\n"), quoted); + dbprintf(_("add_file: file %s already added\n"), quoted); amfree(quoted); } } @@ -980,18 +1074,18 @@ add_file( amfree(cmd); amfree(ditem_path); - amfree(path_on_disk); - amfree(path_on_disk_slash); + amfree(tpath_on_disk); amfree(lditem.path); + amfree(lditem.tpath); amfree(lditem.date); amfree(lditem.tape); if(! found_one) { quoted = quote_string(path); - printf("File %s doesn't exist in directory\n", quoted); - dbprintf(("add_file: (Failed) File %s doesn't exist in directory\n", - quoted)); + g_printf(_("File %s doesn't exist in directory\n"), quoted); + dbprintf(_("add_file: (Failed) File %s doesn't exist in directory\n"), + quoted); amfree(quoted); } } @@ -1004,29 +1098,53 @@ delete_glob( char *regex; char *regex_path; char *s; - char *uqglob = unquote_string(glob); - - regex = glob_to_regex(uqglob); - dbprintf(("delete_glob (%s) -> %s\n", uqglob, regex)); - if ((s = validate_regexp(regex)) != NULL) { - printf("\"%s\" is not a valid shell wildcard pattern: ", glob); - puts(s); - } else { - /* - * glob_to_regex() anchors the beginning of the pattern with ^, - * but we will be tacking it onto the end of the current directory - * in add_file, so strip that off. Also, it anchors the end with - * $, but we need to match an optional trailing /, so tack that on - * the end. - */ - regex_path = stralloc(regex + 1); - regex_path[strlen(regex_path) - 1] = '\0'; - strappend(regex_path, "[/]*$"); - delete_file(uqglob, regex_path); - amfree(regex_path); + char *uqglob; + char *newglob; + char *dir; + char *sdir = NULL; + int result = 1; + + if (disk_path == NULL) { + g_printf(_("Must select directory before adding files\n")); + return; } - amfree(regex); + + uqglob = unquote_string(glob); + newglob = file_of_path(uqglob, &dir); + if (dir) { + sdir = merge_path(mount_point, disk_path); + result = cd_glob(dir, 0); + amfree(dir); + } + if (result) { + regex = glob_to_regex(newglob); + dbprintf(_("delete_glob (%s) -> %s\n"), newglob, regex); + if ((s = validate_regexp(regex)) != NULL) { + g_printf(_("\"%s\" is not a valid shell wildcard pattern: "), + newglob); + puts(s); +} else { + /* + * glob_to_regex() anchors the beginning of the pattern with ^, + * but we will be tacking it onto the end of the current directory + * in add_file, so strip that off. Also, it anchors the end with + * $, but we need to match an optional trailing /, so tack that on + * the end. + */ + regex_path = stralloc(regex + 1); + regex_path[strlen(regex_path) - 1] = '\0'; + strappend(regex_path, "[/]*$"); + delete_file(uqglob, regex_path); + amfree(regex_path); + } + if (sdir) { + set_directory(sdir, 0); + } + amfree(regex); + } + amfree(sdir); amfree(uqglob); + amfree(newglob); } void @@ -1034,25 +1152,48 @@ delete_regex( char * regex) { char *s; - char *uqregex = unquote_string(regex); + char *dir; + char *sdir = NULL; + char *uqregex; + char *newregex; + int result = 1; - if ((s = validate_regexp(regex)) != NULL) { - printf("\"%s\" is not a valid regular expression: ", regex); - puts(s); - } else { - delete_file(uqregex, uqregex); + if (disk_path == NULL) { + g_printf(_("Must select directory before adding files\n")); + return; } + + uqregex = unquote_string(regex); + newregex = file_of_path(uqregex, &dir); + if (dir) { + sdir = merge_path(mount_point, disk_path); + result = cd_regex(dir, 0); + amfree(dir); + } + + if (result == 1) { + if ((s = validate_regexp(newregex)) != NULL) { + g_printf(_("\"%s\" is not a valid regular expression: "), newregex); + puts(s); + } else { + delete_file(newregex, regex); + } + if (sdir) { + set_directory(sdir, 0); + } + } + amfree(sdir); amfree(uqregex); + amfree(newregex); } void delete_file( - char * path, + char * tpath, char * regex) { DIR_ITEM *ditem, lditem; - char *path_on_disk = NULL; - char *path_on_disk_slash = NULL; + char *tpath_on_disk = NULL; char *cmd = NULL; char *err = NULL; int i; @@ -1061,8 +1202,9 @@ delete_file( char *tape, *tape_undo, tape_undo_ch = '\0'; char *dir_undo, dir_undo_ch = '\0'; int level = 0; - off_t fileno; char *ditem_path = NULL; + char *ditem_tpath = NULL; + char *qditem_path; char *l = NULL; int deleted; char *s; @@ -1071,12 +1213,12 @@ delete_file( char *quoted; if (disk_path == NULL) { - printf("Must select directory before deleting files\n"); + g_printf(_("Must select directory before deleting files\n")); return; } memset(&lditem, 0, sizeof(lditem)); /* Prevent use of bogus data... */ - dbprintf(("delete_file: Looking for \"%s\"\n", path)); + dbprintf(_("delete_file: Looking for \"%s\"\n"), tpath); if (strcmp(regex, "[^/]*[/]*$") == 0) { /* Looking for * find everything but single . */ @@ -1092,69 +1234,68 @@ delete_file( if (*regex == '/') { if (strcmp(regex, "/[/]*$") == 0) { /* We want "/" to match the directory itself: "/." */ - path_on_disk = stralloc("/\\.[/]*$"); + tpath_on_disk = stralloc("/\\.[/]*$"); } else { /* No mods needed if already starts with '/' */ - path_on_disk = stralloc(regex); + tpath_on_disk = stralloc(regex); } } else { /* Prepend '/' */ - path_on_disk = stralloc2("/", regex); + tpath_on_disk = g_strconcat("/", regex, NULL); } } else { - char *clean_disk_path = clean_regex(disk_path); - path_on_disk = vstralloc(clean_disk_path, "/", regex, NULL); - amfree(clean_disk_path); + char *clean_disk_tpath = clean_regex(disk_tpath, 0); + tpath_on_disk = g_strjoin(NULL, clean_disk_tpath, "/", regex, NULL); + amfree(clean_disk_tpath); } - path_on_disk_slash = stralloc2(path_on_disk, "/"); - - dbprintf(("delete_file: Converted path=\"%s\" to path_on_disk=\"%s\"\n", - regex, path_on_disk)); + dbprintf(_("delete_file: Converted path=\"%s\" to tpath_on_disk=\"%s\"\n"), + regex, tpath_on_disk); found_one = 0; for (ditem=get_dir_list(); ditem!=NULL; ditem=get_next_dir_item(ditem)) { - quoted = quote_string(ditem->path); - dbprintf(("delete_file: Pondering ditem->path=%s\n", quoted)); + quoted = quote_string(ditem->tpath); + dbprintf(_("delete_file: Pondering ditem->path=%s\n"), quoted); amfree(quoted); - if (match(path_on_disk, ditem->path) - || match(path_on_disk_slash, ditem->path)) + if (match(tpath_on_disk, ditem->tpath)) { found_one = 1; - j = (ssize_t)strlen(ditem->path); - if((j > 0 && ditem->path[j-1] == '/') - || (j > 1 && ditem->path[j-2] == '/' && ditem->path[j-1] == '.')) + j = (ssize_t)strlen(ditem->tpath); + if((j > 0 && ditem->tpath[j-1] == '/') + || (j > 1 && ditem->tpath[j-2] == '/' && ditem->tpath[j-1] == '.')) { /* It is a directory */ ditem_path = newstralloc(ditem_path, ditem->path); + ditem_tpath = newstralloc(ditem_tpath, ditem->tpath); clean_pathname(ditem_path); + clean_pathname(ditem_tpath); - cmd = stralloc2("ORLD ", ditem_path); + qditem_path = quote_string(ditem_path); + cmd = newstralloc2(cmd, "ORLD ", qditem_path); + amfree(qditem_path); if(send_command(cmd) == -1) { amfree(cmd); amfree(ditem_path); - amfree(path_on_disk); - amfree(path_on_disk_slash); + amfree(tpath_on_disk); exit(1); } amfree(cmd); /* skip preamble */ if ((i = get_reply_line()) == -1) { amfree(ditem_path); - amfree(path_on_disk); - amfree(path_on_disk_slash); + amfree(tpath_on_disk); exit(1); } if(i==0) /* assume something wrong */ { amfree(ditem_path); - amfree(path_on_disk); - amfree(path_on_disk_slash); + amfree(tpath_on_disk); l = reply_line(); - printf("%s\n", l); + g_printf("%s\n", l); return; } deleted=0; lditem.path = newstralloc(lditem.path, ditem->path); + lditem.tpath = newstralloc(lditem.tpath, ditem->tpath); amfree(cmd); tape_undo = dir_undo = NULL; /* skip the last line -- duplicate of the preamble */ @@ -1162,8 +1303,7 @@ delete_file( { if (i == -1) { amfree(ditem_path); - amfree(path_on_disk); - amfree(path_on_disk_slash); + amfree(tpath_on_disk); exit(1); } if(err) { @@ -1180,17 +1320,17 @@ delete_file( puts(l); continue; } -#define sc "201-" - if(strncmp(l, sc, sizeof(sc)-1) != 0) { - err = "bad reply: not 201-"; + + s = l; + if(strncmp_const_skip(l, "201-", s, ch) != 0) { + err = _("bad reply: not 201-"); continue; } - s = l + sizeof(sc)-1; ch = *s++; -#undef sc + skip_whitespace(s, ch); if(ch == '\0') { - err = "bad reply: missing date field"; + err = _("bad reply: missing date field"); continue; } date = s - 1; @@ -1199,14 +1339,14 @@ delete_file( skip_whitespace(s, ch); if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) { - err = "bad reply: cannot parse level field"; + err = _("bad reply: cannot parse level field"); continue; } skip_integer(s, ch); skip_whitespace(s, ch); if(ch == '\0') { - err = "bad reply: missing tape field"; + err = _("bad reply: missing tape field"); continue; } tape = s - 1; @@ -1216,10 +1356,11 @@ delete_file( *tape_undo = '\0'; if(am_has_feature(indexsrv_features, fe_amindexd_fileno_in_ORLD)) { + long long fileno_ = (long long)0; skip_whitespace(s, ch); - if(ch == '\0' || sscanf(s - 1, OFF_T_FMT, - (OFF_T_FMT_TYPE *)&fileno) != 1) { - err = "bad reply: cannot parse fileno field"; + if(ch == '\0' || + sscanf(s - 1, "%lld", &fileno_) != 1) { + err = _("bad reply: cannot parse fileno field"); continue; } skip_integer(s, ch); @@ -1227,7 +1368,7 @@ delete_file( skip_whitespace(s, ch); if(ch == '\0') { - err = "bad reply: missing directory field"; + err = _("bad reply: missing directory field"); continue; } skip_non_whitespace(s, ch); @@ -1237,16 +1378,17 @@ delete_file( lditem.date = newstralloc(lditem.date, date); lditem.level=level; - lditem.tape = newstralloc(lditem.tape, tape); + g_free(lditem.tape); + lditem.tape = unquote_string(tape); switch(delete_extract_item(&lditem)) { case -1: - printf("System error\n"); - dbprintf(("delete_file: (Failed) System error\n")); + g_printf(_("System error\n")); + dbprintf(_("delete_file: (Failed) System error\n")); break; case 0: - printf("Deleted dir %s at date %s\n", ditem_path, date); - dbprintf(("delete_file: (Successful) Deleted dir %s at date %s\n", - ditem_path, date)); + g_printf(_("Deleted dir %s at date %s\n"), ditem_tpath, date); + dbprintf(_("delete_file: (Successful) Deleted dir %s at date %s\n"), + ditem_tpath, date); deleted=1; break; case 1: @@ -1261,29 +1403,29 @@ delete_file( if (cmd) puts(cmd); } else if(deleted == 0) { - printf("Warning - dir '%s' not on tape list\n", - ditem_path); - dbprintf(("delete_file: dir '%s' not on tape list\n", - ditem_path)); + g_printf(_("Warning - dir '%s' not on tape list\n"), + ditem_tpath); + dbprintf(_("delete_file: dir '%s' not on tape list\n"), + ditem_tpath); } } else { switch(delete_extract_item(ditem)) { case -1: - printf("System error\n"); - dbprintf(("delete_file: (Failed) System error\n")); + g_printf(_("System error\n")); + dbprintf(_("delete_file: (Failed) System error\n")); break; case 0: - printf("Deleted %s\n", ditem->path); - dbprintf(("delete_file: (Successful) Deleted %s\n", - ditem->path)); + g_printf(_("Deleted %s\n"), ditem->tpath); + dbprintf(_("delete_file: (Successful) Deleted %s\n"), + ditem->tpath); break; case 1: - printf("Warning - file '%s' not on tape list\n", - ditem->path); - dbprintf(("delete_file: file '%s' not on tape list\n", - ditem->path)); + g_printf(_("Warning - file '%s' not on tape list\n"), + ditem->tpath); + dbprintf(_("delete_file: file '%s' not on tape list\n"), + ditem->tpath); break; } } @@ -1291,13 +1433,13 @@ delete_file( } amfree(cmd); amfree(ditem_path); - amfree(path_on_disk); - amfree(path_on_disk_slash); + amfree(ditem_tpath); + amfree(tpath_on_disk); if(! found_one) { - printf("File %s doesn't exist in directory\n", path); - dbprintf(("delete_file: (Failed) File %s doesn't exist in directory\n", - path)); + g_printf(_("File %s doesn't exist in directory\n"), tpath); + dbprintf(_("delete_file: (Failed) File %s doesn't exist in directory\n"), + tpath); } } @@ -1327,7 +1469,7 @@ display_extract_list( pager_command = stralloc2(pager, " ; /bin/cat > /dev/null"); if ((fp = popen(pager_command, "w")) == NULL) { - printf("Warning - can't pipe through %s\n", pager); + g_printf(_("Warning - can't pipe through %s\n"), pager); fp = stdout; } amfree(pager_command); @@ -1337,7 +1479,7 @@ display_extract_list( uqfile = unquote_string(file); if ((fp = fopen(uqfile, "w")) == NULL) { - printf("Can't open file %s to print extract list into\n", file); + g_printf(_("Can't open file %s to print extract list into\n"), file); amfree(uqfile); return; } @@ -1346,16 +1488,16 @@ display_extract_list( for (this = extract_list; this != NULL; this = this->next) { - fprintf(fp, "TAPE %s LEVEL %d DATE %s\n", + g_fprintf(fp, _("TAPE %s LEVEL %d DATE %s\n"), this->tape, this->level, this->date); for (that = this->files; that != NULL; that = that->next) - fprintf(fp, "\t%s\n", that->path); + g_fprintf(fp, "\t%s\n", that->tpath); } if (file == NULL) { apclose(fp); } else { - printf("Extract list written to file %s\n", file); + g_printf(_("Extract list written to file %s\n"), file); afclose(fp); } } @@ -1403,20 +1545,20 @@ okay_to_continue( char *line = NULL; char *s; char *prompt; - int get_tape; + int get_device; - get_tape = 0; + get_device = 0; while (ret < 0) { - if (get_tape) { - prompt = "New tape device [?]: "; + if (get_device) { + prompt = _("New device name [?]: "); } else if (allow_tape && allow_skip) { - prompt = "Continue [?/Y/n/s/t]? "; + prompt = _("Continue [?/Y/n/s/d]? "); } else if (allow_tape && !allow_skip) { - prompt = "Continue [?/Y/n/t]? "; + prompt = _("Continue [?/Y/n/d]? "); } else if (allow_retry) { - prompt = "Continue [?/Y/n/r]? "; + prompt = _("Continue [?/Y/n/r]? "); } else { - prompt = "Continue [?/Y/n]? "; + prompt = _("Continue [?/Y/n]? "); } fputs(prompt, stdout); fflush(stdout); fflush(stderr); @@ -1424,40 +1566,53 @@ okay_to_continue( if ((line = agets(stdin)) == NULL) { putchar('\n'); clearerr(stdin); - if (get_tape) { - get_tape = 0; + if (get_device) { + get_device = 0; continue; } ret = 0; break; } + dbprintf("User prompt: '%s'; response: '%s'\n", prompt, line); + s = line; - while ((ch = *s++) != '\0' && isspace(ch)) { + while ((ch = *s++) != '\0' && g_ascii_isspace(ch)) { (void)ch; /* Quiet empty loop compiler warning */ } if (ch == '?') { - if (get_tape) { - printf("Enter a new device ([host:]device) or \"default\"\n"); + if (get_device) { + g_printf(_("Enter a new device name or \"default\"\n")); } else { - printf("Enter \"y\"es to continue, \"n\"o to stop"); + g_printf(_("Enter \"y\"es to continue, \"n\"o to stop")); if(allow_skip) { - printf(", \"s\"kip this tape"); + g_printf(_(", \"s\"kip this tape")); } if(allow_retry) { - printf(" or \"r\"etry this tape"); + g_printf(_(" or \"r\"etry this tape")); } if (allow_tape) { - printf(" or \"t\"ape to change tape drives"); + g_printf(_(" or \"d\" to change to a new device")); } putchar('\n'); } - } else if (get_tape) { - set_tape(s - 1); - get_tape = 0; + } else if (get_device) { + char *tmp = stralloc(tape_server_name); + + if (strncmp_const(s - 1, "default") == 0) { + set_device(tmp, NULL); /* default device, existing host */ + } else if (s[-1] != '\0') { + set_device(tmp, s - 1); /* specified device, existing host */ + } else { + g_printf(_("No change.\n")); + } + + amfree(tmp); + + get_device = 0; } else if (ch == '\0' || ch == 'Y' || ch == 'y') { ret = 1; - } else if (allow_tape && (ch == 'T' || ch == 't')) { - get_tape = 1; + } else if (allow_tape && (ch == 'D' || ch == 'd' || ch == 'T' || ch == 't')) { + get_device = 1; /* ('T' and 't' are for backward-compatibility) */ } else if (ch == 'N' || ch == 'n') { ret = 0; } else if (allow_retry && (ch == 'R' || ch == 'r')) { @@ -1479,9 +1634,10 @@ send_to_tape_server( { char *msg = stralloc2(cmd, "\r\n"); + g_debug("send_to_tape_server: %s\n", cmd); if (security_stream_write(stream, msg, strlen(msg)) < 0) { - error("Error writing to tape server"); + error(_("Error writing to tape server")); exit(101); /*NOTREACHED*/ } @@ -1506,7 +1662,7 @@ extract_files_setup( amidxtaped_secdrv = security_getdriver(authopt); if (amidxtaped_secdrv == NULL) { - error("no '%s' security driver available for host '%s'", + error(_("no '%s' security driver available for host '%s'"), authopt, tape_server_name); } @@ -1518,7 +1674,7 @@ extract_files_setup( "auth=", authopt, ";", "\n", NULL); protocol_sendreq(tape_server_name, amidxtaped_secdrv, - amidxtaped_client_get_security_conf, req, STARTUP_TIMEOUT, + generic_client_get_security_conf, req, STARTUP_TIMEOUT, amidxtaped_response, &response_error); amfree(req); protocol_run(); @@ -1526,53 +1682,8 @@ extract_files_setup( return -1; } - disk_regex = alloc(strlen(disk_name) * 2 + 3); - - ch = disk_name; - ch1 = disk_regex; - - /* we want to force amrestore to only match disk_name exactly */ - *(ch1++) = '^'; - - /* We need to escape some characters first... NT compatibilty crap */ - for (; *ch != 0; ch++, ch1++) { - switch (*ch) { /* done this way in case there are more */ - case '$': - *(ch1++) = '\\'; - /* no break; we do want to fall through... */ - default: - *ch1 = *ch; - } - } - - /* we want to force amrestore to only match disk_name exactly */ - *(ch1++) = '$'; - - *ch1 = '\0'; - - host_regex = alloc(strlen(dump_hostname) * 2 + 3); - - ch = dump_hostname; - ch1 = host_regex; - - /* we want to force amrestore to only match dump_hostname exactly */ - *(ch1++) = '^'; - - /* We need to escape some characters first... NT compatibilty crap */ - for (; *ch != 0; ch++, ch1++) { - switch (*ch) { /* done this way in case there are more */ - case '$': - *(ch1++) = '\\'; - /* no break; we do want to fall through... */ - default: - *ch1 = *ch; - } - } - - /* we want to force amrestore to only match dump_hostname exactly */ - *(ch1++) = '$'; - - *ch1 = '\0'; + disk_regex = make_exact_disk_expression(disk_name); + host_regex = make_exact_host_expression(dump_hostname); clean_datestamp = stralloc(dump_datestamp); for(ch=ch1=clean_datestamp;*ch1 != '\0';ch1++) { @@ -1589,17 +1700,25 @@ extract_files_setup( tt = newstralloc2(tt, "FEATURES=", our_features_string); send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt); get_amidxtaped_line(); - if(strncmp(amidxtaped_line,"FEATURES=",9) == 0) { + if (!amidxtaped_line) { + g_fprintf(stderr, _("amrecover - amidxtaped closed the connection\n")); + stop_amidxtaped(); + amfree(disk_regex); + amfree(host_regex); + amfree(clean_datestamp); + return -1; + } else if(strncmp_const(amidxtaped_line,"FEATURES=") == 0) { tapesrv_features = am_string_to_feature(amidxtaped_line+9); } else { - fprintf(stderr, "amrecover - expecting FEATURES line from amidxtaped\n"); + g_fprintf(stderr, _("amrecover - expecting FEATURES line from amidxtaped\n")); stop_amidxtaped(); amfree(disk_regex); amfree(host_regex); amfree(clean_datestamp); return -1; } - am_release_feature_set(tapesrv_features); + } else { + *tapesrv_features = *indexsrv_features; } @@ -1610,7 +1729,7 @@ extract_files_setup( am_has_feature(indexsrv_features, fe_amidxtaped_datestamp)) { if(am_has_feature(indexsrv_features, fe_amidxtaped_config)) { - tt = newstralloc2(tt, "CONFIG=", config); + tt = newstralloc2(tt, "CONFIG=", get_config_name()); send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt); } if(am_has_feature(indexsrv_features, fe_amidxtaped_label) && @@ -1620,7 +1739,7 @@ extract_files_setup( } if(am_has_feature(indexsrv_features, fe_amidxtaped_fsf)) { char v_fsf[100]; - snprintf(v_fsf, 99, OFF_T_FMT, (OFF_T_FMT_TYPE)fsf); + g_snprintf(v_fsf, 99, "%lld", (long long)fsf); tt = newstralloc2(tt, "FSF=",v_fsf); send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt); } @@ -1654,8 +1773,8 @@ extract_files_setup( send_to_tape_server(amidxtaped_streams[CTLFD].fd, disk_regex); send_to_tape_server(amidxtaped_streams[CTLFD].fd, clean_datestamp); - dbprintf(("Started amidxtaped with arguments \"6 -h -p %s %s %s %s\"\n", - dump_device_name, host_regex, disk_regex, clean_datestamp)); + dbprintf(_("Started amidxtaped with arguments \"6 -h -p %s %s %s %s\"\n"), + dump_device_name, host_regex, disk_regex, clean_datestamp); } amfree(disk_regex); @@ -1680,16 +1799,17 @@ read_file_header( ssize_t bytes_read; bytes_read = read_buffer(tapedev, buffer, buflen, READ_TIMEOUT); if(bytes_read < 0) { - error("error reading header (%s), check amidxtaped.*.debug on server", + error(_("error reading header (%s), check amidxtaped.*.debug on server"), strerror(errno)); /*NOTREACHED*/ } if((size_t)bytes_read < buflen) { - fprintf(stderr, "%s: short block %d byte%s\n", - get_pname(), (int)bytes_read, (bytes_read == 1) ? "" : "s"); + g_fprintf(stderr, plural(_("%s: short block %d byte\n"), + _("%s: short block %d bytes\n"), bytes_read), + get_pname(), (int)bytes_read); print_header(stdout, file); - error("Can't read file header"); + error(_("Can't read file header")); /*NOTREACHED*/ } @@ -1703,26 +1823,24 @@ enum dumptypes { IS_GNUTAR, IS_TAR, IS_SAMBA, - IS_SAMBA_TAR + IS_SAMBA_TAR, + IS_APPLICATION_API }; static void extract_files_child( - int in_fd, - EXTRACT_LIST * elist) + ctl_data_t *ctl_data) { int save_errno; - int extra_params = 0; - int i,j=0; - char **restore_args = NULL; + int i; + guint j; + GPtrArray *argv_ptr = g_ptr_array_new(); int files_off_tape; EXTRACT_LIST_ITEM *fn; enum dumptypes dumptype = IS_UNKNOWN; - char buffer[DISK_BLOCK_BYTES]; - dumpfile_t file; size_t len_program; char *cmd = NULL; - int passwd_field = -1; + guint passwd_field = 999999999; #ifdef SAMBA_CLIENT char *domain = NULL, *smbpass = NULL; #endif @@ -1731,37 +1849,35 @@ extract_files_child( /* never returns */ /* make in_fd be our stdin */ - if (dup2(in_fd, STDIN_FILENO) == -1) + if (dup2(ctl_data->child_pipe[0], STDIN_FILENO) == -1) { - error("dup2 failed in extract_files_child: %s", strerror(errno)); + error(_("dup2 failed in extract_files_child: %s"), strerror(errno)); /*NOTREACHED*/ } - /* read the file header */ - fh_init(&file); - read_file_header(buffer, &file, sizeof(buffer), STDIN_FILENO); - - if(file.type != F_DUMPFILE) { - print_header(stdout, &file); - error("bad header"); + if(ctl_data->file.type != F_DUMPFILE) { + dump_dumpfile_t(&ctl_data->file); + error(_("bad header")); /*NOTREACHED*/ } - if (file.program != NULL) { + if (ctl_data->file.program[0] != '\0') { + if (strcmp(ctl_data->file.program, "APPLICATION") == 0) + dumptype = IS_APPLICATION_API; #ifdef GNUTAR - if (strcmp(file.program, GNUTAR) == 0) + if (strcmp(ctl_data->file.program, GNUTAR) == 0) dumptype = IS_GNUTAR; #endif if (dumptype == IS_UNKNOWN) { - len_program = strlen(file.program); + len_program = strlen(ctl_data->file.program); if(len_program >= 3 && - strcmp(&file.program[len_program-3],"tar") == 0) + strcmp(&ctl_data->file.program[len_program-3],"tar") == 0) dumptype = IS_TAR; } #ifdef SAMBA_CLIENT - if (dumptype == IS_UNKNOWN && strcmp(file.program, SAMBA_CLIENT) ==0) { + if (dumptype == IS_UNKNOWN && strcmp(ctl_data->file.program, SAMBA_CLIENT) ==0) { if (samba_extract_method == SAMBA_TAR) dumptype = IS_SAMBA_TAR; else @@ -1771,135 +1887,151 @@ extract_files_child( } /* form the arguments to restore */ - files_off_tape = length_of_tape_list(elist); - switch (dumptype) { - case IS_SAMBA: -#ifdef SAMBA_CLIENT - extra_params = 10; - break; -#endif - case IS_TAR: - case IS_GNUTAR: - extra_params = 4; - break; - case IS_SAMBA_TAR: - extra_params = 3; - break; - case IS_UNKNOWN: - case IS_DUMP: -#ifdef AIX_BACKUP - extra_params = 2; -#else -#if defined(XFSDUMP) - if (strcmp(file.program, XFSDUMP) == 0) { - extra_params = 4 + files_off_tape; - } else -#endif - { - extra_params = 4; - } -#endif - break; - } - - restore_args = (char **)alloc((size_t)((extra_params + files_off_tape + 1) - * sizeof(char *))); + files_off_tape = length_of_tape_list(ctl_data->elist); switch(dumptype) { case IS_SAMBA: #ifdef SAMBA_CLIENT - restore_args[j++] = stralloc("smbclient"); - smbpass = findpass(file.disk, &domain); - if (smbpass) { - restore_args[j++] = stralloc(file.disk); - passwd_field=j; - restore_args[j++] = stralloc("-U"); - restore_args[j++] = smbpass; - if (domain) { - restore_args[j++] = stralloc("-W"); - restore_args[j++] = stralloc(domain); - } else - extra_params -= 2; - } else - extra_params -= 6; - restore_args[j++] = stralloc("-d0"); - restore_args[j++] = stralloc("-Tx"); - restore_args[j++] = stralloc("-"); /* data on stdin */ - break; + g_ptr_array_add(argv_ptr, stralloc("smbclient")); + smbpass = findpass(ctl_data->file.disk, &domain); + if (smbpass) { + g_ptr_array_add(argv_ptr, stralloc(ctl_data->file.disk)); + g_ptr_array_add(argv_ptr, stralloc("-U")); + passwd_field = argv_ptr->len; + g_ptr_array_add(argv_ptr, stralloc(smbpass)); + if (domain) { + g_ptr_array_add(argv_ptr, stralloc("-W")); + g_ptr_array_add(argv_ptr, stralloc(domain)); + } + } + g_ptr_array_add(argv_ptr, stralloc("-d0")); + g_ptr_array_add(argv_ptr, stralloc("-Tx")); + g_ptr_array_add(argv_ptr, stralloc("-")); /* data on stdin */ + break; #endif case IS_TAR: case IS_GNUTAR: - restore_args[j++] = stralloc("tar"); - restore_args[j++] = stralloc("--numeric-owner"); - restore_args[j++] = stralloc("-xpGvf"); - restore_args[j++] = stralloc("-"); /* data on stdin */ + g_ptr_array_add(argv_ptr, stralloc("tar")); + /* ignore trailing zero blocks on input (this was the default until tar-1.21) */ + g_ptr_array_add(argv_ptr, stralloc("--ignore-zeros")); + g_ptr_array_add(argv_ptr, stralloc("--numeric-owner")); + g_ptr_array_add(argv_ptr, stralloc("-xpGvf")); + g_ptr_array_add(argv_ptr, stralloc("-")); /* data on stdin */ break; case IS_SAMBA_TAR: - restore_args[j++] = stralloc("tar"); - restore_args[j++] = stralloc("-xpvf"); - restore_args[j++] = stralloc("-"); /* data on stdin */ + g_ptr_array_add(argv_ptr, stralloc("tar")); + g_ptr_array_add(argv_ptr, stralloc("-xpvf")); + g_ptr_array_add(argv_ptr, stralloc("-")); /* data on stdin */ break; case IS_UNKNOWN: case IS_DUMP: - restore_args[j++] = stralloc("restore"); + g_ptr_array_add(argv_ptr, stralloc("restore")); #ifdef AIX_BACKUP - restore_args[j++] = stralloc("-xB"); + g_ptr_array_add(argv_ptr, stralloc("-xB")); #else #if defined(XFSDUMP) - if (strcmp(file.program, XFSDUMP) == 0) { - restore_args[j++] = stralloc("-v"); - restore_args[j++] = stralloc("silent"); + if (strcmp(ctl_data->file.program, XFSDUMP) == 0) { + g_ptr_array_add(argv_ptr, stralloc("-v")); + g_ptr_array_add(argv_ptr, stralloc("silent")); } else #endif #if defined(VDUMP) - if (strcmp(file.program, VDUMP) == 0) { - restore_args[j++] = stralloc("xf"); - restore_args[j++] = stralloc("-"); /* data on stdin */ + if (strcmp(ctl_data->file.program, VDUMP) == 0) { + g_ptr_array_add(argv_ptr, stralloc("xf")); + g_ptr_array_add(argv_ptr, stralloc("-")); /* data on stdin */ } else #endif { - restore_args[j++] = stralloc("xbf"); - restore_args[j++] = stralloc("2"); /* read in units of 1K */ - restore_args[j++] = stralloc("-"); /* data on stdin */ + g_ptr_array_add(argv_ptr, stralloc("xbf")); + g_ptr_array_add(argv_ptr, stralloc("2")); /* read in units of 1K */ + g_ptr_array_add(argv_ptr, stralloc("-")); /* data on stdin */ } #endif + break; + case IS_APPLICATION_API: + g_ptr_array_add(argv_ptr, stralloc(ctl_data->file.application)); + g_ptr_array_add(argv_ptr, stralloc("restore")); + g_ptr_array_add(argv_ptr, stralloc("--config")); + g_ptr_array_add(argv_ptr, stralloc(get_config_name())); + g_ptr_array_add(argv_ptr, stralloc("--disk")); + g_ptr_array_add(argv_ptr, stralloc(ctl_data->file.disk)); + if (dump_dle && dump_dle->device) { + g_ptr_array_add(argv_ptr, stralloc("--device")); + g_ptr_array_add(argv_ptr, stralloc(dump_dle->device)); + } + if (ctl_data->data_path == DATA_PATH_DIRECTTCP) { + g_ptr_array_add(argv_ptr, stralloc("--data-path")); + g_ptr_array_add(argv_ptr, stralloc("DIRECTTCP")); + g_ptr_array_add(argv_ptr, stralloc("--direct-tcp")); + g_ptr_array_add(argv_ptr, stralloc(ctl_data->addrs)); + } + if (ctl_data->bsu && ctl_data->bsu->smb_recover_mode && + samba_extract_method == SAMBA_SMBCLIENT){ + g_ptr_array_add(argv_ptr, stralloc("--recover-mode")); + g_ptr_array_add(argv_ptr, stralloc("smb")); + } + g_ptr_array_add(argv_ptr, stralloc("--level")); + g_ptr_array_add(argv_ptr, g_strdup_printf("%d", ctl_data->elist->level)); + if (dump_dle) { + GSList *scriptlist; + script_t *script; + + merge_properties(dump_dle, NULL, dump_dle->application_property, + proplist, 0); + application_property_add_to_argv(argv_ptr, dump_dle, NULL, + tapesrv_features); + for (scriptlist = dump_dle->scriptlist; scriptlist != NULL; + scriptlist = scriptlist->next) { + script = (script_t *)scriptlist->data; + if (script->result && script->result->proplist) { + property_add_to_argv(argv_ptr, script->result->proplist); + } + } + + } else if (proplist) { + property_add_to_argv(argv_ptr, proplist); + } + break; } - - for (i = 0, fn = elist->files; i < files_off_tape; i++, fn = fn->next) + + for (i = 0, fn = ctl_data->elist->files; i < files_off_tape; + i++, fn = fn->next) { switch (dumptype) { + case IS_APPLICATION_API: case IS_TAR: case IS_GNUTAR: case IS_SAMBA_TAR: case IS_SAMBA: if (strcmp(fn->path, "/") == 0) - restore_args[j++] = stralloc("."); + g_ptr_array_add(argv_ptr, stralloc(".")); else - restore_args[j++] = stralloc2(".", fn->path); + g_ptr_array_add(argv_ptr, stralloc2(".", fn->path)); break; case IS_UNKNOWN: case IS_DUMP: #if defined(XFSDUMP) - if (strcmp(file.program, XFSDUMP) == 0) { + if (strcmp(ctl_data->file.program, XFSDUMP) == 0) { /* * xfsrestore needs a -s option before each file to be * restored, and also wants them to be relative paths. */ - restore_args[j++] = stralloc("-s"); - restore_args[j++] = stralloc(fn->path + 1); + g_ptr_array_add(argv_ptr, stralloc("-s")); + g_ptr_array_add(argv_ptr, stralloc(fn->path + 1)); } else #endif { - restore_args[j++] = stralloc(fn->path); + g_ptr_array_add(argv_ptr, stralloc(fn->path)); } + break; } } #if defined(XFSDUMP) - if (strcmp(file.program, XFSDUMP) == 0) { - restore_args[j++] = stralloc("-"); - restore_args[j++] = stralloc("."); + if (strcmp(ctl_data->file.program, XFSDUMP) == 0) { + g_ptr_array_add(argv_ptr, stralloc("-")); + g_ptr_array_add(argv_ptr, stralloc(".")); } #endif - restore_args[j] = NULL; + g_ptr_array_add(argv_ptr, NULL); switch (dumptype) { case IS_SAMBA: @@ -1913,7 +2045,7 @@ extract_files_child( case IS_GNUTAR: case IS_SAMBA_TAR: #ifndef GNUTAR - fprintf(stderr, "warning: GNUTAR program not available.\n"); + g_fprintf(stderr, _("warning: GNUTAR program not available.\n")); cmd = stralloc("tar"); #else cmd = stralloc(GNUTAR); @@ -1923,49 +2055,51 @@ extract_files_child( case IS_DUMP: cmd = NULL; #if defined(DUMP) - if (strcmp(file.program, DUMP) == 0) { + if (strcmp(ctl_data->file.program, DUMP) == 0) { cmd = stralloc(RESTORE); } #endif #if defined(VDUMP) - if (strcmp(file.program, VDUMP) == 0) { + if (strcmp(ctl_data->file.program, VDUMP) == 0) { cmd = stralloc(VRESTORE); } #endif #if defined(VXDUMP) - if (strcmp(file.program, VXDUMP) == 0) { + if (strcmp(ctl_data->file.program, VXDUMP) == 0) { cmd = stralloc(VXRESTORE); } #endif #if defined(XFSDUMP) - if (strcmp(file.program, XFSDUMP) == 0) { + if (strcmp(ctl_data->file.program, XFSDUMP) == 0) { cmd = stralloc(XFSRESTORE); } #endif if (cmd == NULL) { - fprintf(stderr, "warning: restore program for %s not available.\n", - file.program); + g_fprintf(stderr, _("warning: restore program for %s not available.\n"), + ctl_data->file.program); cmd = stralloc("restore"); } + break; + case IS_APPLICATION_API: + cmd = vstralloc(APPLICATION_DIR, "/", ctl_data->file.application, NULL); + break; } if (cmd) { - dbprintf(("Exec'ing %s with arguments:\n", cmd)); - for (i = 0; i < j; i++) { - if( i == passwd_field) - dbprintf(("\tXXXXX\n")); + dbprintf(_("Exec'ing %s with arguments:\n"), cmd); + for (j = 0; j < argv_ptr->len - 1; j++) { + if (j == passwd_field) + dbprintf("\tXXXXX\n"); else - dbprintf(("\t%s\n", restore_args[i])); + dbprintf(_("\t%s\n"), (char *)g_ptr_array_index(argv_ptr, j)); } - (void)execv(cmd, restore_args); + safe_fd(-1, 0); + (void)execv(cmd, (char **)argv_ptr->pdata); /* only get here if exec failed */ save_errno = errno; - for (i = 0; i < j; i++) { - amfree(restore_args[i]); - } - amfree(restore_args); + g_ptr_array_free_full(argv_ptr); errno = save_errno; - perror("amrecover couldn't exec"); - fprintf(stderr, " problem executing %s\n", cmd); + perror(_("amrecover couldn't exec")); + g_fprintf(stderr, _(" problem executing %s\n"), cmd); amfree(cmd); } exit(1); @@ -1981,43 +2115,33 @@ int writer_intermediary( EXTRACT_LIST * elist) { - int child_pipe[2]; - pid_t pid; - amwait_t extractor_status; - - if(pipe(child_pipe) == -1) { - error("extract_list - error setting up pipe to extractor: %s\n", - strerror(errno)); - /*NOTREACHED*/ - } - - /* okay, ready to extract. fork a child to do the actual work */ - if ((pid = fork()) == 0) { - /* this is the child process */ - /* never gets out of this clause */ - aclose(child_pipe[1]); - extract_files_child(child_pipe[0], elist); - /*NOTREACHED*/ - } - - /* This is the parent */ - if (pid == -1) { - printf("writer_intermediary - error forking child"); - return -1; - } - - aclose(child_pipe[0]); - + ctl_data_t ctl_data; + amwait_t extractor_status; + + ctl_data.header_done = 0; + ctl_data.child_pipe[0] = -1; + ctl_data.child_pipe[1] = -1; + ctl_data.pid = -1; + ctl_data.elist = elist; + fh_init(&ctl_data.file); + ctl_data.data_path = DATA_PATH_AMANDA; + ctl_data.addrs = NULL; + ctl_data.bsu = NULL; + ctl_data.bytes_read = 0; + + header_size = 0; security_stream_read(amidxtaped_streams[DATAFD].fd, - read_amidxtaped_data, &(child_pipe[1])); + read_amidxtaped_data, &ctl_data); while(get_amidxtaped_line() >= 0) { char desired_tape[MAX_TAPE_LABEL_BUF]; - + g_debug("get amidxtaped line: %s", amidxtaped_line); + /* if prompted for a tape, relay said prompt to the user */ if(sscanf(amidxtaped_line, "FEEDME %132s\n", desired_tape) == 1) { int done; - printf("Load tape %s now\n", desired_tape); + g_printf(_("Load tape %s now\n"), desired_tape); + dbprintf(_("Requesting tape %s from user\n"), desired_tape); done = okay_to_continue(am_has_feature(indexsrv_features, fe_amrecover_feedme_tape), 0, 0); @@ -2034,10 +2158,20 @@ writer_intermediary( send_to_tape_server(amidxtaped_streams[CTLFD].fd, "ERROR"); break; } - } else if(strncmp(amidxtaped_line, "MESSAGE ", 8) == 0) { - printf("%s\n",&amidxtaped_line[8]); + } else if (strncmp_const(amidxtaped_line, "USE-DATAPATH ") == 0) { + if (strncmp_const(amidxtaped_line+13, "AMANDA") == 0) { + ctl_data.data_path = DATA_PATH_AMANDA; + g_debug("Using AMANDA data-path"); + } else if (strncmp_const(amidxtaped_line+13, "DIRECT-TCP") == 0) { + ctl_data.data_path = DATA_PATH_DIRECTTCP; + ctl_data.addrs = stralloc(amidxtaped_line+24); + g_debug("Using DIRECT-TCP data-path with %s", ctl_data.addrs); + } + start_processing_data(&ctl_data); + } else if(strncmp_const(amidxtaped_line, "MESSAGE ") == 0) { + g_printf("%s\n",&amidxtaped_line[8]); } else { - fprintf(stderr, "Strange message from tape server: %s", + g_fprintf(stderr, _("Strange message from tape server: %s"), amidxtaped_line); break; } @@ -2045,15 +2179,26 @@ writer_intermediary( /* CTL might be close before DATA */ event_loop(0); - aclose(child_pipe[1]); - - waitpid(pid, &extractor_status, 0); - if(WEXITSTATUS(extractor_status) != 0){ - int ret = WEXITSTATUS(extractor_status); - if(ret == 255) ret = -1; - printf("Extractor child exited with status %d\n", ret); - return -1; + dumpfile_free_data(&ctl_data.file); + amfree(ctl_data.addrs); + amfree(ctl_data.bsu); + if (ctl_data.child_pipe[1] != -1) + aclose(ctl_data.child_pipe[1]); + + if (ctl_data.header_done == 0) { + g_printf(_("Got no header and data from server, check in amidxtaped.*.debug and amandad.*.debug files on server\n")); + } + + if (ctl_data.pid != -1) { + waitpid(ctl_data.pid, &extractor_status, 0); + if(WEXITSTATUS(extractor_status) != 0){ + int ret = WEXITSTATUS(extractor_status); + if(ret == 255) ret = -1; + g_printf(_("Extractor child exited with status %d\n"), ret); + return -1; + } } + g_debug("bytes read: %jd", (intmax_t)ctl_data.bytes_read); return(0); } @@ -2080,15 +2225,17 @@ void extract_files(void) { EXTRACT_LIST *elist; - char cwd[STR_SIZE]; char *l; int first; int otc; tapelist_t *tlist = NULL, *a_tlist; + g_option_t g_options; + levellist_t all_level = NULL; + int last_level; if (!is_extract_list_nonempty()) { - printf("Extract list empty - No files to extract!\n"); + g_printf(_("Extract list empty - No files to extract!\n")); return; } @@ -2106,7 +2253,7 @@ extract_files(void) l = reply_line(); if (!server_happy()) { - printf("%s\n", l); + g_printf("%s\n", l); exit(1); } /* skip reply number */ @@ -2115,7 +2262,7 @@ extract_files(void) if (strcmp(tape_device_name, "/dev/null") == 0) { - printf("amrecover: warning: using %s as the tape device will not work\n", + g_printf(_("amrecover: warning: using %s as the tape device will not work\n"), tape_device_name); } @@ -2123,17 +2270,17 @@ extract_files(void) for (elist = first_tape_list(); elist != NULL; elist = next_tape_list(elist)) { if(elist->tape[0]!='/') { if(first) { - printf("\nExtracting files using tape drive %s on host %s.\n", + g_printf(_("\nExtracting files using tape drive %s on host %s.\n"), tape_device_name, tape_server_name); - printf("The following tapes are needed:"); + g_printf(_("The following tapes are needed:")); first=0; } else - printf(" "); - tlist = unmarshal_tapelist_str(elist->tape); + g_printf(" "); + tlist = unmarshal_tapelist_str(elist->tape); for(a_tlist = tlist ; a_tlist != NULL; a_tlist = a_tlist->next) - printf(" %s", a_tlist->label); - printf("\n"); + g_printf(" %s", a_tlist->label); + g_printf("\n"); free_tapelist(tlist); } } @@ -2141,61 +2288,55 @@ extract_files(void) for (elist = first_tape_list(); elist != NULL; elist = next_tape_list(elist)) { if(elist->tape[0]=='/') { if(first) { - printf("\nExtracting files from holding disk on host %s.\n", + g_printf(_("\nExtracting files from holding disk on host %s.\n"), tape_server_name); - printf("The following files are needed:"); + g_printf(_("The following files are needed:")); first=0; } else - printf(" "); - tlist = unmarshal_tapelist_str(elist->tape); + g_printf(" "); + tlist = unmarshal_tapelist_str(elist->tape); for(a_tlist = tlist; a_tlist != NULL; a_tlist = a_tlist->next) - printf(" %s", a_tlist->label); - printf("\n"); + g_printf(" %s", a_tlist->label); + g_printf("\n"); free_tapelist(tlist); } } - printf("\n"); + g_printf("\n"); - if (getcwd(cwd, sizeof(cwd)) == NULL) { - perror("extract_list: Current working directory unavailable"); - exit(1); + g_options.config = get_config_name(); + g_options.hostname = dump_hostname; + for (elist = first_tape_list(); elist != NULL; + elist = next_tape_list(elist)) { + am_level_t *level = g_new0(am_level_t, 1); + level->level = elist->level; + all_level = g_slist_append(all_level, level); } - - printf("Restoring files into directory %s\n", cwd); - check_file_overwrite(cwd); - -#ifdef SAMBA_CLIENT - if (samba_extract_method == SAMBA_SMBCLIENT) - printf("(unless it is a Samba backup, that will go through to the SMB server)\n"); -#endif - if (!okay_to_continue(0,0,0)) - return; - printf("\n"); - - if (!do_unlink_list()) { - fprintf(stderr, "Can't recover because I can't cleanup the cwd (%s)\n", - cwd); - return; + if (dump_dle) { + slist_free_full(dump_dle->levellist, g_free); + dump_dle->levellist = all_level; + run_client_scripts(EXECUTE_ON_PRE_RECOVER, &g_options, dump_dle, + stderr); + dump_dle->levellist = NULL; } - free_unlink_list(); - + last_level = -1; while ((elist = first_tape_list()) != NULL) { if(elist->tape[0]=='/') { dump_device_name = newstralloc(dump_device_name, elist->tape); - printf("Extracting from file "); - tlist = unmarshal_tapelist_str(dump_device_name); + g_printf(_("Extracting from file ")); + tlist = unmarshal_tapelist_str(dump_device_name); for(a_tlist = tlist; a_tlist != NULL; a_tlist = a_tlist->next) - printf(" %s", a_tlist->label); - printf("\n"); + g_printf(" %s", a_tlist->label); + g_printf("\n"); free_tapelist(tlist); } else { - printf("Extracting files using tape drive %s on host %s.\n", + g_printf(_("Extracting files using tape drive %s on host %s.\n"), tape_device_name, tape_server_name); - tlist = unmarshal_tapelist_str(elist->tape); - printf("Load tape %s now\n", tlist->label); + tlist = unmarshal_tapelist_str(elist->tape); + g_printf(_("Load tape %s now\n"), tlist->label); + dbprintf(_("Requesting tape %s from user\n"), tlist->label); free_tapelist(tlist); otc = okay_to_continue(1,1,0); if (otc == 0) @@ -2208,12 +2349,39 @@ extract_files(void) } dump_datestamp = newstralloc(dump_datestamp, elist->date); + if (last_level != -1 && dump_dle) { + am_level_t *level; + + level = g_new0(am_level_t, 1); + level->level = last_level; + dump_dle->levellist = g_slist_append(dump_dle->levellist, level); + + level = g_new0(am_level_t, 1); + level->level = elist->level; + dump_dle->levellist = g_slist_append(dump_dle->levellist, level); + run_client_scripts(EXECUTE_ON_INTER_LEVEL_RECOVER, &g_options, + dump_dle, stderr); + slist_free_full(dump_dle->levellist, g_free); + dump_dle->levellist = NULL; + } + /* connect to the tape handler daemon on the tape drive server */ if ((extract_files_setup(elist->tape, elist->fileno)) == -1) { - fprintf(stderr, "amrecover - can't talk to tape server\n"); + g_fprintf(stderr, _("amrecover - can't talk to tape server: %s\n"), + errstr); return; } + if (dump_dle) { + am_level_t *level; + + level = g_new0(am_level_t, 1); + level->level = elist->level; + dump_dle->levellist = g_slist_append(dump_dle->levellist, level); + run_client_scripts(EXECUTE_ON_PRE_LEVEL_RECOVER, &g_options, + dump_dle, stderr); + } + last_level = elist->level; /* if the server have fe_amrecover_feedme_tape, it has asked for * the tape itself, even if the restore didn't succeed, we should @@ -2223,7 +2391,23 @@ extract_files(void) am_has_feature(indexsrv_features, fe_amrecover_feedme_tape)) delete_tape_list(elist); /* tape done so delete from list */ + am_release_feature_set(tapesrv_features); stop_amidxtaped(); + + if (dump_dle) { + run_client_scripts(EXECUTE_ON_POST_LEVEL_RECOVER, &g_options, + dump_dle, stderr); + slist_free_full(dump_dle->levellist, g_free); + dump_dle->levellist = NULL; + } + } + if (dump_dle) { + dump_dle->levellist = all_level; + run_client_scripts(EXECUTE_ON_POST_RECOVER, &g_options, dump_dle, + stderr); + slist_free_full(dump_dle->levellist, g_free); + all_level = NULL; + dump_dle->levellist = NULL; } } @@ -2242,17 +2426,16 @@ amidxtaped_response( assert(sech != NULL); memset(ports, -1, SIZEOF(ports)); - security_close_connection(sech, dump_hostname); if (pkt == NULL) { - errstr = newvstralloc(errstr, "[request failed: ", - security_geterror(sech), "]", NULL); + errstr = newvstrallocf(errstr, _("[request failed: %s]"), security_geterror(sech)); *response_error = 1; return; } + security_close_connection(sech, dump_hostname); if (pkt->type == P_NAK) { #if defined(PACKET_DEBUG) - fprintf(stderr, "got nak response:\n----\n%s\n----\n\n", pkt->body); + g_fprintf(stderr, _("got nak response:\n----\n%s\n----\n\n"), pkt->body); #endif tok = strtok(pkt->body, " "); @@ -2272,14 +2455,14 @@ bad_nak: } if (pkt->type != P_REP) { - errstr = newvstralloc(errstr, "received strange packet type ", - pkt_type2str(pkt->type), ": ", pkt->body, NULL); + errstr = newvstrallocf(errstr, _("received strange packet type %s: %s"), + pkt_type2str(pkt->type), pkt->body); *response_error = 1; return; } #if defined(PACKET_DEBUG) - fprintf(stderr, "got response:\n----\n%s\n----\n\n", pkt->body); + g_fprintf(stderr, _("got response:\n----\n%s\n----\n\n"), pkt->body); #endif for(i = 0; i < NSTREAMS; i++) { @@ -2298,7 +2481,7 @@ bad_nak: if (strcmp(tok, "ERROR") == 0) { tok = strtok(NULL, "\n"); if (tok == NULL) - tok = "[bogus error packet]"; + tok = _("[bogus error packet]"); errstr = newstralloc(errstr, tok); *response_error = 2; return; @@ -2316,22 +2499,16 @@ bad_nak: for (i = 0; i < NSTREAMS; i++) { tok = strtok(NULL, " "); if (tok == NULL || strcmp(tok, amidxtaped_streams[i].name) != 0) { - extra = vstralloc("CONNECT token is \"", + extra = vstrallocf(_("CONNECT token is \"%s\": expected \"%s\""), tok ? tok : "(null)", - "\": expected \"", - amidxtaped_streams[i].name, - "\"", - NULL); + amidxtaped_streams[i].name); goto parse_error; } tok = strtok(NULL, " \n"); if (tok == NULL || sscanf(tok, "%d", &ports[i]) != 1) { - extra = vstralloc("CONNECT ", + extra = vstrallocf(_("CONNECT %s token is \"%s\": expected a port number"), amidxtaped_streams[i].name, - " token is \"", - tok ? tok : "(null)", - "\": expected a port number", - NULL); + tok ? tok : "(null)"); goto parse_error; } } @@ -2344,20 +2521,18 @@ bad_nak: if (strcmp(tok, "OPTIONS") == 0) { tok = strtok(NULL, "\n"); if (tok == NULL) { - extra = stralloc("OPTIONS token is missing"); + extra = stralloc(_("OPTIONS token is missing")); goto parse_error; } /* while((p = strchr(tok, ';')) != NULL) { *p++ = '\0'; -#define sc "features=" - if(strncmp(tok, sc, sizeof(sc)-1) == 0) { - tok += sizeof(sc) - 1; -#undef sc + if(strncmp_const(tok, "features=") == 0) { + tok += sizeof("features=") - 1; am_release_feature_set(their_features); if((their_features = am_string_to_feature(tok)) == NULL) { errstr = newvstralloc(errstr, - "OPTIONS: bad features value: ", + _("OPTIONS: bad features value: "), tok, NULL); goto parse_error; @@ -2369,10 +2544,8 @@ bad_nak: continue; } /* - extra = vstralloc("next token is \"", - tok ? tok : "(null)", - "\": expected \"CONNECT\", \"ERROR\" or \"OPTIONS\"", - NULL); + extra = vstrallocf("next token is \"%s\": expected \"CONNECT\", \"ERROR\" or \"OPTIONS\""), + tok ? tok : _("(null)")); goto parse_error; */ } @@ -2384,11 +2557,12 @@ bad_nak: if (ports[i] == -1) continue; amidxtaped_streams[i].fd = security_stream_client(sech, ports[i]); - dbprintf(("amidxtaped_streams[%d].fd = %p\n",i, amidxtaped_streams[i].fd)); + dbprintf(_("amidxtaped_streams[%d].fd = %p\n"),i, amidxtaped_streams[i].fd); if (amidxtaped_streams[i].fd == NULL) { - errstr = newvstralloc(errstr, - "[could not connect ", amidxtaped_streams[i].name, " stream: ", - security_geterror(sech), "]", NULL); + errstr = newvstrallocf(errstr,\ + _("[could not connect %s stream: %s]"), + amidxtaped_streams[i].name, + security_geterror(sech)); goto connect_error; } } @@ -2399,9 +2573,10 @@ bad_nak: if (amidxtaped_streams[i].fd == NULL) continue; if (security_stream_auth(amidxtaped_streams[i].fd) < 0) { - errstr = newvstralloc(errstr, - "[could not authenticate ", amidxtaped_streams[i].name, " stream: ", - security_stream_geterror(amidxtaped_streams[i].fd), "]", NULL); + errstr = newvstrallocf(errstr, + _("[could not authenticate %s stream: %s]"), + amidxtaped_streams[i].name, + security_stream_geterror(amidxtaped_streams[i].fd)); goto connect_error; } } @@ -2411,11 +2586,11 @@ bad_nak: * them, complain. */ if (amidxtaped_streams[CTLFD].fd == NULL) { - errstr = newstralloc(errstr, "[couldn't open CTL streams]"); + errstr = newvstrallocf(errstr, _("[couldn't open CTL streams]")); goto connect_error; } if (amidxtaped_streams[DATAFD].fd == NULL) { - errstr = newstralloc(errstr, "[couldn't open DATA streams]"); + errstr = newvstrallocf(errstr, _("[couldn't open DATA streams]")); goto connect_error; } @@ -2424,11 +2599,13 @@ bad_nak: return; parse_error: - errstr = newvstralloc(errstr, - "[parse of reply message failed: ", - extra ? extra : "(no additional information)", - "]", - NULL); + if (extra) { + errstr = newvstrallocf(errstr, + _("[parse of reply message failed: %s]"), extra); + } else { + errstr = newvstrallocf(errstr, + _("[parse of reply message failed: (no additional information)")); + } amfree(extra); *response_error = 2; return; @@ -2472,6 +2649,9 @@ get_amidxtaped_line(void) ctl_buffer = stralloc(""); while (!strstr(ctl_buffer,"\r\n")) { + if (amidxtaped_streams[CTLFD].fd == NULL) + return -1; + size = security_stream_read_sync(amidxtaped_streams[CTLFD].fd, &buf); if(size < 0) { return -1; @@ -2485,6 +2665,7 @@ get_amidxtaped_line(void) newbuf[strlen(ctl_buffer)+size] = '\0'; amfree(ctl_buffer); ctl_buffer = newbuf; + amfree(buf); } s = strstr(ctl_buffer,"\r\n"); @@ -2503,13 +2684,11 @@ read_amidxtaped_data( void * buf, ssize_t size) { - int fd; - + ctl_data_t *ctl_data = (ctl_data_t *)cookie; assert(cookie != NULL); - fd = *(int *)cookie; if (size < 0) { - errstr = newstralloc2(errstr, "amidxtaped read: ", + errstr = newstralloc2(errstr, _("amidxtaped read: "), security_stream_geterror(amidxtaped_streams[DATAFD].fd)); return; } @@ -2528,28 +2707,215 @@ read_amidxtaped_data( assert(buf != NULL); - /* - * We ignore errors while writing to the index file. - */ - (void)fullwrite(fd, buf, (size_t)size); - security_stream_read(amidxtaped_streams[DATAFD].fd, read_amidxtaped_data, cookie); + if (ctl_data->header_done == 0) { + GPtrArray *errarray; + g_option_t g_options; + data_path_t data_path_set = DATA_PATH_AMANDA; + int to_move; + + to_move = MIN(32768-header_size, size); + memcpy(header_buf+header_size, buf, to_move); + header_size += to_move; + + g_debug("read header %zd => %d", size, header_size); + if (header_size < 32768) { + /* wait to read more data */ + return; + } else if (header_size > 32768) { + error("header_size is %d\n", header_size); + } + assert (to_move == size); + security_stream_read_cancel(amidxtaped_streams[DATAFD].fd); + /* parse the file header */ + fh_init(&ctl_data->file); + parse_file_header(header_buf, &ctl_data->file, (size_t)header_size); + + /* call backup_support_option */ + g_options.config = get_config_name(); + g_options.hostname = dump_hostname; + if (strcmp(ctl_data->file.program, "APPLICATION") == 0) { + if (dump_dle) { + ctl_data->bsu = backup_support_option(ctl_data->file.application, + &g_options, + ctl_data->file.disk, + dump_dle->device, + &errarray); + } else { + ctl_data->bsu = backup_support_option(ctl_data->file.application, + &g_options, + ctl_data->file.disk, NULL, + &errarray); + } + if (!ctl_data->bsu) { + guint i; + for (i=0; i < errarray->len; i++) { + char *line; + line = g_ptr_array_index(errarray, i); + g_fprintf(stderr, "%s\n", line); + } + g_ptr_array_free_full(errarray); + exit(1); + } + data_path_set = ctl_data->bsu->data_path_set; + } + /* handle backup_support_option failure */ + + ctl_data->header_done = 1; + if (!ask_file_overwrite(ctl_data)) { + if (am_has_feature(tapesrv_features, fe_amidxtaped_abort)) { + send_to_tape_server(amidxtaped_streams[CTLFD].fd, "ABORT"); + } + stop_amidxtaped(); + return; + } + + if (am_has_feature(tapesrv_features, fe_amidxtaped_datapath)) { + char *msg; + /* send DATA-PATH request */ + msg = stralloc("AVAIL-DATAPATH"); + if (data_path_set & DATA_PATH_AMANDA) + vstrextend(&msg, " AMANDA", NULL); + if (data_path_set & DATA_PATH_DIRECTTCP) + vstrextend(&msg, " DIRECT-TCP", NULL); + send_to_tape_server(amidxtaped_streams[CTLFD].fd, msg); + amfree(msg); + } else { + start_processing_data(ctl_data); + } + } else { + ctl_data->bytes_read += size; + /* Only the data is sent to the child */ + /* + * We ignore errors while writing to the index file. + */ + (void)full_write(ctl_data->child_pipe[1], buf, (size_t)size); + } } -char * -amidxtaped_client_get_security_conf( - char * string, - void * arg) +static gboolean +ask_file_overwrite( + ctl_data_t *ctl_data) { - (void)arg; /* Quiet unused parameter warning */ + char *restore_dir = NULL; - if(!string || !*string) - return(NULL); + if (ctl_data->file.dumplevel == 0) { + property_t *property = g_hash_table_lookup(proplist, "directory"); + if (property && property->values && property->values->data) { + /* take first property value */ + restore_dir = strdup(property->values->data); + } + if (samba_extract_method == SAMBA_SMBCLIENT || + (ctl_data->bsu && + ctl_data->bsu->recover_path == RECOVER_PATH_REMOTE)) { + if (!restore_dir) { + restore_dir = g_strdup(ctl_data->file.disk); + } + g_printf(_("Restoring files into target host %s\n"), restore_dir); + } else { + if (!restore_dir) { + restore_dir = g_get_current_dir(); + } + g_printf(_("Restoring files into directory %s\n"), restore_dir); + } + + /* Collect files to delete befause of a bug in gnutar */ + if (strcmp(ctl_data->file.program, "GNUTAR") == 0 || + (strcmp(ctl_data->file.program, "APPLICATION") == 0 && + strcmp(ctl_data->file.application, "amgtar") == 0)) { + check_file_overwrite(restore_dir); + } else { + g_printf(_("All existing files in %s can be deleted\n"), + restore_dir); + } + + if (!okay_to_continue(0,0,0)) { + free_unlink_list(); + amfree(restore_dir); + return FALSE; + } + g_printf("\n"); + + /* delete the files for gnutar */ + if (unlink_list) { + if (!do_unlink_list()) { + g_fprintf(stderr, _("Can't recover because I can't cleanup the restore directory (%s)\n"), + restore_dir); + free_unlink_list(); + amfree(restore_dir); + return FALSE; + } + free_unlink_list(); + } + amfree(restore_dir); + } + return TRUE; +} + +static void +start_processing_data( + ctl_data_t *ctl_data) +{ + if (pipe(ctl_data->child_pipe) == -1) { + error(_("extract_list - error setting up pipe to extractor: %s\n"), + strerror(errno)); + /*NOTREACHED*/ + } - if(strcmp(string, "auth")==0) { - return(client_getconf_str(CLN_AUTH)); + /* decrypt */ + if (ctl_data->file.encrypted) { + char *argv[3]; + int crypt_out; + int errfd = fileno(stderr); + + g_debug("image is encrypted %s %s", ctl_data->file.clnt_encrypt, ctl_data->file.clnt_decrypt_opt); + argv[0] = ctl_data->file.clnt_encrypt; + argv[1] = ctl_data->file.clnt_decrypt_opt; + argv[2] = NULL; + pipespawnv(ctl_data->file.clnt_encrypt, STDOUT_PIPE, 0, &ctl_data->child_pipe[0], &crypt_out, &errfd, argv); + ctl_data->child_pipe[0] = crypt_out; + } + + /* decompress */ + if (ctl_data->file.compressed) { + char *argv[3]; + int comp_out; + int errfd = fileno(stderr); + char *comp_prog; + char *comp_arg; + + g_debug("image is compressed %s", ctl_data->file.clntcompprog); + if (strlen(ctl_data->file.clntcompprog) > 0) { + comp_prog = ctl_data->file.clntcompprog; + comp_arg = "-d"; + } else { + comp_prog = UNCOMPRESS_PATH; + comp_arg = UNCOMPRESS_OPT; + } + argv[0] = comp_prog; + argv[1] = comp_arg; + argv[2] = NULL; + pipespawnv(comp_prog, STDOUT_PIPE, 0, &ctl_data->child_pipe[0], &comp_out, &errfd, argv); + ctl_data->child_pipe[0] = comp_out; + } + + /* okay, ready to extract. fork a child to do the actual work */ + if ((ctl_data->pid = fork()) == 0) { + /* this is the child process */ + /* never gets out of this clause */ + aclose(ctl_data->child_pipe[1]); + extract_files_child(ctl_data); + /*NOTREACHED*/ + } + + if (ctl_data->pid == -1) { + errstr = newstralloc(errstr, _("writer_intermediary - error forking child")); + g_printf(_("writer_intermediary - error forking child")); + return; } - if(strcmp(string, "ssh_keys")==0) { - return(client_getconf_str(CLN_SSH_KEYS)); + aclose(ctl_data->child_pipe[0]); + security_stream_read(amidxtaped_streams[DATAFD].fd, read_amidxtaped_data, + ctl_data); + if (am_has_feature(tapesrv_features, fe_amidxtaped_datapath)) { + send_to_tape_server(amidxtaped_streams[CTLFD].fd, "DATAPATH-OK"); } - return(NULL); }