* file named AUTHORS, in the root directory of this distribution.
*/
/*
- * $Id: extract_list.c,v 1.43.2.13.4.6.2.19 2003/03/04 21:13:58 martinea Exp $
+ * $Id: extract_list.c,v 1.97 2006/03/09 16:51:41 martinea Exp $
*
* implements the "extract" command in amrecover
*/
#include "fileheader.h"
#include "dgram.h"
#include "stream.h"
+#include "tapelist.h"
#ifdef SAMBA_CLIENT
#include "findpass.h"
#endif
-
-#if defined(KRB4_SECURITY)
-#include "krb4-security.h"
-#endif
#include "util.h"
typedef struct EXTRACT_LIST_ITEM
{
- char path[1024];
+ char *path;
struct EXTRACT_LIST_ITEM *next;
}
typedef struct EXTRACT_LIST
{
- char date[11]; /* date tape created */
+ char *date; /* date tape created */
int level; /* level of dump */
- char tape[256]; /* tape label */
+ char *tape; /* tape label */
int fileno; /* fileno on tape */
EXTRACT_LIST_ITEM *files; /* files to get off tape */
/* global pid storage for interrupt handler */
pid_t extract_restore_child_pid = -1;
-
static EXTRACT_LIST *extract_list = NULL;
+static int tape_control_sock = -1;
+static int tape_data_sock = -1;
#ifdef SAMBA_CLIENT
unsigned short samba_extract_method = SAMBA_TAR;
#define READ_TIMEOUT 240*60
static int okay_to_continue P((int, int, int));
+void writer_intermediary P((int ctl_fd, int data_fd, EXTRACT_LIST *elist));
+
+
+/*
+ * Function: ssize_t read_buffer(datafd, buffer, buflen, timeout_s)
+ *
+ * Description:
+ * read data from input file desciptor waiting up to timeout_s
+ * seconds before returning data.
+ *
+ * Inputs:
+ * datafd - File descriptor to read from.
+ * buffer - Buffer to read into.
+ * buflen - Maximum number of bytes to read into buffer.
+ * timeout_s - Seconds to wait before returning what was already read.
+ *
+ * Returns:
+ * >0 - Number of data bytes in buffer.
+ * 0 - EOF
+ * -1 - errno == ETIMEDOUT if no data available in specified time.
+ * errno == ENFILE if datafd is invalid.
+ * otherwise errno is set by select or read..
+ */
-ssize_t read_buffer(datafd, buffer, buflen)
+static ssize_t
+read_buffer(datafd, buffer, buflen, timeout_s)
int datafd;
char *buffer;
size_t buflen;
{
- int maxfd, nfound = 0;
ssize_t size = 0;
- fd_set readset, selectset;
+ fd_set readset;
struct timeval timeout;
char *dataptr;
size_t spaceleft;
- int eof;
+ int nfound;
if(datafd < 0 || datafd >= FD_SETSIZE) {
errno = EMFILE; /* out of range */
dataptr = buffer;
spaceleft = buflen;
- maxfd = datafd + 1;
- eof = 0;
-
- FD_ZERO(&readset);
- FD_SET(datafd, &readset);
-
do {
+ FD_ZERO(&readset);
+ FD_SET(datafd, &readset);
+ timeout.tv_sec = timeout_s;
+ timeout.tv_usec = 0;
+ nfound = select(datafd+1, &readset, NULL, NULL, &timeout);
+ if(nfound < 0 ) {
+ /* Select returned an error. */
+ fprintf(stderr,"select error: %s\n", strerror(errno));
+ size = -1;
+ break;
+ }
+
+ if (nfound == 0) {
+ /* 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");
+ }
+ errno = ETIMEDOUT;
+ size = -1;
+ break;
+ }
- timeout.tv_sec = READ_TIMEOUT;
- timeout.tv_usec = 0;
- memcpy(&selectset, &readset, sizeof(fd_set));
-
- nfound = select(maxfd, (SELECT_ARG_TYPE *)(&selectset), NULL, NULL, &timeout);
-
- /* check for errors or timeout */
-
- if(nfound == 0) {
- size=-2;
- fprintf(stderr,"timeout waiting for amrestore\n");
- fprintf(stderr,"increase READ_TIMEOUT in recover-src/extract_list.c if your tape is slow\n");
- }
- if(nfound == -1) {
- size=-3;
- fprintf(stderr,"nfound == -1\n");
- }
+ if(!FD_ISSET(datafd, &readset))
+ continue;
- /* read any data */
-
- if(FD_ISSET(datafd, &selectset)) {
- size = read(datafd, dataptr, spaceleft);
- switch(size) {
- case -1:
- break;
- case 0:
- spaceleft -= size;
- dataptr += size;
- fprintf(stderr,
- "EOF, check amidxtaped.<timestamp>.debug file on %s.\n",
- tape_server_name);
- break;
- default:
- spaceleft -= size;
- dataptr += size;
- break;
+ /* Select says data is available, so read it. */
+ size = read(datafd, dataptr, spaceleft);
+ if (size < 0) {
+ if ((errno == EINTR) || (errno == EAGAIN)) {
+ continue;
}
+ if (errno != EPIPE) {
+ fprintf(stderr, "read_buffer: read error - %s",
+ strerror(errno));
+ break;
+ }
+ size = 0;
}
- } while (spaceleft>0 && size>0);
+ spaceleft -= size;
+ dataptr += size;
+ } while ((size > 0) && (spaceleft > 0));
- if(size<0) {
- return -1;
- }
- return (ssize_t)(buflen-spaceleft);
+ return (((buflen-spaceleft) > 0) ? (buflen-spaceleft) : size);
}
+
EXTRACT_LIST *first_tape_list P((void))
{
return extract_list;
EXTRACT_LIST *tape_list;
{
EXTRACT_LIST_ITEM *this, *next;
+
this = tape_list->files;
while (this != NULL)
{
next = this->next;
- free(this);
+ amfree(this->path);
+ amfree(this);
this = next;
}
tape_list->files = NULL;
{
EXTRACT_LIST *this, *prev;
+ if (tape_list == NULL)
+ return;
+
/* is it first on the list? */
if (tape_list == extract_list)
{
- clear_tape_list(tape_list);
extract_list = tape_list->next;
+ clear_tape_list(tape_list);
+ amfree(tape_list->date);
+ amfree(tape_list->tape);
amfree(tape_list);
return;
}
{
if (this == tape_list)
{
- clear_tape_list(tape_list);
prev->next = tape_list->next;
+ clear_tape_list(tape_list);
+ amfree(tape_list->date);
+ amfree(tape_list->tape);
amfree(tape_list);
return;
}
curr=curr->next;
}
that = (EXTRACT_LIST_ITEM *)alloc(sizeof(EXTRACT_LIST_ITEM));
- strncpy(that->path, ditem_path, sizeof(that->path)-1);
- that->path[sizeof(that->path)-1] = '\0';
+ that->path = stralloc(ditem_path);
that->next = this->files;
this->files = that; /* add at front since easiest */
amfree(ditem_path);
/* so this is the first time we have seen this tape */
this = (EXTRACT_LIST *)alloc(sizeof(EXTRACT_LIST));
- strncpy(this->tape, ditem->tape, sizeof(this->tape)-1);
- this->tape[sizeof(this->tape)-1] ='\0';
+ this->tape = stralloc(ditem->tape);
this->level = ditem->level;
this->fileno = ditem->fileno;
- strncpy(this->date, ditem->date, sizeof(this->date)-1);
- this->date[sizeof(this->date)-1] = '\0';
+ this->date = stralloc(ditem->date);
that = (EXTRACT_LIST_ITEM *)alloc(sizeof(EXTRACT_LIST_ITEM));
- strncpy(that->path, ditem_path, sizeof(that->path)-1);
- that->path[sizeof(that->path)-1] = '\0';
+ that->path = stralloc(ditem_path);
that->next = NULL;
this->files = that;
{
/* first on list */
this->files = that->next;
+ amfree(that->path);
amfree(that);
/* if list empty delete it */
if (this->files == NULL)
if (strcmp(that->path, ditem_path) == 0)
{
prev->next = that->next;
+ amfree(that->path);
amfree(that);
amfree(ditem_path);
return 0;
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));
while(j >= 0 && regex[j] == '/') regex[j--] = '\0';
/* convert path (assumed in cwd) to one on disk */
- if (strcmp(disk_path, "/") == 0)
- path_on_disk = stralloc2("/", regex);
- else {
+ if (strcmp(disk_path, "/") == 0) {
+ if (*regex == '/') {
+ if (strcmp(regex, "/[/]*$") == 0) {
+ /* We want '/' to match everything in directory... */
+ path_on_disk = stralloc("/[^/]*[/]*$");
+ } else {
+ /* No mods needed if already starts with '/' */
+ path_on_disk = stralloc(regex);
+ }
+ } else {
+ /* Prepend '/' */
+ path_on_disk = stralloc2("/", regex);
+ }
+ } else {
char *clean_disk_path = clean_regex(disk_path);
path_on_disk = vstralloc(clean_disk_path, "/", regex, NULL);
amfree(clean_disk_path);
exit(1);
}
amfree(cmd);
+ cmd = NULL;
/* skip preamble */
if ((i = get_reply_line()) == -1) {
amfree(ditem_path);
printf("%s\n", l);
return;
}
- amfree(err);
dir_undo = NULL;
added=0;
- strncpy(lditem.path, ditem_path, sizeof(lditem.path)-1);
- lditem.path[sizeof(lditem.path)-1] = '\0';
+ lditem.path = newstralloc(lditem.path, ditem->path);
/* skip the last line -- duplicate of the preamble */
while ((i = get_reply_line()) != 0)
{
err = "bad reply: missing date field";
continue;
}
- copy_string(s, ch, lditem.date, sizeof(lditem.date), fp);
- if(fp == NULL) {
- err = "bad reply: date field too large";
- continue;
- }
+ fp = s-1;
+ skip_non_whitespace(s, ch);
+ s[-1] = '\0';
+ lditem.date = newstralloc(lditem.date, fp);
+ s[-1] = ch;
skip_whitespace(s, ch);
if(ch == '\0' || sscanf(s - 1, "%d", &lditem.level) != 1) {
err = "bad reply: missing tape field";
continue;
}
- copy_string(s, ch, lditem.tape, sizeof(lditem.tape), fp);
- if(fp == NULL) {
- err = "bad reply: tape field too large";
- continue;
- }
+ fp = s-1;
+ skip_non_whitespace(s, ch);
+ s[-1] = '\0';
+ lditem.tape = newstralloc(lditem.tape, fp);
+ s[-1] = ch;
- if(am_has_feature(their_features, fe_amindexd_fileno_in_ORLD)) {
+ if(am_has_feature(indexsrv_features, fe_amindexd_fileno_in_ORLD)) {
skip_whitespace(s, ch);
if(ch == '\0' || sscanf(s - 1, "%d", &lditem.fileno) != 1) {
err = "bad reply: cannot parse fileno field";
if(!server_happy()) {
puts(reply_line());
} else if(err) {
- if(*err) {
- puts(err);
- }
+ puts(err);
puts(cmd);
} else if(added == 0) {
printf("dir %s already added\n", ditem_path);
}
}
}
- amfree(cmd);
+ if (cmd != NULL)
+ amfree(cmd);
amfree(ditem_path);
amfree(path_on_disk);
amfree(path_on_disk_slash);
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));
/* remove "/" at the end of the path */
return;
}
deleted=0;
- strncpy(lditem.path, ditem->path, sizeof(lditem.path)-1);
- lditem.path[sizeof(lditem.path)-1] = '\0';
+ lditem.path = newstralloc(lditem.path, ditem->path);
amfree(cmd);
- amfree(err);
date_undo = tape_undo = dir_undo = NULL;
/* skip the last line -- duplicate of the preamble */
while ((i = get_reply_line()) != 0)
tape_undo_ch = *tape_undo;
*tape_undo = '\0';
- if(am_has_feature(their_features, fe_amindexd_fileno_in_ORLD)) {
+ if(am_has_feature(indexsrv_features, fe_amindexd_fileno_in_ORLD)) {
skip_whitespace(s, ch);
if(ch == '\0' || sscanf(s - 1, "%d", &fileno) != 1) {
err = "bad reply: cannot parse fileno field";
dir_undo_ch = *dir_undo;
*dir_undo = '\0';
- strncpy(lditem.date, date, sizeof(lditem.date)-1);
- lditem.date[sizeof(lditem.date)-1] = '\0';
+ lditem.date = newstralloc(lditem.date, date);
lditem.level=level;
- strncpy(lditem.tape, tape, sizeof(lditem.tape)-1);
- lditem.tape[sizeof(lditem.tape)-1] = '\0';
+ lditem.tape = newstralloc(lditem.tape, tape);
switch(delete_extract_item(&lditem)) {
case -1:
printf("System error\n");
int tss;
char *cmd;
{
- size_t l, n;
- ssize_t s;
- char *end;
+ char *msg = stralloc2(cmd, "\r\n");
- for (l = 0, n = strlen(cmd); l < n; l += s)
- if ((s = write(tss, cmd + l, n - l)) < 0)
- {
- perror("Error writing to tape server");
- exit(101);
- }
- end = "\r\n";
- for (l = 0, n = strlen(end); l < n; l += s)
- if ((s = write(tss, end + l, n - l)) < 0)
- {
- perror("Error writing to tape server");
- exit(101);
- }
+ if (fullwrite(tss, msg, strlen(msg)) < 0)
+ {
+ error("Error writing to tape server");
+ exit(101);
+ }
+ amfree(msg);
}
int fsf;
{
struct servent *sp;
- int my_port;
- int tape_server_socket;
+ int my_port, my_data_port;
char *disk_regex = NULL;
char *host_regex = NULL;
char *service_name = NULL;
char *line = NULL;
char *clean_datestamp, *ch, *ch1;
+ char *our_feature_string = NULL;
+ char *tt = NULL;
service_name = stralloc2("amidxtape", SERVICE_SUFFIX);
amfree(service_name);
seteuid(0); /* it either works ... */
setegid(0);
- tape_server_socket = stream_client_privileged(tape_server_name,
+ tape_control_sock = stream_client_privileged(tape_server_name,
ntohs(sp->s_port),
-1,
STREAM_BUFSIZE,
- &my_port);
- if (tape_server_socket < 0)
+ &my_port,
+ 0);
+ if (tape_control_sock < 0)
{
printf("cannot connect to %s: %s\n", tape_server_name, strerror(errno));
return -1;
}
if (my_port >= IPPORT_RESERVED) {
- aclose(tape_server_socket);
+ aclose(tape_control_sock);
printf("did not get a reserved port: %d\n", my_port);
return -1;
}
+
setegid(getgid());
seteuid(getuid()); /* put it back */
/* do the security thing */
-#if defined(KRB4_SECURITY)
-#if 0 /* not yet implemented */
- if(krb4_auth)
- {
- line = get_krb_security();
- }
-#endif /* 0 */
-#endif
- {
- line = get_bsd_security();
- }
- send_to_tape_server(tape_server_socket, line);
+ line = get_security();
+ send_to_tape_server(tape_control_sock, line);
memset(line, '\0', strlen(line));
amfree(line);
}
*ch = '\0';
- if(am_has_feature(their_features, fe_amidxtaped_header) &&
- am_has_feature(their_features, fe_amidxtaped_device) &&
- am_has_feature(their_features, fe_amidxtaped_host) &&
- am_has_feature(their_features, fe_amidxtaped_disk) &&
- am_has_feature(their_features, fe_amidxtaped_datestamp)) {
+ /* push our feature list off to the tape server */
+ /* XXX assumes that index server and tape server are equivalent, ew */
+ if(am_has_feature(indexsrv_features, fe_amidxtaped_exchange_features)){
+ char buffer[32768] = "\0";
+
+ our_feature_string = am_feature_to_string(our_features);
+ tt = newstralloc2(tt, "FEATURES=", our_feature_string);
+ send_to_tape_server(tape_control_sock, tt);
+ if (read(tape_control_sock, buffer, sizeof(buffer)) <= 0) {
+ error("Could not read features from control socket\n");
+ /* NOTREACHED */
+ }
+
+ tapesrv_features = am_string_to_feature(buffer);
+ amfree(our_feature_string);
+ }
+
- char *tt = NULL;
+ if(am_has_feature(indexsrv_features, fe_amidxtaped_header) &&
+ am_has_feature(indexsrv_features, fe_amidxtaped_device) &&
+ am_has_feature(indexsrv_features, fe_amidxtaped_host) &&
+ am_has_feature(indexsrv_features, fe_amidxtaped_disk) &&
+ am_has_feature(indexsrv_features, fe_amidxtaped_datestamp)) {
- if(am_has_feature(their_features, fe_amidxtaped_config)) {
+ if(am_has_feature(indexsrv_features, fe_amidxtaped_config)) {
tt = newstralloc2(tt, "CONFIG=", config);
- send_to_tape_server(tape_server_socket, tt);
+ send_to_tape_server(tape_control_sock, tt);
}
- if(am_has_feature(their_features, fe_amidxtaped_label) &&
+ if(am_has_feature(indexsrv_features, fe_amidxtaped_label) &&
label && label[0] != '/') {
tt = newstralloc2(tt,"LABEL=",label);
- send_to_tape_server(tape_server_socket, tt);
+ send_to_tape_server(tape_control_sock, tt);
}
- if(am_has_feature(their_features, fe_amidxtaped_fsf)) {
+ if(am_has_feature(indexsrv_features, fe_amidxtaped_fsf)) {
char v_fsf[100];
- ap_snprintf(v_fsf, 99, "%d", fsf);
+ snprintf(v_fsf, 99, "%d", fsf);
tt = newstralloc2(tt, "FSF=",v_fsf);
- send_to_tape_server(tape_server_socket, tt);
+ send_to_tape_server(tape_control_sock, tt);
}
- send_to_tape_server(tape_server_socket, "HEADER");
+ send_to_tape_server(tape_control_sock, "HEADER");
tt = newstralloc2(tt, "DEVICE=", dump_device_name);
- send_to_tape_server(tape_server_socket, tt);
+ send_to_tape_server(tape_control_sock, tt);
tt = newstralloc2(tt, "HOST=", host_regex);
- send_to_tape_server(tape_server_socket, tt);
+ send_to_tape_server(tape_control_sock, tt);
tt = newstralloc2(tt, "DISK=", disk_regex);
- send_to_tape_server(tape_server_socket, tt);
+ send_to_tape_server(tape_control_sock, tt);
tt = newstralloc2(tt, "DATESTAMP=", clean_datestamp);
- send_to_tape_server(tape_server_socket, tt);
- send_to_tape_server(tape_server_socket, "END");
+ send_to_tape_server(tape_control_sock, tt);
+ send_to_tape_server(tape_control_sock, "END");
amfree(tt);
}
- else if(1 /* am_has_feature(their_features, fe_amidxtaped_nargs) */) {
- /* 2.4.3 doesn't set fe_amidxtaped_nargs but support it */
- /* must be supported without test until 2005 */
-
+ else if(am_has_feature(indexsrv_features, fe_amidxtaped_nargs)) {
/* send to the tape server what tape file we want */
/* 6 args:
* "-h"
* "diskname"
* "datestamp"
*/
- send_to_tape_server(tape_server_socket, "6");
- send_to_tape_server(tape_server_socket, "-h");
- send_to_tape_server(tape_server_socket, "-p");
- send_to_tape_server(tape_server_socket, dump_device_name);
- send_to_tape_server(tape_server_socket, host_regex);
- send_to_tape_server(tape_server_socket, disk_regex);
- send_to_tape_server(tape_server_socket, clean_datestamp);
+ send_to_tape_server(tape_control_sock, "6");
+ send_to_tape_server(tape_control_sock, "-h");
+ send_to_tape_server(tape_control_sock, "-p");
+ send_to_tape_server(tape_control_sock, dump_device_name);
+ send_to_tape_server(tape_control_sock, host_regex);
+ send_to_tape_server(tape_control_sock, disk_regex);
+ send_to_tape_server(tape_control_sock, clean_datestamp);
dbprintf(("Started amidxtaped with arguments \"6 -h -p %s %s %s %s\"\n",
dump_device_name, host_regex, disk_regex, clean_datestamp));
}
+ /*
+ * split-restoring amidxtaped versions will expect to set up a data
+ * connection for dumpfile data, distinct from the socket we're already
+ * using for control data
+ */
+
+ if(am_has_feature(tapesrv_features, fe_recover_splits)){
+ char buffer[32768];
+ int data_port = -1;
+ int nread;
+
+ nread = read(tape_control_sock, buffer, sizeof(buffer));
+
+ if (nread <= 0) {
+ error("Could not read from control socket: %s\n",
+ strerror(errno));
+ /* NOTREACHED */
+ }
+
+ buffer[nread] = '\0';
+ if (sscanf(buffer, "CONNECT %d\n", &data_port) != 1) {
+ error("Recieved invalid port number message from control socket: %s\n",
+ buffer);
+ /* NOTREACHED */
+ }
+
+ tape_data_sock = stream_client_privileged(server_name,
+ data_port,
+ -1,
+ STREAM_BUFSIZE,
+ &my_data_port,
+ 0);
+ if(tape_data_sock == -1){
+ error("Unable to make data connection to server: %s\n",
+ strerror(errno));
+ /* NOTREACHED */
+ }
+
+ amfree(our_feature_string);
+
+ line = get_security();
+
+ send_to_tape_server(tape_data_sock, line);
+ memset(line, '\0', strlen(line));
+ amfree(line);
+ }
+
amfree(disk_regex);
amfree(host_regex);
amfree(clean_datestamp);
- return tape_server_socket;
+ return tape_control_sock;
}
-size_t read_file_header(buffer, file, buflen, tapedev)
+void read_file_header(buffer, file, buflen, tapedev)
char *buffer;
dumpfile_t *file;
size_t buflen;
*/
{
ssize_t bytes_read;
- bytes_read=read_buffer(tapedev,buffer,buflen);
+
+ bytes_read = read_buffer(tapedev, buffer, buflen, READ_TIMEOUT);
if(bytes_read < 0) {
- error("error reading tape: %s", strerror(errno));
+ error("error reading header (%s), check amidxtaped.*.debug on server",
+ strerror(errno));
+ /* NOTREACHED */
}
- else if((size_t)bytes_read < buflen) {
+
+ if((size_t)bytes_read < buflen) {
fprintf(stderr, "%s: short block %d byte%s\n",
get_pname(), (int)bytes_read, (bytes_read == 1) ? "" : "s");
print_header(stdout, file);
error("Can't read file header");
+ /* NOTREACHED */
}
- else { /* bytes_read == buflen */
- parse_file_header(buffer, file, bytes_read);
- }
- return((size_t)bytes_read);
+
+ /* bytes_read == buflen */
+ parse_file_header(buffer, file, bytes_read);
}
enum dumptypes {IS_UNKNOWN, IS_DUMP, IS_GNUTAR, IS_TAR, IS_SAMBA, IS_SAMBA_TAR};
-/* exec restore to do the actual restoration */
static void extract_files_child(in_fd, elist)
int in_fd;
EXTRACT_LIST *elist;
enum dumptypes dumptype = IS_UNKNOWN;
char buffer[DISK_BLOCK_BYTES];
dumpfile_t file;
- size_t buflen;
size_t len_program;
char *cmd = NULL;
int passwd_field = -1;
/* make in_fd be our stdin */
if (dup2(in_fd, STDIN_FILENO) == -1)
{
- perror("extract_list - extract files client");
- exit(1);
+ error("dup2 failed in extract_files_child: %s", strerror(errno));
+ /* NOTREACHED */
}
/* read the file header */
fh_init(&file);
- buflen=read_file_header(buffer, &file, sizeof(buffer), STDIN_FILENO);
+ read_file_header(buffer, &file, sizeof(buffer), STDIN_FILENO);
- if(buflen == 0 || file.type != F_DUMPFILE) {
+ if(file.type != F_DUMPFILE) {
print_header(stdout, &file);
error("bad header");
+ /* NOTREACHED */
}
if (file.program != NULL) {
#endif
case IS_TAR:
case IS_GNUTAR:
+ extra_params = 4;
+ break;
case IS_SAMBA_TAR:
extra_params = 3;
break;
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 */
break;
case IS_GNUTAR:
case IS_SAMBA_TAR:
case IS_SAMBA:
- restore_args[j++] = stralloc2(".", fn->path);
+ if (strcmp(fn->path, "/") == 0)
+ restore_args[j++] = stralloc(".");
+ else
+ restore_args[j++] = stralloc2(".", fn->path);
break;
case IS_UNKNOWN:
case IS_DUMP:
/*NOT REACHED */
}
+/*
+ * Interpose something between the process writing out the dump (writing it to
+ * some extraction program, really) and the socket from which we're reading, so
+ * that we can do things like prompt for human interaction for multiple tapes.
+ */
+void writer_intermediary(ctl_fd, data_fd, elist)
+ int ctl_fd, data_fd;
+ EXTRACT_LIST *elist;
+{
+ int child_pipe[2];
+ pid_t pid;
+ char buffer[DISK_BLOCK_BYTES];
+ ssize_t s;
+ ssize_t bytes_read;
+ amwait_t extractor_status;
+ int max_fd, nfound;
+ fd_set readset, selectset;
+ struct timeval timeout;
+
+ /*
+ * If there's no distinct data channel (such as if we're talking to an
+ * older server), don't bother doing anything complicated. Just run the
+ * extraction.
+ */
+ if(data_fd == -1){
+ extract_files_child(ctl_fd, elist);
+ /* NOTREACHED */
+ }
+
+ 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) {
+ error("writer_intermediary - error forking child");
+ /* NOTREACHED */
+ }
+
+ aclose(child_pipe[0]);
+
+ if(data_fd > ctl_fd) max_fd = data_fd+1;
+ else max_fd = ctl_fd+1;
+ FD_ZERO(&readset);
+ FD_SET(data_fd, &readset);
+ FD_SET(ctl_fd, &readset);
+
+ do {
+ timeout.tv_sec = READ_TIMEOUT;
+ timeout.tv_usec = 0;
+ FD_COPY(&readset, &selectset);
+
+ nfound = select(max_fd, (SELECT_ARG_TYPE *)(&selectset), NULL, NULL,
+ &timeout);
+ if(nfound < 0) {
+ fprintf(stderr,"select error: %s\n", strerror(errno));
+ break;
+ }
+
+ if (nfound == 0) { /* timeout */
+ fprintf(stderr, "timeout waiting %d seconds for restore\n",
+ READ_TIMEOUT);
+ fprintf(stderr, "increase READ_TIMEOUT in recover-src/extract_list.c if your tape is slow\n");
+ break;
+ }
+
+ if(FD_ISSET(ctl_fd, &selectset)) {
+ bytes_read = read(ctl_fd, buffer, sizeof(buffer)-1);
+ switch(bytes_read) {
+ case -1:
+ if ((errno != EINTR) && (errno != EAGAIN)) {
+ if (errno != EPIPE) {
+ fprintf(stderr,"writer ctl fd read error: %s",
+ strerror(errno));
+ }
+ FD_CLR(ctl_fd, &readset);
+ }
+ break;
+
+ case 0:
+ FD_CLR(ctl_fd, &readset);
+ break;
+
+ default: {
+ char desired_tape[MAX_TAPE_LABEL_BUF];
+
+ buffer[bytes_read] = '\0';
+ /* if prompted for a tape, relay said prompt to the user */
+ if(sscanf(buffer, "FEEDME %s\n", desired_tape) == 1) {
+ int done = 0;
+ while (!done) {
+ char *input = NULL;
+ printf("Please insert tape %s. Continue? [Y|n]: ",
+ desired_tape);
+ fflush(stdout);
+
+ input = agets(stdin); /* strips \n */
+ if (strcasecmp("", input) == 0||
+ strcasecmp("y", input) == 0||
+ strcasecmp("yes", input) == 0) {
+ send_to_tape_server(tape_control_sock, "OK");
+ done = 1;
+ } else if (strcasecmp("n", input) == 0||
+ strcasecmp("no", input) == 0) {
+ send_to_tape_server(tape_control_sock, "ERROR");
+ /* Abort!
+ We are the middle process, so just die. */
+ exit(EXIT_FAILURE);
+ }
+ amfree(input);
+ }
+ } else {
+ fprintf(stderr, "Strange message from tape server: %s", buffer);
+
+ break;
+ }
+ }
+ }
+ }
+
+ /* now read some dump data */
+ if(FD_ISSET(data_fd, &selectset)) {
+ bytes_read = read(data_fd, buffer, sizeof(buffer)-1);
+ switch(bytes_read) {
+ case -1:
+ if ((errno != EINTR) && (errno != EAGAIN)) {
+ if (errno != EPIPE) {
+ fprintf(stderr,"writer data fd read error: %s",
+ strerror(errno));
+ }
+ FD_CLR(data_fd, &readset);
+ }
+ break;
+
+ case 0:
+ FD_CLR(data_fd, &readset);
+ break;
+
+ default:
+ /*
+ * spit what we got from the server to the child
+ * process handling actual dumpfile extraction
+ */
+ if((s = fullwrite(child_pipe[1], buffer, bytes_read)) < 0){
+ if(errno == EPIPE) {
+ error("%s: pipe data reader has quit: %s\n",
+ get_pname(), strerror(errno));
+ /* NOTREACHED */
+ }
+ error("Write error to extract child: %s\n",
+ strerror(errno));
+ /* NOTREACHED */
+ }
+ break;
+ }
+ }
+ } while(FD_ISSET(ctl_fd, &readset) || FD_ISSET(data_fd, &readset));
+
+ aclose(child_pipe[1]);
+
+ waitpid(pid, &extractor_status, 0);
+ if(WEXITSTATUS(extractor_status) != 0){
+ int ret = WEXITSTATUS(extractor_status);
+ if(ret == 255) ret = -1;
+ error("Extractor child exited with status %d\n", ret);
+ /* NOTREACHED */
+ }
+
+ exit(0);
+}
+
+/* exec restore to do the actual restoration */
/* does the actual extraction of files */
/* The original design had the dump image being returned exactly as it
amwait_t child_stat;
char buf[STR_SIZE];
char *l;
- int tape_server_socket;
int first;
int otc;
+ tapelist_t *tlist = NULL;
if (!is_extract_list_nonempty())
{
}
else
printf(" ");
- printf(" %s\n", elist->tape);
+ tlist = unmarshal_tapelist_str(elist->tape);
+ for( ; tlist != NULL; tlist = tlist->next)
+ printf(" %s", tlist->label);
+ printf("\n");
+ amfree(tlist);
}
first=1;
for (elist = first_tape_list(); elist != NULL; elist = next_tape_list(elist))
}
else
printf(" ");
- printf(" %s\n", elist->tape);
+ tlist = unmarshal_tapelist_str(elist->tape);
+ for( ; tlist != NULL; tlist = tlist->next)
+ printf(" %s", tlist->label);
+ printf("\n");
+ amfree(tlist);
}
printf("\n");
getcwd(buf, sizeof(buf));
{
if(elist->tape[0]=='/') {
dump_device_name = newstralloc(dump_device_name, elist->tape);
- printf("Extracting from file %s\n",dump_device_name);
+ printf("Extracting from file ");
+ tlist = unmarshal_tapelist_str(dump_device_name);
+ for( ; tlist != NULL; tlist = tlist->next)
+ printf(" %s", tlist->label);
+ printf("\n");
+ amfree(tlist);
}
else {
printf("Extracting files using tape drive %s on host %s.\n",
tape_device_name, tape_server_name);
- printf("Load tape %s now\n", elist->tape);
+ tlist = unmarshal_tapelist_str(elist->tape);
+ printf("Load tape %s now\n", tlist->label);
+ amfree(tlist);
otc = okay_to_continue(1,1,0);
if (otc == 0)
return;
dump_datestamp = newstralloc(dump_datestamp, elist->date);
/* connect to the tape handler daemon on the tape drive server */
- if ((tape_server_socket = extract_files_setup(elist->tape, elist->fileno)) == -1)
+ if ((tape_control_sock = extract_files_setup(elist->tape, elist->fileno)) == -1)
{
fprintf(stderr, "amrecover - can't talk to tape server\n");
return;
{
/* this is the child process */
/* never gets out of this clause */
- extract_files_child(tape_server_socket, elist);
+ writer_intermediary(tape_control_sock, tape_data_sock, elist);
/*NOT REACHED*/
}
/* this is the parent */
/* store the child pid globally so that it can be killed on intr */
extract_restore_child_pid = pid;
- aclose(tape_server_socket);
-
/* wait for the child process to finish */
if ((pid = waitpid(-1, &child_stat, 0)) == (pid_t)-1)
{
perror("extract_list - error waiting for child");
exit(1);
}
+
+ if(tape_data_sock != -1) {
+ aclose(tape_data_sock);
+ }
+
if (pid == extract_restore_child_pid)
{
extract_restore_child_pid = -1;