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.
34 #include "sendbackup.h"
36 #include "pipespawn.h"
37 #include "amfeatures.h"
41 #include "amandates.h"
44 #define sendbackup_debug(i, ...) do { \
45 if ((i) <= debug_sendbackup) { \
46 dbprintf(__VA_LIST__); \
52 pid_t comppid = (pid_t)-1;
53 pid_t dumppid = (pid_t)-1;
54 pid_t tarpid = (pid_t)-1;
55 pid_t encpid = (pid_t)-1;
56 pid_t indexpid = (pid_t)-1;
57 pid_t application_api_pid = (pid_t)-1;
58 char *errorstr = NULL;
64 g_option_t *g_options = NULL;
68 backup_program_t *program = NULL;
71 static am_feature_t *our_features = NULL;
72 static char *our_feature_string = NULL;
73 static char *amandad_auth = NULL;
76 int main(int argc, char **argv);
77 char *childstr(pid_t pid);
78 int check_status(pid_t pid, amwait_t w, int mesgfd);
80 pid_t pipefork(void (*func)(void), char *fname, int *stdinfd,
81 int stdoutfd, int stderrfd);
82 int check_result(int mesgfd);
83 void parse_backup_messages(dle_t *dle, int mesgin);
84 static void process_dumpline(char *str);
85 static void save_fd(int *, int);
86 void application_api_info_tapeheader(int mesgfd, char *prog, dle_t *dle);
88 int fdprintf(int fd, char *format, ...) G_GNUC_PRINTF(2, 3);
100 arglist_start(argp, format);
101 s = g_strdup_vprintf(format, argp);
104 r = full_write(fd, s, strlen(s));
118 char *dumpdate, *stroptions;
120 char *qamdevice = NULL;
122 char *err_extra = NULL;
130 if (argc > 1 && argv && argv[1] && g_str_equal(argv[1], "--version")) {
131 printf("sendbackup-%s\n", VERSION);
137 * Configure program for internationalization:
138 * 1) Only set the message locale for now.
139 * 2) Set textdomain for all amanda related programs to "amanda"
140 * We don't want to be forced to support dozens of message catalogs.
142 setlocale(LC_MESSAGES, "C");
143 textdomain("amanda");
145 safe_fd(DATA_FD_OFFSET, DATA_FD_COUNT*2);
150 set_pname("sendbackup");
152 /* Don't die when child closes pipe */
153 signal(SIGPIPE, SIG_IGN);
155 /* Don't die when interrupt received */
156 signal(SIGINT, SIG_IGN);
158 if(argc > 1 && strcmp(argv[1],"-t") == 0) {
166 add_amanda_log_handler(amanda_log_stderr);
167 add_amanda_log_handler(amanda_log_syslog);
168 dbopen(DBG_SUBDIR_CLIENT);
170 dbprintf(_("Version %s\n"), VERSION);
172 if(argc > 2 && strcmp(argv[1], "amandad") == 0) {
173 amandad_auth = stralloc(argv[2]);
176 our_features = am_init_feature_set();
177 our_feature_string = am_feature_to_string(our_features);
179 config_init(CONFIG_INIT_CLIENT, NULL);
180 /* (check for config errors comes later) */
182 check_running_as(RUNNING_AS_CLIENT_LOGIN);
186 * In interactive (debug) mode, the backup data is sent to
187 * /dev/null and none of the network connections back to driver
188 * programs on the tape host are set up. The index service is
189 * run and goes to stdout.
191 g_fprintf(stderr, _("%s: running in interactive test mode\n"), get_pname());
199 for(; (line = agets(stdin)) != NULL; free(line)) {
203 g_fprintf(stderr, "%s> ", get_pname());
206 if(strncmp_const(line, "OPTIONS ") == 0) {
207 g_options = parse_g_options(line+8, 1);
208 if(!g_options->hostname) {
209 g_options->hostname = alloc(MAX_HOSTNAME_LENGTH+1);
210 gethostname(g_options->hostname, MAX_HOSTNAME_LENGTH);
211 g_options->hostname[MAX_HOSTNAME_LENGTH] = '\0';
214 if (g_options->config) {
215 /* overlay this configuration on the existing (nameless) configuration */
216 config_init(CONFIG_INIT_CLIENT | CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_OVERLAY,
219 dbrename(get_config_name(), DBG_SUBDIR_CLIENT);
222 /* check for any config errors now */
223 if (config_errors(&errlist) >= CFGERR_ERRORS) {
224 char *errstr = config_errors_to_error_string(errlist);
225 g_printf("%s\n", errstr);
230 if (am_has_feature(g_options->features, fe_req_xml)) {
236 if (dle && dle->program != NULL) {
237 err_extra = _("multiple requests");
241 dbprintf(_(" sendbackup req: <%s>\n"), line);
247 skip_whitespace(s, ch); /* find the program name */
249 err_extra = _("no program name");
250 goto err; /* no program name */
252 dle->program = s - 1;
253 skip_non_whitespace(s, ch);
256 if (strcmp(dle->program, "APPLICATION")==0) {
257 dle->program_is_application_api=1;
258 skip_whitespace(s, ch); /* find dumper name */
260 goto err; /* no program */
262 dle->program = s - 1;
263 skip_non_whitespace(s, ch);
266 dle->program = stralloc(dle->program);
268 skip_whitespace(s, ch); /* find the disk name */
270 err_extra = _("no disk name");
271 goto err; /* no disk name */
277 skip_quoted_string(s, ch);
279 qdisk = stralloc(qdisk);
280 dle->disk = unquote_string(qdisk);
282 skip_whitespace(s, ch); /* find the device or level */
284 err_extra = _("bad level");
288 if(!isdigit((int)s[-1])) {
292 skip_quoted_string(s, ch);
294 qamdevice = stralloc(qamdevice);
295 dle->device = unquote_string(qamdevice);
296 skip_whitespace(s, ch); /* find level number */
299 dle->device = stralloc(dle->disk);
300 qamdevice = stralloc(qdisk);
302 /* find the level number */
303 if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
304 err_extra = _("bad level");
305 goto err; /* bad level */
308 alevel = g_new0(am_level_t, 1);
309 alevel->level = level;
310 dle->levellist = g_slist_append(dle->levellist, alevel);
312 skip_whitespace(s, ch); /* find the dump date */
314 err_extra = _("no dumpdate");
315 goto err; /* no dumpdate */
319 skip_non_whitespace(s, ch);
321 dumpdate = stralloc(dumpdate);
323 skip_whitespace(s, ch); /* find the options keyword */
325 err_extra = _("no options");
326 goto err; /* no options */
328 if(strncmp_const_skip(s - 1, "OPTIONS ", s, ch) != 0) {
329 err_extra = _("no OPTIONS keyword");
330 goto err; /* no options */
332 skip_whitespace(s, ch); /* find the options string */
334 err_extra = _("bad options string");
335 goto err; /* no options */
338 stroptions = stralloc(s - 1);
341 if (g_options == NULL) {
342 g_printf(_("ERROR [Missing OPTIONS line in sendbackup input]\n"));
343 error(_("Missing OPTIONS line in sendbackup input\n"));
347 if (am_has_feature(g_options->features, fe_req_xml)) {
350 dle = amxml_parse_node_FILE(stdin, &errmsg);
356 err_extra = _("One DLE required");
358 } else if (dle->next) {
359 err_extra = _("Only one DLE allowed");
363 qdisk = quote_string(dle->disk);
364 if (dle->device == NULL)
365 dle->device = stralloc(dle->disk);
366 qamdevice = quote_string(dle->device);
367 dumpdate = stralloc("NODATE");
368 stroptions = stralloc("");
370 parse_options(stroptions, dle, g_options->features, 0);
374 if (dle->program == NULL ||
376 dle->device == NULL ||
377 dle->levellist == NULL ||
379 err_extra = _("no valid sendbackup request");
383 if (g_slist_length(dle->levellist) != 1) {
384 err_extra = _("Too many level");
388 alevel = (am_level_t *)dle->levellist->data;
389 level = alevel->level;
390 dbprintf(_(" Parsed request as: program `%s'\n"), dle->program);
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);
396 dbprintf(_(" datapath `%s'\n"),
397 data_path_to_string(dle->data_path));
399 if (dle->program_is_application_api==1) {
400 /* check that the application_api exist */
402 for(i = 0; programs[i]; i++) {
403 if (strcmp(programs[i]->name, dle->program) == 0) {
407 if (programs[i] == NULL) {
408 dbprintf(_("ERROR [%s: unknown program %s]\n"), get_pname(),
410 error(_("ERROR [%s: unknown program %s]"), get_pname(),
414 program = programs[i];
418 datafd = DATA_FD_OFFSET + 0;
419 mesgfd = DATA_FD_OFFSET + 2;
420 indexfd = DATA_FD_OFFSET + 4;
422 if (!dle->create_index)
425 if (dle->auth && amandad_auth) {
426 if(strcasecmp(dle->auth, amandad_auth) != 0) {
427 g_printf(_("ERROR [client configured for auth=%s while server requested '%s']\n"),
428 amandad_auth, dle->auth);
434 g_printf("KENCRYPT\n");
437 g_printf(_("CONNECT DATA %d MESG %d INDEX %d\n"),
438 DATA_FD_OFFSET, DATA_FD_OFFSET+1,
439 indexfd == -1 ? -1 : DATA_FD_OFFSET+2);
440 g_printf(_("OPTIONS "));
441 if(am_has_feature(g_options->features, fe_rep_options_features)) {
442 g_printf("features=%s;", our_feature_string);
444 if(am_has_feature(g_options->features, fe_rep_options_hostname)) {
445 g_printf("hostname=%s;", g_options->hostname);
447 if (!am_has_feature(g_options->features, fe_rep_options_features) &&
448 !am_has_feature(g_options->features, fe_rep_options_hostname)) {
453 if (freopen("/dev/null", "w", stdout) == NULL) {
454 dbprintf(_("Error redirecting stdout to /dev/null: %s\n"),
460 if((datafd = open("/dev/null", O_RDWR)) < 0) {
461 error(_("ERROR [open of /dev/null for debug data stream: %s]\n"),
470 if(datafd == -1 || mesgfd == -1 || (dle->create_index && indexfd == -1)) {
476 if (merge_dles_properties(dle, 1) == 0) {
477 g_debug("merge_dles_properties failed");
480 mesgstream = fdopen(mesgfd,"w");
481 run_client_scripts(EXECUTE_ON_PRE_DLE_BACKUP, g_options, dle, mesgstream);
484 if (dle->program_is_application_api==1) {
489 backup_support_option_t *bsu;
490 char *compopt = NULL;
491 char *encryptopt = skip_argument;
492 int compout, dumpout;
501 /* apply client-side encryption here */
502 if ( dle->encrypt == ENCRYPT_CUST ) {
503 encpid = pipespawn(dle->clnt_encrypt, STDIN_PIPE, 0,
504 &compout, &datafd, &mesgfd,
505 dle->clnt_encrypt, encryptopt, NULL);
506 dbprintf(_("encrypt: pid %ld: %s\n"), (long)encpid, dle->clnt_encrypt);
512 /* now do the client-side compression */
513 if(dle->compress == COMP_FAST || dle->compress == COMP_BEST) {
514 compopt = skip_argument;
515 #if defined(COMPRESS_BEST_OPT) && defined(COMPRESS_FAST_OPT)
516 if(dle->compress == COMP_BEST) {
517 compopt = COMPRESS_BEST_OPT;
519 compopt = COMPRESS_FAST_OPT;
522 comppid = pipespawn(COMPRESS_PATH, STDIN_PIPE, 0,
523 &dumpout, &compout, &mesgfd,
524 COMPRESS_PATH, compopt, NULL);
525 if(compopt != skip_argument) {
526 dbprintf(_("compress pid %ld: %s %s\n"),
527 (long)comppid, COMPRESS_PATH, compopt);
529 dbprintf(_("compress pid %ld: %s\n"), (long)comppid, COMPRESS_PATH);
531 } else if (dle->compress == COMP_CUST) {
532 compopt = skip_argument;
533 comppid = pipespawn(dle->compprog, STDIN_PIPE, 0,
534 &dumpout, &compout, &mesgfd,
535 dle->compprog, compopt, NULL);
536 if(compopt != skip_argument) {
537 dbprintf(_("pid %ld: %s %s\n"),
538 (long)comppid, dle->compprog, compopt);
540 dbprintf(_("pid %ld: %s\n"), (long)comppid, dle->compprog);
547 cur_dumptime = time(0);
548 bsu = backup_support_option(dle->program, g_options, dle->disk,
549 dle->device, &errarray);
554 for (i=0; i < errarray->len; i++) {
555 errmsg = g_ptr_array_index(errarray, i);
556 qerrmsg = quote_string(errmsg);
558 _("sendbackup: error [Application '%s': %s]\n"),
559 dle->program, errmsg);
560 dbprintf("aa: %s\n",qerrmsg);
563 if (i == 0) { /* no errarray */
564 errmsg = vstrallocf(_("Can't execute application '%s'"),
566 qerrmsg = quote_string(errmsg);
567 fdprintf(mesgfd, _("sendbackup: error [%s]\n"), errmsg);
568 dbprintf(_("ERROR %s\n"), qerrmsg);
575 if (pipe(errfd) < 0) {
578 errmsg = vstrallocf(_("Application '%s': can't create pipe"),
580 qerrmsg = quote_string(errmsg);
581 fdprintf(mesgfd, _("sendbackup: error [%s]\n"), errmsg);
582 dbprintf(_("ERROR %s\n"), qerrmsg);
588 switch(application_api_pid=fork()) {
590 application_api_info_tapeheader(mesgfd, dle->program, dle);
592 /* find directt-tcp address from indirect direct-tcp */
593 if (dle->data_path == DATA_PATH_DIRECTTCP &&
594 bsu->data_path_set & DATA_PATH_DIRECTTCP &&
595 strncmp(dle->directtcp_list->data, "255.255.255.255:", 16) == 0) {
604 indirect_tcp = g_strdup(dle->directtcp_list->data);
605 g_slist_free(dle->directtcp_list);
606 dle->directtcp_list = NULL;
607 str_port = strchr(indirect_tcp, ':');
609 port = atoi(str_port);
610 fd = stream_client("localhost", port, 32768, 32768, NULL, 0);
612 g_debug("Failed to connect to indirect-direct-tcp port: %s",
616 size = full_read(fd, buffer, 32768);
618 g_debug("Failed to read from indirect-direct-tcp port: %s",
622 buffer[size++] = ' ';
625 while ((s = strchr(s1, ' ')) != NULL) {
627 dle->directtcp_list = g_slist_append(dle->directtcp_list, g_strdup(s1));
630 amfree(indirect_tcp);
633 argv_ptr = g_ptr_array_new();
634 cmd = vstralloc(APPLICATION_DIR, "/", dle->program, NULL);
635 g_ptr_array_add(argv_ptr, stralloc(dle->program));
636 g_ptr_array_add(argv_ptr, stralloc("backup"));
637 if (bsu->message_line == 1) {
638 g_ptr_array_add(argv_ptr, stralloc("--message"));
639 g_ptr_array_add(argv_ptr, stralloc("line"));
641 if (g_options->config && bsu->config == 1) {
642 g_ptr_array_add(argv_ptr, stralloc("--config"));
643 g_ptr_array_add(argv_ptr, stralloc(g_options->config));
645 if (g_options->hostname && bsu->host == 1) {
646 g_ptr_array_add(argv_ptr, stralloc("--host"));
647 g_ptr_array_add(argv_ptr, stralloc(g_options->hostname));
649 if (dle->disk && bsu->disk == 1) {
650 g_ptr_array_add(argv_ptr, stralloc("--disk"));
651 g_ptr_array_add(argv_ptr, stralloc(dle->disk));
653 g_ptr_array_add(argv_ptr, stralloc("--device"));
654 g_ptr_array_add(argv_ptr, stralloc(dle->device));
655 if (level <= bsu->max_level) {
656 g_ptr_array_add(argv_ptr, stralloc("--level"));
657 g_snprintf(levelstr,19,"%d",level);
658 g_ptr_array_add(argv_ptr, stralloc(levelstr));
660 if (indexfd != -1 && bsu->index_line == 1) {
661 g_ptr_array_add(argv_ptr, stralloc("--index"));
662 g_ptr_array_add(argv_ptr, stralloc("line"));
664 if (dle->record && bsu->record == 1) {
665 g_ptr_array_add(argv_ptr, stralloc("--record"));
667 application_property_add_to_argv(argv_ptr, dle, bsu,
668 g_options->features);
670 for (scriptlist = dle->scriptlist; scriptlist != NULL;
671 scriptlist = scriptlist->next) {
672 script = (script_t *)scriptlist->data;
673 if (script->result && script->result->proplist) {
674 property_add_to_argv(argv_ptr, script->result->proplist);
678 g_ptr_array_add(argv_ptr, NULL);
679 dbprintf(_("%s: running \"%s\n"), get_pname(), cmd);
680 for (j = 1; j < argv_ptr->len - 1; j++)
681 dbprintf(" %s\n", (char *)g_ptr_array_index(argv_ptr,j));
683 if(dup2(dumpout, 1) == -1) {
684 error(_("Can't dup2: %s"),strerror(errno));
687 if (dup2(errfd[1], 2) == -1) {
688 error(_("Can't dup2: %s"),strerror(errno));
691 if(dup2(mesgfd, 3) == -1) {
692 error(_("Can't dup2: %s"),strerror(errno));
696 if(dup2(indexfd, 4) == -1) {
697 error(_("Can't dup2: %s"),strerror(errno));
700 fcntl(indexfd, F_SETFD, 0);
707 execve(cmd, (char **)argv_ptr->pdata, safe_env());
714 error(_("%s: fork returned: %s"), get_pname(), strerror(errno));
718 dumperr = fdopen(errfd[0],"r");
720 error(_("Can't fdopen: %s"), strerror(errno));
725 while ((line = agets(dumperr)) != NULL) {
726 if (strlen(line) > 0) {
727 fdprintf(mesgfd, "sendbackup: error [%s]\n", line);
728 dbprintf("error: %s\n", line);
734 result |= check_result(mesgfd);
736 char *amandates_file;
738 amandates_file = getconf_str(CNF_AMANDATES);
739 if(start_amandates(amandates_file, 1)) {
740 amandates_updateone(dle->disk, level, cur_dumptime);
744 if (GPOINTER_TO_INT(dle->estimatelist->data) == ES_CALCSIZE &&
746 error(_("error [opening %s for writing: %s]"),
747 amandates_file, strerror(errno));
749 g_debug(_("non-fatal error opening '%s' for writing: %s]"),
750 amandates_file, strerror(errno));
757 /* redirect stderr */
758 if(dup2(mesgfd, 2) == -1) {
759 dbprintf(_("Error redirecting stderr to fd %d: %s\n"),
760 mesgfd, strerror(errno));
766 if(pipe(mesgpipe) == -1) {
768 dbprintf(_("error [opening mesg pipe: %s]\n"), s);
769 error(_("error [opening mesg pipe: %s]"), s);
772 program->start_backup(dle, g_options->hostname,
773 datafd, mesgpipe[1], indexfd);
774 dbprintf(_("Started backup\n"));
775 parse_backup_messages(dle, mesgpipe[0]);
776 dbprintf(_("Parsed backup messages\n"));
779 run_client_scripts(EXECUTE_ON_POST_DLE_BACKUP, g_options, dle, mesgstream);
786 amfree(our_feature_string);
787 am_release_feature_set(our_features);
789 free_g_options(g_options);
797 g_printf(_("ERROR FORMAT ERROR IN REQUEST PACKET '%s'\n"), err_extra);
798 dbprintf(_("REQ packet is bogus: %s\n"), err_extra);
800 g_printf(_("ERROR FORMAT ERROR IN REQUEST PACKET\n"));
801 dbprintf(_("REQ packet is bogus\n"));
808 amfree(our_feature_string);
816 * Returns a string for a child process. Checks the saved dump and
817 * compress pids to see which it is.
824 if(pid == dumppid) return program->backup_name;
825 if(pid == comppid) return "compress";
826 if(pid == encpid) return "encrypt";
827 if(pid == indexpid) return "index";
828 if(pid == application_api_pid) {
830 dbprintf("gdle == NULL\n");
831 return "gdle == NULL";
833 return gdle->program;
840 * Determine if the child return status really indicates an error.
841 * If so, add the error message to the error string; more than one
842 * child can have an error.
851 char *thiserr = NULL;
859 rc = sig = WTERMSIG(w);
862 rc = ret = WEXITSTATUS(w);
865 if(pid == indexpid) {
867 * Treat an index failure (other than signal) as a "STRANGE"
868 * rather than an error so the dump goes ahead and gets processed
869 * but the failure is noted.
872 fdprintf(mesgfd, _("? index %s returned %d\n"), str, ret);
877 } else if(pid == comppid) {
879 * compress returns 2 sometimes, but it is ok.
888 } else if(pid == dumppid && tarpid == -1) {
890 * Ultrix dump returns 1 sometimes, but it is ok.
892 #ifdef DUMP_RETURNS_1
899 } else if(pid == tarpid) {
904 * tar bitches about active filesystems, but we do not care.
906 #ifdef IGNORE_TAR_ERRORS
911 dumppid = tarpid = -1;
913 } else if(pid == application_api_pid) {
914 strX = "Application";
920 return 0; /* normal exit */
924 thiserr = vstrallocf(_("%s (%d) %s got signal %d"), strX, (int)pid, str,
927 thiserr = vstrallocf(_("%s (%d) %s returned %d"), strX, (int)pid, str, ret);
930 fdprintf(mesgfd, "? %s\n", thiserr);
933 errorstr = newvstrallocf(errorstr, "%s, %s", errorstr, thiserr);
944 *Send header info to the message file.
950 g_fprintf(stderr, "%s: info BACKUP=%s\n", get_pname(), program->backup_name);
952 g_fprintf(stderr, "%s: info RECOVER_CMD=", get_pname());
953 if (dle->compress == COMP_FAST || dle->compress == COMP_BEST)
954 g_fprintf(stderr, "%s %s |", UNCOMPRESS_PATH,
955 #ifdef UNCOMPRESS_OPT
962 g_fprintf(stderr, "%s -xpGf - ...\n", program->restore_name);
964 if (dle->compress == COMP_FAST || dle->compress == COMP_BEST)
965 g_fprintf(stderr, "%s: info COMPRESS_SUFFIX=%s\n",
966 get_pname(), COMPRESS_SUFFIX);
968 g_fprintf(stderr, "%s: info end\n", get_pname());
972 application_api_info_tapeheader(
979 g_snprintf(line, 1024, "%s: info BACKUP=APPLICATION\n", get_pname());
980 if (full_write(mesgfd, line, strlen(line)) != strlen(line)) {
981 dbprintf(_("error writing to mesgfd socket: %s"), strerror(errno));
985 g_snprintf(line, 1024, "%s: info APPLICATION=%s\n", get_pname(), prog);
986 if (full_write(mesgfd, line, strlen(line)) != strlen(line)) {
987 dbprintf(_("error writing to mesgfd socket: %s"), strerror(errno));
991 g_snprintf(line, 1024, "%s: info RECOVER_CMD=", get_pname());
992 if (full_write(mesgfd, line, strlen(line)) != strlen(line)) {
993 dbprintf(_("error writing to mesgfd socket: %s"), strerror(errno));
997 if (dle->compress == COMP_FAST || dle->compress == COMP_BEST) {
998 g_snprintf(line, 1024, "%s %s |", UNCOMPRESS_PATH,
999 #ifdef UNCOMPRESS_OPT
1005 if (full_write(mesgfd, line, strlen(line)) != strlen(line)) {
1006 dbprintf(_("error writing to mesgfd socket: %s"), strerror(errno));
1010 g_snprintf(line, 1024, "%s/%s restore [./file-to-restore]+\n",
1011 APPLICATION_DIR, prog);
1012 if (full_write(mesgfd, line, strlen(line)) != strlen(line)) {
1013 dbprintf(_("error writing to mesgfd socket: %s"), strerror(errno));
1017 if (dle->compress) {
1018 g_snprintf(line, 1024, "%s: info COMPRESS_SUFFIX=%s\n",
1019 get_pname(), COMPRESS_SUFFIX);
1020 if (full_write(mesgfd, line, strlen(line)) != strlen(line)) {
1021 dbprintf(_("error writing to mesgfd socket: %s"), strerror(errno));
1026 g_snprintf(line, 1024, "%s: info end\n", get_pname());
1027 if (full_write(mesgfd, line, strlen(line)) != strlen(line)) {
1028 dbprintf(_("error writing to mesgfd socket: %s"), strerror(errno));
1044 dbprintf(_("Forking function %s in pipeline\n"), fname);
1046 if(pipe(inpipe) == -1) {
1047 error(_("error [open pipe to %s: %s]"), fname, strerror(errno));
1051 switch(pid = fork()) {
1053 error(_("error [fork %s: %s]"), fname, strerror(errno));
1055 default: /* parent process */
1056 aclose(inpipe[0]); /* close input side of pipe */
1057 *stdinfd = inpipe[1];
1059 case 0: /* child process */
1060 aclose(inpipe[1]); /* close output side of pipe */
1062 if(dup2(inpipe[0], 0) == -1) {
1063 error(_("error [fork %s: dup2(%d, in): %s]"),
1064 fname, inpipe[0], strerror(errno));
1067 if(dup2(stdoutfd, 1) == -1) {
1068 error(_("error [fork %s: dup2(%d, out): %s]"),
1069 fname, stdoutfd, strerror(errno));
1072 if(dup2(stderrfd, 2) == -1) {
1073 error(_("error [fork %s: dup2(%d, err): %s]"),
1074 fname, stderrfd, strerror(errno));
1096 while((wpid = waitpid((pid_t)-1, &retstat, WNOHANG)) > 0) {
1097 if(check_status(wpid, retstat, mesgfd)) goterror = 1;
1100 if (dumppid != -1) {
1102 while((wpid = waitpid((pid_t)-1, &retstat, WNOHANG)) > 0) {
1103 if(check_status(wpid, retstat, mesgfd)) goterror = 1;
1106 if (dumppid != -1) {
1107 dbprintf(_("Sending SIGHUP to dump process %d\n"),
1110 if(kill(dumppid, SIGHUP) == -1) {
1111 dbprintf(_("Can't send SIGHUP to %d: %s\n"),
1117 while((wpid = waitpid((pid_t)-1, &retstat, WNOHANG)) > 0) {
1118 if(check_status(wpid, retstat, mesgfd)) goterror = 1;
1121 if (dumppid != -1) {
1122 dbprintf(_("Sending SIGKILL to dump process %d\n"),
1125 if(kill(dumppid, SIGKILL) == -1) {
1126 dbprintf(_("Can't send SIGKILL to %d: %s\n"),
1132 while((wpid = waitpid((pid_t)-1, &retstat, WNOHANG)) > 0) {
1133 if(check_status(wpid, retstat, mesgfd)) goterror = 1;
1141 parse_backup_messages(
1150 for(; (line = areads(mesgin)) != NULL; free(line)) {
1151 process_dumpline(line);
1155 error(_("error [read mesg pipe: %s]"), strerror(errno));
1159 goterror = check_result(mesgfd);
1162 error(_("error [%s]"), errorstr);
1164 } else if(dump_size == -1) {
1165 error(_("error [no backup size line]"));
1169 program->end_backup(dle, goterror);
1171 fdprintf(mesgfd, _("%s: size %ld\n"), get_pname(), dump_size);
1172 fdprintf(mesgfd, _("%s: end\n"), get_pname());
1184 for(rp = program->re_table; rp->regex != NULL; rp++) {
1185 if(match(rp->regex, str)) {
1189 if(rp->typ == DMP_SIZE) {
1190 dump_size = (long)((the_num(str, rp->field)* rp->scale+1023.0)/1024.0);
1211 * Should never get here.
1217 dbprintf("%3d: %7s(%c): %s\n",
1222 fdprintf(mesgfd, "%c %s\n", startchr, str);
1227 * start_index. Creates an index file from the output of dump/tar.
1228 * It arranges that input is the fd to be written by the dump process.
1229 * If createindex is not enabled, it does nothing. If it is not, a
1230 * new process will be created that tees input both to a pipe whose
1231 * read fd is dup2'ed input and to a program that outputs an index
1234 * make sure that the chat from restore doesn't go to stderr cause
1235 * this goes back to amanda which doesn't expect to see it
1236 * (2>/dev/null should do it)
1238 * Originally by Alan M. McIvor, 13 April 1996
1240 * Adapted by Alexandre Oliva, 1 May 1997
1242 * This program owes a lot to tee.c from GNU sh-utils and dumptee.c
1243 * from the DeeJay backup package.
1253 while (*fd >= 0 && *fd < min) {
1254 int newfd = dup(*fd);
1256 dbprintf(_("Unable to save file descriptor [%s]\n"), strerror(errno));
1260 dbprintf(_("Dupped file descriptor %i to %i\n"), origfd, *fd);
1278 if (pipe(pipefd) != 0) {
1279 error(_("creating index pipe: %s"), strerror(errno));
1283 switch(indexpid = fork()) {
1285 error(_("forking index tee process: %s"), strerror(errno));
1290 if (dup2(pipefd[1], input) == -1) {
1291 error(_("dup'ping index tee output: %s"), strerror(errno));
1301 /* now in a child process */
1302 save_fd(&pipefd[0], 4);
1310 for(index = 4; index < (int)FD_SETSIZE; index++) {
1311 if (index != dbfd()) {
1316 if ((pipe_fp = popen(cmd, "w")) == NULL) {
1317 error(_("couldn't start index creator [%s]"), strerror(errno));
1321 dbprintf(_("Started index creator: \"%s\"\n"), cmd);
1323 char buffer[BUFSIZ], *ptr;
1325 size_t bytes_written;
1326 size_t just_written;
1329 bytes_read = read(0, buffer, SIZEOF(buffer));
1330 } while ((bytes_read < 0) && ((errno == EINTR) || (errno == EAGAIN)));
1332 if (bytes_read < 0) {
1333 error(_("index tee cannot read [%s]"), strerror(errno));
1337 if (bytes_read == 0)
1338 break; /* finished */
1340 /* write the stuff to the subprocess */
1343 just_written = full_write(fileno(pipe_fp), ptr, (size_t)bytes_read);
1344 if (just_written < (size_t)bytes_read) {
1346 * just as we waited for write() to complete.
1348 if (errno != EPIPE) {
1349 dbprintf(_("Index tee cannot write to index creator [%s]\n"),
1353 bytes_written += just_written;
1354 ptr += just_written;
1357 /* write the stuff to stdout, ensuring none lost when interrupt
1361 just_written = full_write(3, ptr, bytes_read);
1362 if (just_written < (size_t)bytes_read) {
1363 error(_("index tee cannot write [%s]"), strerror(errno));
1366 bytes_written += just_written;
1367 ptr += just_written;
1374 /* check the exit code of the pipe and moan if not 0 */
1375 if ((exitcode = pclose(pipe_fp)) != 0) {
1376 char *exitstr = str_exit_status("Index pipe", exitcode);
1377 dbprintf("%s\n", exitstr);
1380 dbprintf(_("Index created successfully\n"));
1387 extern backup_program_t dump_program, gnutar_program;
1389 backup_program_t *programs[] = {
1390 &dump_program, &gnutar_program, NULL