X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=client-src%2Fsendbackup.c;h=dacb961e143ab296e4c4e19e3de67a14994795cd;hb=b116e9366c7b2ea2c2eb53b0a13df4090e176235;hp=e8050448a6544d6b2f298187ac0d835b233fd17d;hpb=2df780bff19c457b0debb7adc29972a0bc2a5dc2;p=debian%2Famanda diff --git a/client-src/sendbackup.c b/client-src/sendbackup.c index e805044..dacb961 100644 --- a/client-src/sendbackup.c +++ b/client-src/sendbackup.c @@ -1,6 +1,6 @@ /* * Amanda, The Advanced Maryland Automatic Network Disk Archiver - * Copyright (c) 1991-1998 University of Maryland at College Park + * Copyright (c) 1991-1999 University of Maryland at College Park * All Rights Reserved. * * Permission to use, copy, modify, distribute, and sell this software and its @@ -24,158 +24,157 @@ * file named AUTHORS, in the root directory of this distribution. */ /* - * $Id: sendbackup.c,v 1.44.2.9.4.4.2.16.2.1 2005/09/20 21:31:52 jrjackson Exp $ + * $Id: sendbackup.c,v 1.88 2006/07/25 18:27:56 martinea Exp $ * * common code for the sendbackup-* programs. */ #include "amanda.h" +#include "match.h" #include "sendbackup.h" #include "clock.h" #include "pipespawn.h" #include "amfeatures.h" -#include "stream.h" #include "arglist.h" #include "getfsent.h" -#include "version.h" +#include "conffile.h" +#include "amandates.h" + +#define sendbackup_debug(i, ...) do { \ + if ((i) <= debug_sendbackup) { \ + dbprintf(__VA_LIST__); \ + } \ +} while (0) #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; +pid_t application_api_pid = (pid_t)-1; char *errorstr = NULL; -int data_socket, data_port, dataf; -int mesg_socket, mesg_port, mesgf; -int index_socket, index_port, indexf; - -option_t *options; +int datafd; +int mesgfd; +int indexfd; -#ifdef KRB4_SECURITY -#include "sendbackup-krb4.h" -#else /* I'd tell you what this does */ -#define NAUGHTY_BITS /* but then I'd have to kill you */ -#endif +g_option_t *g_options = NULL; long dump_size = -1; backup_program_t *program = NULL; +dle_t *gdle = NULL; 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)); +int main(int argc, char **argv); +char *childstr(pid_t pid); +int check_status(pid_t pid, amwait_t w, int mesgfd); + +pid_t pipefork(void (*func)(void), char *fname, int *stdinfd, + int stdoutfd, int stderrfd); +int check_result(int mesgfd); +void parse_backup_messages(dle_t *dle, int mesgin); +static void process_dumpline(char *str); +static void save_fd(int *, int); +void application_api_info_tapeheader(int mesgfd, char *prog, dle_t *dle); + +int fdprintf(int fd, char *format, ...) G_GNUC_PRINTF(2, 3); + +int +fdprintf( + int fd, + char *format, + ...) +{ + va_list argp; + char *s; + int r; + arglist_start(argp, format); + s = g_strdup_vprintf(format, argp); + arglist_end(argp); -char *optionstr(option_t *options) -{ - static char *optstr = NULL; - char *compress_opt = ""; - char *record_opt = ""; - char *bsd_opt = ""; - char *krb4_opt = ""; - char *kencrypt_opt = ""; - char *index_opt = ""; - char *exclude_file_opt; - char *exclude_list_opt; - char *exc = NULL; - sle_t *excl; - - if(options->compress == COMPR_BEST) - compress_opt = "compress-best;"; - else if(options->compress == COMPR_FAST) - compress_opt = "compress-fast;"; - else if(options->compress == COMPR_SERVER_BEST) - compress_opt = "srvcomp-best;"; - else if(options->compress == COMPR_SERVER_FAST) - compress_opt = "srvcomp-fast;"; - if(options->no_record) record_opt = "no-record;"; - if(options->bsd_auth) bsd_opt = "bsd-auth;"; -#ifdef KRB4_SECURITY - if(options->krb4_auth) krb4_opt = "krb4-auth;"; - if(options->kencrypt) kencrypt_opt = "kencrypt;"; -#endif - if(options->createindex) index_opt = "index;"; - - exclude_file_opt = stralloc(""); - if(options->exclude_file) { - for(excl = options->exclude_file->first; excl != NULL; excl=excl->next){ - exc = newvstralloc(exc, "exclude-file=", excl->name, ";", NULL); - strappend(exclude_file_opt, exc); - } - } - exclude_list_opt = stralloc(""); - if(options->exclude_list) { - for(excl = options->exclude_list->first; excl != NULL; excl=excl->next){ - exc = newvstralloc(exc, "exclude-list=", excl->name, ";", NULL); - strappend(exclude_list_opt, exc); - } - } - optstr = newvstralloc(optstr, - compress_opt, - record_opt, - bsd_opt, - krb4_opt, - kencrypt_opt, - index_opt, - exclude_file_opt, - exclude_list_opt, - NULL); - return optstr; + r = full_write(fd, s, strlen(s)); + amfree(s); + return r; } - -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]; + dle_t *dle = NULL; + char *dumpdate, *stroptions; + char *qdisk = NULL; + char *qamdevice = NULL; char *line = NULL; char *err_extra = NULL; char *s; int i; int ch; - unsigned long malloc_hist_1, malloc_size_1; - unsigned long malloc_hist_2, malloc_size_2; + GSList *errlist; + FILE *mesgstream; + level_t *alevel; /* initialize */ - -#ifdef KRB4_SECURITY - safe_fd(KEY_PIPE, 1); /* XXX interface needs to be fixed */ -#else - safe_fd(-1, 0); -#endif + /* + * Configure program for internationalization: + * 1) Only set the message locale for now. + * 2) Set textdomain for all amanda related programs to "amanda" + * We don't want to be forced to support dozens of message catalogs. + */ + setlocale(LC_MESSAGES, "C"); + textdomain("amanda"); + + safe_fd(DATA_FD_OFFSET, DATA_FD_COUNT*2); + openbsd_fd_inform(); safe_cd(); set_pname("sendbackup"); - malloc_size_1 = malloc_inuse(&malloc_hist_1); + /* Don't die when child closes pipe */ + signal(SIGPIPE, SIG_IGN); - interactive = (argc > 1 && strcmp(argv[1],"-t") == 0); - erroutput_type = (ERR_INTERACTIVE|ERR_SYSLOG); - dbopen(); + /* Don't die when interrupt received */ + signal(SIGINT, SIG_IGN); + + if(argc > 1 && strcmp(argv[1],"-t") == 0) { + interactive = 1; + argc--; + argv++; + } else { + interactive = 0; + } + + add_amanda_log_handler(amanda_log_stderr); + add_amanda_log_handler(amanda_log_syslog); + dbopen(DBG_SUBDIR_CLIENT); startclock(); - dbprintf(("%s: version %s\n", argv[0], version())); + dbprintf(_("Version %s\n"), 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); + config_init(CONFIG_INIT_CLIENT, NULL); + /* (check for config errors comes later) */ + + check_running_as(RUNNING_AS_CLIENT_LOGIN); + if(interactive) { /* * In interactive (debug) mode, the backup data is sent to @@ -183,92 +182,130 @@ char **argv; * programs on the tape host are set up. The index service is * run and goes to stdout. */ - fprintf(stderr, "%s: running in interactive test mode\n", get_pname()); + g_fprintf(stderr, _("%s: running in interactive test mode\n"), get_pname()); fflush(stderr); } - prog = NULL; - disk = NULL; - amdevice = NULL; + qdisk = NULL; dumpdate = NULL; stroptions = NULL; - /* parse dump request */ - for(; (line = agets(stdin)) != NULL; free(line)) { + if (line[0] == '\0') + continue; if(interactive) { - fprintf(stderr, "%s> ", get_pname()); + g_fprintf(stderr, "%s> ", get_pname()); fflush(stderr); } -#define sc "OPTIONS " - if(strncmp(line, sc, sizeof(sc)-1) == 0) { -#undef sc + if(strncmp_const(line, "OPTIONS ") == 0) { g_options = parse_g_options(line+8, 1); if(!g_options->hostname) { g_options->hostname = alloc(MAX_HOSTNAME_LENGTH+1); gethostname(g_options->hostname, MAX_HOSTNAME_LENGTH); g_options->hostname[MAX_HOSTNAME_LENGTH] = '\0'; } + + if (g_options->config) { + /* overlay this configuration on the existing (nameless) configuration */ + config_init(CONFIG_INIT_CLIENT | CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_OVERLAY, + g_options->config); + + dbrename(get_config_name(), DBG_SUBDIR_CLIENT); + } + + /* check for any config errors now */ + if (config_errors(&errlist) >= CFGERR_ERRORS) { + char *errstr = config_errors_to_error_string(errlist); + g_printf("%s\n", errstr); + dbclose(); + return 1; + } + + if (am_has_feature(g_options->features, fe_req_xml)) { + break; + } continue; } - if (prog != NULL) { - err_extra = "multiple requests"; + if (dle && dle->program != NULL) { + err_extra = _("multiple requests"); goto err; } + dbprintf(_(" sendbackup req: <%s>\n"), line); + dle = alloc_dle(); + s = line; ch = *s++; skip_whitespace(s, ch); /* find the program name */ if(ch == '\0') { - err_extra = "no program name"; + err_extra = _("no program name"); goto err; /* no program name */ } - prog = s - 1; + dle->program = s - 1; skip_non_whitespace(s, ch); s[-1] = '\0'; - prog = stralloc(prog); + + if (strcmp(dle->program, "APPLICATION")==0) { + dle->program_is_application_api=1; + skip_whitespace(s, ch); /* find dumper name */ + if (ch == '\0') { + goto err; /* no program */ + } + dle->program = s - 1; + skip_non_whitespace(s, ch); + s[-1] = '\0'; + } + dle->program = stralloc(dle->program); skip_whitespace(s, ch); /* find the disk name */ if(ch == '\0') { - err_extra = "no disk name"; + 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); + dle->disk = unquote_string(qdisk); skip_whitespace(s, ch); /* find the device or level */ if (ch == '\0') { - err_extra = "bad level"; + err_extra = _("bad level"); goto err; } if(!isdigit((int)s[-1])) { - amfree(amdevice); - amdevice = s - 1; - skip_non_whitespace(s, ch); + amfree(qamdevice); + qamdevice = s - 1; + ch = *qamdevice; + skip_quoted_string(s, ch); s[-1] = '\0'; - amdevice = stralloc(amdevice); + qamdevice = stralloc(qamdevice); + dle->device = unquote_string(qamdevice); skip_whitespace(s, ch); /* find level number */ } else { - amdevice = stralloc(disk); + dle->device = stralloc(dle->disk); + qamdevice = stralloc(qdisk); } - /* find the level number */ if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) { - err_extra = "bad level"; + err_extra = _("bad level"); goto err; /* bad level */ } skip_integer(s, ch); + alevel = g_new0(level_t, 1); + alevel->level = level; + dle->levellist = g_slist_append(dle->levellist, alevel); skip_whitespace(s, ch); /* find the dump date */ if(ch == '\0') { - err_extra = "no dumpdate"; + err_extra = _("no dumpdate"); goto err; /* no dumpdate */ } amfree(dumpdate); @@ -279,254 +316,489 @@ char **argv; skip_whitespace(s, ch); /* find the options keyword */ if(ch == '\0') { - err_extra = "no options"; + err_extra = _("no options"); goto err; /* no options */ } -#define sc "OPTIONS " - if(strncmp(s - 1, sc, sizeof(sc)-1) != 0) { - err_extra = "no OPTIONS keyword"; + if(strncmp_const_skip(s - 1, "OPTIONS ", s, ch) != 0) { + err_extra = _("no OPTIONS keyword"); goto err; /* no options */ } - s += sizeof(sc)-1; - ch = s[-1]; -#undef sc skip_whitespace(s, ch); /* find the options string */ if(ch == '\0') { - err_extra = "bad options string"; + err_extra = _("bad options string"); goto err; /* no options */ } amfree(stroptions); stroptions = stralloc(s - 1); } amfree(line); + if (g_options == NULL) { + g_printf(_("ERROR [Missing OPTIONS line in sendbackup input]\n")); + error(_("Missing OPTIONS line in sendbackup input\n")); + /*NOTREACHED*/ + } - dbprintf((" parsed request as: program `%s'\n", prog)); - dbprintf((" disk `%s'\n", disk)); - dbprintf((" device `%s'\n", amdevice)); - dbprintf((" level %d\n", level)); - dbprintf((" since %s\n", dumpdate)); - dbprintf((" options `%s'\n", stroptions)); + if (am_has_feature(g_options->features, fe_req_xml)) { + char *errmsg = NULL; - for(i = 0; programs[i] != NULL; i++) { - if (strcmp(programs[i]->name, prog) == 0) { - break; + dle = amxml_parse_node_FILE(stdin, &errmsg); + if (errmsg) { + err_extra = errmsg; + goto err; + } + if (!dle) { + err_extra = _("One DLE required"); + goto err; + } else if (dle->next) { + err_extra = _("Only one DLE allowed"); + goto err; } + + qdisk = quote_string(dle->disk); + if (dle->device == NULL) + dle->device = stralloc(dle->disk); + qamdevice = quote_string(dle->device); + dumpdate = stralloc("NODATE"); + stroptions = stralloc(""); + } else { + parse_options(stroptions, dle, g_options->features, 0); } - if (programs[i] == NULL) { - error("ERROR [%s: unknown program %s]", get_pname(), prog); + gdle = dle; + + if (dle->program == NULL || + dle->disk == NULL || + dle->device == NULL || + dle->levellist == NULL || + dumpdate == NULL) { + err_extra = _("no valid sendbackup request"); + goto err; } - program = programs[i]; - options = parse_options(stroptions, disk, amdevice, g_options->features, 0); + if (g_slist_length(dle->levellist) != 1) { + err_extra = _("Too many level"); + goto err; + } -#ifdef KRB4_SECURITY - /* modification by BIS@BBN 4/25/2003: - * with the option processing changes in amanda 2.4.4, must change - * the conditional from krb4_auth to options->krb4_auth */ - if(options->krb4_auth) { - if(read(KEY_PIPE, session_key, sizeof session_key) - != sizeof session_key) { - error("ERROR [%s: could not read session key]", get_pname()); + alevel = (level_t *)dle->levellist->data; + level = alevel->level; + dbprintf(_(" Parsed request as: program `%s'\n"), dle->program); + 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); + dbprintf(_(" datapath `%s'\n"), + data_path_to_string(dle->data_path)); + + if (dle->program_is_application_api==1) { + /* check that the application_api exist */ + } else { + for(i = 0; programs[i]; i++) { + if (strcmp(programs[i]->name, dle->program) == 0) { + break; + } } + if (programs[i] == NULL) { + dbprintf(_("ERROR [%s: unknown program %s]\n"), get_pname(), + dle->program); + error(_("ERROR [%s: unknown program %s]"), get_pname(), + dle->program); + /*NOTREACHED*/ + } + program = programs[i]; } -#endif if(!interactive) { - data_socket = stream_server(&data_port, STREAM_BUFSIZE, -1); - if(data_socket < 0) { - error("ERROR [%s: could not create data socket: %s]", - get_pname(), strerror(errno)); - } - mesg_socket = stream_server(&mesg_port, -1, -1); - if(mesg_socket < 0) { - error("ERROR [%s: could not create mesg socket: %s]", - get_pname(), strerror(errno)); - } + datafd = DATA_FD_OFFSET + 0; + mesgfd = DATA_FD_OFFSET + 2; + indexfd = DATA_FD_OFFSET + 4; } - if (!interactive && options->createindex) { - index_socket = stream_server(&index_port, -1, -1); - if(index_socket < 0) { - error("ERROR [%s: could not create index socket: %s]", - get_pname(), strerror(errno)); - } - } else { - index_port = -1; + if (!dle->create_index) + indexfd = -1; + + if (dle->auth && amandad_auth) { + if(strcasecmp(dle->auth, amandad_auth) != 0) { + g_printf(_("ERROR [client configured for auth=%s while server requested '%s']\n"), + amandad_auth, dle->auth); + exit(-1); + } + } + + if (dle->kencrypt) { + g_printf("KENCRYPT\n"); } - printf("CONNECT DATA %d MESG %d INDEX %d\n", - data_port, mesg_port, index_port); - printf("OPTIONS "); + g_printf(_("CONNECT DATA %d MESG %d INDEX %d\n"), + DATA_FD_OFFSET, DATA_FD_OFFSET+1, + indexfd == -1 ? -1 : DATA_FD_OFFSET+2); + g_printf(_("OPTIONS ")); if(am_has_feature(g_options->features, fe_rep_options_features)) { - printf("features=%s;", our_feature_string); + g_printf("features=%s;", our_feature_string); } if(am_has_feature(g_options->features, fe_rep_options_hostname)) { - printf("hostname=%s;", g_options->hostname); + g_printf("hostname=%s;", g_options->hostname); } - if(am_has_feature(g_options->features, fe_rep_options_sendbackup_options)) { - printf("%s", optionstr(options)); + if (!am_has_feature(g_options->features, fe_rep_options_features) && + !am_has_feature(g_options->features, fe_rep_options_hostname)) { + g_printf(";"); } - printf("\n"); + g_printf("\n"); fflush(stdout); - freopen("/dev/null", "w", stdout); - - if (options->createindex) - dbprintf(("%s: waiting for connect on %d, then %d, then %d\n", - debug_prefix_time(NULL), data_port, mesg_port, index_port)); - else - dbprintf(("%s: waiting for connect on %d, then %d\n", - debug_prefix_time(NULL), data_port, mesg_port)); - - if(interactive) { - if((dataf = open("/dev/null", O_RDWR)) < 0) { - error("ERROR [%s: open of /dev/null for debug data stream: %s]", - get_pname(), strerror(errno)); - } - mesgf = 2; - } else { - dataf = stream_accept(data_socket, TIMEOUT, -1, -1); - if(dataf == -1) { - dbprintf(("%s: timeout on data port %d\n", - debug_prefix_time(NULL), data_port)); - } - mesgf = stream_accept(mesg_socket, TIMEOUT, -1, -1); - if(mesgf == -1) { - dbprintf(("%s: timeout on mesg port %d\n", - debug_prefix_time(NULL), mesg_port)); - } + if (freopen("/dev/null", "w", stdout) == NULL) { + dbprintf(_("Error redirecting stdout to /dev/null: %s\n"), + strerror(errno)); + exit(1); } + if(interactive) { - indexf = 1; - } else if (options->createindex) { - indexf = stream_accept(index_socket, TIMEOUT, -1, -1); - if (indexf == -1) { - dbprintf(("%s: timeout on index port %d\n", - debug_prefix_time(NULL), index_port)); + if((datafd = open("/dev/null", O_RDWR)) < 0) { + error(_("ERROR [open of /dev/null for debug data stream: %s]\n"), + strerror(errno)); + /*NOTREACHED*/ } + mesgfd = 2; + indexfd = 1; } if(!interactive) { - if(dataf == -1 || mesgf == -1 || (options->createindex && indexf == -1)) { + if(datafd == -1 || mesgfd == -1 || (dle->create_index && indexfd == -1)) { dbclose(); exit(1); } } - dbprintf(("%s: got all connections\n", debug_prefix_time(NULL))); + mesgstream = fdopen(mesgfd,"w"); + run_client_scripts(EXECUTE_ON_PRE_DLE_BACKUP, g_options, dle, mesgstream); + fflush(mesgstream); + + if (dle->program_is_application_api==1) { + guint j; + char *cmd=NULL; + GPtrArray *argv_ptr; + char levelstr[20]; + backup_support_option_t *bsu; + char *compopt = NULL; + char *encryptopt = skip_argument; + int compout, dumpout; + GSList *scriptlist; + script_t *script; + time_t cur_dumptime; + int result; + GPtrArray *errarray; + int errfd[2]; + FILE *dumperr; + + /* apply client-side encryption here */ + if ( dle->encrypt == ENCRYPT_CUST ) { + encpid = pipespawn(dle->clnt_encrypt, STDIN_PIPE, 0, + &compout, &datafd, &mesgfd, + dle->clnt_encrypt, encryptopt, NULL); + dbprintf(_("encrypt: pid %ld: %s\n"), (long)encpid, dle->clnt_encrypt); + } else { + compout = datafd; + encpid = -1; + } -#ifdef KRB4_SECURITY - if(!interactive) { - /* modification by BIS@BBN 4/25/2003: - * with the option processing changes in amanda 2.4.4, must change - * the conditional from krb4_auth to options->krb4_auth */ - if (options->krb4_auth) { - if(kerberos_handshake(dataf, session_key) == 0) { - dbprintf(("%s: kerberos_handshake on data socket failed\n", - debug_prefix_time(NULL))); - dbclose(); - exit(1); - } else { - dbprintf(("%s: kerberos_handshake on data socket succeeded\n", - debug_prefix_time(NULL))); + /* now do the client-side compression */ + if(dle->compress == COMP_FAST || dle->compress == COMP_BEST) { + compopt = skip_argument; +#if defined(COMPRESS_BEST_OPT) && defined(COMPRESS_FAST_OPT) + if(dle->compress == COMP_BEST) { + compopt = COMPRESS_BEST_OPT; + } else { + compopt = COMPRESS_FAST_OPT; + } +#endif + comppid = pipespawn(COMPRESS_PATH, STDIN_PIPE, 0, + &dumpout, &compout, &mesgfd, + COMPRESS_PATH, compopt, NULL); + if(compopt != skip_argument) { + dbprintf(_("compress pid %ld: %s %s\n"), + (long)comppid, COMPRESS_PATH, compopt); + } else { + dbprintf(_("compress pid %ld: %s\n"), (long)comppid, COMPRESS_PATH); + } + } else if (dle->compress == COMP_CUST) { + compopt = skip_argument; + comppid = pipespawn(dle->compprog, STDIN_PIPE, 0, + &dumpout, &compout, &mesgfd, + dle->compprog, compopt, NULL); + if(compopt != skip_argument) { + dbprintf(_("pid %ld: %s %s\n"), + (long)comppid, dle->compprog, compopt); + } else { + dbprintf(_("pid %ld: %s\n"), (long)comppid, dle->compprog); + } + } else { + dumpout = compout; + comppid = -1; + } + + cur_dumptime = time(0); + bsu = backup_support_option(dle->program, g_options, dle->disk, + dle->device, &errarray); + if (!bsu) { + char *errmsg; + char *qerrmsg; + guint i; + for (i=0; i < errarray->len; i++) { + errmsg = g_ptr_array_index(errarray, i); + qerrmsg = quote_string(errmsg); + fdprintf(mesgfd, + _("sendbackup: error [Application '%s': %s]\n"), + dle->program, errmsg); + dbprintf("aa: %s\n",qerrmsg); + amfree(qerrmsg); + } + if (i == 0) { /* no errarray */ + errmsg = vstrallocf(_("Can't execute application '%s'"), + dle->program); + qerrmsg = quote_string(errmsg); + fdprintf(mesgfd, _("sendbackup: error [%s]\n"), errmsg); + dbprintf(_("ERROR %s\n"), qerrmsg); + amfree(qerrmsg); + amfree(errmsg); + } + return 0; + } + if (pipe(errfd) < 0) { + char *errmsg; + char *qerrmsg; + errmsg = vstrallocf(_("Application '%s': can't create pipe"), + dle->program); + qerrmsg = quote_string(errmsg); + fdprintf(mesgfd, _("sendbackup: error [%s]\n"), errmsg); + dbprintf(_("ERROR %s\n"), qerrmsg); + amfree(qerrmsg); + amfree(errmsg); + return 0; } - if(kerberos_handshake(mesgf, session_key) == 0) { - dbprintf(("%s: kerberos_handshake on mesg socket failed\n", - debug_prefix_time(NULL))); - dbclose(); + switch(application_api_pid=fork()) { + case 0: + argv_ptr = g_ptr_array_new(); + cmd = vstralloc(APPLICATION_DIR, "/", dle->program, NULL); + g_ptr_array_add(argv_ptr, stralloc(dle->program)); + g_ptr_array_add(argv_ptr, stralloc("backup")); + if (bsu->message_line == 1) { + g_ptr_array_add(argv_ptr, stralloc("--message")); + g_ptr_array_add(argv_ptr, stralloc("line")); + } + if (g_options->config && bsu->config == 1) { + g_ptr_array_add(argv_ptr, stralloc("--config")); + g_ptr_array_add(argv_ptr, stralloc(g_options->config)); + } + if (g_options->hostname && bsu->host == 1) { + g_ptr_array_add(argv_ptr, stralloc("--host")); + g_ptr_array_add(argv_ptr, stralloc(g_options->hostname)); + } + if (dle->disk && bsu->disk == 1) { + g_ptr_array_add(argv_ptr, stralloc("--disk")); + g_ptr_array_add(argv_ptr, stralloc(dle->disk)); + } + g_ptr_array_add(argv_ptr, stralloc("--device")); + g_ptr_array_add(argv_ptr, stralloc(dle->device)); + if (level <= bsu->max_level) { + g_ptr_array_add(argv_ptr, stralloc("--level")); + g_snprintf(levelstr,19,"%d",level); + g_ptr_array_add(argv_ptr, stralloc(levelstr)); + } + if (indexfd != -1 && bsu->index_line == 1) { + g_ptr_array_add(argv_ptr, stralloc("--index")); + g_ptr_array_add(argv_ptr, stralloc("line")); + } + if (dle->record && bsu->record == 1) { + g_ptr_array_add(argv_ptr, stralloc("--record")); + } + application_property_add_to_argv(argv_ptr, dle, bsu, + g_options->features); + + for (scriptlist = dle->scriptlist; scriptlist != NULL; + scriptlist = scriptlist->next) { + script = (script_t *)scriptlist->data; + if (script->result && script->result->proplist) { + property_add_to_argv(argv_ptr, script->result->proplist); + } + } + + g_ptr_array_add(argv_ptr, NULL); + dbprintf(_("%s: running \"%s\n"), get_pname(), cmd); + for (j = 1; j < argv_ptr->len - 1; j++) + dbprintf(" %s\n", (char *)g_ptr_array_index(argv_ptr,j)); + dbprintf(_("\"\n")); + if(dup2(dumpout, 1) == -1) { + error(_("Can't dup2: %s"),strerror(errno)); + /*NOTREACHED*/ + } + if (dup2(errfd[1], 2) == -1) { + error(_("Can't dup2: %s"),strerror(errno)); + /*NOTREACHED*/ + } + if(dup2(mesgfd, 3) == -1) { + error(_("Can't dup2: %s"),strerror(errno)); + /*NOTREACHED*/ + } + if(indexfd > 0) { + if(dup2(indexfd, 4) == -1) { + error(_("Can't dup2: %s"),strerror(errno)); + /*NOTREACHED*/ + } + fcntl(indexfd, F_SETFD, 0); + } + application_api_info_tapeheader(mesgfd, dle->program, dle); + if (indexfd != 0) { + safe_fd(3, 2); + } else { + safe_fd(3, 1); + } + execve(cmd, (char **)argv_ptr->pdata, safe_env()); exit(1); - } else { - dbprintf(("%s: kerberos_handshake on mesg socket succeeded\n", - debug_prefix_time(NULL))); + break; + + default: + break; + case -1: + error(_("%s: fork returned: %s"), get_pname(), strerror(errno)); + } + close(errfd[1]); + dumperr = fdopen(errfd[0],"r"); + if (!dumperr) { + error(_("Can't fdopen: %s"), strerror(errno)); + /*NOTREACHED*/ } - dbprintf(("%s: kerberos handshakes succeeded!\n", - debug_prefix_time(NULL))); - } - } -#endif + result = 0; + while ((line = agets(dumperr)) != NULL) { + if (strlen(line) > 0) { + fdprintf(mesgfd, "sendbackup: error [%s]\n", line); + dbprintf("error: %s\n", line); + result = 1; + } + amfree(line); + } - if(!interactive) { - /* redirect stderr */ - if(dup2(mesgf, 2) == -1) { - dbprintf(("%s: error redirecting stderr: %s\n", - debug_prefix(NULL), strerror(errno))); - dbclose(); - exit(1); - } - } + result |= check_result(mesgfd); + if (result == 0) { + char *amandates_file; + + amandates_file = getconf_str(CNF_AMANDATES); + if(start_amandates(amandates_file, 1)) { + amandates_updateone(dle->disk, level, cur_dumptime); + finish_amandates(); + free_amandates(); + } else { + if (GPOINTER_TO_INT(dle->estimatelist->data) == ES_CALCSIZE && + bsu->calcsize) { + error(_("error [opening %s for writing: %s]"), + amandates_file, strerror(errno)); + } else { + g_debug(_("non-fatal error opening '%s' for writing: %s]"), + amandates_file, strerror(errno)); + } + } + } + amfree(bsu); + } else { + if(!interactive) { + /* redirect stderr */ + if(dup2(mesgfd, 2) == -1) { + dbprintf(_("Error redirecting stderr to fd %d: %s\n"), + mesgfd, strerror(errno)); + dbclose(); + exit(1); + } + } + + if(pipe(mesgpipe) == -1) { + s = strerror(errno); + dbprintf(_("error [opening mesg pipe: %s]\n"), s); + error(_("error [opening mesg pipe: %s]"), s); + } - if(pipe(mesgpipe) == -1) { - error("error [opening mesg pipe: %s]", strerror(errno)); + program->start_backup(dle, g_options->hostname, + datafd, mesgpipe[1], indexfd); + dbprintf(_("Started backup\n")); + parse_backup_messages(dle, mesgpipe[0]); + dbprintf(_("Parsed backup messages\n")); } - program->start_backup(g_options->hostname, disk, amdevice, level, dumpdate, - dataf, mesgpipe[1], indexf); - parse_backup_messages(mesgpipe[0]); + run_client_scripts(EXECUTE_ON_POST_DLE_BACKUP, g_options, dle, mesgstream); + fflush(mesgstream); - amfree(prog); - amfree(disk); - amfree(amdevice); + amfree(qdisk); + amfree(qamdevice); amfree(dumpdate); amfree(stroptions); amfree(our_feature_string); am_release_feature_set(our_features); our_features = NULL; - am_release_feature_set(g_options->features); - g_options->features = NULL; - amfree(g_options->hostname); - amfree(g_options->str); - amfree(g_options); + free_g_options(g_options); dbclose(); - malloc_size_2 = malloc_inuse(&malloc_hist_2); + return 0; - if(malloc_size_1 != malloc_size_2) { - malloc_list(fileno(stderr), malloc_hist_1, malloc_hist_2); + err: + if (err_extra) { + g_printf(_("ERROR FORMAT ERROR IN REQUEST PACKET '%s'\n"), err_extra); + dbprintf(_("REQ packet is bogus: %s\n"), err_extra); + } else { + g_printf(_("ERROR FORMAT ERROR IN REQUEST PACKET\n")); + dbprintf(_("REQ packet is bogus\n")); } - return 0; + amfree(qdisk); + amfree(qamdevice); + amfree(dumpdate); + amfree(stroptions); + amfree(our_feature_string); - err: - printf("FORMAT ERROR IN REQUEST PACKET\n"); - dbprintf(("%s: REQ packet is bogus%s%s\n", - debug_prefix_time(NULL), - err_extra ? ": " : "", - err_extra ? err_extra : "")); dbclose(); 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"; - if(pid == encpid) return "kencrypt"; + if(pid == encpid) return "encrypt"; if(pid == indexpid) return "index"; + if(pid == application_api_pid) { + if (!gdle) { + dbprintf("gdle == NULL\n"); + return "gdle == NULL"; + } + return gdle->program; + } return "unknown"; } -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, + int mesgfd) { char *thiserr = NULL; - char *str; + char *str, *strX; int ret, sig, rc; - char number[NUM_STR_SIZE]; str = childstr(pid); @@ -545,59 +817,68 @@ amwait_t w; * but the failure is noted. */ if(ret != 0) { - fprintf(stderr, "? %s returned %d\n", str, ret); + fdprintf(mesgfd, _("? index %s returned %d\n"), str, ret); rc = 0; } - } - -#ifndef HAVE_GZIP - if(pid == comppid) { + indexpid = -1; + strX = "index"; + } else if(pid == comppid) { /* * compress returns 2 sometimes, but it is ok. */ +#ifndef HAVE_GZIP if(ret == 2) { rc = 0; } - } #endif - -#ifdef DUMP_RETURNS_1 - if(pid == dumppid && tarpid == -1) { + comppid = -1; + strX = "compress"; + } else if(pid == dumppid && tarpid == -1) { /* * Ultrix dump returns 1 sometimes, but it is ok. */ +#ifdef DUMP_RETURNS_1 if(ret == 1) { rc = 0; } - } #endif - -#ifdef IGNORE_TAR_ERRORS - if(pid == tarpid) { + dumppid = -1; + strX = "dump"; + } else if(pid == tarpid) { + if (ret == 1) { + rc = 0; + } /* * tar bitches about active filesystems, but we do not care. */ +#ifdef IGNORE_TAR_ERRORS if(ret == 2) { rc = 0; } - } #endif + dumppid = tarpid = -1; + strX = "dump"; + } else if(pid == application_api_pid) { + strX = "Application"; + } else { + strX = "unknown"; + } if(rc == 0) { return 0; /* normal exit */ } if(ret == 0) { - ap_snprintf(number, sizeof(number), "%d", sig); - thiserr = vstralloc(str, " got signal ", number, NULL); + thiserr = vstrallocf(_("%s (%d) %s got signal %d"), strX, (int)pid, str, + sig); } else { - ap_snprintf(number, sizeof(number), "%d", ret); - thiserr = vstralloc(str, " returned ", number, NULL); + thiserr = vstrallocf(_("%s (%d) %s returned %d"), strX, (int)pid, str, ret); } + fdprintf(mesgfd, "? %s\n", thiserr); + if(errorstr) { - strappend(errorstr, ", "); - strappend(errorstr, thiserr); + errorstr = newvstrallocf(errorstr, "%s, %s", errorstr, thiserr); amfree(thiserr); } else { errorstr = thiserr; @@ -607,15 +888,18 @@ amwait_t w; } -/* Send header info to the message file. -*/ -void write_tapeheader() +/* + *Send header info to the message file. + */ +void +info_tapeheader( + dle_t *dle) { - fprintf(stderr, "%s: info BACKUP=%s\n", get_pname(), program->backup_name); + g_fprintf(stderr, "%s: info BACKUP=%s\n", get_pname(), program->backup_name); - fprintf(stderr, "%s: info RECOVER_CMD=", get_pname()); - if (options->compress == COMPR_FAST || options->compress == COMPR_BEST) - fprintf(stderr, "%s %s |", UNCOMPRESS_PATH, + g_fprintf(stderr, "%s: info RECOVER_CMD=", get_pname()); + if (dle->compress == COMP_FAST || dle->compress == COMP_BEST) + g_fprintf(stderr, "%s %s |", UNCOMPRESS_PATH, #ifdef UNCOMPRESS_OPT UNCOMPRESS_OPT #else @@ -623,33 +907,99 @@ void write_tapeheader() #endif ); - fprintf(stderr, "%s -f... -\n", program->restore_name); + g_fprintf(stderr, "%s -xpGf - ...\n", program->restore_name); - if (options->compress == COMPR_FAST || options->compress == COMPR_BEST) - fprintf(stderr, "%s: info COMPRESS_SUFFIX=%s\n", + if (dle->compress == COMP_FAST || dle->compress == COMP_BEST) + g_fprintf(stderr, "%s: info COMPRESS_SUFFIX=%s\n", get_pname(), COMPRESS_SUFFIX); - fprintf(stderr, "%s: info end\n", get_pname()); + g_fprintf(stderr, "%s: info end\n", get_pname()); +} + +void +application_api_info_tapeheader( + int mesgfd, + char *prog, + dle_t *dle) +{ + char line[1024]; + + g_snprintf(line, 1024, "%s: info BACKUP=APPLICATION\n", get_pname()); + if (full_write(mesgfd, line, strlen(line)) != strlen(line)) { + dbprintf(_("error writing to mesgfd socket: %s"), strerror(errno)); + return; + } + + g_snprintf(line, 1024, "%s: info APPLICATION=%s\n", get_pname(), prog); + if (full_write(mesgfd, line, strlen(line)) != strlen(line)) { + dbprintf(_("error writing to mesgfd socket: %s"), strerror(errno)); + return; + } + + g_snprintf(line, 1024, "%s: info RECOVER_CMD=", get_pname()); + if (full_write(mesgfd, line, strlen(line)) != strlen(line)) { + dbprintf(_("error writing to mesgfd socket: %s"), strerror(errno)); + return; + } + + if (dle->compress == COMP_FAST || dle->compress == COMP_BEST) { + g_snprintf(line, 1024, "%s %s |", UNCOMPRESS_PATH, +#ifdef UNCOMPRESS_OPT + UNCOMPRESS_OPT +#else + "" +#endif + ); + if (full_write(mesgfd, line, strlen(line)) != strlen(line)) { + dbprintf(_("error writing to mesgfd socket: %s"), strerror(errno)); + return; + } + } + g_snprintf(line, 1024, "%s/%s restore [./file-to-restore]+\n", + APPLICATION_DIR, prog); + if (full_write(mesgfd, line, strlen(line)) != strlen(line)) { + dbprintf(_("error writing to mesgfd socket: %s"), strerror(errno)); + return; + } + + if (dle->compress) { + g_snprintf(line, 1024, "%s: info COMPRESS_SUFFIX=%s\n", + get_pname(), COMPRESS_SUFFIX); + if (full_write(mesgfd, line, strlen(line)) != strlen(line)) { + dbprintf(_("error writing to mesgfd socket: %s"), strerror(errno)); + return; + } + } + + g_snprintf(line, 1024, "%s: info end\n", get_pname()); + if (full_write(mesgfd, line, strlen(line)) != strlen(line)) { + dbprintf(_("error writing to mesgfd socket: %s"), strerror(errno)); + return; + } } -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)); + dbprintf(_("Forking function %s in pipeline\n"), fname); if(pipe(inpipe) == -1) { - error("error [open pipe to %s: %s]", fname, strerror(errno)); + error(_("error [open pipe to %s: %s]"), fname, strerror(errno)); + /*NOTREACHED*/ } switch(pid = fork()) { case -1: - error("error [fork %s: %s]", fname, strerror(errno)); + error(_("error [fork %s: %s]"), fname, strerror(errno)); + /*NOTREACHED*/ default: /* parent process */ aclose(inpipe[0]); /* close input side of pipe */ *stdinfd = inpipe[1]; @@ -658,30 +1008,91 @@ int stdoutfd, stderrfd; aclose(inpipe[1]); /* close output side of pipe */ if(dup2(inpipe[0], 0) == -1) { - error("error [dup2 0 %s: dup2 in: %s]", fname, strerror(errno)); + error(_("error [fork %s: dup2(%d, in): %s]"), + fname, inpipe[0], strerror(errno)); + /*NOTRACHED*/ } if(dup2(stdoutfd, 1) == -1) { - error("error [dup2 1 %s: dup2 out: %s]", fname, strerror(errno)); + error(_("error [fork %s: dup2(%d, out): %s]"), + fname, stdoutfd, strerror(errno)); + /*NOTRACHED*/ } if(dup2(stderrfd, 2) == -1) { - error("error [dup2 2 %s: dup2 err: %s]", fname, strerror(errno)); + 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; +int +check_result( + int mesgfd) { - int goterror, wpid; + int goterror; + pid_t wpid; amwait_t retstat; - char *line; goterror = 0; + + + while((wpid = waitpid((pid_t)-1, &retstat, WNOHANG)) > 0) { + if(check_status(wpid, retstat, mesgfd)) goterror = 1; + } + + if (dumppid != -1) { + sleep(5); + while((wpid = waitpid((pid_t)-1, &retstat, WNOHANG)) > 0) { + if(check_status(wpid, retstat, mesgfd)) goterror = 1; + } + } + if (dumppid != -1) { + dbprintf(_("Sending SIGHUP to dump process %d\n"), + (int)dumppid); + if(dumppid != -1) { + if(kill(dumppid, SIGHUP) == -1) { + dbprintf(_("Can't send SIGHUP to %d: %s\n"), + (int)dumppid, + strerror(errno)); + } + } + sleep(5); + while((wpid = waitpid((pid_t)-1, &retstat, WNOHANG)) > 0) { + if(check_status(wpid, retstat, mesgfd)) goterror = 1; + } + } + if (dumppid != -1) { + dbprintf(_("Sending SIGKILL to dump process %d\n"), + (int)dumppid); + if(dumppid != -1) { + if(kill(dumppid, SIGKILL) == -1) { + dbprintf(_("Can't send SIGKILL to %d: %s\n"), + (int)dumppid, + strerror(errno)); + } + } + sleep(5); + while((wpid = waitpid((pid_t)-1, &retstat, WNOHANG)) > 0) { + if(check_status(wpid, retstat, mesgfd)) goterror = 1; + } + } + + return goterror; +} + +void +parse_backup_messages( + dle_t *dle, + int mesgin) +{ + int goterror; + char *line; + amfree(errorstr); for(; (line = areads(mesgin)) != NULL; free(line)) { @@ -689,52 +1100,32 @@ int mesgin; } if(errno) { - error("error [read mesg pipe: %s]", strerror(errno)); + error(_("error [read mesg pipe: %s]"), strerror(errno)); + /*NOTREACHED*/ } - while((wpid = wait(&retstat)) != -1) { - if(check_status(wpid, retstat)) goterror = 1; - } + goterror = check_result(mesgfd); if(errorstr) { - error("error [%s]", errorstr); + error(_("error [%s]"), errorstr); + /*NOTREACHED*/ } else if(dump_size == -1) { - error("error [no backup size line]"); + error(_("error [no backup size line]")); + /*NOTREACHED*/ } - program->end_backup(goterror); + program->end_backup(dle, goterror); - fprintf(stderr, "%s: size %ld\n", get_pname(), dump_size); - fprintf(stderr, "%s: end\n", get_pname()); + fdprintf(mesgfd, _("%s: size %ld\n"), get_pname(), dump_size); + fdprintf(mesgfd, _("%s: end\n"), get_pname()); } -double first_num P((char *str)); - -double first_num(str) -char *str; -/* - * Returns the value of the first integer in a string. - */ +static void +process_dumpline( + char * str) { - char *num; - int ch; - double d; - - ch = *str++; - while(ch && !isdigit(ch)) ch = *str++; - num = str - 1; - while(isdigit(ch) || ch == '.') ch = *str++; - str[-1] = '\0'; - d = atof(num); - str[-1] = ch; - return d; -} - -static void process_dumpline(str) -char *str; -{ - regex_t *rp; + amregex_t *rp; char *type; char startchr; @@ -744,7 +1135,7 @@ char *str; } } if(rp->typ == DMP_SIZE) { - dump_size = (long)((first_num(str) * rp->scale + 1023.0)/1024.0); + dump_size = (long)((the_num(str, rp->field)* rp->scale+1023.0)/1024.0); } switch(rp->typ) { case DMP_NORMAL: @@ -771,66 +1162,60 @@ char *str; startchr = '!'; break; } - dbprintf(("%s: %3d: %7s(%c): %s\n", - debug_prefix_time(NULL), + dbprintf("%3d: %7s(%c): %s\n", rp->srcline, type, startchr, - str)); - fprintf(stderr, "%c %s\n", startchr, str); + str); + fdprintf(mesgfd, "%c %s\n", startchr, str); } -/* 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; - -static void index_closed(sig) -int sig; -{ - index_finished = 1; -} +/* + * 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. + */ -void save_fd(fd, min) -int *fd, min; +static void +save_fd( + int * fd, + int min) { int origfd = *fd; while (*fd >= 0 && *fd < min) { int newfd = dup(*fd); if (newfd == -1) - dbprintf(("%s: unable to save file descriptor [%s]\n", - debug_prefix(NULL), strerror(errno))); + dbprintf(_("Unable to save file descriptor [%s]\n"), strerror(errno)); *fd = newfd; } if (origfd != *fd) - dbprintf(("%s: dupped file descriptor %i to %i\n", - debug_prefix(NULL), origfd, *fd)); + dbprintf(_("Dupped file descriptor %i to %i\n"), 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) { - struct sigaction act, oact; int pipefd[2]; FILE *pipe_fp; int exitcode; @@ -839,17 +1224,20 @@ char *cmd; return; if (pipe(pipefd) != 0) { - error("creating index pipe: %s", strerror(errno)); + error(_("creating index pipe: %s"), strerror(errno)); + /*NOTREACHED*/ } switch(indexpid = fork()) { case -1: - error("forking index tee process: %s", strerror(errno)); + 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)); + error(_("dup'ping index tee output: %s"), strerror(errno)); + /*NOTREACHED*/ } aclose(pipefd[1]); return; @@ -867,40 +1255,31 @@ char *cmd; dup2(index, 1); dup2(mesg, 2); dup2(input, 3); - for(index = 4; index < FD_SETSIZE; index++) { + for(index = 4; index < (int)FD_SETSIZE; index++) { if (index != dbfd()) { close(index); } } - /* set up a signal handler for SIGPIPE for when the pipe is finished - creating the index file */ - /* at that point we obviously want to stop writing to it */ - act.sa_handler = index_closed; - sigemptyset(&act.sa_mask); - act.sa_flags = 0; - if (sigaction(SIGPIPE, &act, &oact) != 0) { - error("couldn't set index SIGPIPE handler [%s]", strerror(errno)); - } - if ((pipe_fp = popen(cmd, "w")) == NULL) { - error("couldn't start index creator [%s]", strerror(errno)); + error(_("couldn't start index creator [%s]"), strerror(errno)); + /*NOTREACHED*/ } - dbprintf(("%s: started index creator: \"%s\"\n", - debug_prefix_time(NULL), cmd)); + dbprintf(_("Started index creator: \"%s\"\n"), cmd); while(1) { char buffer[BUFSIZ], *ptr; - int bytes_read; - int bytes_written; - int just_written; + ssize_t bytes_read; + size_t bytes_written; + size_t just_written; - bytes_read = read(0, buffer, sizeof(buffer)); - if ((bytes_read < 0) && (errno == EINTR)) - continue; + do { + 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)); + error(_("index tee cannot read [%s]"), strerror(errno)); + /*NOTREACHED*/ } if (bytes_read == 0) @@ -909,36 +1288,31 @@ char *cmd; /* write the stuff to the subprocess */ ptr = buffer; bytes_written = 0; - while (bytes_read > bytes_written && !index_finished) { - just_written = write(fileno(pipe_fp), ptr, bytes_read - bytes_written); - if (just_written < 0) { - /* the signal handler may have assigned to index_finished - * just as we waited for write() to complete. */ - if (!index_finished) { - dbprintf(("%s: index tee cannot write to index creator [%s]\n", - debug_prefix_time(NULL), strerror(errno))); - index_finished = 1; - } - } else { + just_written = full_write(fileno(pipe_fp), ptr, (size_t)bytes_read); + if (just_written < (size_t)bytes_read) { + /* + * just as we waited for write() to complete. + */ + if (errno != EPIPE) { + dbprintf(_("Index tee cannot write to index creator [%s]\n"), + strerror(errno)); + } + } else { bytes_written += just_written; ptr += just_written; - } } /* write the stuff to stdout, ensuring none lost when interrupt occurs */ ptr = buffer; bytes_written = 0; - while (bytes_read > bytes_written) { - just_written = write(3, ptr, bytes_read - bytes_written); - if ((just_written < 0) && (errno == EINTR)) - continue; - if (just_written < 0) { - error("index tee cannot write [%s]", strerror(errno)); - } else { + just_written = full_write(3, ptr, bytes_read); + if (just_written < (size_t)bytes_read) { + error(_("index tee cannot write [%s]"), strerror(errno)); + /*NOTREACHED*/ + } else { bytes_written += just_written; ptr += just_written; - } } } @@ -947,10 +1321,11 @@ char *cmd; /* finished */ /* check the exit code of the pipe and moan if not 0 */ if ((exitcode = pclose(pipe_fp)) != 0) { - dbprintf(("%s: index pipe returned %d\n", - debug_prefix_time(NULL), exitcode)); + char *exitstr = str_exit_status("Index pipe", exitcode); + dbprintf("%s\n", exitstr); + amfree(exitstr); } else { - dbprintf(("%s: index created successfully\n", debug_prefix_time(NULL))); + dbprintf(_("Index created successfully\n")); } pipe_fp = NULL; @@ -962,7 +1337,3 @@ extern backup_program_t dump_program, gnutar_program; backup_program_t *programs[] = { &dump_program, &gnutar_program, NULL }; - -#ifdef KRB4_SECURITY -#include "sendbackup-krb4.c" -#endif