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"
43 #define sendbackup_debug(i,x) do { \
44 if ((i) <= debug_sendbackup) { \
51 pid_t comppid = (pid_t)-1;
52 pid_t dumppid = (pid_t)-1;
53 pid_t tarpid = (pid_t)-1;
54 pid_t encpid = (pid_t)-1;
55 pid_t indexpid = (pid_t)-1;
56 char *errorstr = NULL;
63 g_option_t *g_options = NULL;
67 backup_program_t *program = NULL;
69 static am_feature_t *our_features = NULL;
70 static char *our_feature_string = NULL;
71 static char *amandad_auth = NULL;
74 int main(int argc, char **argv);
75 char *optionstr(option_t *options);
76 char *childstr(pid_t pid);
77 int check_status(pid_t pid, amwait_t w);
79 pid_t pipefork(void (*func)(void), char *fname, int *stdinfd,
80 int stdoutfd, int stderrfd);
81 void parse_backup_messages(int mesgin);
82 static void process_dumpline(char *str);
83 static void save_fd(int *, int);
84 void backup_api_info_tapeheader(int mesgfd, char *prog, option_t *options);
86 double the_num(char *str, int pos);
93 static char *optstr = NULL;
97 char *record_opt = "";
100 char *exclude_file_opt;
101 char *exclude_list_opt;
105 if(options->compress == COMP_BEST)
106 compress_opt = stralloc("compress-best;");
107 else if(options->compress == COMP_FAST)
108 compress_opt = stralloc("compress-fast;");
109 else if(options->compress == COMP_SERVER_BEST)
110 compress_opt = stralloc("srvcomp-best;");
111 else if(options->compress == COMP_SERVER_FAST)
112 compress_opt = stralloc("srvcomp-fast;");
113 else if(options->compress == COMP_SERVER_CUST)
114 compress_opt = vstralloc("srvcomp-cust=", options->srvcompprog, ";", NULL);
115 else if(options->compress == COMP_CUST)
116 compress_opt = vstralloc("comp-cust=", options->clntcompprog, ";", NULL);
118 compress_opt = stralloc("");
120 if(options->encrypt == ENCRYPT_CUST) {
121 encrypt_opt = vstralloc("encrypt-cust=", options->clnt_encrypt, ";", NULL);
122 if (options->clnt_decrypt_opt)
123 decrypt_opt = vstralloc("client-decrypt-option=", options->clnt_decrypt_opt, ";", NULL);
125 decrypt_opt = stralloc("");
127 else if(options->encrypt == ENCRYPT_SERV_CUST) {
128 encrypt_opt = vstralloc("encrypt-serv-cust=", options->srv_encrypt, ";", NULL);
129 if(options->srv_decrypt_opt)
130 decrypt_opt = vstralloc("server-decrypt-option=", options->srv_decrypt_opt, ";", NULL);
132 decrypt_opt = stralloc("");
135 encrypt_opt = stralloc("");
136 decrypt_opt = stralloc("");
139 if(options->no_record) record_opt = "no-record;";
140 if(options->auth) auth_opt = vstralloc("auth=", options->auth, ";", NULL);
141 else auth_opt = stralloc("");
142 if(options->createindex) index_opt = "index;";
144 exclude_file_opt = stralloc("");
145 if(options->exclude_file) {
146 for(excl = options->exclude_file->first; excl != NULL; excl=excl->next){
147 exc = newvstralloc(exc, "exclude-file=", excl->name, ";", NULL);
148 strappend(exclude_file_opt, exc);
151 exclude_list_opt = stralloc("");
152 if(options->exclude_list) {
153 for(excl = options->exclude_list->first; excl != NULL; excl=excl->next){
154 exc = newvstralloc(exc, "exclude-list=", excl->name, ";", NULL);
155 strappend(exclude_list_opt, exc);
159 optstr = newvstralloc(optstr,
169 amfree(compress_opt);
173 amfree(exclude_file_opt);
174 amfree(exclude_list_opt);
187 char *prog, *dumpdate, *stroptions;
188 int program_is_backup_api;
191 char *amdevice = NULL;
192 char *qamdevice = NULL;
194 char *err_extra = NULL;
199 unsigned long malloc_hist_1, malloc_size_1;
200 unsigned long malloc_hist_2, malloc_size_2;
206 safe_fd(DATA_FD_OFFSET, DATA_FD_COUNT*2);
210 set_pname("sendbackup");
212 /* Don't die when child closes pipe */
213 signal(SIGPIPE, SIG_IGN);
215 /* Don't die when interrupt received */
216 signal(SIGINT, SIG_IGN);
218 malloc_size_1 = malloc_inuse(&malloc_hist_1);
220 if(argc > 1 && strcmp(argv[1],"-t") == 0) {
228 erroutput_type = (ERR_INTERACTIVE|ERR_SYSLOG);
229 dbopen(DBG_SUBDIR_CLIENT);
231 dbprintf(("%s: version %s\n", get_pname(), version()));
233 if(argc > 2 && strcmp(argv[1], "amandad") == 0) {
234 amandad_auth = stralloc(argv[2]);
237 our_features = am_init_feature_set();
238 our_feature_string = am_feature_to_string(our_features);
240 conffile = vstralloc(CONFIG_DIR, "/", "amanda-client.conf", NULL);
241 if (read_clientconf(conffile) > 0) {
242 error("error reading conffile: %s", conffile);
249 * In interactive (debug) mode, the backup data is sent to
250 * /dev/null and none of the network connections back to driver
251 * programs on the tape host are set up. The index service is
252 * run and goes to stdout.
254 fprintf(stderr, "%s: running in interactive test mode\n", get_pname());
264 program_is_backup_api=0;
266 for(; (line = agets(stdin)) != NULL; free(line)) {
270 fprintf(stderr, "%s> ", get_pname());
273 if(strncmp_const(line, "OPTIONS ") == 0) {
274 g_options = parse_g_options(line+8, 1);
275 if(!g_options->hostname) {
276 g_options->hostname = alloc(MAX_HOSTNAME_LENGTH+1);
277 gethostname(g_options->hostname, MAX_HOSTNAME_LENGTH);
278 g_options->hostname[MAX_HOSTNAME_LENGTH] = '\0';
281 if (g_options->config) {
282 conffile = vstralloc(CONFIG_DIR, "/", g_options->config, "/",
283 "amanda-client.conf", NULL);
284 if (read_clientconf(conffile) > 0) {
285 error("error reading conffile: %s", conffile);
290 dbrename(g_options->config, DBG_SUBDIR_CLIENT);
296 err_extra = "multiple requests";
300 dbprintf((" sendbackup req: <%s>\n", line));
304 skip_whitespace(s, ch); /* find the program name */
306 err_extra = "no program name";
307 goto err; /* no program name */
310 skip_non_whitespace(s, ch);
313 if(strcmp(prog,"BACKUP")==0) {
314 program_is_backup_api=1;
315 skip_whitespace(s, ch); /* find dumper name */
317 goto err; /* no program */
320 skip_non_whitespace(s, ch);
323 prog = stralloc(prog);
325 skip_whitespace(s, ch); /* find the disk name */
327 err_extra = "no disk name";
328 goto err; /* no disk name */
335 skip_quoted_string(s, ch);
337 qdisk = stralloc(qdisk);
338 disk = unquote_string(qdisk);
340 skip_whitespace(s, ch); /* find the device or level */
342 err_extra = "bad level";
346 if(!isdigit((int)s[-1])) {
351 skip_quoted_string(s, ch);
353 qamdevice = stralloc(qamdevice);
354 amdevice = unquote_string(qamdevice);
355 skip_whitespace(s, ch); /* find level number */
358 amdevice = stralloc(disk);
359 qamdevice = stralloc(qdisk);
361 /* find the level number */
362 if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
363 err_extra = "bad level";
364 goto err; /* bad level */
368 skip_whitespace(s, ch); /* find the dump date */
370 err_extra = "no dumpdate";
371 goto err; /* no dumpdate */
375 skip_non_whitespace(s, ch);
377 dumpdate = stralloc(dumpdate);
379 skip_whitespace(s, ch); /* find the options keyword */
381 err_extra = "no options";
382 goto err; /* no options */
384 if(strncmp_const_skip(s - 1, "OPTIONS ", s, ch) != 0) {
385 err_extra = "no OPTIONS keyword";
386 goto err; /* no options */
388 skip_whitespace(s, ch); /* find the options string */
390 err_extra = "bad options string";
391 goto err; /* no options */
394 stroptions = stralloc(s - 1);
402 stroptions == NULL) {
403 err_extra = "no valid sendbackup request";
407 dbprintf((" parsed request as: program `%s'\n", prog));
408 dbprintf((" disk `%s'\n", qdisk));
409 dbprintf((" device `%s'\n", qamdevice));
410 dbprintf((" level %d\n", level));
411 dbprintf((" since %s\n", dumpdate));
412 dbprintf((" options `%s'\n", stroptions));
414 if(program_is_backup_api==1) {
415 /* check that the backup_api exist */
418 for(i = 0; programs[i]; i++) {
419 if (strcmp(programs[i]->name, prog) == 0) {
423 if (programs[i] == NULL) {
424 dbprintf(("ERROR [%s: unknown program %s]\n", get_pname(), prog));
425 error("ERROR [%s: unknown program %s]", get_pname(), prog);
428 program = programs[i];
431 options = parse_options(stroptions, disk, amdevice, g_options->features, 0);
434 datafd = DATA_FD_OFFSET + 0;
435 mesgfd = DATA_FD_OFFSET + 2;
436 indexfd = DATA_FD_OFFSET + 4;
438 if (!options->createindex)
441 if(options->auth && amandad_auth) {
442 if(strcasecmp(options->auth, amandad_auth) != 0) {
443 printf("ERROR [client configured for auth=%s while server requested '%s']\n",
444 amandad_auth, options->auth);
449 printf("CONNECT DATA %d MESG %d INDEX %d\n",
450 DATA_FD_OFFSET, DATA_FD_OFFSET+1,
451 indexfd == -1 ? -1 : DATA_FD_OFFSET+2);
453 if(am_has_feature(g_options->features, fe_rep_options_features)) {
454 printf("features=%s;", our_feature_string);
456 if(am_has_feature(g_options->features, fe_rep_options_hostname)) {
457 printf("hostname=%s;", g_options->hostname);
459 if(am_has_feature(g_options->features, fe_rep_options_sendbackup_options)) {
460 printf("%s", optionstr(options));
464 if (freopen("/dev/null", "w", stdout) == NULL) {
465 dbprintf(("%s: error redirecting stdout to /dev/null: %s\n",
466 debug_prefix_time(NULL), strerror(errno)));
471 if((datafd = open("/dev/null", O_RDWR)) < 0) {
473 error("ERROR [%s: open of /dev/null for debug data stream: %s]\n",
482 if(datafd == -1 || mesgfd == -1 || (options->createindex && indexfd == -1)) {
488 if(program_is_backup_api==1) {
489 pid_t backup_api_pid;
494 int property_pipe[2];
495 backup_support_option_t *bsu;
497 if (pipe(property_pipe) < 0) {
498 error("Can't create pipe: %s",strerror(errno));
501 bsu = backup_support_option(prog, g_options, disk, amdevice);
503 switch(backup_api_pid=fork()) {
505 aclose(property_pipe[1]);
506 if(dup2(property_pipe[0], 0) == -1) {
507 error("Can't dup2: %s",strerror(errno));
510 if(dup2(datafd, 1) == -1) {
511 error("Can't dup2: %s",strerror(errno));
514 if(dup2(mesgfd, 2) == -1) {
515 error("Can't dup2: %s",strerror(errno));
519 if(dup2(indexfd, 3) == -1) {
520 error("Can't dup2: %s",strerror(errno));
523 fcntl(indexfd, F_SETFD, 0);
524 fcntl(3, F_SETFD, 0);
526 cmd = vstralloc(DUMPER_DIR, "/", prog, NULL);
528 argvchild[i++] = prog;
529 argvchild[i++] = "backup";
530 if (bsu->message_line == 1) {
531 argvchild[i++] = "--message";
532 argvchild[i++] = "line";
534 if (g_options->config && bsu->config == 1) {
535 argvchild[i++] = "--config";
536 argvchild[i++] = g_options->config;
538 if (g_options->hostname && bsu->host == 1) {
539 argvchild[i++] = "--host";
540 argvchild[i++] = g_options->hostname;
542 if (disk && bsu->disk == 1) {
543 argvchild[i++] = "--disk";
544 argvchild[i++] = disk;
546 argvchild[i++] = "--device";
547 argvchild[i++] = amdevice;
548 if (level <= bsu->max_level) {
549 argvchild[i++] = "--level";
550 snprintf(levelstr,19,"%d",level);
551 argvchild[i++] = levelstr;
553 if (indexfd != 0 && bsu->index_line == 1) {
554 argvchild[i++] = "--index";
555 argvchild[i++] = "line";
557 if (!options->no_record && bsu->record == 1) {
558 argvchild[i++] = "--record";
561 dbprintf(("%s: running \"%s", get_pname(), cmd));
562 for(j=1;j<i;j++) dbprintf((" %s",argvchild[j]));
564 backup_api_info_tapeheader(mesgfd, prog, options);
565 execve(cmd, argvchild, safe_env());
570 aclose(property_pipe[0]);
571 toolin = fdopen(property_pipe[1],"w");
573 error("Can't fdopen: %s", strerror(errno));
576 output_tool_property(toolin, options);
581 error("%s: fork returned: %s", get_pname(), strerror(errno));
584 if (waitpid(backup_api_pid, &status, 0) < 0) {
585 if (!WIFEXITED(status)) {
586 dbprintf(("Tool exited with signal %d", WTERMSIG(status)));
587 } else if (WEXITSTATUS(status) != 0) {
588 dbprintf(("Tool exited with status %d", WEXITSTATUS(status)));
590 dbprintf(("waitpid returned negative value"));
596 /* redirect stderr */
597 if(dup2(mesgfd, 2) == -1) {
598 dbprintf(("%s: error redirecting stderr to fd %d: %s\n",
599 debug_prefix_time(NULL), mesgfd, strerror(errno)));
605 if(pipe(mesgpipe) == -1) {
607 dbprintf(("error [opening mesg pipe: %s]\n", s));
608 error("error [opening mesg pipe: %s]", s);
611 program->start_backup(g_options->hostname, disk, amdevice, level,
612 dumpdate, datafd, mesgpipe[1], indexfd);
613 dbprintf(("%s: started backup\n", debug_prefix_time(NULL)));
614 parse_backup_messages(mesgpipe[0]);
615 dbprintf(("%s: parsed backup messages\n", debug_prefix_time(NULL)));
625 amfree(our_feature_string);
626 am_release_feature_set(our_features);
628 am_release_feature_set(g_options->features);
629 g_options->features = NULL;
630 amfree(g_options->hostname);
631 amfree(g_options->str);
636 malloc_size_2 = malloc_inuse(&malloc_hist_2);
638 if(malloc_size_1 != malloc_size_2) {
639 malloc_list(fileno(stderr), malloc_hist_1, malloc_hist_2);
645 printf("FORMAT ERROR IN REQUEST PACKET\n");
646 dbprintf(("%s: REQ packet is bogus%s%s\n",
647 debug_prefix_time(NULL),
648 err_extra ? ": " : "",
649 err_extra ? err_extra : ""));
656 * Returns a string for a child process. Checks the saved dump and
657 * compress pids to see which it is.
664 if(pid == dumppid) return program->backup_name;
665 if(pid == comppid) return "compress";
666 if(pid == encpid) return "encrypt";
667 if(pid == indexpid) return "index";
673 * Determine if the child return status really indicates an error.
674 * If so, add the error message to the error string; more than one
675 * child can have an error.
683 char *thiserr = NULL;
686 char number[NUM_STR_SIZE];
687 char numberpid[NUM_STR_SIZE];
693 rc = sig = WTERMSIG(w);
696 rc = ret = WEXITSTATUS(w);
699 if(pid == indexpid) {
701 * Treat an index failure (other than signal) as a "STRANGE"
702 * rather than an error so the dump goes ahead and gets processed
703 * but the failure is noted.
706 fprintf(stderr, "? index %s returned %d\n", str, ret);
711 } else if(pid == comppid) {
713 * compress returns 2 sometimes, but it is ok.
722 } else if(pid == dumppid && tarpid == -1) {
724 * Ultrix dump returns 1 sometimes, but it is ok.
726 #ifdef DUMP_RETURNS_1
733 } else if(pid == tarpid) {
738 * tar bitches about active filesystems, but we do not care.
740 #ifdef IGNORE_TAR_ERRORS
745 dumppid = tarpid = -1;
752 return 0; /* normal exit */
755 snprintf(numberpid, SIZEOF(number), "%d", (int)pid);
757 snprintf(number, SIZEOF(number), "%d", sig);
758 thiserr = vstralloc(strX, "(", numberpid, ") ", str, " got signal ", number, NULL);
760 snprintf(number, SIZEOF(number), "%d", ret);
761 thiserr = vstralloc(strX, "(", numberpid, ") ", str, " returned ", number, NULL);
765 strappend(errorstr, ", ");
766 strappend(errorstr, thiserr);
777 *Send header info to the message file.
780 info_tapeheader(void)
782 fprintf(stderr, "%s: info BACKUP=%s\n", get_pname(), program->backup_name);
784 fprintf(stderr, "%s: info RECOVER_CMD=", get_pname());
785 if (options->compress == COMP_FAST || options->compress == COMP_BEST)
786 fprintf(stderr, "%s %s |", UNCOMPRESS_PATH,
787 #ifdef UNCOMPRESS_OPT
794 fprintf(stderr, "%s -xpGf - ...\n", program->restore_name);
796 if (options->compress == COMP_FAST || options->compress == COMP_BEST)
797 fprintf(stderr, "%s: info COMPRESS_SUFFIX=%s\n",
798 get_pname(), COMPRESS_SUFFIX);
800 fprintf(stderr, "%s: info end\n", get_pname());
804 backup_api_info_tapeheader(
811 snprintf(line, 1024, "%s: info BACKUP=DUMPER\n", get_pname());
812 if (fullwrite(mesgfd, line, strlen(line)) != (ssize_t)strlen(line)) {
813 dbprintf(("error writing to mesgfd socket: %s", strerror(errno)));
817 snprintf(line, 1024, "%s: info DUMPER=%s\n", get_pname(), prog);
818 if (fullwrite(mesgfd, line, strlen(line)) != (ssize_t)strlen(line)) {
819 dbprintf(("error writing to mesgfd socket: %s", strerror(errno)));
823 snprintf(line, 1024, "%s: info RECOVER_CMD=", get_pname());
824 if (fullwrite(mesgfd, line, strlen(line)) != (ssize_t)strlen(line)) {
825 dbprintf(("error writing to mesgfd socket: %s", strerror(errno)));
829 if (options->compress) {
830 snprintf(line, 1024, "%s %s |", UNCOMPRESS_PATH,
831 #ifdef UNCOMPRESS_OPT
837 if (fullwrite(mesgfd, line, strlen(line)) != (ssize_t)strlen(line)) {
838 dbprintf(("error writing to mesgfd socket: %s", strerror(errno)));
842 snprintf(line, 1024, "%s -f... -\n", prog);
843 if (fullwrite(mesgfd, line, strlen(line)) != (ssize_t)strlen(line)) {
844 dbprintf(("error writing to mesgfd socket: %s", strerror(errno)));
848 if (options->compress) {
849 snprintf(line, 1024, "%s: info COMPRESS_SUFFIX=%s\n",
850 get_pname(), COMPRESS_SUFFIX);
851 if (fullwrite(mesgfd, line, strlen(line)) != (ssize_t)strlen(line)) {
852 dbprintf(("error writing to mesgfd socket: %s", strerror(errno)));
857 snprintf(line, 1024, "%s: info end\n", get_pname());
858 if (fullwrite(mesgfd, line, strlen(line)) != (ssize_t)strlen(line)) {
859 dbprintf(("error writing to mesgfd socket: %s", strerror(errno)));
875 dbprintf(("%s: forking function %s in pipeline\n",
876 debug_prefix_time(NULL), fname));
878 if(pipe(inpipe) == -1) {
879 error("error [open pipe to %s: %s]", fname, strerror(errno));
883 switch(pid = fork()) {
885 error("error [fork %s: %s]", fname, strerror(errno));
887 default: /* parent process */
888 aclose(inpipe[0]); /* close input side of pipe */
889 *stdinfd = inpipe[1];
891 case 0: /* child process */
892 aclose(inpipe[1]); /* close output side of pipe */
894 if(dup2(inpipe[0], 0) == -1) {
895 error("error [fork %s: dup2(%d, in): %s]",
896 fname, inpipe[0], strerror(errno));
899 if(dup2(stdoutfd, 1) == -1) {
900 error("error [fork %s: dup2(%d, out): %s]",
901 fname, stdoutfd, strerror(errno));
904 if(dup2(stderrfd, 2) == -1) {
905 error("error [fork %s: dup2(%d, err): %s]",
906 fname, stderrfd, strerror(errno));
918 parse_backup_messages(
929 for(; (line = areads(mesgin)) != NULL; free(line)) {
930 process_dumpline(line);
934 error("error [read mesg pipe: %s]", strerror(errno));
938 while((wpid = waitpid((pid_t)-1, &retstat, WNOHANG)) > 0) {
939 if(check_status(wpid, retstat)) goterror = 1;
944 while((wpid = waitpid((pid_t)-1, &retstat, WNOHANG)) > 0) {
945 if(check_status(wpid, retstat)) goterror = 1;
949 dbprintf(("%s: Sending SIGHUP to dump process %d\n",
950 debug_prefix_time(NULL), (int)dumppid));
952 if(kill(dumppid, SIGHUP) == -1) {
953 dbprintf(("%s: Can't send SIGHUP to %d: %s\n",
954 debug_prefix_time(NULL), (int)dumppid,
959 while((wpid = waitpid((pid_t)-1, &retstat, WNOHANG)) > 0) {
960 if(check_status(wpid, retstat)) goterror = 1;
964 dbprintf(("%s: Sending SIGKILL to dump process %d\n",
965 debug_prefix_time(NULL), (int)dumppid));
967 if(kill(dumppid, SIGKILL) == -1) {
968 dbprintf(("%s: Can't send SIGKILL to %d: %s\n",
969 debug_prefix_time(NULL), (int)dumppid,
974 while((wpid = waitpid((pid_t)-1, &retstat, WNOHANG)) > 0) {
975 if(check_status(wpid, retstat)) goterror = 1;
980 error("error [%s]", errorstr);
982 } else if(dump_size == -1) {
983 error("error [no backup size line]");
987 program->end_backup(goterror);
989 fprintf(stderr, "%s: size %ld\n", get_pname(), dump_size);
990 fprintf(stderr, "%s: end\n", get_pname());
995 * Returns the value of the first integer in a string.
1009 while(ch && !isdigit(ch)) ch = *str++;
1010 if (pos == 1) break;
1012 while(ch && (isdigit(ch) || ch == '.')) ch = *str++;
1015 while(isdigit(ch) || ch == '.') ch = *str++;
1031 for(rp = program->re_table; rp->regex != NULL; rp++) {
1032 if(match(rp->regex, str)) {
1036 if(rp->typ == DMP_SIZE) {
1037 dump_size = (long)((the_num(str, rp->field)* rp->scale+1023.0)/1024.0);
1058 * Should never get here.
1064 dbprintf(("%s: %3d: %7s(%c): %s\n",
1065 debug_prefix_time(NULL),
1070 fprintf(stderr, "%c %s\n", startchr, str);
1075 * start_index. Creates an index file from the output of dump/tar.
1076 * It arranges that input is the fd to be written by the dump process.
1077 * If createindex is not enabled, it does nothing. If it is not, a
1078 * new process will be created that tees input both to a pipe whose
1079 * read fd is dup2'ed input and to a program that outputs an index
1082 * make sure that the chat from restore doesn't go to stderr cause
1083 * this goes back to amanda which doesn't expect to see it
1084 * (2>/dev/null should do it)
1086 * Originally by Alan M. McIvor, 13 April 1996
1088 * Adapted by Alexandre Oliva, 1 May 1997
1090 * This program owes a lot to tee.c from GNU sh-utils and dumptee.c
1091 * from the DeeJay backup package.
1101 while (*fd >= 0 && *fd < min) {
1102 int newfd = dup(*fd);
1104 dbprintf(("%s: unable to save file descriptor [%s]\n",
1105 debug_prefix_time(NULL), strerror(errno)));
1109 dbprintf(("%s: dupped file descriptor %i to %i\n",
1110 debug_prefix_time(NULL), origfd, *fd));
1128 if (pipe(pipefd) != 0) {
1129 error("creating index pipe: %s", strerror(errno));
1133 switch(indexpid = fork()) {
1135 error("forking index tee process: %s", strerror(errno));
1140 if (dup2(pipefd[1], input) == -1) {
1141 error("dup'ping index tee output: %s", strerror(errno));
1151 /* now in a child process */
1152 save_fd(&pipefd[0], 4);
1160 for(index = 4; index < FD_SETSIZE; index++) {
1161 if (index != dbfd()) {
1166 if ((pipe_fp = popen(cmd, "w")) == NULL) {
1167 error("couldn't start index creator [%s]", strerror(errno));
1171 dbprintf(("%s: started index creator: \"%s\"\n",
1172 debug_prefix_time(NULL), cmd));
1174 char buffer[BUFSIZ], *ptr;
1176 size_t bytes_written;
1177 ssize_t just_written;
1180 bytes_read = read(0, buffer, SIZEOF(buffer));
1181 } while ((bytes_read < 0) && ((errno == EINTR) || (errno == EAGAIN)));
1183 if (bytes_read < 0) {
1184 error("index tee cannot read [%s]", strerror(errno));
1188 if (bytes_read == 0)
1189 break; /* finished */
1191 /* write the stuff to the subprocess */
1194 just_written = fullwrite(fileno(pipe_fp), ptr, (size_t)bytes_read);
1195 if (just_written < 0) {
1197 * just as we waited for write() to complete.
1199 if (errno != EPIPE) {
1200 dbprintf(("%s: index tee cannot write to index creator [%s]\n",
1201 debug_prefix_time(NULL), strerror(errno)));
1204 bytes_written += just_written;
1205 ptr += just_written;
1208 /* write the stuff to stdout, ensuring none lost when interrupt
1212 just_written = fullwrite(3, ptr, (size_t)bytes_read);
1213 if (just_written < 0) {
1214 error("index tee cannot write [%s]", strerror(errno));
1217 bytes_written += just_written;
1218 ptr += just_written;
1225 /* check the exit code of the pipe and moan if not 0 */
1226 if ((exitcode = pclose(pipe_fp)) != 0) {
1227 dbprintf(("%s: index pipe returned %d\n",
1228 debug_prefix_time(NULL), exitcode));
1230 dbprintf(("%s: index created successfully\n", debug_prefix_time(NULL)));
1237 extern backup_program_t dump_program, gnutar_program;
1239 backup_program_t *programs[] = {
1240 &dump_program, &gnutar_program, NULL