* file named AUTHORS, in the root directory of this distribution.
*/
/*
- * $Id: sendbackup.c,v 1.77 2006/03/09 16:51:41 martinea Exp $
+ * $Id: sendbackup.c,v 1.88 2006/07/25 18:27:56 martinea Exp $
*
* common code for the sendbackup-* programs.
*/
#include "arglist.h"
#include "getfsent.h"
#include "version.h"
+#include "clientconf.h"
#define TIMEOUT 30
-int comppid = -1;
-int dumppid = -1;
-int tarpid = -1;
-int encpid = -1;
-int indexpid = -1;
+pid_t comppid = (pid_t)-1;
+pid_t dumppid = (pid_t)-1;
+pid_t tarpid = (pid_t)-1;
+pid_t encpid = (pid_t)-1;
+pid_t indexpid = (pid_t)-1;
char *errorstr = NULL;
int datafd;
int indexfd;
option_t *options;
+g_option_t *g_options = NULL;
long dump_size = -1;
static am_feature_t *our_features = NULL;
static char *our_feature_string = NULL;
-static g_option_t *g_options = NULL;
+static char *amandad_auth = NULL;
/* local functions */
-int main P((int argc, char **argv));
-char *optionstr P((option_t *options));
-char *childstr P((int pid));
-int check_status P((int pid, amwait_t w));
-
-int pipefork P((void (*func) P((void)), char *fname, int *stdinfd,
- int stdoutfd, int stderrfd));
-void parse_backup_messages P((int mesgin));
-static void process_dumpline P((char *str));
-static void save_fd P((int *, int));
-
-char *optionstr(options)
-option_t *options;
+int main(int argc, char **argv);
+char *optionstr(option_t *options);
+char *childstr(pid_t pid);
+int check_status(pid_t pid, amwait_t w);
+
+pid_t pipefork(void (*func)(void), char *fname, int *stdinfd,
+ int stdoutfd, int stderrfd);
+void parse_backup_messages(int mesgin);
+static void process_dumpline(char *str);
+static void save_fd(int *, int);
+
+double first_num(char *str);
+
+
+
+char *
+optionstr(
+ option_t * options)
{
static char *optstr = NULL;
char *compress_opt;
strappend(exclude_list_opt, exc);
}
}
+ amfree(exc);
optstr = newvstralloc(optstr,
compress_opt,
encrypt_opt,
}
-int main(argc, argv)
-int argc;
-char **argv;
+int
+main(
+ int argc,
+ char ** argv)
{
int interactive = 0;
- int level, mesgpipe[2];
- char *prog, *disk, *amdevice, *dumpdate, *stroptions;
+ int level = 0;
+ int mesgpipe[2];
+ char *prog, *dumpdate, *stroptions;
+ char *disk = NULL;
+ char *qdisk = NULL;
+ char *amdevice = NULL;
+ char *qamdevice = NULL;
char *line = NULL;
char *err_extra = NULL;
char *s;
+ char *conffile;
int i;
int ch;
unsigned long malloc_hist_1, malloc_size_1;
/* initialize */
- safe_fd(DATA_FD_OFFSET, DATA_FD_COUNT);
+ safe_fd(DATA_FD_OFFSET, DATA_FD_COUNT*2);
+
safe_cd();
set_pname("sendbackup");
/* Don't die when child closes pipe */
signal(SIGPIPE, SIG_IGN);
+ /* Don't die when interrupt received */
+ signal(SIGINT, SIG_IGN);
+
malloc_size_1 = malloc_inuse(&malloc_hist_1);
- interactive = (argc > 1 && strcmp(argv[1],"-t") == 0);
+ if(argc > 1 && strcmp(argv[1],"-t") == 0) {
+ interactive = 1;
+ argc--;
+ argv++;
+ } else {
+ interactive = 0;
+ }
+
erroutput_type = (ERR_INTERACTIVE|ERR_SYSLOG);
- dbopen();
+ dbopen(DBG_SUBDIR_CLIENT);
startclock();
dbprintf(("%s: version %s\n", get_pname(), version()));
+ if(argc > 2 && strcmp(argv[1], "amandad") == 0) {
+ amandad_auth = stralloc(argv[2]);
+ }
+
our_features = am_init_feature_set();
our_feature_string = am_feature_to_string(our_features);
+ conffile = vstralloc(CONFIG_DIR, "/", "amanda-client.conf", NULL);
+ if (read_clientconf(conffile) > 0) {
+ error("error reading conffile: %s", conffile);
+ /*NOTREACHED*/
+ }
+ amfree(conffile);
+
if(interactive) {
/*
* In interactive (debug) mode, the backup data is sent to
prog = NULL;
disk = NULL;
+ qdisk = NULL;
amdevice = NULL;
dumpdate = NULL;
stroptions = NULL;
for(; (line = agets(stdin)) != NULL; free(line)) {
+ if (line[0] == '\0')
+ continue;
if(interactive) {
fprintf(stderr, "%s> ", get_pname());
fflush(stderr);
}
#define sc "OPTIONS "
- if(strncmp(line, sc, sizeof(sc)-1) == 0) {
+ if(strncmp(line, sc, SIZEOF(sc)-1) == 0) {
#undef sc
g_options = parse_g_options(line+8, 1);
if(!g_options->hostname) {
gethostname(g_options->hostname, MAX_HOSTNAME_LENGTH);
g_options->hostname[MAX_HOSTNAME_LENGTH] = '\0';
}
+
+ if (g_options->config) {
+ conffile = vstralloc(CONFIG_DIR, "/", g_options->config, "/",
+ "amanda-client.conf", NULL);
+ if (read_clientconf(conffile) > 0) {
+ error("error reading conffile: %s", conffile);
+ /*NOTREACHED*/
+ }
+ amfree(conffile);
+
+ dbrename(g_options->config, DBG_SUBDIR_CLIENT);
+ }
continue;
}
goto err;
}
+ dbprintf((" sendbackup req: <%s>\n", line));
s = line;
ch = *s++;
err_extra = "no disk name";
goto err; /* no disk name */
}
+
amfree(disk);
- disk = s - 1;
- skip_non_whitespace(s, ch);
+ amfree(qdisk);
+ qdisk = s - 1;
+ ch = *qdisk;
+ skip_quoted_string(s, ch);
s[-1] = '\0';
- disk = stralloc(disk);
+ qdisk = stralloc(qdisk);
+ disk = unquote_string(qdisk);
skip_whitespace(s, ch); /* find the device or level */
if (ch == '\0') {
if(!isdigit((int)s[-1])) {
amfree(amdevice);
+ amfree(qamdevice);
amdevice = s - 1;
skip_non_whitespace(s, ch);
s[-1] = '\0';
else {
amdevice = stralloc(disk);
}
-
+ qamdevice = quote_string(amdevice);
/* find the level number */
if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
err_extra = "bad level";
goto err; /* no options */
}
#define sc "OPTIONS "
- if(strncmp(s - 1, sc, sizeof(sc)-1) != 0) {
+ if(strncmp(s - 1, sc, SIZEOF(sc)-1) != 0) {
err_extra = "no OPTIONS keyword";
goto err; /* no options */
}
- s += sizeof(sc)-1;
+ s += SIZEOF(sc)-1;
ch = s[-1];
#undef sc
skip_whitespace(s, ch); /* find the options string */
}
amfree(line);
+ if (prog == NULL ||
+ disk == NULL ||
+ amdevice == NULL ||
+ dumpdate == NULL ||
+ stroptions == NULL) {
+ err_extra = "no valid sendbackup request";
+ goto err;
+ }
+
dbprintf((" parsed request as: program `%s'\n", prog));
- dbprintf((" disk `%s'\n", disk));
- dbprintf((" device `%s'\n", amdevice));
+ dbprintf((" disk `%s'\n", qdisk));
+ dbprintf((" device `%s'\n", qamdevice));
dbprintf((" level %d\n", level));
dbprintf((" since %s\n", dumpdate));
dbprintf((" options `%s'\n", stroptions));
}
if (programs[i] == NULL) {
error("ERROR [%s: unknown program %s]", get_pname(), prog);
+ /*NOTREACHED*/
}
program = programs[i];
if(!interactive) {
datafd = DATA_FD_OFFSET + 0;
- mesgfd = DATA_FD_OFFSET + 1;
- indexfd = DATA_FD_OFFSET + 2;
+ mesgfd = DATA_FD_OFFSET + 2;
+ indexfd = DATA_FD_OFFSET + 4;
}
if (!options->createindex)
indexfd = -1;
+ if(options->auth && amandad_auth) {
+ if(strcasecmp(options->auth, amandad_auth) != 0) {
+ printf("ERROR [client configured for auth=%s while server requested '%s']\n",
+ amandad_auth, options->auth);
+ exit(-1);
+ }
+ }
+
printf("CONNECT DATA %d MESG %d INDEX %d\n",
- datafd, mesgfd, indexfd);
+ DATA_FD_OFFSET, DATA_FD_OFFSET+1,
+ indexfd == -1 ? -1 : DATA_FD_OFFSET+2);
printf("OPTIONS ");
if(am_has_feature(g_options->features, fe_rep_options_features)) {
printf("features=%s;", our_feature_string);
s = strerror(errno);
error("ERROR [%s: open of /dev/null for debug data stream: %s]\n",
get_pname(), s);
+ /*NOTREACHED*/
}
mesgfd = 2;
indexfd = 1;
if(pipe(mesgpipe) == -1) {
error("error [opening mesg pipe: %s]", strerror(errno));
+ /*NOTREACHED*/
}
program->start_backup(g_options->hostname, disk, amdevice, level, dumpdate, datafd, mesgpipe[1],
amfree(prog);
amfree(disk);
+ amfree(qdisk);
amfree(amdevice);
+ amfree(qamdevice);
amfree(dumpdate);
amfree(stroptions);
amfree(our_feature_string);
return 1;
}
-char *childstr(pid)
-int pid;
+
/*
* Returns a string for a child process. Checks the saved dump and
* compress pids to see which it is.
*/
+
+char *
+childstr(
+ pid_t pid)
{
if(pid == dumppid) return program->backup_name;
if(pid == comppid) return "compress";
}
-int check_status(pid, w)
-int pid;
-amwait_t w;
/*
* Determine if the child return status really indicates an error.
* If so, add the error message to the error string; more than one
* child can have an error.
*/
+
+int
+check_status(
+ pid_t pid,
+ amwait_t w)
{
char *thiserr = NULL;
char *str;
}
if(ret == 0) {
- snprintf(number, sizeof(number), "%d", sig);
+ snprintf(number, SIZEOF(number), "%d", sig);
thiserr = vstralloc(str, " got signal ", number, NULL);
} else {
- snprintf(number, sizeof(number), "%d", ret);
+ snprintf(number, SIZEOF(number), "%d", ret);
thiserr = vstralloc(str, " returned ", number, NULL);
}
}
-/* Send header info to the message file.
-*/
-void info_tapeheader()
+/*
+ *Send header info to the message file.
+ */
+void
+info_tapeheader(void)
{
fprintf(stderr, "%s: info BACKUP=%s\n", get_pname(), program->backup_name);
#endif
);
- fprintf(stderr, "%s -f... -\n", program->restore_name);
+ fprintf(stderr, "%s -f - ...\n", program->restore_name);
if (options->compress == COMPR_FAST || options->compress == COMPR_BEST)
fprintf(stderr, "%s: info COMPRESS_SUFFIX=%s\n",
fprintf(stderr, "%s: info end\n", get_pname());
}
-int pipefork(func, fname, stdinfd, stdoutfd, stderrfd)
-void (*func) P((void));
-char *fname;
-int *stdinfd;
-int stdoutfd, stderrfd;
+pid_t
+pipefork(
+ void (*func)(void),
+ char * fname,
+ int * stdinfd,
+ int stdoutfd,
+ int stderrfd)
{
- int pid, inpipe[2];
+ int inpipe[2];
+ pid_t pid;
dbprintf(("%s: forking function %s in pipeline\n",
debug_prefix_time(NULL), fname));
if(pipe(inpipe) == -1) {
error("error [open pipe to %s: %s]", fname, strerror(errno));
+ /*NOTREACHED*/
}
switch(pid = fork()) {
case -1:
error("error [fork %s: %s]", fname, strerror(errno));
+ /*NOTREACHED*/
default: /* parent process */
aclose(inpipe[0]); /* close input side of pipe */
*stdinfd = inpipe[1];
if(dup2(inpipe[0], 0) == -1) {
error("error [fork %s: dup2(%d, in): %s]",
fname, inpipe[0], strerror(errno));
+ /*NOTRACHED*/
}
if(dup2(stdoutfd, 1) == -1) {
error("error [fork %s: dup2(%d, out): %s]",
fname, stdoutfd, strerror(errno));
+ /*NOTRACHED*/
}
if(dup2(stderrfd, 2) == -1) {
error("error [fork %s: dup2(%d, err): %s]",
fname, stderrfd, strerror(errno));
+ /*NOTRACHED*/
}
func();
exit(0);
- /* NOTREACHED */
+ /*NOTREACHED*/
}
return pid;
}
-void parse_backup_messages(mesgin)
-int mesgin;
+void
+parse_backup_messages(
+ int mesgin)
{
- int goterror, wpid;
+ int goterror;
+ pid_t wpid;
amwait_t retstat;
char *line;
if(errno) {
error("error [read mesg pipe: %s]", strerror(errno));
+ /*NOTREACHED*/
}
while((wpid = wait(&retstat)) != -1) {
if(errorstr) {
error("error [%s]", errorstr);
+ /*NOTREACHED*/
} else if(dump_size == -1) {
error("error [no backup size line]");
+ /*NOTREACHED*/
}
program->end_backup(goterror);
}
-double first_num P((char *str));
-
-double first_num(str)
-char *str;
/*
* Returns the value of the first integer in a string.
*/
+
+double
+first_num(
+ char * str)
{
char *num;
int ch;
while(isdigit(ch) || ch == '.') ch = *str++;
str[-1] = '\0';
d = atof(num);
- str[-1] = ch;
+ str[-1] = (char)ch;
return d;
}
-static void process_dumpline(str)
-char *str;
+static void
+process_dumpline(
+ char * str)
{
- regex_t *rp;
+ amregex_t *rp;
char *type;
char startchr;
}
-/* start_index. Creates an index file from the output of dump/tar.
- It arranges that input is the fd to be written by the dump process.
- If createindex is not enabled, it does nothing. If it is not, a
- new process will be created that tees input both to a pipe whose
- read fd is dup2'ed input and to a program that outputs an index
- file to `index'.
-
- make sure that the chat from restore doesn't go to stderr cause
- this goes back to amanda which doesn't expect to see it
- (2>/dev/null should do it)
-
- Originally by Alan M. McIvor, 13 April 1996
-
- Adapted by Alexandre Oliva, 1 May 1997
-
- This program owes a lot to tee.c from GNU sh-utils and dumptee.c
- from the DeeJay backup package.
-
-*/
-
-static volatile int index_finished = 0;
+/*
+ * start_index. Creates an index file from the output of dump/tar.
+ * It arranges that input is the fd to be written by the dump process.
+ * If createindex is not enabled, it does nothing. If it is not, a
+ * new process will be created that tees input both to a pipe whose
+ * read fd is dup2'ed input and to a program that outputs an index
+ * file to `index'.
+ *
+ * make sure that the chat from restore doesn't go to stderr cause
+ * this goes back to amanda which doesn't expect to see it
+ * (2>/dev/null should do it)
+ *
+ * Originally by Alan M. McIvor, 13 April 1996
+ *
+ * Adapted by Alexandre Oliva, 1 May 1997
+ *
+ * This program owes a lot to tee.c from GNU sh-utils and dumptee.c
+ * from the DeeJay backup package.
+ */
-static void save_fd(fd, min)
-int *fd, min;
+static void
+save_fd(
+ int * fd,
+ int min)
{
int origfd = *fd;
debug_prefix_time(NULL), origfd, *fd));
}
-void start_index(createindex, input, mesg, index, cmd)
-int createindex, input, mesg, index;
-char *cmd;
+void
+start_index(
+ int createindex,
+ int input,
+ int mesg,
+ int index,
+ char * cmd)
{
int pipefd[2];
FILE *pipe_fp;
if (pipe(pipefd) != 0) {
error("creating index pipe: %s", strerror(errno));
+ /*NOTREACHED*/
}
switch(indexpid = fork()) {
case -1:
error("forking index tee process: %s", strerror(errno));
+ /*NOTREACHED*/
default:
aclose(pipefd[0]);
if (dup2(pipefd[1], input) == -1) {
error("dup'ping index tee output: %s", strerror(errno));
+ /*NOTREACHED*/
}
aclose(pipefd[1]);
return;
if ((pipe_fp = popen(cmd, "w")) == NULL) {
error("couldn't start index creator [%s]", strerror(errno));
+ /*NOTREACHED*/
}
dbprintf(("%s: started index creator: \"%s\"\n",
debug_prefix_time(NULL), cmd));
while(1) {
char buffer[BUFSIZ], *ptr;
- int bytes_read;
- int bytes_written;
- int just_written;
+ ssize_t bytes_read;
+ size_t bytes_written;
+ ssize_t just_written;
do {
- bytes_read = read(0, buffer, sizeof(buffer));
+ bytes_read = read(0, buffer, SIZEOF(buffer));
} while ((bytes_read < 0) && ((errno == EINTR) || (errno == EAGAIN)));
if (bytes_read < 0) {
error("index tee cannot read [%s]", strerror(errno));
+ /*NOTREACHED*/
}
if (bytes_read == 0)
/* write the stuff to the subprocess */
ptr = buffer;
bytes_written = 0;
- just_written = fullwrite(fileno(pipe_fp), ptr, bytes_read);
+ just_written = fullwrite(fileno(pipe_fp), ptr, (size_t)bytes_read);
if (just_written < 0) {
- /* the signal handler may have assigned to index_finished
+ /*
* just as we waited for write() to complete.
*/
if (errno != EPIPE) {
occurs */
ptr = buffer;
bytes_written = 0;
- just_written = fullwrite(3, ptr, bytes_read);
+ just_written = fullwrite(3, ptr, (size_t)bytes_read);
if (just_written < 0) {
error("index tee cannot write [%s]", strerror(errno));
- /* NOTREACHED */
+ /*NOTREACHED*/
} else {
bytes_written += just_written;
ptr += just_written;