2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1999 University of Maryland at College Park
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of U.M. not be used in advertising or
11 * publicity pertaining to distribution of the software without specific,
12 * written prior permission. U.M. makes no representations about the
13 * suitability of this software for any purpose. It is provided "as is"
14 * without express or implied warranty.
16 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 * Authors: the Amanda Development Team. Its members are listed in a
24 * file named AUTHORS, in the root directory of this distribution.
27 * $Id: sendbackup.c,v 1.77 2006/03/09 16:51:41 martinea Exp $
29 * common code for the sendbackup-* programs.
33 #include "sendbackup.h"
35 #include "pipespawn.h"
36 #include "amfeatures.h"
49 char *errorstr = NULL;
59 backup_program_t *program = NULL;
61 static am_feature_t *our_features = NULL;
62 static char *our_feature_string = NULL;
63 static g_option_t *g_options = NULL;
66 int main P((int argc, char **argv));
67 char *optionstr P((option_t *options));
68 char *childstr P((int pid));
69 int check_status P((int pid, amwait_t w));
71 int pipefork P((void (*func) P((void)), char *fname, int *stdinfd,
72 int stdoutfd, int stderrfd));
73 void parse_backup_messages P((int mesgin));
74 static void process_dumpline P((char *str));
75 static void save_fd P((int *, int));
77 char *optionstr(options)
80 static char *optstr = NULL;
84 char *record_opt = "";
87 char *exclude_file_opt;
88 char *exclude_list_opt;
92 if(options->compress == COMPR_BEST)
93 compress_opt = stralloc("compress-best;");
94 else if(options->compress == COMPR_FAST)
95 compress_opt = stralloc("compress-fast;");
96 else if(options->compress == COMPR_SERVER_BEST)
97 compress_opt = stralloc("srvcomp-best;");
98 else if(options->compress == COMPR_SERVER_FAST)
99 compress_opt = stralloc("srvcomp-fast;");
100 else if(options->compress == COMPR_SERVER_CUST)
101 compress_opt = vstralloc("srvcomp-cust=", options->srvcompprog, ";", NULL);
102 else if(options->compress == COMPR_CUST)
103 compress_opt = vstralloc("comp-cust=", options->clntcompprog, ";", NULL);
105 compress_opt = stralloc("");
107 if(options->encrypt == ENCRYPT_CUST) {
108 encrypt_opt = vstralloc("encrypt-cust=", options->clnt_encrypt, ";", NULL);
109 if (options->clnt_decrypt_opt)
110 decrypt_opt = vstralloc("client-decrypt-option=", options->clnt_decrypt_opt, ";", NULL);
112 decrypt_opt = stralloc("");
114 else if(options->encrypt == ENCRYPT_SERV_CUST) {
115 encrypt_opt = vstralloc("encrypt-serv-cust=", options->srv_encrypt, ";", NULL);
116 if(options->srv_decrypt_opt)
117 decrypt_opt = vstralloc("server-decrypt-option=", options->srv_decrypt_opt, ";", NULL);
119 decrypt_opt = stralloc("");
122 encrypt_opt = stralloc("");
123 decrypt_opt = stralloc("");
126 if(options->no_record) record_opt = "no-record;";
127 if(options->auth) auth_opt = vstralloc("auth=", options->auth, ";", NULL);
128 else auth_opt = stralloc("");
129 if(options->createindex) index_opt = "index;";
131 exclude_file_opt = stralloc("");
132 if(options->exclude_file) {
133 for(excl = options->exclude_file->first; excl != NULL; excl=excl->next){
134 exc = newvstralloc(exc, "exclude-file=", excl->name, ";", NULL);
135 strappend(exclude_file_opt, exc);
138 exclude_list_opt = stralloc("");
139 if(options->exclude_list) {
140 for(excl = options->exclude_list->first; excl != NULL; excl=excl->next){
141 exc = newvstralloc(exc, "exclude-list=", excl->name, ";", NULL);
142 strappend(exclude_list_opt, exc);
145 optstr = newvstralloc(optstr,
155 amfree(compress_opt);
159 amfree(exclude_file_opt);
160 amfree(exclude_list_opt);
170 int level, mesgpipe[2];
171 char *prog, *disk, *amdevice, *dumpdate, *stroptions;
173 char *err_extra = NULL;
177 unsigned long malloc_hist_1, malloc_size_1;
178 unsigned long malloc_hist_2, malloc_size_2;
182 safe_fd(DATA_FD_OFFSET, DATA_FD_COUNT);
185 set_pname("sendbackup");
187 /* Don't die when child closes pipe */
188 signal(SIGPIPE, SIG_IGN);
190 malloc_size_1 = malloc_inuse(&malloc_hist_1);
192 interactive = (argc > 1 && strcmp(argv[1],"-t") == 0);
193 erroutput_type = (ERR_INTERACTIVE|ERR_SYSLOG);
196 dbprintf(("%s: version %s\n", get_pname(), version()));
198 our_features = am_init_feature_set();
199 our_feature_string = am_feature_to_string(our_features);
203 * In interactive (debug) mode, the backup data is sent to
204 * /dev/null and none of the network connections back to driver
205 * programs on the tape host are set up. The index service is
206 * run and goes to stdout.
208 fprintf(stderr, "%s: running in interactive test mode\n", get_pname());
218 for(; (line = agets(stdin)) != NULL; free(line)) {
220 fprintf(stderr, "%s> ", get_pname());
223 #define sc "OPTIONS "
224 if(strncmp(line, sc, sizeof(sc)-1) == 0) {
226 g_options = parse_g_options(line+8, 1);
227 if(!g_options->hostname) {
228 g_options->hostname = alloc(MAX_HOSTNAME_LENGTH+1);
229 gethostname(g_options->hostname, MAX_HOSTNAME_LENGTH);
230 g_options->hostname[MAX_HOSTNAME_LENGTH] = '\0';
236 err_extra = "multiple requests";
243 skip_whitespace(s, ch); /* find the program name */
245 err_extra = "no program name";
246 goto err; /* no program name */
249 skip_non_whitespace(s, ch);
251 prog = stralloc(prog);
253 skip_whitespace(s, ch); /* find the disk name */
255 err_extra = "no disk name";
256 goto err; /* no disk name */
260 skip_non_whitespace(s, ch);
262 disk = stralloc(disk);
264 skip_whitespace(s, ch); /* find the device or level */
266 err_extra = "bad level";
270 if(!isdigit((int)s[-1])) {
273 skip_non_whitespace(s, ch);
275 amdevice = stralloc(amdevice);
276 skip_whitespace(s, ch); /* find level number */
279 amdevice = stralloc(disk);
282 /* find the level number */
283 if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
284 err_extra = "bad level";
285 goto err; /* bad level */
289 skip_whitespace(s, ch); /* find the dump date */
291 err_extra = "no dumpdate";
292 goto err; /* no dumpdate */
296 skip_non_whitespace(s, ch);
298 dumpdate = stralloc(dumpdate);
300 skip_whitespace(s, ch); /* find the options keyword */
302 err_extra = "no options";
303 goto err; /* no options */
305 #define sc "OPTIONS "
306 if(strncmp(s - 1, sc, sizeof(sc)-1) != 0) {
307 err_extra = "no OPTIONS keyword";
308 goto err; /* no options */
313 skip_whitespace(s, ch); /* find the options string */
315 err_extra = "bad options string";
316 goto err; /* no options */
319 stroptions = stralloc(s - 1);
323 dbprintf((" parsed request as: program `%s'\n", prog));
324 dbprintf((" disk `%s'\n", disk));
325 dbprintf((" device `%s'\n", amdevice));
326 dbprintf((" level %d\n", level));
327 dbprintf((" since %s\n", dumpdate));
328 dbprintf((" options `%s'\n", stroptions));
330 for(i = 0; programs[i]; i++) {
331 if (strcmp(programs[i]->name, prog) == 0) {
335 if (programs[i] == NULL) {
336 error("ERROR [%s: unknown program %s]", get_pname(), prog);
338 program = programs[i];
340 options = parse_options(stroptions, disk, amdevice, g_options->features, 0);
343 datafd = DATA_FD_OFFSET + 0;
344 mesgfd = DATA_FD_OFFSET + 1;
345 indexfd = DATA_FD_OFFSET + 2;
347 if (!options->createindex)
350 printf("CONNECT DATA %d MESG %d INDEX %d\n",
351 datafd, mesgfd, indexfd);
353 if(am_has_feature(g_options->features, fe_rep_options_features)) {
354 printf("features=%s;", our_feature_string);
356 if(am_has_feature(g_options->features, fe_rep_options_hostname)) {
357 printf("hostname=%s;", g_options->hostname);
359 if(am_has_feature(g_options->features, fe_rep_options_sendbackup_options)) {
360 printf("%s", optionstr(options));
364 if (freopen("/dev/null", "w", stdout) == NULL) {
365 dbprintf(("%s: error redirecting stdout to /dev/null: %s\n",
366 debug_prefix_time(NULL), mesgfd, strerror(errno)));
371 if((datafd = open("/dev/null", O_RDWR)) < 0) {
373 error("ERROR [%s: open of /dev/null for debug data stream: %s]\n",
381 if(datafd == -1 || mesgfd == -1 || (options->createindex && indexfd == -1)) {
388 /* redirect stderr */
389 if(dup2(mesgfd, 2) == -1) {
390 dbprintf(("%s: error redirecting stderr to fd %d: %s\n",
391 debug_prefix_time(NULL), mesgfd, strerror(errno)));
397 if(pipe(mesgpipe) == -1) {
398 error("error [opening mesg pipe: %s]", strerror(errno));
401 program->start_backup(g_options->hostname, disk, amdevice, level, dumpdate, datafd, mesgpipe[1],
403 dbprintf(("%s: started backup\n", debug_prefix_time(NULL)));
404 parse_backup_messages(mesgpipe[0]);
405 dbprintf(("%s: parsed backup messages\n", debug_prefix_time(NULL)));
412 amfree(our_feature_string);
413 am_release_feature_set(our_features);
415 am_release_feature_set(g_options->features);
416 g_options->features = NULL;
417 amfree(g_options->hostname);
418 amfree(g_options->str);
423 malloc_size_2 = malloc_inuse(&malloc_hist_2);
425 if(malloc_size_1 != malloc_size_2) {
426 malloc_list(fileno(stderr), malloc_hist_1, malloc_hist_2);
432 printf("FORMAT ERROR IN REQUEST PACKET\n");
433 dbprintf(("%s: REQ packet is bogus%s%s\n",
434 debug_prefix_time(NULL),
435 err_extra ? ": " : "",
436 err_extra ? err_extra : ""));
444 * Returns a string for a child process. Checks the saved dump and
445 * compress pids to see which it is.
448 if(pid == dumppid) return program->backup_name;
449 if(pid == comppid) return "compress";
450 if(pid == encpid) return "encrypt";
451 if(pid == indexpid) return "index";
456 int check_status(pid, w)
460 * Determine if the child return status really indicates an error.
461 * If so, add the error message to the error string; more than one
462 * child can have an error.
465 char *thiserr = NULL;
468 char number[NUM_STR_SIZE];
474 rc = sig = WTERMSIG(w);
477 rc = ret = WEXITSTATUS(w);
480 if(pid == indexpid) {
482 * Treat an index failure (other than signal) as a "STRANGE"
483 * rather than an error so the dump goes ahead and gets processed
484 * but the failure is noted.
487 fprintf(stderr, "? %s returned %d\n", str, ret);
495 * compress returns 2 sometimes, but it is ok.
503 #ifdef DUMP_RETURNS_1
504 if(pid == dumppid && tarpid == -1) {
506 * Ultrix dump returns 1 sometimes, but it is ok.
514 #ifdef IGNORE_TAR_ERRORS
517 * tar bitches about active filesystems, but we do not care.
526 return 0; /* normal exit */
530 snprintf(number, sizeof(number), "%d", sig);
531 thiserr = vstralloc(str, " got signal ", number, NULL);
533 snprintf(number, sizeof(number), "%d", ret);
534 thiserr = vstralloc(str, " returned ", number, NULL);
538 strappend(errorstr, ", ");
539 strappend(errorstr, thiserr);
549 /* Send header info to the message file.
551 void info_tapeheader()
553 fprintf(stderr, "%s: info BACKUP=%s\n", get_pname(), program->backup_name);
555 fprintf(stderr, "%s: info RECOVER_CMD=", get_pname());
556 if (options->compress == COMPR_FAST || options->compress == COMPR_BEST)
557 fprintf(stderr, "%s %s |", UNCOMPRESS_PATH,
558 #ifdef UNCOMPRESS_OPT
565 fprintf(stderr, "%s -f... -\n", program->restore_name);
567 if (options->compress == COMPR_FAST || options->compress == COMPR_BEST)
568 fprintf(stderr, "%s: info COMPRESS_SUFFIX=%s\n",
569 get_pname(), COMPRESS_SUFFIX);
571 fprintf(stderr, "%s: info end\n", get_pname());
574 int pipefork(func, fname, stdinfd, stdoutfd, stderrfd)
575 void (*func) P((void));
578 int stdoutfd, stderrfd;
582 dbprintf(("%s: forking function %s in pipeline\n",
583 debug_prefix_time(NULL), fname));
585 if(pipe(inpipe) == -1) {
586 error("error [open pipe to %s: %s]", fname, strerror(errno));
589 switch(pid = fork()) {
591 error("error [fork %s: %s]", fname, strerror(errno));
592 default: /* parent process */
593 aclose(inpipe[0]); /* close input side of pipe */
594 *stdinfd = inpipe[1];
596 case 0: /* child process */
597 aclose(inpipe[1]); /* close output side of pipe */
599 if(dup2(inpipe[0], 0) == -1) {
600 error("error [fork %s: dup2(%d, in): %s]",
601 fname, inpipe[0], strerror(errno));
603 if(dup2(stdoutfd, 1) == -1) {
604 error("error [fork %s: dup2(%d, out): %s]",
605 fname, stdoutfd, strerror(errno));
607 if(dup2(stderrfd, 2) == -1) {
608 error("error [fork %s: dup2(%d, err): %s]",
609 fname, stderrfd, strerror(errno));
619 void parse_backup_messages(mesgin)
629 for(; (line = areads(mesgin)) != NULL; free(line)) {
630 process_dumpline(line);
634 error("error [read mesg pipe: %s]", strerror(errno));
637 while((wpid = wait(&retstat)) != -1) {
638 if(check_status(wpid, retstat)) goterror = 1;
642 error("error [%s]", errorstr);
643 } else if(dump_size == -1) {
644 error("error [no backup size line]");
647 program->end_backup(goterror);
649 fprintf(stderr, "%s: size %ld\n", get_pname(), dump_size);
650 fprintf(stderr, "%s: end\n", get_pname());
654 double first_num P((char *str));
656 double first_num(str)
659 * Returns the value of the first integer in a string.
667 while(ch && !isdigit(ch)) ch = *str++;
669 while(isdigit(ch) || ch == '.') ch = *str++;
677 static void process_dumpline(str)
684 for(rp = program->re_table; rp->regex != NULL; rp++) {
685 if(match(rp->regex, str)) {
689 if(rp->typ == DMP_SIZE) {
690 dump_size = (long)((first_num(str) * rp->scale + 1023.0)/1024.0);
711 * Should never get here.
717 dbprintf(("%s: %3d: %7s(%c): %s\n",
718 debug_prefix_time(NULL),
723 fprintf(stderr, "%c %s\n", startchr, str);
727 /* start_index. Creates an index file from the output of dump/tar.
728 It arranges that input is the fd to be written by the dump process.
729 If createindex is not enabled, it does nothing. If it is not, a
730 new process will be created that tees input both to a pipe whose
731 read fd is dup2'ed input and to a program that outputs an index
734 make sure that the chat from restore doesn't go to stderr cause
735 this goes back to amanda which doesn't expect to see it
736 (2>/dev/null should do it)
738 Originally by Alan M. McIvor, 13 April 1996
740 Adapted by Alexandre Oliva, 1 May 1997
742 This program owes a lot to tee.c from GNU sh-utils and dumptee.c
743 from the DeeJay backup package.
747 static volatile int index_finished = 0;
749 static void save_fd(fd, min)
754 while (*fd >= 0 && *fd < min) {
755 int newfd = dup(*fd);
757 dbprintf(("%s: unable to save file descriptor [%s]\n",
758 debug_prefix_time(NULL), strerror(errno)));
762 dbprintf(("%s: dupped file descriptor %i to %i\n",
763 debug_prefix_time(NULL), origfd, *fd));
766 void start_index(createindex, input, mesg, index, cmd)
767 int createindex, input, mesg, index;
777 if (pipe(pipefd) != 0) {
778 error("creating index pipe: %s", strerror(errno));
781 switch(indexpid = fork()) {
783 error("forking index tee process: %s", strerror(errno));
787 if (dup2(pipefd[1], input) == -1) {
788 error("dup'ping index tee output: %s", strerror(errno));
797 /* now in a child process */
798 save_fd(&pipefd[0], 4);
806 for(index = 4; index < FD_SETSIZE; index++) {
807 if (index != dbfd()) {
812 if ((pipe_fp = popen(cmd, "w")) == NULL) {
813 error("couldn't start index creator [%s]", strerror(errno));
816 dbprintf(("%s: started index creator: \"%s\"\n",
817 debug_prefix_time(NULL), cmd));
819 char buffer[BUFSIZ], *ptr;
825 bytes_read = read(0, buffer, sizeof(buffer));
826 } while ((bytes_read < 0) && ((errno == EINTR) || (errno == EAGAIN)));
828 if (bytes_read < 0) {
829 error("index tee cannot read [%s]", strerror(errno));
833 break; /* finished */
835 /* write the stuff to the subprocess */
838 just_written = fullwrite(fileno(pipe_fp), ptr, bytes_read);
839 if (just_written < 0) {
840 /* the signal handler may have assigned to index_finished
841 * just as we waited for write() to complete.
843 if (errno != EPIPE) {
844 dbprintf(("%s: index tee cannot write to index creator [%s]\n",
845 debug_prefix_time(NULL), strerror(errno)));
848 bytes_written += just_written;
852 /* write the stuff to stdout, ensuring none lost when interrupt
856 just_written = fullwrite(3, ptr, bytes_read);
857 if (just_written < 0) {
858 error("index tee cannot write [%s]", strerror(errno));
861 bytes_written += just_written;
869 /* check the exit code of the pipe and moan if not 0 */
870 if ((exitcode = pclose(pipe_fp)) != 0) {
871 dbprintf(("%s: index pipe returned %d\n",
872 debug_prefix_time(NULL), exitcode));
874 dbprintf(("%s: index created successfully\n", debug_prefix_time(NULL)));
881 extern backup_program_t dump_program, gnutar_program;
883 backup_program_t *programs[] = {
884 &dump_program, &gnutar_program, NULL