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.88 2006/07/25 18:27:56 martinea Exp $
29 * common code for the sendbackup-* programs.
33 #include "sendbackup.h"
35 #include "pipespawn.h"
36 #include "amfeatures.h"
41 #include "clientconf.h"
45 pid_t comppid = (pid_t)-1;
46 pid_t dumppid = (pid_t)-1;
47 pid_t tarpid = (pid_t)-1;
48 pid_t encpid = (pid_t)-1;
49 pid_t indexpid = (pid_t)-1;
50 char *errorstr = NULL;
57 g_option_t *g_options = NULL;
61 backup_program_t *program = NULL;
63 static am_feature_t *our_features = NULL;
64 static char *our_feature_string = NULL;
65 static char *amandad_auth = NULL;
68 int main(int argc, char **argv);
69 char *optionstr(option_t *options);
70 char *childstr(pid_t pid);
71 int check_status(pid_t pid, amwait_t w);
73 pid_t pipefork(void (*func)(void), char *fname, int *stdinfd,
74 int stdoutfd, int stderrfd);
75 void parse_backup_messages(int mesgin);
76 static void process_dumpline(char *str);
77 static void save_fd(int *, int);
79 double first_num(char *str);
87 static char *optstr = NULL;
91 char *record_opt = "";
94 char *exclude_file_opt;
95 char *exclude_list_opt;
99 if(options->compress == COMPR_BEST)
100 compress_opt = stralloc("compress-best;");
101 else if(options->compress == COMPR_FAST)
102 compress_opt = stralloc("compress-fast;");
103 else if(options->compress == COMPR_SERVER_BEST)
104 compress_opt = stralloc("srvcomp-best;");
105 else if(options->compress == COMPR_SERVER_FAST)
106 compress_opt = stralloc("srvcomp-fast;");
107 else if(options->compress == COMPR_SERVER_CUST)
108 compress_opt = vstralloc("srvcomp-cust=", options->srvcompprog, ";", NULL);
109 else if(options->compress == COMPR_CUST)
110 compress_opt = vstralloc("comp-cust=", options->clntcompprog, ";", NULL);
112 compress_opt = stralloc("");
114 if(options->encrypt == ENCRYPT_CUST) {
115 encrypt_opt = vstralloc("encrypt-cust=", options->clnt_encrypt, ";", NULL);
116 if (options->clnt_decrypt_opt)
117 decrypt_opt = vstralloc("client-decrypt-option=", options->clnt_decrypt_opt, ";", NULL);
119 decrypt_opt = stralloc("");
121 else if(options->encrypt == ENCRYPT_SERV_CUST) {
122 encrypt_opt = vstralloc("encrypt-serv-cust=", options->srv_encrypt, ";", NULL);
123 if(options->srv_decrypt_opt)
124 decrypt_opt = vstralloc("server-decrypt-option=", options->srv_decrypt_opt, ";", NULL);
126 decrypt_opt = stralloc("");
129 encrypt_opt = stralloc("");
130 decrypt_opt = stralloc("");
133 if(options->no_record) record_opt = "no-record;";
134 if(options->auth) auth_opt = vstralloc("auth=", options->auth, ";", NULL);
135 else auth_opt = stralloc("");
136 if(options->createindex) index_opt = "index;";
138 exclude_file_opt = stralloc("");
139 if(options->exclude_file) {
140 for(excl = options->exclude_file->first; excl != NULL; excl=excl->next){
141 exc = newvstralloc(exc, "exclude-file=", excl->name, ";", NULL);
142 strappend(exclude_file_opt, exc);
145 exclude_list_opt = stralloc("");
146 if(options->exclude_list) {
147 for(excl = options->exclude_list->first; excl != NULL; excl=excl->next){
148 exc = newvstralloc(exc, "exclude-list=", excl->name, ";", NULL);
149 strappend(exclude_list_opt, exc);
153 optstr = newvstralloc(optstr,
163 amfree(compress_opt);
167 amfree(exclude_file_opt);
168 amfree(exclude_list_opt);
181 char *prog, *dumpdate, *stroptions;
184 char *amdevice = NULL;
185 char *qamdevice = NULL;
187 char *err_extra = NULL;
192 unsigned long malloc_hist_1, malloc_size_1;
193 unsigned long malloc_hist_2, malloc_size_2;
197 safe_fd(DATA_FD_OFFSET, DATA_FD_COUNT*2);
201 set_pname("sendbackup");
203 /* Don't die when child closes pipe */
204 signal(SIGPIPE, SIG_IGN);
206 /* Don't die when interrupt received */
207 signal(SIGINT, SIG_IGN);
209 malloc_size_1 = malloc_inuse(&malloc_hist_1);
211 if(argc > 1 && strcmp(argv[1],"-t") == 0) {
219 erroutput_type = (ERR_INTERACTIVE|ERR_SYSLOG);
220 dbopen(DBG_SUBDIR_CLIENT);
222 dbprintf(("%s: version %s\n", get_pname(), version()));
224 if(argc > 2 && strcmp(argv[1], "amandad") == 0) {
225 amandad_auth = stralloc(argv[2]);
228 our_features = am_init_feature_set();
229 our_feature_string = am_feature_to_string(our_features);
231 conffile = vstralloc(CONFIG_DIR, "/", "amanda-client.conf", NULL);
232 if (read_clientconf(conffile) > 0) {
233 error("error reading conffile: %s", conffile);
240 * In interactive (debug) mode, the backup data is sent to
241 * /dev/null and none of the network connections back to driver
242 * programs on the tape host are set up. The index service is
243 * run and goes to stdout.
245 fprintf(stderr, "%s: running in interactive test mode\n", get_pname());
256 for(; (line = agets(stdin)) != NULL; free(line)) {
260 fprintf(stderr, "%s> ", get_pname());
263 #define sc "OPTIONS "
264 if(strncmp(line, sc, SIZEOF(sc)-1) == 0) {
266 g_options = parse_g_options(line+8, 1);
267 if(!g_options->hostname) {
268 g_options->hostname = alloc(MAX_HOSTNAME_LENGTH+1);
269 gethostname(g_options->hostname, MAX_HOSTNAME_LENGTH);
270 g_options->hostname[MAX_HOSTNAME_LENGTH] = '\0';
273 if (g_options->config) {
274 conffile = vstralloc(CONFIG_DIR, "/", g_options->config, "/",
275 "amanda-client.conf", NULL);
276 if (read_clientconf(conffile) > 0) {
277 error("error reading conffile: %s", conffile);
282 dbrename(g_options->config, DBG_SUBDIR_CLIENT);
288 err_extra = "multiple requests";
292 dbprintf((" sendbackup req: <%s>\n", line));
296 skip_whitespace(s, ch); /* find the program name */
298 err_extra = "no program name";
299 goto err; /* no program name */
302 skip_non_whitespace(s, ch);
304 prog = stralloc(prog);
306 skip_whitespace(s, ch); /* find the disk name */
308 err_extra = "no disk name";
309 goto err; /* no disk name */
316 skip_quoted_string(s, ch);
318 qdisk = stralloc(qdisk);
319 disk = unquote_string(qdisk);
321 skip_whitespace(s, ch); /* find the device or level */
323 err_extra = "bad level";
327 if(!isdigit((int)s[-1])) {
331 skip_non_whitespace(s, ch);
333 amdevice = stralloc(amdevice);
334 skip_whitespace(s, ch); /* find level number */
337 amdevice = stralloc(disk);
339 qamdevice = quote_string(amdevice);
340 /* find the level number */
341 if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
342 err_extra = "bad level";
343 goto err; /* bad level */
347 skip_whitespace(s, ch); /* find the dump date */
349 err_extra = "no dumpdate";
350 goto err; /* no dumpdate */
354 skip_non_whitespace(s, ch);
356 dumpdate = stralloc(dumpdate);
358 skip_whitespace(s, ch); /* find the options keyword */
360 err_extra = "no options";
361 goto err; /* no options */
363 #define sc "OPTIONS "
364 if(strncmp(s - 1, sc, SIZEOF(sc)-1) != 0) {
365 err_extra = "no OPTIONS keyword";
366 goto err; /* no options */
371 skip_whitespace(s, ch); /* find the options string */
373 err_extra = "bad options string";
374 goto err; /* no options */
377 stroptions = stralloc(s - 1);
385 stroptions == NULL) {
386 err_extra = "no valid sendbackup request";
390 dbprintf((" parsed request as: program `%s'\n", prog));
391 dbprintf((" disk `%s'\n", qdisk));
392 dbprintf((" device `%s'\n", qamdevice));
393 dbprintf((" level %d\n", level));
394 dbprintf((" since %s\n", dumpdate));
395 dbprintf((" options `%s'\n", stroptions));
397 for(i = 0; programs[i]; i++) {
398 if (strcmp(programs[i]->name, prog) == 0) {
402 if (programs[i] == NULL) {
403 error("ERROR [%s: unknown program %s]", get_pname(), prog);
406 program = programs[i];
408 options = parse_options(stroptions, disk, amdevice, g_options->features, 0);
411 datafd = DATA_FD_OFFSET + 0;
412 mesgfd = DATA_FD_OFFSET + 2;
413 indexfd = DATA_FD_OFFSET + 4;
415 if (!options->createindex)
418 if(options->auth && amandad_auth) {
419 if(strcasecmp(options->auth, amandad_auth) != 0) {
420 printf("ERROR [client configured for auth=%s while server requested '%s']\n",
421 amandad_auth, options->auth);
426 printf("CONNECT DATA %d MESG %d INDEX %d\n",
427 DATA_FD_OFFSET, DATA_FD_OFFSET+1,
428 indexfd == -1 ? -1 : DATA_FD_OFFSET+2);
430 if(am_has_feature(g_options->features, fe_rep_options_features)) {
431 printf("features=%s;", our_feature_string);
433 if(am_has_feature(g_options->features, fe_rep_options_hostname)) {
434 printf("hostname=%s;", g_options->hostname);
436 if(am_has_feature(g_options->features, fe_rep_options_sendbackup_options)) {
437 printf("%s", optionstr(options));
441 if (freopen("/dev/null", "w", stdout) == NULL) {
442 dbprintf(("%s: error redirecting stdout to /dev/null: %s\n",
443 debug_prefix_time(NULL), mesgfd, strerror(errno)));
448 if((datafd = open("/dev/null", O_RDWR)) < 0) {
450 error("ERROR [%s: open of /dev/null for debug data stream: %s]\n",
459 if(datafd == -1 || mesgfd == -1 || (options->createindex && indexfd == -1)) {
466 /* redirect stderr */
467 if(dup2(mesgfd, 2) == -1) {
468 dbprintf(("%s: error redirecting stderr to fd %d: %s\n",
469 debug_prefix_time(NULL), mesgfd, strerror(errno)));
475 if(pipe(mesgpipe) == -1) {
476 error("error [opening mesg pipe: %s]", strerror(errno));
480 program->start_backup(g_options->hostname, disk, amdevice, level, dumpdate, datafd, mesgpipe[1],
482 dbprintf(("%s: started backup\n", debug_prefix_time(NULL)));
483 parse_backup_messages(mesgpipe[0]);
484 dbprintf(("%s: parsed backup messages\n", debug_prefix_time(NULL)));
493 amfree(our_feature_string);
494 am_release_feature_set(our_features);
496 am_release_feature_set(g_options->features);
497 g_options->features = NULL;
498 amfree(g_options->hostname);
499 amfree(g_options->str);
504 malloc_size_2 = malloc_inuse(&malloc_hist_2);
506 if(malloc_size_1 != malloc_size_2) {
507 malloc_list(fileno(stderr), malloc_hist_1, malloc_hist_2);
513 printf("FORMAT ERROR IN REQUEST PACKET\n");
514 dbprintf(("%s: REQ packet is bogus%s%s\n",
515 debug_prefix_time(NULL),
516 err_extra ? ": " : "",
517 err_extra ? err_extra : ""));
524 * Returns a string for a child process. Checks the saved dump and
525 * compress pids to see which it is.
532 if(pid == dumppid) return program->backup_name;
533 if(pid == comppid) return "compress";
534 if(pid == encpid) return "encrypt";
535 if(pid == indexpid) return "index";
541 * Determine if the child return status really indicates an error.
542 * If so, add the error message to the error string; more than one
543 * child can have an error.
551 char *thiserr = NULL;
554 char number[NUM_STR_SIZE];
560 rc = sig = WTERMSIG(w);
563 rc = ret = WEXITSTATUS(w);
566 if(pid == indexpid) {
568 * Treat an index failure (other than signal) as a "STRANGE"
569 * rather than an error so the dump goes ahead and gets processed
570 * but the failure is noted.
573 fprintf(stderr, "? %s returned %d\n", str, ret);
581 * compress returns 2 sometimes, but it is ok.
589 #ifdef DUMP_RETURNS_1
590 if(pid == dumppid && tarpid == -1) {
592 * Ultrix dump returns 1 sometimes, but it is ok.
600 #ifdef IGNORE_TAR_ERRORS
603 * tar bitches about active filesystems, but we do not care.
612 return 0; /* normal exit */
616 snprintf(number, SIZEOF(number), "%d", sig);
617 thiserr = vstralloc(str, " got signal ", number, NULL);
619 snprintf(number, SIZEOF(number), "%d", ret);
620 thiserr = vstralloc(str, " returned ", number, NULL);
624 strappend(errorstr, ", ");
625 strappend(errorstr, thiserr);
636 *Send header info to the message file.
639 info_tapeheader(void)
641 fprintf(stderr, "%s: info BACKUP=%s\n", get_pname(), program->backup_name);
643 fprintf(stderr, "%s: info RECOVER_CMD=", get_pname());
644 if (options->compress == COMPR_FAST || options->compress == COMPR_BEST)
645 fprintf(stderr, "%s %s |", UNCOMPRESS_PATH,
646 #ifdef UNCOMPRESS_OPT
653 fprintf(stderr, "%s -f - ...\n", program->restore_name);
655 if (options->compress == COMPR_FAST || options->compress == COMPR_BEST)
656 fprintf(stderr, "%s: info COMPRESS_SUFFIX=%s\n",
657 get_pname(), COMPRESS_SUFFIX);
659 fprintf(stderr, "%s: info end\n", get_pname());
673 dbprintf(("%s: forking function %s in pipeline\n",
674 debug_prefix_time(NULL), fname));
676 if(pipe(inpipe) == -1) {
677 error("error [open pipe to %s: %s]", fname, strerror(errno));
681 switch(pid = fork()) {
683 error("error [fork %s: %s]", fname, strerror(errno));
685 default: /* parent process */
686 aclose(inpipe[0]); /* close input side of pipe */
687 *stdinfd = inpipe[1];
689 case 0: /* child process */
690 aclose(inpipe[1]); /* close output side of pipe */
692 if(dup2(inpipe[0], 0) == -1) {
693 error("error [fork %s: dup2(%d, in): %s]",
694 fname, inpipe[0], strerror(errno));
697 if(dup2(stdoutfd, 1) == -1) {
698 error("error [fork %s: dup2(%d, out): %s]",
699 fname, stdoutfd, strerror(errno));
702 if(dup2(stderrfd, 2) == -1) {
703 error("error [fork %s: dup2(%d, err): %s]",
704 fname, stderrfd, strerror(errno));
716 parse_backup_messages(
727 for(; (line = areads(mesgin)) != NULL; free(line)) {
728 process_dumpline(line);
732 error("error [read mesg pipe: %s]", strerror(errno));
736 while((wpid = wait(&retstat)) != -1) {
737 if(check_status(wpid, retstat)) goterror = 1;
741 error("error [%s]", errorstr);
743 } else if(dump_size == -1) {
744 error("error [no backup size line]");
748 program->end_backup(goterror);
750 fprintf(stderr, "%s: size %ld\n", get_pname(), dump_size);
751 fprintf(stderr, "%s: end\n", get_pname());
756 * Returns the value of the first integer in a string.
768 while(ch && !isdigit(ch)) ch = *str++;
770 while(isdigit(ch) || ch == '.') ch = *str++;
786 for(rp = program->re_table; rp->regex != NULL; rp++) {
787 if(match(rp->regex, str)) {
791 if(rp->typ == DMP_SIZE) {
792 dump_size = (long)((first_num(str) * rp->scale + 1023.0)/1024.0);
813 * Should never get here.
819 dbprintf(("%s: %3d: %7s(%c): %s\n",
820 debug_prefix_time(NULL),
825 fprintf(stderr, "%c %s\n", startchr, str);
830 * start_index. Creates an index file from the output of dump/tar.
831 * It arranges that input is the fd to be written by the dump process.
832 * If createindex is not enabled, it does nothing. If it is not, a
833 * new process will be created that tees input both to a pipe whose
834 * read fd is dup2'ed input and to a program that outputs an index
837 * make sure that the chat from restore doesn't go to stderr cause
838 * this goes back to amanda which doesn't expect to see it
839 * (2>/dev/null should do it)
841 * Originally by Alan M. McIvor, 13 April 1996
843 * Adapted by Alexandre Oliva, 1 May 1997
845 * This program owes a lot to tee.c from GNU sh-utils and dumptee.c
846 * from the DeeJay backup package.
856 while (*fd >= 0 && *fd < min) {
857 int newfd = dup(*fd);
859 dbprintf(("%s: unable to save file descriptor [%s]\n",
860 debug_prefix_time(NULL), strerror(errno)));
864 dbprintf(("%s: dupped file descriptor %i to %i\n",
865 debug_prefix_time(NULL), origfd, *fd));
883 if (pipe(pipefd) != 0) {
884 error("creating index pipe: %s", strerror(errno));
888 switch(indexpid = fork()) {
890 error("forking index tee process: %s", strerror(errno));
895 if (dup2(pipefd[1], input) == -1) {
896 error("dup'ping index tee output: %s", strerror(errno));
906 /* now in a child process */
907 save_fd(&pipefd[0], 4);
915 for(index = 4; index < FD_SETSIZE; index++) {
916 if (index != dbfd()) {
921 if ((pipe_fp = popen(cmd, "w")) == NULL) {
922 error("couldn't start index creator [%s]", strerror(errno));
926 dbprintf(("%s: started index creator: \"%s\"\n",
927 debug_prefix_time(NULL), cmd));
929 char buffer[BUFSIZ], *ptr;
931 size_t bytes_written;
932 ssize_t just_written;
935 bytes_read = read(0, buffer, SIZEOF(buffer));
936 } while ((bytes_read < 0) && ((errno == EINTR) || (errno == EAGAIN)));
938 if (bytes_read < 0) {
939 error("index tee cannot read [%s]", strerror(errno));
944 break; /* finished */
946 /* write the stuff to the subprocess */
949 just_written = fullwrite(fileno(pipe_fp), ptr, (size_t)bytes_read);
950 if (just_written < 0) {
952 * just as we waited for write() to complete.
954 if (errno != EPIPE) {
955 dbprintf(("%s: index tee cannot write to index creator [%s]\n",
956 debug_prefix_time(NULL), strerror(errno)));
959 bytes_written += just_written;
963 /* write the stuff to stdout, ensuring none lost when interrupt
967 just_written = fullwrite(3, ptr, (size_t)bytes_read);
968 if (just_written < 0) {
969 error("index tee cannot write [%s]", strerror(errno));
972 bytes_written += just_written;
980 /* check the exit code of the pipe and moan if not 0 */
981 if ((exitcode = pclose(pipe_fp)) != 0) {
982 dbprintf(("%s: index pipe returned %d\n",
983 debug_prefix_time(NULL), exitcode));
985 dbprintf(("%s: index created successfully\n", debug_prefix_time(NULL)));
992 extern backup_program_t dump_program, gnutar_program;
994 backup_program_t *programs[] = {
995 &dump_program, &gnutar_program, NULL