X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=client-src%2Fsendsize.c;h=8eb5c046c56afe7ca5e13589afefbadf3445b137;hb=b116e9366c7b2ea2c2eb53b0a13df4090e176235;hp=abd30d3ac86d2247a1c44cedabbf317fb293a7bb;hpb=71325c297e0436e9930a3e129a26696e78c27f62;p=debian%2Famanda diff --git a/client-src/sendsize.c b/client-src/sendsize.c index abd30d3..8eb5c04 100644 --- a/client-src/sendsize.c +++ b/client-src/sendsize.c @@ -24,46 +24,51 @@ * file named AUTHORS, in the root directory of this distribution. */ /* - * $Id: sendsize.c,v 1.171.2.1 2006/09/22 11:51:32 martinea Exp $ + * $Id: sendsize.c 10421 2008-03-06 18:48:30Z martineau $ * * send estimated backup sizes using dump */ #include "amanda.h" +#include "match.h" #include "pipespawn.h" #include "amfeatures.h" #include "amandates.h" #include "clock.h" #include "util.h" #include "getfsent.h" -#include "version.h" #include "client_util.h" -#include "clientconf.h" -#include "amandad.h" +#include "conffile.h" #ifdef SAMBA_CLIENT #include "findpass.h" #endif +#define sendsize_debug(i, ...) do { \ + if ((i) <= debug_sebdsize) { \ + dbprintf(__VA_ARGS__); \ + } \ +} while (0) + #ifdef HAVE_SETPGID # define SETPGRP setpgid(getpid(), getpid()) # define SETPGRP_FAILED() do { \ - dbprintf(("setpgid(%ld,%ld) failed: %s\n", \ - (long)getpid(), (long)getpid(), strerror(errno))); \ + dbprintf(_("setpgid(%ld,%ld) failed: %s\n"), \ + (long)getpid(), (long)getpid(), strerror(errno)); \ } while(0) #else /* () line 0 */ #if defined(SETPGRP_VOID) # define SETPGRP setpgrp() # define SETPGRP_FAILED() do { \ - dbprintf(("setpgrp() failed: %s\n", strerror(errno))); \ + dbprintf(_("setpgrp() failed: %s\n"), strerror(errno)); \ } while(0) #else # define SETPGRP setpgrp(0, getpid()) # define SETPGRP_FAILED() do { \ - dbprintf(("setpgrp(0,%ld) failed: %s\n", \ - (long)getpid(), strerror(errno))); \ + dbprintf(_("setpgrp(0,%ld) failed: %s\n"), \ + (long)getpid(), strerror(errno)); \ } while(0) #endif @@ -73,23 +78,18 @@ typedef struct level_estimates_s { time_t dumpsince; int estsize; int needestimate; + int server; /* server can do estimate */ } level_estimate_t; typedef struct disk_estimates_s { struct disk_estimates_s *next; - char *amname; char *qamname; - char *amdevice; char *qamdevice; char *dirname; char *qdirname; - char *program; - char *calcprog; - int program_is_wrapper; - int spindle; pid_t child; int done; - option_t *options; + dle_t *dle; level_estimate_t est[DUMP_LEVELS]; } disk_estimates_t; @@ -98,31 +98,27 @@ disk_estimates_t *est_list; static am_feature_t *our_features = NULL; static char *our_feature_string = NULL; static g_option_t *g_options = NULL; +static gboolean amandates_started = FALSE; /* local functions */ int main(int argc, char **argv); -void add_diskest(char *disk, char *amdevice, int level, int spindle, - int program_is_wrapper, char *prog, char *calcprog, - option_t *options); +void dle_add_diskest(dle_t *dle); void calc_estimates(disk_estimates_t *est); void free_estimates(disk_estimates_t *est); void dump_calc_estimates(disk_estimates_t *); void star_calc_estimates(disk_estimates_t *); void smbtar_calc_estimates(disk_estimates_t *); void gnutar_calc_estimates(disk_estimates_t *); -void wrapper_calc_estimates(disk_estimates_t *); +void application_api_calc_estimate(disk_estimates_t *); void generic_calc_estimates(disk_estimates_t *); - int main( int argc, char ** argv) { - int level, spindle; - char *prog, *calcprog, *dumpdate; - option_t *options = NULL; - int program_is_wrapper; + int level; + char *dumpdate; disk_estimates_t *est; disk_estimates_t *est1; disk_estimates_t *est_prev; @@ -133,24 +129,29 @@ main( int done; int need_wait; int dumpsrunning; - char *disk = NULL; char *qdisk = NULL; char *qlist = NULL; - char *amdevice = NULL; char *qamdevice = NULL; - char *conffile; - char *amandates_file; -#if defined(USE_DBMALLOC) - unsigned long malloc_hist_1, malloc_size_1; - unsigned long malloc_hist_2, malloc_size_2; -#endif + dle_t *dle; + GSList *errlist; + level_t *alevel; (void)argc; /* Quiet unused parameter warning */ (void)argv; /* Quiet unused parameter warning */ /* initialize */ + /* + * 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(-1, 0); + openbsd_fd_inform(); safe_cd(); set_pname("sendsize"); @@ -158,39 +159,26 @@ main( /* Don't die when child closes pipe */ signal(SIGPIPE, SIG_IGN); -#if defined(USE_DBMALLOC) - malloc_size_1 = malloc_inuse(&malloc_hist_1); -#endif - - erroutput_type = (ERR_INTERACTIVE|ERR_SYSLOG); + add_amanda_log_handler(amanda_log_stderr); + add_amanda_log_handler(amanda_log_syslog); dbopen(DBG_SUBDIR_CLIENT); startclock(); - dbprintf(("%s: version %s\n", get_pname(), version())); + dbprintf(_("version %s\n"), VERSION); our_features = am_init_feature_set(); our_feature_string = am_feature_to_string(our_features); - set_debug_prefix_pid(getpid()); + config_init(CONFIG_INIT_CLIENT, NULL); + /* (check for config errors comes later) */ - conffile = vstralloc(CONFIG_DIR, "/", "amanda-client.conf", NULL); - if (read_clientconf(conffile) > 0) { - error("error reading conffile: %s", conffile); - /*NOTREACHED*/ - } - amfree(conffile); + check_running_as(RUNNING_AS_CLIENT_LOGIN); /* handle all service requests */ - amandates_file = client_getconf_str(CLN_AMANDATES); - if(!start_amandates(amandates_file, 0)) - error("error [opening %s: %s]", amandates_file, strerror(errno)); - for(; (line = agets(stdin)) != NULL; free(line)) { if (line[0] == '\0') continue; -#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); @@ -198,92 +186,111 @@ main( g_options->hostname[MAX_HOSTNAME_LENGTH] = '\0'; } - printf("OPTIONS "); + 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_maxdumps)) { - printf("maxdumps=%d;", g_options->maxdumps); + g_printf("maxdumps=%d;", g_options->maxdumps); } if(am_has_feature(g_options->features, fe_rep_options_hostname)) { - printf("hostname=%s;", g_options->hostname); + g_printf("hostname=%s;", g_options->hostname); } - printf("\n"); + g_printf("\n"); fflush(stdout); if (g_options->config) { - conffile = vstralloc(CONFIG_DIR, "/", g_options->config, "/", - "amanda-client.conf", NULL); - if (read_clientconf(conffile) > 0) { - error("error reading conffile: %s", conffile); - /*NOTREACHED*/ - } - amfree(conffile); + /* 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); + } - dbrename(g_options->config, 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; } + dle = alloc_dle(); s = line; ch = *s++; skip_whitespace(s, ch); /* find the program name */ if(ch == '\0') { - err_extra = stralloc("no program name"); + err_extra = stralloc(_("no program name")); goto err; /* no program name */ } - prog = s - 1; + dle->program = s - 1; skip_non_whitespace(s, ch); s[-1] = '\0'; - program_is_wrapper=0; - if(strcmp(prog,"DUMPER")==0) { - program_is_wrapper=1; - skip_whitespace(s, ch); /* find dumper name */ - if (ch == '\0') { - goto err; /* no program */ - } - prog = s - 1; - skip_non_whitespace(s, ch); - s[-1] = '\0'; - } - - if(strncmp(prog, "CALCSIZE", 8) == 0) { + dle->program_is_application_api=0; + if(strncmp_const(dle->program, "CALCSIZE") == 0) { skip_whitespace(s, ch); /* find the program name */ if(ch == '\0') { - err_extra = stralloc("no program name"); + err_extra = stralloc(_("no program name")); goto err; } - calcprog = s - 1; + dle->estimatelist = g_slist_append(dle->estimatelist, + GINT_TO_POINTER(ES_CALCSIZE)); + dle->program = s - 1; skip_non_whitespace(s, ch); s[-1] = '\0'; + 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'; + } } else { - calcprog = NULL; + dle->estimatelist = g_slist_append(dle->estimatelist, + GINT_TO_POINTER(ES_CLIENT)); + 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 = stralloc("no disk name"); + err_extra = stralloc(_("no disk name")); goto err; /* no disk name */ } if (qdisk != NULL) amfree(qdisk); - if (disk != NULL) - amfree(disk); fp = s - 1; skip_quoted_string(s, ch); s[-1] = '\0'; /* terminate the disk name */ qdisk = stralloc(fp); - disk = unquote_string(qdisk); + dle->disk = unquote_string(qdisk); skip_whitespace(s, ch); /* find the device or level */ if (ch == '\0') { - err_extra = stralloc("bad level"); + err_extra = stralloc(_("bad level")); goto err; } if(!isdigit((int)s[-1])) { @@ -291,28 +298,31 @@ main( skip_quoted_string(s, ch); s[-1] = '\0'; qamdevice = stralloc(fp); - amdevice = unquote_string(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 = stralloc("bad level"); + err_extra = stralloc(_("bad level")); goto err; /* bad level */ } if (level < 0 || level >= DUMP_LEVELS) { - err_extra = stralloc("bad level"); + err_extra = stralloc(_("bad level")); goto err; } 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 = stralloc("no dumpdate"); + err_extra = stralloc(_("no dumpdate")); goto err; /* no dumpdate */ } dumpdate = s - 1; @@ -320,52 +330,48 @@ main( s[-1] = '\0'; (void)dumpdate; /* XXX: Set but not used */ - spindle = 0; /* default spindle */ + dle->spindle = 0; /* default spindle */ skip_whitespace(s, ch); /* find the spindle */ if(ch != '\0') { - if(sscanf(s - 1, "%d", &spindle) != 1) { - err_extra = stralloc("bad spindle"); + if(sscanf(s - 1, "%d", &dle->spindle) != 1) { + err_extra = stralloc(_("bad spindle")); goto err; /* bad spindle */ } skip_integer(s, ch); skip_whitespace(s, ch); /* find the parameters */ if(ch != '\0') { - if(strncmp(s-1, "OPTIONS |;",10) == 0) { - options = parse_options(s + 8, - disk, - amdevice, - g_options->features, - 0); + if(strncmp_const(s-1, "OPTIONS |;") == 0) { + parse_options(s + 8, + dle, + g_options->features, + 0); } else { - options = alloc(SIZEOF(option_t)); - init_options(options); while (ch != '\0') { - if(strncmp(s-1, "exclude-file=", 13) == 0) { + if(strncmp_const(s-1, "exclude-file=") == 0) { qlist = unquote_string(s+12); - options->exclude_file = - append_sl(options->exclude_file, qlist); + dle->exclude_file = + append_sl(dle->exclude_file, qlist); amfree(qlist); - } else if(strncmp(s-1, "exclude-list=", 13) == 0) { - options->exclude_list = - append_sl(options->exclude_list, qlist); + } else if(strncmp_const(s-1, "exclude-list=") == 0) { qlist = unquote_string(s+12); + dle->exclude_list = + append_sl(dle->exclude_list, qlist); amfree(qlist); - } else if(strncmp(s-1, "include-file=", 13) == 0) { - options->include_file = - append_sl(options->include_file, qlist); + } else if(strncmp_const(s-1, "include-file=") == 0) { qlist = unquote_string(s+12); + dle->include_file = + append_sl(dle->include_file, qlist); amfree(qlist); - } else if(strncmp(s-1, "include-list=", 13) == 0) { - options->include_list = - append_sl(options->include_list, qlist); + } else if(strncmp_const(s-1, "include-list=") == 0) { qlist = unquote_string(s+12); + dle->include_list = + append_sl(dle->include_list, qlist); amfree(qlist); } else { - err_extra = vstralloc("Invalid parameter (", - s-1, ")", NULL); + err_extra = vstrallocf(_("Invalid parameter (%s)"), s-1); goto err; /* should have gotten to end */ } skip_quoted_string(s, ch); @@ -374,32 +380,43 @@ main( } } } - else { - options = alloc(SIZEOF(option_t)); - init_options(options); - } - } - else { - options = alloc(SIZEOF(option_t)); - init_options(options); } /*@ignore@*/ - add_diskest(disk, amdevice, level, spindle, program_is_wrapper, prog, calcprog, options); + dle_add_diskest(dle); /*@end@*/ - amfree(disk); - amfree(qdisk); - amfree(amdevice); - amfree(qamdevice); } if (g_options == NULL) { - error("Missing OPTIONS line in sendsize input\n"); + g_printf(_("ERROR [Missing OPTIONS line in sendsize input]\n")); + error(_("Missing OPTIONS line in sendsize input\n")); /*NOTREACHED*/ } amfree(line); - finish_amandates(); - free_amandates(); + if (am_has_feature(g_options->features, fe_req_xml)) { + char *errmsg = NULL; + dle_t *dles, *dle; + + dles = amxml_parse_node_FILE(stdin, &errmsg); + if (errmsg) { + err_extra = errmsg; + goto err; + } + for (dle = dles; dle != NULL; dle = dle->next) { + dle_add_diskest(dle); + } + } + + if (amandates_started) { + finish_amandates(); + free_amandates(); + amandates_started = FALSE; + } + + for(est = est_list; est != NULL; est = est->next) { + run_client_scripts(EXECUTE_ON_PRE_HOST_ESTIMATE, g_options, est->dle, + stdout); + } dumpsrunning = 0; need_wait = 0; @@ -413,31 +430,24 @@ main( if(need_wait) { pid_t child_pid; amwait_t child_status; - int exit_code; need_wait = 0; - dbprintf(("%s: waiting for any estimate child: %d running\n", - debug_prefix_time(NULL), dumpsrunning)); + dbprintf(_("waiting for any estimate child: %d running\n"), + dumpsrunning); child_pid = wait(&child_status); if(child_pid == -1) { - error("wait failed: %s", strerror(errno)); + error(_("wait failed: %s"), strerror(errno)); /*NOTREACHED*/ } - if(WIFSIGNALED(child_status)) { - dbprintf(("%s: child %ld terminated with signal %d\n", - debug_prefix_time(NULL), - (long) child_pid, WTERMSIG(child_status))); - } else { - exit_code = WEXITSTATUS(child_status); - if(exit_code == 0) { - dbprintf(("%s: child %ld terminated normally\n", - debug_prefix_time(NULL), (long) child_pid)); - } else { - dbprintf(("%s: child %ld terminated with code %d\n", - debug_prefix_time(NULL), - (long) child_pid, exit_code)); - } + + if (!WIFEXITED(child_status) || WEXITSTATUS(child_status) != 0) { + char *child_name = vstrallocf(_("child %ld"), (long)child_pid); + char *child_status_str = str_exit_status(child_name, child_status); + dbprintf("%s\n", child_status_str); + amfree(child_status_str); + amfree(child_name); } + /* * Find the child and mark it done. */ @@ -447,12 +457,13 @@ main( } } if(est == NULL) { - dbprintf(("%s: unexpected child %ld\n", - debug_prefix_time(NULL), (long)child_pid)); + dbprintf(_("unexpected child %ld\n"), (long)child_pid); } else { est->done = 1; est->child = 0; dumpsrunning--; + run_client_scripts(EXECUTE_ON_POST_DLE_ESTIMATE, g_options, + est->dle, stdout); } } /* @@ -477,7 +488,7 @@ main( /* * Make sure there is no spindle conflict. */ - if(est->spindle != -1) { + if(est->dle->spindle != -1) { for(est1 = est_list; est1 != NULL; est1 = est1->next) { if(est1->child == 0 || est == est1 || est1->done) { /* @@ -486,7 +497,7 @@ main( */ continue; } - if(est1->spindle == est->spindle) { + if(est1->dle->spindle == est->dle->spindle) { break; /* oops -- they match */ } } @@ -502,18 +513,25 @@ main( } } else { done = 0; + run_client_scripts(EXECUTE_ON_PRE_DLE_ESTIMATE, g_options, + est->dle, stdout); + if((est->child = fork()) == 0) { - set_debug_prefix_pid(getpid()); calc_estimates(est); /* child does the estimate */ exit(0); } else if(est->child == -1) { - error("calc_estimates fork failed: %s", strerror(errno)); + error(_("calc_estimates fork failed: %s"), strerror(errno)); /*NOTREACHED*/ } dumpsrunning++; /* parent */ } } + for(est = est_list; est != NULL; est = est->next) { + run_client_scripts(EXECUTE_ON_POST_HOST_ESTIMATE, g_options, est->dle, + stdout); + } + est_prev = NULL; for(est = est_list; est != NULL; est = est->next) { free_estimates(est); @@ -524,68 +542,101 @@ main( 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); - -#if defined(USE_DBMALLOC) - malloc_size_2 = malloc_inuse(&malloc_hist_2); - - if(malloc_size_1 != malloc_size_2) { - malloc_list(dbfd(), malloc_hist_1, malloc_hist_2); - } -#endif + free_g_options(g_options); dbclose(); return 0; 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 : "")); - amfree(err_extra); + if (err_extra) { + g_printf(_("ERROR FORMAT ERROR IN REQUEST PACKET '%s'\n"), err_extra); + dbprintf(_("REQ packet is bogus: %s\n"), err_extra); + amfree(err_extra); + } else { + g_printf(_("ERROR FORMAT ERROR IN REQUEST PACKET\n")); + dbprintf(_("REQ packet is bogus\n")); + } + + free_g_options(g_options); + dbclose(); return 1; } void -add_diskest( - char * disk, - char * amdevice, - int level, - int spindle, - int program_is_wrapper, - char * prog, - char * calcprog, - option_t * options) +dle_add_diskest( + dle_t *dle) { disk_estimates_t *newp, *curp; amandates_t *amdp; int dumplev, estlev; time_t dumpdate; + levellist_t levellist; + char *amandates_file; + gboolean need_amandates = FALSE; + estimatelist_t el; + + if (dle->levellist == NULL) { + g_printf(_("ERROR Missing level in request\n")); + return; + } + + /* should we use amandates for this? */ + for (el = dle->estimatelist; el != NULL; el=el->next) { + estimate_t estimate = (estimate_t)GPOINTER_TO_INT(el->data); + if (estimate == ES_CALCSIZE) + need_amandates = TRUE; + } + + if (strcmp(dle->program, "GNUTAR") == 0) { + /* GNUTAR only needs amandates if gnutar_list_dir is NULL */ + char *gnutar_list_dir = getconf_str(CNF_GNUTAR_LIST_DIR); + if (!gnutar_list_dir || !*gnutar_list_dir) + need_amandates = TRUE; + } + + /* start amandates here, before adding this DLE to est_list, in case + * we encounter an error. */ + if (need_amandates) { + if (!amandates_started) { + amandates_file = getconf_str(CNF_AMANDATES); + if(!start_amandates(amandates_file, 0)) { + char *errstr = strerror(errno); + char *qamname = quote_string(dle->disk); + char *errmsg = vstrallocf(_("could not open %s: %s"), amandates_file, errstr); + char *qerrmsg = quote_string(errmsg); + g_printf(_("%s %d ERROR %s\n"), qamname, 0, qerrmsg); + amfree(qamname); + amfree(errmsg); + amfree(qerrmsg); + return; + } + amandates_started = TRUE; + } + } - if (level < 0) - level = 0; - if (level >= DUMP_LEVELS) - level = DUMP_LEVELS - 1; + levellist = dle->levellist; + while (levellist != NULL) { + level_t *alevel = (level_t *)levellist->data; + if (alevel->level < 0) + alevel->level = 0; + if (alevel->level >= DUMP_LEVELS) + alevel->level = DUMP_LEVELS - 1; + levellist = g_slist_next(levellist); + } for(curp = est_list; curp != NULL; curp = curp->next) { - if(strcmp(curp->amname, disk) == 0) { + if(strcmp(curp->dle->disk, dle->disk) == 0) { /* already have disk info, just note the level request */ - curp->est[level].needestimate = 1; - if(options) { - free_sl(options->exclude_file); - free_sl(options->exclude_list); - free_sl(options->include_file); - free_sl(options->include_list); - amfree(options->auth); - amfree(options->str); - amfree(options); + levellist = dle->levellist; + while (levellist != NULL) { + level_t *alevel = (level_t *)levellist->data; + int level = alevel->level; + curp->est[level].needestimate = 1; + curp->est[level].server = alevel->server; + levellist = g_slist_next(levellist); } + return; } } @@ -594,32 +645,41 @@ add_diskest( memset(newp, 0, SIZEOF(*newp)); newp->next = est_list; est_list = newp; - newp->amname = stralloc(disk); - newp->qamname = quote_string(disk); - newp->amdevice = stralloc(amdevice); - newp->qamdevice = quote_string(amdevice); - newp->dirname = amname_to_dirname(newp->amdevice); - newp->qdirname = quote_string(newp->dirname); - newp->program = stralloc(prog); - if(calcprog != NULL) - newp->calcprog = stralloc(calcprog); - else - newp->calcprog = NULL; - newp->program_is_wrapper = program_is_wrapper; - newp->spindle = spindle; - newp->est[level].needestimate = 1; - newp->options = options; + newp->qamname = quote_string(dle->disk); + if (dle->device) { + newp->qamdevice = quote_string(dle->device); + newp->dirname = amname_to_dirname(dle->device); + newp->qdirname = quote_string(newp->dirname); + } else { + newp->qamdevice = stralloc(""); + newp->dirname = stralloc(""); + newp->qdirname = stralloc(""); + } + levellist = dle->levellist; + while (levellist != NULL) { + level_t *alevel = (level_t *)levellist->data; + newp->est[alevel->level].needestimate = 1; + newp->est[alevel->level].server = alevel->server; + levellist = g_slist_next(levellist); + } + newp->dle = dle; /* fill in dump-since dates */ - - amdp = amandates_lookup(newp->amname); - - newp->est[0].dumpsince = EPOCH; - for(dumplev = 0; dumplev < DUMP_LEVELS; dumplev++) { - dumpdate = amdp->dates[dumplev]; - for(estlev = dumplev+1; estlev < DUMP_LEVELS; estlev++) { - if(dumpdate > newp->est[estlev].dumpsince) - newp->est[estlev].dumpsince = dumpdate; + if (need_amandates) { + amdp = amandates_lookup(newp->dle->disk); + + newp->est[0].dumpsince = EPOCH; + for(dumplev = 0; dumplev < DUMP_LEVELS; dumplev++) { + dumpdate = amdp->dates[dumplev]; + for(estlev = dumplev+1; estlev < DUMP_LEVELS; estlev++) { + if(dumpdate > newp->est[estlev].dumpsince) + newp->est[estlev].dumpsince = dumpdate; + } + } + } else { + /* just zero everything out */ + for(dumplev = 0; dumplev < DUMP_LEVELS; dumplev++) { + newp->est[dumplev].dumpsince = 0; } } } @@ -629,21 +689,12 @@ void free_estimates( disk_estimates_t * est) { - amfree(est->amname); amfree(est->qamname); - amfree(est->amdevice); amfree(est->qamdevice); amfree(est->dirname); amfree(est->qdirname); - amfree(est->program); - if(est->options) { - free_sl(est->options->exclude_file); - free_sl(est->options->exclude_list); - free_sl(est->options->include_file); - free_sl(est->options->include_list); - amfree(est->options->str); - amfree(est->options->auth); - amfree(est->options); + if (est->dle) { + free_dle(est->dle); } } @@ -656,41 +707,77 @@ void calc_estimates( disk_estimates_t * est) { - dbprintf(("%s: calculating for amname %s, dirname %s, spindle %d\n", - debug_prefix_time(NULL), - est->qamname, est->qdirname, est->spindle)); - - if(est->program_is_wrapper == 1) - wrapper_calc_estimates(est); - else + dbprintf(_("calculating for amname %s, dirname %s, spindle %d %s\n"), + est->qamname, est->qdirname, est->dle->spindle, est->dle->program); + + if(est->dle->program_is_application_api == 1) + application_api_calc_estimate(est); + else { + estimatelist_t el; + estimate_t estimate; + int level; + estimate_t estimate_method = ES_ES; + estimate_t client_method = ES_ES; + + /* find estimate method to use */ + for (el = est->dle->estimatelist; el != NULL; el = el->next) { + estimate = (estimate_t)GPOINTER_TO_INT(el->data); + if (estimate == ES_SERVER) { + if (estimate_method == ES_ES) + estimate_method = ES_SERVER; + } + if (estimate == ES_CLIENT || + (estimate == ES_CALCSIZE && + (est->dle->device[0] != '/' || est->dle->device[1] != '/'))) { + if (client_method == ES_ES) + client_method = estimate; + if (estimate_method == ES_ES) + estimate_method = estimate; + } + } + + /* do server estimate */ + if (estimate_method == ES_SERVER) { + for (level = 0; level < DUMP_LEVELS; level++) { + if (est->est[level].needestimate) { + if (est->est[level].server || client_method == ES_ES) { + g_printf(_("%s %d SIZE -1\n"), est->qamname, level); + est->est[level].needestimate = 0; + } + } + } + } + + if (client_method == ES_ES && estimate_method != ES_SERVER) { + g_printf(_("%s %d SIZE -2\n"), est->qamname, 0); + dbprintf(_("Can't use CALCSIZE for samba estimate: %s %s\n"), + est->qamname, est->qdirname); + } else if (client_method == ES_CALCSIZE) { + generic_calc_estimates(est); + } else if (client_method == ES_CLIENT) { #ifndef USE_GENERIC_CALCSIZE - if(strcmp(est->program, "DUMP") == 0) - dump_calc_estimates(est); - else + if (strcmp(est->dle->program, "DUMP") == 0) + dump_calc_estimates(est); + else #endif #ifdef SAMBA_CLIENT - if (strcmp(est->program, "GNUTAR") == 0 && - est->amdevice[0] == '/' && est->amdevice[1] == '/') - smbtar_calc_estimates(est); - else + if (strcmp(est->dle->program, "GNUTAR") == 0 && + est->dle->device[0] == '/' && est->dle->device[1] == '/') + smbtar_calc_estimates(est); + else #endif #ifdef GNUTAR - if (strcmp(est->program, "GNUTAR") == 0) - gnutar_calc_estimates(est); - else -#endif -#ifdef SAMBA_CLIENT - if (est->amdevice[0] == '/' && est->amdevice[1] == '/') - dbprintf(("%s: Can't use CALCSIZE for samba estimate: %s %s\n", - debug_prefix_time(NULL), - est->qamname, est->qdirname)); - else + if (strcmp(est->dle->program, "GNUTAR") == 0) + gnutar_calc_estimates(est); + else #endif - generic_calc_estimates(est); + dbprintf(_("Invalid program: %s %s %s\n"), + est->qamname, est->qdirname, est->dle->program); + } + } - dbprintf(("%s: done with amname %s dirname %s spindle %d\n", - debug_prefix_time(NULL), - est->qamname, est->qdirname, est->spindle)); + dbprintf(_("done with amname %s dirname %s spindle %d\n"), + est->qamname, est->qdirname, est->dle->spindle); } /* @@ -699,45 +786,190 @@ calc_estimates( */ /* local functions */ -off_t getsize_dump(char *disk, char *amdevice, int level, option_t *options); -off_t getsize_star(char *disk, char *amdevice, int level, - option_t *options, time_t dumpsince); -off_t getsize_smbtar(char *disk, char *amdevice, int level, option_t *options); -off_t getsize_gnutar(char *disk, char *amdevice, int level, - option_t *options, time_t dumpsince); -off_t getsize_wrapper(char *program, char *disk, char *amdevice, int level, - option_t *options, time_t dumpsince); +off_t getsize_dump(dle_t *dle, int level, char **errmsg); +off_t getsize_smbtar(dle_t *dle, int level, char **errmsg); +off_t getsize_gnutar(dle_t *dle, int level, time_t dumpsince, char **errmsg); +off_t getsize_application_api(disk_estimates_t *est, int nb_level, + int *levels, backup_support_option_t *bsu); off_t handle_dumpline(char *str); double first_num(char *str); void -wrapper_calc_estimates( +application_api_calc_estimate( disk_estimates_t * est) { - int level; - off_t size; - - for(level = 0; level < DUMP_LEVELS; level++) { - if (est->est[level].needestimate) { - dbprintf(("%s: getting size via wrapper for %s level %d\n", - debug_prefix_time(NULL), est->qamname, level)); - size = getsize_wrapper(est->program, est->amname, est->amdevice, - level, est->options, est->est[level].dumpsince); - - amflock(1, "size"); - - if (fseek(stdout, 0L, SEEK_END) < 0) { - dbprintf(("wrapper_calc_estimates: warning - seek failed: %s\n", - strerror(errno))); - } - - printf("%s %d SIZE " OFF_T_FMT "\n", est->qamname, level, - (OFF_T_FMT_TYPE)size); - fflush(stdout); - - amfunlock(1, "size"); - } - } + int level; + int i; + int levels[DUMP_LEVELS]; + int nb_level = 0; + backup_support_option_t *bsu; + GPtrArray *errarray; + estimatelist_t el; + estimate_t estimate; + estimate_t estimate_method = ES_ES; + estimate_t client_method = ES_ES; + int has_calcsize = 0; + int has_client = 0; + + bsu = backup_support_option(est->dle->program, g_options, est->dle->disk, + est->dle->device, &errarray); + if (!bsu) { + guint i; + for (i=0; i < errarray->len; i++) { + char *line; + char *errmsg; + char *qerrmsg; + line = g_ptr_array_index(errarray, i); + if(am_has_feature(g_options->features, + fe_rep_sendsize_quoted_error)) { + errmsg = g_strdup_printf(_("Application '%s': %s"), + est->dle->program, line); + qerrmsg = quote_string(errmsg); + for (level = 0; level < DUMP_LEVELS; level++) { + if (est->est[level].needestimate) { + g_printf(_("%s %d ERROR %s\n"), + est->dle->disk, level, qerrmsg); + dbprintf(_("%s %d ERROR %s\n"), + est->qamname, level, qerrmsg); + } + } + amfree(errmsg); + amfree(qerrmsg); + } + } + if (i == 0) { /* nothing in errarray */ + char *errmsg; + char *qerrmsg; + errmsg = g_strdup_printf( + _("Application '%s': cannon execute support command"), + est->dle->program); + qerrmsg = quote_string(errmsg); + for (level = 0; level < DUMP_LEVELS; level++) { + if (est->est[level].needestimate) { + g_printf(_("%s %d ERROR %s\n"), + est->dle->disk, level, qerrmsg); + dbprintf(_("%s %d ERROR %s\n"), + est->qamname, level, qerrmsg); + } + } + amfree(errmsg); + amfree(qerrmsg); + } + for (level = 0; level < DUMP_LEVELS; level++) { + est->est[level].needestimate = 0; + } + g_ptr_array_free(errarray, TRUE); + } + + if (est->dle->data_path == DATA_PATH_AMANDA && + (bsu->data_path_set & DATA_PATH_AMANDA)==0) { + g_printf("%s %d ERROR application %s doesn't support amanda data-path\n", est->qamname, 0, est->dle->program); + amfree(bsu); + return; + } + if (est->dle->data_path == DATA_PATH_DIRECTTCP && + (bsu->data_path_set & DATA_PATH_DIRECTTCP)==0) { + g_printf("%s %d ERROR application %s doesn't support directtcp data-path\n", est->qamname, 0, est->dle->program); + amfree(bsu); + return; + } + + /* find estimate method to use */ + for (el = est->dle->estimatelist; el != NULL; el = el->next) { + estimate = (estimate_t)GPOINTER_TO_INT(el->data); + if (estimate == ES_CLIENT) + has_client = 1; + if (estimate == ES_CALCSIZE) + has_calcsize = 1; + if (estimate == ES_SERVER) { + if (estimate_method == ES_ES) + estimate_method = ES_SERVER; + } + if ((estimate == ES_CLIENT && bsu->client_estimate) || + (estimate == ES_CALCSIZE && bsu->calcsize)) { + if (client_method == ES_ES) + client_method = estimate; + if (estimate_method == ES_ES) + estimate_method = estimate; + } + } + + for(level = 0; level < DUMP_LEVELS; level++) { + if (est->est[level].needestimate) { + if (level > bsu->max_level) { + /* planner will not even consider this level */ + g_printf("%s %d SIZE %lld\n", est->qamname, level, + (long long)-2); + est->est[level].needestimate = 0; + dbprintf(_("Application '%s' can't estimate level %d\n"), + est->dle->program, level); + } else if (estimate_method == ES_ES) { + g_printf("%s %d SIZE %lld\n", est->qamname, level, + (long long)-2); + est->est[level].needestimate = 0; + if (am_has_feature(g_options->features, + fe_rep_sendsize_quoted_error)) { + char *errmsg, *qerrmsg; + if (has_client && !bsu->client_estimate && + has_calcsize && !bsu->calcsize) { + errmsg = vstrallocf(_("Application '%s' can't do CLIENT or CALCSIZE estimate"), + est->dle->program); + } else if (has_client && !bsu->client_estimate) { + errmsg = vstrallocf(_("Application '%s' can't do CLIENT estimate"), + est->dle->program); + } else if (has_calcsize && !bsu->calcsize) { + errmsg = vstrallocf(_("Application '%s' can't do CALCSIZE estimate"), + est->dle->program); + } else { + errmsg = vstrallocf(_("Application '%s' can't do estimate"), + est->dle->program); + } + qerrmsg = quote_string(errmsg); + dbprintf(_("errmsg is %s\n"), errmsg); + g_printf("%s %d ERROR %s\n", + est->qamname, 0, qerrmsg); + amfree(errmsg); + amfree(qerrmsg); + } + } else if (estimate_method == ES_SERVER && + (est->est[level].server || client_method == ES_ES)) { + /* planner will consider this level, */ + /* but use a server-side estimate */ + g_printf("%s %d SIZE -1\n", est->qamname, level); + est->est[level].needestimate = 0; + } else if (client_method == ES_CLIENT) { + levels[nb_level++] = level; + } else if (client_method == ES_CALCSIZE) { + levels[nb_level++] = level; + } + } + } + + if (nb_level == 0) { + amfree(bsu); + return; + } + + if (bsu->multi_estimate) { + for (i=0;iqamname, est->qamdevice, levels[i]); + } + getsize_application_api(est, nb_level, levels, bsu); + + } else { + for(level = 0; level < DUMP_LEVELS; level++) { + if (est->est[level].needestimate) { + dbprintf( + _("getting size via application API for %s %s level %d\n"), + est->qamname, est->qamdevice, level); + levels[0] = level; + getsize_application_api(est, 1, levels, bsu); + } + } + } + + amfree(bsu); } @@ -747,9 +979,12 @@ generic_calc_estimates( { int pipefd = -1, nullfd = -1; char *cmd; - char *my_argv[DUMP_LEVELS*2+22]; + char *cmdline; + char *command; + GPtrArray *argv_ptr = g_ptr_array_new(); char number[NUM_STR_SIZE]; - int i, level, my_argc, status; + unsigned int i; + int level; pid_t calcpid; int nb_exclude = 0; int nb_include = 0; @@ -760,115 +995,150 @@ generic_calc_estimates( off_t size = (off_t)1; char *line = NULL; char *match_expr; + amwait_t wait_status; + char *errmsg = NULL, *qerrmsg; + char tmppath[PATH_MAX]; + int len; - cmd = vstralloc(libexecdir, "/", "calcsize", versionsuffix(), NULL); + cmd = vstralloc(amlibexecdir, "/", "calcsize", NULL); - my_argc = 0; - - my_argv[my_argc++] = stralloc("calcsize"); + g_ptr_array_add(argv_ptr, stralloc("calcsize")); if (g_options->config) - my_argv[my_argc++] = stralloc(g_options->config); + g_ptr_array_add(argv_ptr, stralloc(g_options->config)); else - my_argv[my_argc++] = stralloc("NOCONFIG"); - - my_argv[my_argc++] = stralloc(est->calcprog); - - my_argv[my_argc++] = stralloc(est->amname); - my_argv[my_argc++] = stralloc(est->dirname); - - - if(est->options->exclude_file) - nb_exclude += est->options->exclude_file->nb_element; - if(est->options->exclude_list) - nb_exclude += est->options->exclude_list->nb_element; - if(est->options->include_file) - nb_include += est->options->include_file->nb_element; - if(est->options->include_list) - nb_include += est->options->include_list->nb_element; - - if(nb_exclude > 0) - file_exclude = build_exclude(est->amname, - est->amdevice, est->options, 0); - if(nb_include > 0) - file_include = build_include(est->amname, - est->amdevice, est->options, 0); + g_ptr_array_add(argv_ptr, stralloc("NOCONFIG")); + + g_ptr_array_add(argv_ptr, stralloc(est->dle->program)); + canonicalize_pathname(est->dle->disk, tmppath); + g_ptr_array_add(argv_ptr, stralloc(tmppath)); + canonicalize_pathname(est->dirname, tmppath); + g_ptr_array_add(argv_ptr, stralloc(tmppath)); + + if (est->dle->exclude_file) + nb_exclude += est->dle->exclude_file->nb_element; + if (est->dle->exclude_list) + nb_exclude += est->dle->exclude_list->nb_element; + if (est->dle->include_file) + nb_include += est->dle->include_file->nb_element; + if (est->dle->include_list) + nb_include += est->dle->include_list->nb_element; + + if (nb_exclude > 0) + file_exclude = build_exclude(est->dle, 0); + if (nb_include > 0) + file_include = build_include(est->dle, 0); if(file_exclude) { - my_argv[my_argc++] = stralloc("-X"); - my_argv[my_argc++] = file_exclude; + g_ptr_array_add(argv_ptr, stralloc("-X")); + g_ptr_array_add(argv_ptr, stralloc(file_exclude)); } if(file_include) { - my_argv[my_argc++] = stralloc("-I"); - my_argv[my_argc++] = file_include; + g_ptr_array_add(argv_ptr, stralloc("-I")); + g_ptr_array_add(argv_ptr, stralloc(file_include)); } start_time = curclock(); - dbprintf(("%s: running cmd: %s", debug_prefix_time(NULL), my_argv[0])); - for(i=0; ilen-1; i++) { + cmdline = vstrextend(&cmdline, " ", + (char *)g_ptr_array_index(argv_ptr, i), NULL); + } + dbprintf(_("running: \"%s\"\n"), cmdline); + amfree(cmdline); for(level = 0; level < DUMP_LEVELS; level++) { if(est->est[level].needestimate) { - snprintf(number, SIZEOF(number), "%d", level); - my_argv[my_argc++] = stralloc(number); - dbprintf((" %s", number)); - snprintf(number, SIZEOF(number), + g_snprintf(number, SIZEOF(number), "%d", level); + g_ptr_array_add(argv_ptr, stralloc(number)); + dbprintf(" %s", number); + g_snprintf(number, SIZEOF(number), "%ld", (long)est->est[level].dumpsince); - my_argv[my_argc++] = stralloc(number); - dbprintf((" %s", number)); + g_ptr_array_add(argv_ptr, stralloc(number)); + dbprintf(" %s", number); } } - my_argv[my_argc] = NULL; - dbprintf(("\n")); + g_ptr_array_add(argv_ptr, NULL); + dbprintf("\n"); fflush(stderr); fflush(stdout); if ((nullfd = open("/dev/null", O_RDWR)) == -1) { - dbprintf(("Cannot access /dev/null : %s\n", strerror(errno))); + errmsg = vstrallocf(_("Cannot access /dev/null : %s"), + strerror(errno)); + dbprintf("%s\n", errmsg); goto common_exit; } - calcpid = pipespawnv(cmd, STDERR_PIPE, &nullfd, &nullfd, &pipefd, my_argv); + calcpid = pipespawnv(cmd, STDERR_PIPE, 0, + &nullfd, &nullfd, &pipefd, (char **)argv_ptr->pdata); amfree(cmd); dumpout = fdopen(pipefd,"r"); if (!dumpout) { - error("Can't fdopen: %s", strerror(errno)); + error(_("Can't fdopen: %s"), strerror(errno)); /*NOTREACHED*/ } - match_expr = vstralloc(est->qamname," %d SIZE " OFF_T_FMT, NULL); + match_expr = vstralloc(" %d SIZE %lld", NULL); + len = strlen(est->qamname); for(size = (off_t)-1; (line = agets(dumpout)) != NULL; free(line)) { - if (line[0] == '\0') + long long size_ = (long long)0; + if (line[0] == '\0' || (int)strlen(line) <= len) continue; - if(sscanf(line, match_expr, &level, &size) == 2) { - printf("%s\n", line); /* write to amandad */ - dbprintf(("%s: estimate size for %s level %d: " OFF_T_FMT " KB\n", - debug_prefix(NULL), + /* Don't use sscanf for est->qamname because it can have a '%'. */ + if (strncmp(line, est->qamname, len) == 0 && + sscanf(line+len, match_expr, &level, &size_) == 2) { + g_printf("%s\n", line); /* write to amandad */ + dbprintf(_("estimate size for %s level %d: %lld KB\n"), est->qamname, level, - size)); + size_); } + size = (off_t)size_; } amfree(match_expr); - dbprintf(("%s: waiting for %s %s child (pid=%d)\n", - debug_prefix_time(NULL), my_argv[0], est->qamdevice, calcpid)); - wait(&status); - dbprintf(("%s: after %s %s wait: child pid=%d status=%d\n", - debug_prefix_time(NULL), my_argv[0], est->qamdevice, - calcpid, WEXITSTATUS(status))); + dbprintf(_("waiting for %s %s child (pid=%d)\n"), + command, est->qamdevice, (int)calcpid); + waitpid(calcpid, &wait_status, 0); + if (WIFSIGNALED(wait_status)) { + errmsg = vstrallocf(_("%s terminated with signal %d: see %s"), + "calcsize", WTERMSIG(wait_status), + dbfn()); + } else if (WIFEXITED(wait_status)) { + if (WEXITSTATUS(wait_status) != 0) { + errmsg = vstrallocf(_("%s exited with status %d: see %s"), + "calcsize", WEXITSTATUS(wait_status), + dbfn()); + } else { + /* Normal exit */ + } + } else { + errmsg = vstrallocf(_("%s got bad exit: see %s"), + "calcsize", dbfn()); + } + dbprintf(_("after %s %s wait: child pid=%d status=%d\n"), + command, est->qamdevice, + (int)calcpid, WEXITSTATUS(wait_status)); - dbprintf(("%s: .....\n", debug_prefix_time(NULL))); - dbprintf(("%s: estimate time for %s: %s\n", - debug_prefix(NULL), + dbprintf(_(".....\n")); + dbprintf(_("estimate time for %s: %s\n"), est->qamname, - walltime_str(timessub(curclock(), start_time)))); + walltime_str(timessub(curclock(), start_time))); common_exit: - for(i = 0; i < my_argc; i++) { - amfree(my_argv[i]); + if (errmsg && errmsg[0] != '\0') { + if(am_has_feature(g_options->features, fe_rep_sendsize_quoted_error)) { + qerrmsg = quote_string(errmsg); + dbprintf(_("errmsg is %s\n"), errmsg); + g_printf("%s %d ERROR %s\n", + est->qamname, 0, qerrmsg); + amfree(qerrmsg); + } } + amfree(errmsg); + g_ptr_array_free_full(argv_ptr); amfree(cmd); } @@ -879,23 +1149,29 @@ dump_calc_estimates( { int level; off_t size; + char *errmsg=NULL, *qerrmsg; for(level = 0; level < DUMP_LEVELS; level++) { if(est->est[level].needestimate) { - dbprintf(("%s: getting size via dump for %s level %d\n", - debug_prefix_time(NULL), est->qamname, level)); - size = getsize_dump(est->amname, est->amdevice, - level, est->options); + dbprintf(_("getting size via dump for %s level %d\n"), + est->qamname, level); + size = getsize_dump(est->dle, level, &errmsg); amflock(1, "size"); - if (fseek(stdout, 0L, SEEK_END) < 0) { - dbprintf(("dump_calc_estimates: warning - seek failed: %s\n", - strerror(errno))); + g_printf(_("%s %d SIZE %lld\n"), + est->qamname, level, (long long)size); + if (errmsg && errmsg[0] != '\0') { + if(am_has_feature(g_options->features, + fe_rep_sendsize_quoted_error)) { + qerrmsg = quote_string(errmsg); + dbprintf(_("errmsg is %s\n"), errmsg); + g_printf("%s %d ERROR %s\n", + est->qamname, level, qerrmsg); + amfree(qerrmsg); + } } - - printf("%s %d SIZE " OFF_T_FMT "\n", - est->qamname, level, (OFF_T_FMT_TYPE)size); + amfree(errmsg); fflush(stdout); amfunlock(1, "size"); @@ -910,22 +1186,29 @@ smbtar_calc_estimates( { int level; off_t size; + char *errmsg = NULL, *qerrmsg; for(level = 0; level < DUMP_LEVELS; level++) { if(est->est[level].needestimate) { - dbprintf(("%s: getting size via smbclient for %s level %d\n", - debug_prefix_time(NULL), est->qamname, level)); - size = getsize_smbtar(est->amname, est->amdevice, level, est->options); + dbprintf(_("getting size via smbclient for %s level %d\n"), + est->qamname, level); + size = getsize_smbtar(est->dle, level, &errmsg); amflock(1, "size"); - if (fseek(stdout, 0L, SEEK_END) < 0) { - dbprintf(("smbtar_calc_estimates: warning - seek failed: %s\n", - strerror(errno))); + g_printf(_("%s %d SIZE %lld\n"), + est->qamname, level, (long long)size); + if (errmsg && errmsg[0] != '\0') { + if(am_has_feature(g_options->features, + fe_rep_sendsize_quoted_error)) { + qerrmsg = quote_string(errmsg); + dbprintf(_("errmsg is %s\n"), errmsg); + g_printf("%s %d ERROR %s\n", + est->qamname, level, qerrmsg); + amfree(qerrmsg); + } } - - printf("%s %d SIZE " OFF_T_FMT "\n", - est->qamname, level, (OFF_T_FMT_TYPE)size); + amfree(errmsg); fflush(stdout); amfunlock(1, "size"); @@ -939,40 +1222,48 @@ void gnutar_calc_estimates( disk_estimates_t * est) { - int level; - off_t size; - - for(level = 0; level < DUMP_LEVELS; level++) { - if (est->est[level].needestimate) { - dbprintf(("%s: getting size via gnutar for %s level %d\n", - debug_prefix_time(NULL), est->qamname, level)); - size = getsize_gnutar(est->amname, est->amdevice, level, - est->options, est->est[level].dumpsince); - - amflock(1, "size"); - - if (fseek(stdout, 0L, SEEK_END) < 0) { - dbprintf(("gnutar_calc_estimates: warning - seek failed: %s\n", - strerror(errno))); - } - - printf("%s %d SIZE " OFF_T_FMT "\n", - est->qamname, level, (OFF_T_FMT_TYPE)size); - fflush(stdout); - - amfunlock(1, "size"); - } - } + int level; + off_t size; + char *errmsg = NULL, *qerrmsg; + + for(level = 0; level < DUMP_LEVELS; level++) { + if (est->est[level].needestimate) { + dbprintf(_("getting size via gnutar for %s level %d\n"), + est->qamname, level); + size = getsize_gnutar(est->dle, level, + est->est[level].dumpsince, + &errmsg); + + amflock(1, "size"); + + g_printf(_("%s %d SIZE %lld\n"), + est->qamname, level, (long long)size); + if (errmsg && errmsg[0] != '\0') { + if(am_has_feature(g_options->features, + fe_rep_sendsize_quoted_error)) { + qerrmsg = quote_string(errmsg); + dbprintf(_("errmsg is %s\n"), errmsg); + g_printf(_("%s %d ERROR %s\n"), + est->qamname, level, qerrmsg); + amfree(qerrmsg); + } + } + amfree(errmsg); + fflush(stdout); + + amfunlock(1, "size"); + } + } } #endif -typedef struct regex_s { +typedef struct regex_scale_s { char *regex; int scale; -} regex_t; +} regex_scale_t; /*@ignore@*/ -regex_t re_size[] = { +regex_scale_t re_size[] = { #ifdef DUMP {" DUMP: estimated -*[0-9][0-9]* tape blocks", 1024}, {" DUMP: [Ee]stimated [0-9][0-9]* blocks", 512}, @@ -1032,10 +1323,9 @@ regex_t re_size[] = { off_t getsize_dump( - char *disk, - char *amdevice, + dle_t *dle, int level, - option_t * options) + char **errmsg) { int pipefd[2], nullfd, stdoutfd, killctl[2]; pid_t dumppid; @@ -1051,35 +1341,36 @@ getsize_dump( char level_str[NUM_STR_SIZE]; int s; times_t start_time; - char *qdisk = quote_string(disk); + char *qdisk = quote_string(dle->disk); char *qdevice; char *config; -#ifdef DUMP + amwait_t wait_status; +#if defined(DUMP) || defined(VDUMP) || defined(VXDUMP) || defined(XFSDUMP) int is_rundump = 1; #endif - (void)options; /* Quiet unused parameter warning */ + if (level > 9) + return -2; /* planner will not even consider this level */ - (void)getsize_smbtar; /* Quiet unused parameter warning */ + g_snprintf(level_str, SIZEOF(level_str), "%d", level); - snprintf(level_str, SIZEOF(level_str), "%d", level); - - device = amname_to_devname(amdevice); + device = amname_to_devname(dle->device); qdevice = quote_string(device); - fstype = amname_to_fstype(amdevice); + fstype = amname_to_fstype(dle->device); - dbprintf(("%s: calculating for device %s with %s\n", - debug_prefix_time(NULL), qdevice, fstype)); + dbprintf(_("calculating for device %s with %s\n"), + qdevice, fstype); - cmd = vstralloc(libexecdir, "/rundump", versionsuffix(), NULL); + cmd = vstralloc(amlibexecdir, "/rundump", NULL); rundump_cmd = stralloc(cmd); if (g_options->config) config = g_options->config; else config = "NOCONFIG"; if ((stdoutfd = nullfd = open("/dev/null", O_RDWR)) == -1) { - dbprintf(("getsize_dump could not open /dev/null: %s\n", - strerror(errno))); + *errmsg = vstrallocf(_("getsize_dump could not open /dev/null: %s"), + strerror(errno)); + dbprintf("%s\n", *errmsg); amfree(cmd); amfree(rundump_cmd); amfree(fstype); @@ -1090,8 +1381,9 @@ getsize_dump( } pipefd[0] = pipefd[1] = killctl[0] = killctl[1] = -1; if (pipe(pipefd) < 0) { - dbprintf(("getsize_dump could create data pipes: %s\n", - strerror(errno))); + *errmsg = vstrallocf(_("getsize_dump could create data pipes: %s"), + strerror(errno)); + dbprintf("%s\n", *errmsg); amfree(cmd); amfree(rundump_cmd); amfree(fstype); @@ -1109,8 +1401,8 @@ getsize_dump( #endif /* } */ { name = stralloc(" (xfsdump)"); - dbprintf(("%s: running \"%s%s -F -J -l %s - %s\"\n", - debug_prefix_time(NULL), cmd, name, level_str, qdevice)); + dbprintf(_("running \"%s%s -F -J -l %s - %s\"\n"), + cmd, name, level_str, qdevice); } else #endif /* } */ @@ -1130,8 +1422,8 @@ getsize_dump( is_rundump = 0; #endif dumpkeys = vstralloc(level_str, "s", "f", NULL); - dbprintf(("%s: running \"%s%s %s 1048576 - %s\"\n", - debug_prefix_time(NULL), cmd, name, dumpkeys, qdevice)); + dbprintf(_("running \"%s%s %s 1048576 - %s\"\n"), + cmd, name, dumpkeys, qdevice); } else #endif /* } */ @@ -1143,13 +1435,9 @@ getsize_dump( #endif /* } */ { name = stralloc(" (vdump)"); - amfree(device); - amfree(qdevice); - device = amname_to_dirname(amdevice); - qdevice = quote_string(device); dumpkeys = vstralloc(level_str, "b", "f", NULL); - dbprintf(("%s: running \"%s%s %s 60 - %s\"\n", - debug_prefix_time(NULL), cmd, name, dumpkeys, qdevice)); + dbprintf(_("running \"%s%s %s 60 - %s\"\n"), + cmd, name, dumpkeys, qdevice); } else #endif /* } */ @@ -1170,16 +1458,22 @@ getsize_dump( # ifdef AIX_BACKUP /* { */ dumpkeys = vstralloc("-", level_str, "f", NULL); - dbprintf(("%s: running \"%s%s %s - %s\"\n", - debug_prefix_time(NULL), cmd, name, dumpkeys, qdevice)); + dbprintf(_("running \"%s%s %s - %s\"\n"), + cmd, name, dumpkeys, qdevice); # else /* } { */ +# ifdef HAVE_DUMP_ESTIMATE +# define PARAM_DUMP_ESTIMATE HAVE_DUMP_ESTIMATE +# else +# define PARAM_DUMP_ESTIMATE "" +# endif +# ifdef HAVE_HONOR_NODUMP +# define PARAM_HONOR_NODUMP "h" +# else +# define PARAM_HONOR_NODUMP "" +# endif dumpkeys = vstralloc(level_str, -# ifdef HAVE_DUMP_ESTIMATE /* { */ - HAVE_DUMP_ESTIMATE, -# endif /* } */ -# ifdef HAVE_HONOR_NODUMP /* { */ - "h", -# endif /* } */ + PARAM_DUMP_ESTIMATE, + PARAM_HONOR_NODUMP, "s", "f", NULL); # ifdef HAVE_DUMP_ESTIMATE @@ -1187,24 +1481,23 @@ getsize_dump( # endif # ifdef HAVE_HONOR_NODUMP /* { */ - dbprintf(("%s: running \"%s%s %s 0 1048576 - %s\"\n", - debug_prefix_time(NULL), cmd, name, dumpkeys, qdevice)); + dbprintf(_("running \"%s%s %s 0 1048576 - %s\"\n"), + cmd, name, dumpkeys, qdevice); # else /* } { */ - dbprintf(("%s: running \"%s%s %s 1048576 - %s\"\n", - debug_prefix_time(NULL), cmd, name, dumpkeys, qdevice)); + dbprintf(_("running \"%s%s %s 1048576 - %s\"\n"), + cmd, name, dumpkeys, qdevice); # endif /* } */ # endif /* } */ } else #endif /* } */ { - error("no dump program available"); + error(_("no dump program available")); /*NOTREACHED*/ } if (pipe(killctl) < 0) { - dbprintf(("%s: Could not create pipe: %s\n", - debug_prefix(NULL), strerror(errno))); + dbprintf(_("Could not create pipe: %s\n"), strerror(errno)); /* Message will be printed later... */ killctl[0] = killctl[1] = -1; } @@ -1212,8 +1505,9 @@ getsize_dump( start_time = curclock(); switch(dumppid = fork()) { case -1: - dbprintf(("%s: cannot fork for killpgrp: %s\n", - debug_prefix(NULL), strerror(errno))); + *errmsg = vstrallocf(_("cannot fork for killpgrp: %s"), + strerror(errno)); + dbprintf("%s\n", *errmsg); amfree(dumpkeys); amfree(cmd); amfree(rundump_cmd); @@ -1229,21 +1523,18 @@ getsize_dump( if(SETPGRP == -1) SETPGRP_FAILED(); else if (killctl[0] == -1 || killctl[1] == -1) - dbprintf(("%s: Trying without killpgrp\n", debug_prefix(NULL))); + dbprintf(_("Trying without killpgrp\n")); else { switch(fork()) { case -1: - dbprintf(("%s: fork failed, trying without killpgrp\n", - debug_prefix(NULL))); + dbprintf(_("fork failed, trying without killpgrp\n")); break; default: { char *config; - char *killpgrp_cmd = vstralloc(libexecdir, "/killpgrp", - versionsuffix(), NULL); - dbprintf(("%s: running %s\n", - debug_prefix_time(NULL), killpgrp_cmd)); + char *killpgrp_cmd = vstralloc(amlibexecdir, "/killpgrp", NULL); + dbprintf(_("running %s\n"), killpgrp_cmd); dup2(killctl[0], 0); dup2(nullfd, 1); dup2(nullfd, 2); @@ -1255,10 +1546,11 @@ getsize_dump( config = g_options->config; else config = "NOCONFIG"; + safe_fd(-1, 0); execle(killpgrp_cmd, killpgrp_cmd, config, (char *)0, safe_env()); - dbprintf(("%s: cannot execute %s: %s\n", - debug_prefix(NULL), killpgrp_cmd, strerror(errno))); + dbprintf(_("cannot execute %s: %s\n"), + killpgrp_cmd, strerror(errno)); exit(-1); } @@ -1275,6 +1567,7 @@ getsize_dump( aclose(killctl[0]); if (killctl[1] != -1) aclose(killctl[1]); + safe_fd(-1, 0); #ifdef XFSDUMP #ifdef DUMP @@ -1343,7 +1636,7 @@ getsize_dump( # endif #endif { - error("exec %s failed or no dump program available: %s", + error(_("exec %s failed or no dump program available: %s"), cmd, strerror(errno)); /*NOTREACHED*/ } @@ -1357,14 +1650,14 @@ getsize_dump( aclose(killctl[0]); dumpout = fdopen(pipefd[0],"r"); if (!dumpout) { - error("Can't fdopen: %s", strerror(errno)); + error(_("Can't fdopen: %s"), strerror(errno)); /*NOTREACHED*/ } for(size = (off_t)-1; (line = agets(dumpout)) != NULL; free(line)) { if (line[0] == '\0') continue; - dbprintf(("%s: %s\n", debug_prefix_time(NULL), line)); + dbprintf("%s\n", line); size = handle_dumpline(line); if(size > (off_t)-1) { amfree(line); @@ -1374,40 +1667,40 @@ getsize_dump( amfree(line); } if (line != NULL) { - dbprintf(("%s: %s\n", debug_prefix_time(NULL), line)); + dbprintf("%s\n", line); } break; } } amfree(line); - dbprintf(("%s: .....\n", debug_prefix_time(NULL))); - dbprintf(("%s: estimate time for %s level %d: %s\n", - debug_prefix(NULL), + dbprintf(".....\n"); + dbprintf(_("estimate time for %s level %d: %s\n"), qdisk, level, - walltime_str(timessub(curclock(), start_time)))); + walltime_str(timessub(curclock(), start_time))); if(size == (off_t)-1) { - dbprintf(("%s: no size line match in %s%s output for \"%s\"\n", - debug_prefix(NULL), cmd, name, disk)); - dbprintf(("%s: .....\n", debug_prefix(NULL))); - dbprintf(("%s: Run %s%s manually to check for errors\n", - debug_prefix(NULL), cmd, name)); + *errmsg = vstrallocf(_("no size line match in %s%s output"), + cmd, name); + dbprintf(_("%s for %s\n"), + *errmsg, qdisk); + + dbprintf(".....\n"); + dbprintf(_("Run %s%s manually to check for errors\n"), + cmd, name); } else if(size == (off_t)0 && level == 0) { - dbprintf(("%s: possible %s%s problem -- is \"%s\" really empty?\n", - debug_prefix(NULL), cmd, name, disk)); - dbprintf(("%s: .....\n", debug_prefix(NULL))); + dbprintf(_("possible %s%s problem -- is \"%s\" really empty?\n"), + cmd, name, dle->disk); + dbprintf(".....\n"); } else { - dbprintf(("%s: estimate size for %s level %d: %ld KB\n", - debug_prefix(NULL), + dbprintf(_("estimate size for %s level %d: %lld KB\n"), qdisk, level, - size)); + (long long)size); } if (killctl[1] != -1) { - dbprintf(("%s: asking killpgrp to terminate\n", - debug_prefix_time(NULL))); + dbprintf(_("asking killpgrp to terminate\n")); aclose(killctl[1]); for(s = 5; s > 0; --s) { sleep(1); @@ -1420,11 +1713,9 @@ getsize_dump( * First, try to kill the dump process nicely. If it ignores us * for several seconds, hit it harder. */ - dbprintf(("%s: sending SIGTERM to process group %ld\n", - debug_prefix_time(NULL), (long)dumppid)); + dbprintf(_("sending SIGTERM to process group %ld\n"), (long)dumppid); if (kill(-dumppid, SIGTERM) == -1) { - dbprintf(("%s: kill failed: %s\n", - debug_prefix(NULL), strerror(errno))); + dbprintf(_("kill failed: %s\n"), strerror(errno)); } /* Now check whether it dies */ for(s = 5; s > 0; --s) { @@ -1433,11 +1724,9 @@ getsize_dump( goto terminated; } - dbprintf(("%s: sending SIGKILL to process group %ld\n", - debug_prefix_time(NULL), (long)dumppid)); + dbprintf(_("sending SIGKILL to process group %ld\n"), (long)dumppid); if (kill(-dumppid, SIGKILL) == -1) { - dbprintf(("%s: kill failed: %s\n", - debug_prefix(NULL), strerror(errno))); + dbprintf(_("kill failed: %s\n"), strerror(errno)); } for(s = 5; s > 0; --s) { sleep(1); @@ -1445,11 +1734,23 @@ getsize_dump( goto terminated; } - dbprintf(("%s: waiting for %s%s \"%s\" child\n", - debug_prefix_time(NULL), cmd, name, qdisk)); - wait(NULL); - dbprintf(("%s: after %s%s %s wait\n", - debug_prefix_time(NULL), cmd, name, qdisk)); + dbprintf(_("waiting for %s%s \"%s\" child\n"), cmd, name, qdisk); + waitpid(dumppid, &wait_status, 0); + if (WIFSIGNALED(wait_status)) { + *errmsg = vstrallocf(_("%s terminated with signal %d: see %s"), + cmd, WTERMSIG(wait_status), dbfn()); + } else if (WIFEXITED(wait_status)) { + if (WEXITSTATUS(wait_status) != 0) { + *errmsg = vstrallocf(_("%s exited with status %d: see %s"), + cmd, WEXITSTATUS(wait_status), dbfn()); + } else { + /* Normal exit */ + } + } else { + *errmsg = vstrallocf(_("%s got bad exit: see %s"), + cmd, dbfn()); + } + dbprintf(_("after %s%s %s wait\n"), cmd, name, qdisk); terminated: @@ -1470,10 +1771,9 @@ getsize_dump( #ifdef SAMBA_CLIENT off_t getsize_smbtar( - char *disk, - char *amdevice, + dle_t *dle, int level, - option_t * options) + char **errmsg) { int pipefd = -1, nullfd = -1, passwdfd = -1; pid_t dumppid; @@ -1488,19 +1788,21 @@ getsize_smbtar( char *pw_fd_env; times_t start_time; char *error_pn = NULL; - char *qdisk = quote_string(disk); - - (void)options; /* Quiet unused parameter warning */ + char *qdisk = quote_string(dle->disk); + amwait_t wait_status; error_pn = stralloc2(get_pname(), "-smbclient"); - parsesharename(amdevice, &share, &subdir); + if (level > 1) + return -2; /* planner will not even consider this level */ + + parsesharename(dle->device, &share, &subdir); if (!share) { amfree(share); amfree(subdir); set_pname(error_pn); amfree(error_pn); - error("cannot parse disk entry %s for share/subdir", qdisk); + error(_("cannot parse disk entry %s for share/subdir"), qdisk); /*NOTREACHED*/ } if ((subdir) && (SAMBA_VERSION < 2)) { @@ -1508,7 +1810,7 @@ getsize_smbtar( amfree(subdir); set_pname(error_pn); amfree(error_pn); - error("subdirectory specified for share %s but samba not v2 or better", qdisk); + error(_("subdirectory specified for share %s but samba not v2 or better"), qdisk); /*NOTREACHED*/ } if ((user_and_password = findpass(share, &domain)) == NULL) { @@ -1519,7 +1821,7 @@ getsize_smbtar( } set_pname(error_pn); amfree(error_pn); - error("cannot find password for %s", disk); + error(_("cannot find password for %s"), dle->disk); /*NOTREACHED*/ } lpass = strlen(user_and_password); @@ -1532,7 +1834,7 @@ getsize_smbtar( } set_pname(error_pn); amfree(error_pn); - error("password field not \'user%%pass\' for %s", disk); + error(_("password field not \'user%%pass\' for %s"), dle->disk); /*NOTREACHED*/ } *pwtext++ = '\0'; @@ -1546,7 +1848,7 @@ getsize_smbtar( } set_pname(error_pn); amfree(error_pn); - error("cannot make share name of %s", share); + error(_("cannot make share name of %s"), share); /*NOTREACHED*/ } if ((nullfd = open("/dev/null", O_RDWR)) == -1) { @@ -1559,7 +1861,7 @@ getsize_smbtar( set_pname(error_pn); amfree(error_pn); amfree(sharename); - error("could not open /dev/null: %s\n", + error(_("could not open /dev/null: %s\n"), strerror(errno)); /*NOTREACHED*/ } @@ -1583,7 +1885,7 @@ getsize_smbtar( } else { pw_fd_env = "dummy_PASSWD_FD"; } - dumppid = pipespawn(SAMBA_CLIENT, STDERR_PIPE|PASSWD_PIPE, + dumppid = pipespawn(SAMBA_CLIENT, STDERR_PIPE|PASSWD_PIPE, 0, &nullfd, &nullfd, &pipefd, pw_fd_env, &passwdfd, "smbclient", @@ -1605,7 +1907,7 @@ getsize_smbtar( amfree(domain); } aclose(nullfd); - if(pwtext_len > 0 && fullwrite(passwdfd, pwtext, (size_t)pwtext_len) < 0) { + if(pwtext_len > 0 && full_write(passwdfd, pwtext, pwtext_len) < pwtext_len) { int save_errno = errno; memset(user_and_password, '\0', (size_t)lpass); @@ -1613,7 +1915,7 @@ getsize_smbtar( aclose(passwdfd); set_pname(error_pn); amfree(error_pn); - error("password write failed: %s", strerror(save_errno)); + error(_("password write failed: %s"), strerror(save_errno)); /*NOTREACHED*/ } memset(user_and_password, '\0', (size_t)lpass); @@ -1625,14 +1927,14 @@ getsize_smbtar( amfree(error_pn); dumpout = fdopen(pipefd,"r"); if (!dumpout) { - error("Can't fdopen: %s", strerror(errno)); + error(_("Can't fdopen: %s"), strerror(errno)); /*NOTREACHED*/ } for(size = (off_t)-1; (line = agets(dumpout)) != NULL; free(line)) { if (line[0] == '\0') continue; - dbprintf(("%s: %s\n", debug_prefix_time(NULL), line)); + dbprintf("%s\n", line); size = handle_dumpline(line); if(size > -1) { amfree(line); @@ -1642,41 +1944,54 @@ getsize_smbtar( amfree(line); } if(line != NULL) { - dbprintf(("%s: %s\n", debug_prefix_time(NULL), line)); + dbprintf("%s\n", line); } break; } } amfree(line); - dbprintf(("%s: .....\n", debug_prefix_time(NULL))); - dbprintf(("%s: estimate time for %s level %d: %s\n", - debug_prefix(NULL), + dbprintf(".....\n"); + dbprintf(_("estimate time for %s level %d: %s\n"), qdisk, level, - walltime_str(timessub(curclock(), start_time)))); + walltime_str(timessub(curclock(), start_time))); if(size == (off_t)-1) { - dbprintf(("%s: no size line match in %s output for \"%s\"\n", - debug_prefix(NULL), SAMBA_CLIENT, disk)); - dbprintf(("%s: .....\n", debug_prefix(NULL))); + *errmsg = vstrallocf(_("no size line match in %s output"), + SAMBA_CLIENT); + dbprintf(_("%s for %s\n"), + *errmsg, qdisk); + dbprintf(".....\n"); } else if(size == (off_t)0 && level == 0) { - dbprintf(("%s: possible %s problem -- is \"%s\" really empty?\n", - debug_prefix(NULL), SAMBA_CLIENT, disk)); - dbprintf(("%s: .....\n", debug_prefix(NULL))); + dbprintf(_("possible %s problem -- is \"%s\" really empty?\n"), + SAMBA_CLIENT, dle->disk); + dbprintf(".....\n"); } - dbprintf(("%s: estimate size for %s level %d: %ld KB\n", - debug_prefix(NULL), + dbprintf(_("estimate size for %s level %d: %lld KB\n"), qdisk, level, - size)); + (long long)size); kill(-dumppid, SIGTERM); - dbprintf(("%s: waiting for %s \"%s\" child\n", - debug_prefix_time(NULL), SAMBA_CLIENT, qdisk)); - wait(NULL); - dbprintf(("%s: after %s %s wait\n", - debug_prefix_time(NULL), SAMBA_CLIENT, qdisk)); + dbprintf(_("waiting for %s \"%s\" child\n"), SAMBA_CLIENT, qdisk); + waitpid(dumppid, &wait_status, 0); + if (WIFSIGNALED(wait_status)) { + *errmsg = vstrallocf(_("%s terminated with signal %d: see %s"), + SAMBA_CLIENT, WTERMSIG(wait_status), dbfn()); + } else if (WIFEXITED(wait_status)) { + if (WEXITSTATUS(wait_status) != 0) { + *errmsg = vstrallocf(_("%s exited with status %d: see %s"), + SAMBA_CLIENT, WEXITSTATUS(wait_status), + dbfn()); + } else { + /* Normal exit */ + } + } else { + *errmsg = vstrallocf(_("%s got bad exit: see %s"), + SAMBA_CLIENT, dbfn()); + } + dbprintf(_("after %s %s wait\n"), SAMBA_CLIENT, qdisk); afclose(dumpout); pipefd = -1; @@ -1691,11 +2006,10 @@ getsize_smbtar( #ifdef GNUTAR off_t getsize_gnutar( - char *disk, - char *amdevice, + dle_t *dle, int level, - option_t * options, - time_t dumpsince) + time_t dumpsince, + char **errmsg) { int pipefd = -1, nullfd = -1; pid_t dumppid; @@ -1709,56 +2023,50 @@ getsize_gnutar( FILE *out = NULL; char *line = NULL; char *cmd = NULL; + char *command = NULL; char dumptimestr[80]; struct tm *gmtm; int nb_exclude = 0; int nb_include = 0; - char **my_argv; - int i; + GPtrArray *argv_ptr = g_ptr_array_new(); char *file_exclude = NULL; char *file_include = NULL; times_t start_time; int infd, outfd; ssize_t nb; char buf[32768]; - char *qdisk = quote_string(disk); + char *qdisk = quote_string(dle->disk); char *gnutar_list_dir; + amwait_t wait_status; + char tmppath[PATH_MAX]; - if(options->exclude_file) nb_exclude += options->exclude_file->nb_element; - if(options->exclude_list) nb_exclude += options->exclude_list->nb_element; - if(options->include_file) nb_include += options->include_file->nb_element; - if(options->include_list) nb_include += options->include_list->nb_element; + if (level > 9) + return -2; /* planner will not even consider this level */ - if(nb_exclude > 0) file_exclude = build_exclude(disk, amdevice, options, 0); - if(nb_include > 0) file_include = build_include(disk, amdevice, options, 0); + if(dle->exclude_file) nb_exclude += dle->exclude_file->nb_element; + if(dle->exclude_list) nb_exclude += dle->exclude_list->nb_element; + if(dle->include_file) nb_include += dle->include_file->nb_element; + if(dle->include_list) nb_include += dle->include_list->nb_element; - my_argv = alloc(SIZEOF(char *) * 22); - i = 0; + if(nb_exclude > 0) file_exclude = build_exclude(dle, 0); + if(nb_include > 0) file_include = build_include(dle, 0); - gnutar_list_dir = client_getconf_str(CLN_GNUTAR_LIST_DIR); + gnutar_list_dir = getconf_str(CNF_GNUTAR_LIST_DIR); if (strlen(gnutar_list_dir) == 0) gnutar_list_dir = NULL; if (gnutar_list_dir) { char number[NUM_STR_SIZE]; - char *s; - int ch; int baselevel; + char *sdisk = sanitise_filename(dle->disk); basename = vstralloc(gnutar_list_dir, "/", g_options->hostname, - disk, + sdisk, NULL); - /* - * The loop starts at the first character of the host name, - * not the '/'. - */ - s = basename + strlen(gnutar_list_dir) + 1; - while((ch = *s++) != '\0') { - if(ch == '/' || isspace(ch)) s[-1] = '_'; - } + amfree(sdisk); - snprintf(number, SIZEOF(number), "%d", level); + g_snprintf(number, SIZEOF(number), "%d", level); incrname = vstralloc(basename, "_", number, ".new", NULL); unlink(incrname); @@ -1771,20 +2079,21 @@ getsize_gnutar( infd = -1; while (infd == -1) { if (--baselevel >= 0) { - snprintf(number, SIZEOF(number), "%d", baselevel); + g_snprintf(number, SIZEOF(number), "%d", baselevel); inputname = newvstralloc(inputname, basename, "_", number, NULL); } else { inputname = newstralloc(inputname, "/dev/null"); } if ((infd = open(inputname, O_RDONLY)) == -1) { - int save_errno = errno; - dbprintf(("%s: gnutar: error opening %s: %s\n", - debug_prefix(NULL), inputname, strerror(save_errno))); + *errmsg = vstrallocf(_("gnutar: error opening %s: %s"), + inputname, strerror(errno)); + dbprintf("%s\n", *errmsg); if (baselevel < 0) { goto common_exit; } + amfree(*errmsg); } } @@ -1792,33 +2101,38 @@ getsize_gnutar( * Copy the previous listed incremental file to the new one. */ if ((outfd = open(incrname, O_WRONLY|O_CREAT, 0600)) == -1) { - dbprintf(("%s: opening %s: %s\n", - debug_prefix(NULL), incrname, strerror(errno))); + *errmsg = vstrallocf(_("opening %s: %s"), + incrname, strerror(errno)); + dbprintf("%s\n", *errmsg); goto common_exit; } while ((nb = read(infd, &buf, SIZEOF(buf))) > 0) { - if (fullwrite(outfd, &buf, (size_t)nb) < nb) { - dbprintf(("%s: writing to %s: %s\n", - debug_prefix(NULL), incrname, strerror(errno))); + if (full_write(outfd, &buf, (size_t)nb) < (size_t)nb) { + *errmsg = vstrallocf(_("writing to %s: %s"), + incrname, strerror(errno)); + dbprintf("%s\n", *errmsg); goto common_exit; } } if (nb < 0) { - dbprintf(("%s: reading from %s: %s\n", - debug_prefix(NULL), inputname, strerror(errno))); + *errmsg = vstrallocf(_("reading from %s: %s"), + inputname, strerror(errno)); + dbprintf("%s\n", *errmsg); goto common_exit; } if (close(infd) != 0) { - dbprintf(("%s: closing %s: %s\n", - debug_prefix(NULL), inputname, strerror(errno))); + *errmsg = vstrallocf(_("closing %s: %s"), + inputname, strerror(errno)); + dbprintf("%s\n", *errmsg); goto common_exit; } if (close(outfd) != 0) { - dbprintf(("%s: closing %s: %s\n", - debug_prefix(NULL), incrname, strerror(errno))); + *errmsg = vstrallocf(_("closing %s: %s"), + incrname, strerror(errno)); + dbprintf("%s\n", *errmsg); goto common_exit; } @@ -1827,38 +2141,42 @@ getsize_gnutar( } gmtm = gmtime(&dumpsince); - snprintf(dumptimestr, SIZEOF(dumptimestr), + g_snprintf(dumptimestr, SIZEOF(dumptimestr), "%04d-%02d-%02d %2d:%02d:%02d GMT", gmtm->tm_year + 1900, gmtm->tm_mon+1, gmtm->tm_mday, gmtm->tm_hour, gmtm->tm_min, gmtm->tm_sec); - dirname = amname_to_dirname(amdevice); + dirname = amname_to_dirname(dle->device); - cmd = vstralloc(libexecdir, "/", "runtar", versionsuffix(), NULL); - my_argv[i++] = "runtar"; + cmd = vstralloc(amlibexecdir, "/", "runtar", NULL); + g_ptr_array_add(argv_ptr, stralloc("runtar")); if (g_options->config) - my_argv[i++] = g_options->config; + g_ptr_array_add(argv_ptr, stralloc(g_options->config)); else - my_argv[i++] = "NOCONFIG"; + g_ptr_array_add(argv_ptr, stralloc("NOCONFIG")); #ifdef GNUTAR - my_argv[i++] = GNUTAR; + g_ptr_array_add(argv_ptr, stralloc(GNUTAR)); #else - my_argv[i++] = "tar"; + g_ptr_array_add(argv_ptr, stralloc("tar")); #endif - my_argv[i++] = "--create"; - my_argv[i++] = "--file"; - my_argv[i++] = "/dev/null"; - my_argv[i++] = "--directory"; - my_argv[i++] = dirname; - my_argv[i++] = "--one-file-system"; + g_ptr_array_add(argv_ptr, stralloc("--create")); + g_ptr_array_add(argv_ptr, stralloc("--file")); + g_ptr_array_add(argv_ptr, stralloc("/dev/null")); + /* use --numeric-owner for estimates, to reduce the number of user/group + * lookups required */ + g_ptr_array_add(argv_ptr, stralloc("--numeric-owner")); + g_ptr_array_add(argv_ptr, stralloc("--directory")); + canonicalize_pathname(dirname, tmppath); + g_ptr_array_add(argv_ptr, stralloc(tmppath)); + g_ptr_array_add(argv_ptr, stralloc("--one-file-system")); if (gnutar_list_dir) { - my_argv[i++] = "--listed-incremental"; - my_argv[i++] = incrname; + g_ptr_array_add(argv_ptr, stralloc("--listed-incremental")); + g_ptr_array_add(argv_ptr, stralloc(incrname)); } else { - my_argv[i++] = "--incremental"; - my_argv[i++] = "--newer"; - my_argv[i++] = dumptimestr; + g_ptr_array_add(argv_ptr, stralloc("--incremental")); + g_ptr_array_add(argv_ptr, stralloc("--newer")); + g_ptr_array_add(argv_ptr, stralloc(dumptimestr)); } #ifdef ENABLE_GNUTAR_ATIME_PRESERVE /* --atime-preserve causes gnutar to call @@ -1866,45 +2184,49 @@ getsize_gnutar( * adjust their atime. However, utime() * updates the file's ctime, so incremental * dumps will think the file has changed. */ - my_argv[i++] = "--atime-preserve"; + g_ptr_array_add(argv_ptr, stralloc("--atime-preserve")); #endif - my_argv[i++] = "--sparse"; - my_argv[i++] = "--ignore-failed-read"; - my_argv[i++] = "--totals"; + g_ptr_array_add(argv_ptr, stralloc("--sparse")); + g_ptr_array_add(argv_ptr, stralloc("--ignore-failed-read")); + g_ptr_array_add(argv_ptr, stralloc("--totals")); if(file_exclude) { - my_argv[i++] = "--exclude-from"; - my_argv[i++] = file_exclude; + g_ptr_array_add(argv_ptr, stralloc("--exclude-from")); + g_ptr_array_add(argv_ptr, stralloc(file_exclude)); } if(file_include) { - my_argv[i++] = "--files-from"; - my_argv[i++] = file_include; + g_ptr_array_add(argv_ptr, stralloc("--files-from")); + g_ptr_array_add(argv_ptr, stralloc(file_include)); } else { - my_argv[i++] = "."; + g_ptr_array_add(argv_ptr, stralloc(".")); } - my_argv[i++] = NULL; + g_ptr_array_add(argv_ptr, NULL); start_time = curclock(); if ((nullfd = open("/dev/null", O_RDWR)) == -1) { - dbprintf(("Cannot access /dev/null : %s\n", strerror(errno))); + *errmsg = vstrallocf(_("Cannot access /dev/null : %s"), + strerror(errno)); + dbprintf("%s\n", *errmsg); goto common_exit; } - dumppid = pipespawnv(cmd, STDERR_PIPE, &nullfd, &nullfd, &pipefd, my_argv); + command = (char *)g_ptr_array_index(argv_ptr, 0); + dumppid = pipespawnv(cmd, STDERR_PIPE, 0, + &nullfd, &nullfd, &pipefd, (char **)argv_ptr->pdata); dumpout = fdopen(pipefd,"r"); if (!dumpout) { - error("Can't fdopen: %s", strerror(errno)); + error(_("Can't fdopen: %s"), strerror(errno)); /*NOTREACHED*/ } for(size = (off_t)-1; (line = agets(dumpout)) != NULL; free(line)) { if (line[0] == '\0') continue; - dbprintf(("%s: %s\n", debug_prefix_time(NULL), line)); + dbprintf("%s\n", line); size = handle_dumpline(line); if(size > (off_t)-1) { amfree(line); @@ -1915,7 +2237,7 @@ getsize_gnutar( amfree(line); } if (line != NULL) { - dbprintf(("%s: %s\n", debug_prefix_time(NULL), line)); + dbprintf("%s\n", line); break; } break; @@ -1923,34 +2245,46 @@ getsize_gnutar( } amfree(line); - dbprintf(("%s: .....\n", debug_prefix_time(NULL))); - dbprintf(("%s: estimate time for %s level %d: %s\n", - debug_prefix(NULL), + dbprintf(".....\n"); + dbprintf(_("estimate time for %s level %d: %s\n"), qdisk, level, - walltime_str(timessub(curclock(), start_time)))); + walltime_str(timessub(curclock(), start_time))); if(size == (off_t)-1) { - dbprintf(("%s: no size line match in %s output for \"%s\"\n", - debug_prefix(NULL), my_argv[0], disk)); - dbprintf(("%s: .....\n", debug_prefix(NULL))); + *errmsg = vstrallocf(_("no size line match in %s output"), + command); + dbprintf(_("%s for %s\n"), *errmsg, qdisk); + dbprintf(".....\n"); } else if(size == (off_t)0 && level == 0) { - dbprintf(("%s: possible %s problem -- is \"%s\" really empty?\n", - debug_prefix(NULL), my_argv[0], disk)); - dbprintf(("%s: .....\n", debug_prefix(NULL))); + dbprintf(_("possible %s problem -- is \"%s\" really empty?\n"), + command, dle->disk); + dbprintf(".....\n"); } - dbprintf(("%s: estimate size for %s level %d: %ld KB\n", - debug_prefix(NULL), + dbprintf(_("estimate size for %s level %d: %lld KB\n"), qdisk, level, - size)); + (long long)size); kill(-dumppid, SIGTERM); - dbprintf(("%s: waiting for %s \"%s\" child\n", - debug_prefix_time(NULL), my_argv[0], qdisk)); - wait(NULL); - dbprintf(("%s: after %s %s wait\n", - debug_prefix_time(NULL), my_argv[0], qdisk)); + dbprintf(_("waiting for %s \"%s\" child\n"), + command, qdisk); + waitpid(dumppid, &wait_status, 0); + if (WIFSIGNALED(wait_status)) { + *errmsg = vstrallocf(_("%s terminated with signal %d: see %s"), + cmd, WTERMSIG(wait_status), dbfn()); + } else if (WIFEXITED(wait_status)) { + if (WEXITSTATUS(wait_status) != 0) { + *errmsg = vstrallocf(_("%s exited with status %d: see %s"), + cmd, WEXITSTATUS(wait_status), dbfn()); + } else { + /* Normal exit */ + } + } else { + *errmsg = vstrallocf(_("%s got bad exit: see %s"), + cmd, dbfn()); + } + dbprintf(_("after %s %s wait\n"), command, qdisk); common_exit: @@ -1961,7 +2295,7 @@ common_exit: amfree(basename); amfree(dirname); amfree(inputname); - amfree(my_argv); + g_ptr_array_free_full(argv_ptr); amfree(qdisk); amfree(cmd); amfree(file_exclude); @@ -1977,68 +2311,111 @@ common_exit: #endif off_t -getsize_wrapper( - char *program, - char *disk, - char *amdevice, - int level, - option_t * options, - time_t dumpsince) +getsize_application_api( + disk_estimates_t *est, + int nb_level, + int *levels, + backup_support_option_t *bsu) { - int pipefd[2], nullfd; + dle_t *dle = est->dle; + int pipeinfd[2], pipeoutfd[2], pipeerrfd[2]; pid_t dumppid; off_t size = (off_t)-1; FILE *dumpout; + FILE *dumperr; char *line = NULL; char *cmd = NULL; - char dumptimestr[80]; - struct tm *gmtm; - int i, j; - char *argvchild[10]; + char *cmdline; + guint i; + int j; + GPtrArray *argv_ptr = g_ptr_array_new(); char *newoptstr = NULL; off_t size1, size2; times_t start_time; - char *qdisk = quote_string(disk); - char *qamdevice = quote_string(amdevice); - - gmtm = gmtime(&dumpsince); - snprintf(dumptimestr, SIZEOF(dumptimestr), - "%04d-%02d-%02d %2d:%02d:%02d GMT", - gmtm->tm_year + 1900, gmtm->tm_mon+1, gmtm->tm_mday, - gmtm->tm_hour, gmtm->tm_min, gmtm->tm_sec); + char *qdisk = quote_string(dle->disk); + char *qamdevice = quote_string(dle->device); + amwait_t wait_status; + char levelstr[NUM_STR_SIZE]; + GSList *scriptlist; + script_t *script; + char *errmsg = NULL; + estimate_t estimate; + estimatelist_t el; + + cmd = vstralloc(APPLICATION_DIR, "/", dle->program, NULL); + + g_ptr_array_add(argv_ptr, stralloc(dle->program)); + g_ptr_array_add(argv_ptr, stralloc("estimate")); + 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)); + } + g_ptr_array_add(argv_ptr, stralloc("--device")); + g_ptr_array_add(argv_ptr, stralloc(dle->device)); + if (dle->disk && bsu->disk == 1) { + g_ptr_array_add(argv_ptr, stralloc("--disk")); + g_ptr_array_add(argv_ptr, stralloc(dle->disk)); + } + for (j=0; j < nb_level; j++) { + g_ptr_array_add(argv_ptr, stralloc("--level")); + g_snprintf(levelstr,SIZEOF(levelstr),"%d", levels[j]); + g_ptr_array_add(argv_ptr, stralloc(levelstr)); + } + /* find the first in ES_CLIENT and ES_CALCSIZE */ + estimate = ES_CLIENT; + for (el = dle->estimatelist; el != NULL; el = el->next) { + estimate = (estimate_t)GPOINTER_TO_INT(el->data); + if ((estimate == ES_CLIENT && bsu->client_estimate) || + (estimate == ES_CALCSIZE && bsu->calcsize)) + break; + estimate = ES_CLIENT; + } + if (estimate == ES_CALCSIZE && bsu->calcsize) { + g_ptr_array_add(argv_ptr, stralloc("--calcsize")); + } - cmd = vstralloc(DUMPER_DIR, "/", program, NULL); + application_property_add_to_argv(argv_ptr, dle, bsu, g_options->features); - i=0; - argvchild[i++] = program; - argvchild[i++] = "estimate"; - if(level == 0) - argvchild[i++] = "full"; - else { - char levelstr[NUM_STR_SIZE]; - snprintf(levelstr,SIZEOF(levelstr),"%d",level); - argvchild[i++] = "level"; - argvchild[i++] = levelstr; + 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); + } } - argvchild[i++] = amdevice; - newoptstr = vstralloc(options->str,"estimate-direct;", NULL); - argvchild[i++] = newoptstr; - argvchild[i] = NULL; - dbprintf(("%s: running %s", debug_prefix_time(NULL), cmd)); - for(j = 1; j < i; j++) { - dbprintf((" %s", argvchild[j])); + g_ptr_array_add(argv_ptr, NULL); + + cmdline = stralloc(cmd); + for(i = 1; i < argv_ptr->len-1; i++) + cmdline = vstrextend(&cmdline, " ", + (char *)g_ptr_array_index(argv_ptr, i), NULL); + dbprintf("running: \"%s\"\n", cmdline); + amfree(cmdline); + + if (pipe(pipeerrfd) < 0) { + errmsg = vstrallocf(_("getsize_application_api could not create data pipes: %s"), + strerror(errno)); + goto common_exit; } - dbprintf(("\n")); - if ((nullfd = open("/dev/null", O_RDWR)) == -1) { - dbprintf(("Cannot access /dev/null : %s\n", strerror(errno))); + if (pipe(pipeinfd) < 0) { + errmsg = vstrallocf(_("getsize_application_api could not create data pipes: %s"), + strerror(errno)); goto common_exit; } - if (pipe(pipefd) < 0) { - dbprintf(("getsize_wrapper could create data pipes: %s\n", - strerror(errno))); + if (pipe(pipeoutfd) < 0) { + errmsg = vstrallocf(_("getsize_application_api could not create data pipes: %s"), + strerror(errno)); goto common_exit; } @@ -2051,87 +2428,147 @@ getsize_wrapper( default: break; /* parent */ case 0: - dup2(nullfd, 0); - dup2(nullfd, 2); - dup2(pipefd[1], 1); - aclose(pipefd[0]); - - execve(cmd, argvchild, safe_env()); - error("exec %s failed: %s", cmd, strerror(errno)); + dup2(pipeinfd[0], 0); + dup2(pipeoutfd[1], 1); + dup2(pipeerrfd[1], 2); + aclose(pipeinfd[1]); + aclose(pipeoutfd[0]); + aclose(pipeerrfd[0]); + safe_fd(-1, 0); + + execve(cmd, (char **)argv_ptr->pdata, safe_env()); + error(_("exec %s failed: %s"), cmd, strerror(errno)); /*NOTREACHED*/ } amfree(newoptstr); - aclose(pipefd[1]); - dumpout = fdopen(pipefd[0],"r"); + aclose(pipeinfd[0]); + aclose(pipeoutfd[1]); + aclose(pipeerrfd[1]); + aclose(pipeinfd[1]); + + dumpout = fdopen(pipeoutfd[0],"r"); if (!dumpout) { - error("Can't fdopen: %s", strerror(errno)); + error(_("Can't fdopen: %s"), strerror(errno)); /*NOTREACHED*/ } for(size = (off_t)-1; (line = agets(dumpout)) != NULL; free(line)) { + long long size1_ = (long long)0; + long long size2_ = (long long)0; + int level = 0; if (line[0] == '\0') continue; - dbprintf(("%s: %s\n", debug_prefix_time(NULL), line)); - i = sscanf(line, OFF_T_FMT " " OFF_T_FMT, - (OFF_T_FMT_TYPE *)&size1, - (OFF_T_FMT_TYPE *)&size2); - if(i == 2) { - size = size1 * size2; + dbprintf("%s\n", line); + if (strncmp(line,"ERROR ", 6) == 0) { + char *errmsg, *qerrmsg; + + errmsg = stralloc(line+6); + qerrmsg = quote_string(errmsg); + dbprintf(_("errmsg is %s\n"), errmsg); + g_printf(_("%s %d ERROR %s\n"), est->qamname, levels[0], qerrmsg); + amfree(qerrmsg); + continue; } - if(size > -1) { - amfree(line); - while ((line = agets(dumpout)) != NULL) { - if (line[0] != '\0') - break; - amfree(line); - } - if(line != NULL) { - dbprintf(("%s: %s\n", debug_prefix_time(NULL), line)); + i = sscanf(line, "%d %lld %lld", &level, &size1_, &size2_); + if (i != 3) { + i = sscanf(line, "%lld %lld", &size1_, &size2_); + level = levels[0]; + if (i != 2) { + char *errmsg, *qerrmsg; + + errmsg = vstrallocf(_("bad line %s"), line); + qerrmsg = quote_string(errmsg); + dbprintf(_("errmsg is %s\n"), errmsg); + g_printf(_("%s %d ERROR %s\n"), est->qamname, levels[0], qerrmsg); + amfree(qerrmsg); + continue; } - break; } + size1 = (off_t)size1_; + size2 = (off_t)size2_; + if (size1 <= 0 || size2 <=0) + size = -1; + else if (size1 * size2 > 0) + size = size1 * size2; + dbprintf(_("estimate size for %s level %d: %lld KB\n"), + qamdevice, + level, + (long long)size); + g_printf("%s %d SIZE %lld\n", est->qamname, level, (long long)size); } amfree(line); - dbprintf(("%s: .....\n", debug_prefix_time(NULL))); - dbprintf(("%s: estimate time for %s level %d: %s\n", - debug_prefix(NULL), - qamdevice, - level, - walltime_str(timessub(curclock(), start_time)))); - if(size == (off_t)-1) { - dbprintf(("%s: no size line match in %s output for \"%s\"\n", - debug_prefix(NULL), cmd, qdisk)); - dbprintf(("%s: .....\n", debug_prefix(NULL))); - } else if(size == (off_t)0 && level == 0) { - dbprintf(("%s: possible %s problem -- is \"%s\" really empty?\n", - debug_prefix(NULL), cmd, qdisk)); - dbprintf(("%s: .....\n", debug_prefix(NULL))); + dumperr = fdopen(pipeerrfd[0],"r"); + if (!dumperr) { + error(_("Can't fdopen: %s"), strerror(errno)); + /*NOTREACHED*/ + } + + while ((line = agets(dumperr)) != NULL) { + if (strlen(line) > 0) { + char *err = g_strdup_printf(_("Application '%s': %s"), + dle->program, line); + char *qerr = quote_string(err); + for (j=0; j < nb_level; j++) { + fprintf(stdout, "%s %d ERROR %s\n", + est->qamname, levels[j], qerr); + } + dbprintf("ERROR %s", qerr); + amfree(err); + amfree(qerr); + } + amfree(line); + } + + dbprintf(".....\n"); + if (nb_level == 1) { + dbprintf(_("estimate time for %s level %d: %s\n"), qamdevice, + levels[0], walltime_str(timessub(curclock(), start_time))); + } else { + dbprintf(_("estimate time for %s all level: %s\n"), qamdevice, + walltime_str(timessub(curclock(), start_time))); } - dbprintf(("%s: estimate size for %s level %d: " OFF_T_FMT " KB\n", - debug_prefix(NULL), - qamdevice, - level, - size)); kill(-dumppid, SIGTERM); - dbprintf(("%s: waiting for %s \"%s\" child\n", - debug_prefix_time(NULL), cmd, qdisk)); - wait(NULL); - dbprintf(("%s: after %s %s wait\n", - debug_prefix_time(NULL), cmd, qdisk)); + dbprintf(_("waiting for %s \"%s\" child\n"), cmd, qdisk); + waitpid(dumppid, &wait_status, 0); + if (WIFSIGNALED(wait_status)) { + errmsg = vstrallocf(_("%s terminated with signal %d: see %s"), + cmd, WTERMSIG(wait_status), dbfn()); + } else if (WIFEXITED(wait_status)) { + if (WEXITSTATUS(wait_status) != 0) { + errmsg = vstrallocf(_("%s exited with status %d: see %s"), cmd, + WEXITSTATUS(wait_status), dbfn()); + } else { + /* Normal exit */ + } + } else { + errmsg = vstrallocf(_("%s got bad exit: see %s"), + cmd, dbfn()); + } + dbprintf(_("after %s %s wait\n"), cmd, qdisk); - aclose(nullfd); afclose(dumpout); + afclose(dumperr); common_exit: amfree(cmd); + g_ptr_array_free_full(argv_ptr); amfree(newoptstr); amfree(qdisk); amfree(qamdevice); + if (errmsg) { + char *qerrmsg = quote_string(errmsg); + dbprintf(_("errmsg is %s\n"), errmsg); + for (j=0; j < nb_level; j++) { + g_printf(_("%s %d ERROR %s\n"), est->qamname, levels[j], qerrmsg); + } + amfree(errmsg); + amfree(qerrmsg); + } return size; } @@ -2167,7 +2604,7 @@ off_t handle_dumpline( char * str) { - regex_t *rp; + regex_scale_t *rp; double size; /* check for size match */