X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=client-src%2Fsendsize.c;h=8eb5c046c56afe7ca5e13589afefbadf3445b137;hb=b116e9366c7b2ea2c2eb53b0a13df4090e176235;hp=b7bf68815c8a3298806f372738a169d05eacd1ad;hpb=0de2ad0a86685398621fb8ffa6990c029681bb3a;p=debian%2Famanda diff --git a/client-src/sendsize.c b/client-src/sendsize.c index b7bf688..8eb5c04 100644 --- a/client-src/sendsize.c +++ b/client-src/sendsize.c @@ -24,44 +24,51 @@ * file named AUTHORS, in the root directory of this distribution. */ /* - * $Id: sendsize.c,v 1.97.2.13.4.6.2.23.2.3 2005/04/06 12:31:04 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 "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 @@ -71,19 +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 *amdevice; + char *qamname; + char *qamdevice; char *dirname; - char *program; - char *calcprog; - int spindle; + char *qdirname; pid_t child; int done; - option_t *options; + dle_t *dle; level_estimate_t est[DUMP_LEVELS]; } disk_estimates_t; @@ -92,26 +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 P((int argc, char **argv)); -void add_diskest P((char *disk, char *amdevice, int level, int spindle, - char *prog, char *calcprog, option_t *options)); -void calc_estimates P((disk_estimates_t *est)); -void free_estimates P((disk_estimates_t *est)); -void dump_calc_estimates P((disk_estimates_t *)); -void smbtar_calc_estimates P((disk_estimates_t *)); -void gnutar_calc_estimates P((disk_estimates_t *)); -void generic_calc_estimates P((disk_estimates_t *)); - - -int main(argc, argv) -int argc; -char **argv; +int main(int argc, char **argv); +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 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, *disk, *amdevice, *dumpdate; - option_t *options = NULL; + int level; + char *dumpdate; disk_estimates_t *est; disk_estimates_t *est1; disk_estimates_t *est_prev; @@ -119,50 +126,59 @@ char **argv; char *s, *fp; int ch; char *err_extra = NULL; - int fd; - unsigned long malloc_hist_1, malloc_size_1; - unsigned long malloc_hist_2, malloc_size_2; int done; int need_wait; int dumpsrunning; + char *qdisk = NULL; + char *qlist = NULL; + char *qamdevice = NULL; + dle_t *dle; + GSList *errlist; + level_t *alevel; + (void)argc; /* Quiet unused parameter warning */ + (void)argv; /* Quiet unused parameter warning */ /* initialize */ - for(fd = 3; fd < FD_SETSIZE; fd++) { - /* - * Make sure nobody spoofs us with a lot of extra open files - * that would cause an open we do to get a very high file - * descriptor, which in turn might be used as an index into - * an array (e.g. an fd_set). - */ - close(fd); - } - + /* + * 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"); - malloc_size_1 = malloc_inuse(&malloc_hist_1); + /* Don't die when child closes pipe */ + signal(SIGPIPE, SIG_IGN); - erroutput_type = (ERR_INTERACTIVE|ERR_SYSLOG); - dbopen(); + 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) */ - /* handle all service requests */ + check_running_as(RUNNING_AS_CLIENT_LOGIN); - start_amandates(0); + /* handle all service requests */ for(; (line = agets(stdin)) != NULL; free(line)) { -#define sc "OPTIONS " - if(strncmp(line, sc, sizeof(sc)-1) == 0) { -#undef sc + if (line[0] == '\0') + continue; + 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); @@ -170,139 +186,237 @@ char **argv; 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) { + /* 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; } + 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 = stralloc(_("no program name")); goto err; /* no program name */ } - prog = s - 1; + dle->program = 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 = "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 = "no disk name"; + err_extra = stralloc(_("no disk name")); goto err; /* no disk name */ } - disk = s - 1; - skip_non_whitespace(s, ch); - s[-1] = '\0'; + + if (qdisk != NULL) + amfree(qdisk); + + fp = s - 1; + skip_quoted_string(s, ch); + s[-1] = '\0'; /* terminate the disk name */ + qdisk = stralloc(fp); + dle->disk = unquote_string(qdisk); skip_whitespace(s, ch); /* find the device or level */ if (ch == '\0') { - err_extra = "bad level"; + err_extra = stralloc(_("bad level")); goto err; } if(!isdigit((int)s[-1])) { fp = s - 1; - skip_non_whitespace(s, ch); + skip_quoted_string(s, ch); s[-1] = '\0'; - amdevice = stralloc(fp); + qamdevice = stralloc(fp); + 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 = stralloc(_("bad level")); goto err; /* bad level */ } + if (level < 0 || level >= DUMP_LEVELS) { + 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 = "no dumpdate"; + err_extra = stralloc(_("no dumpdate")); goto err; /* no dumpdate */ } dumpdate = s - 1; skip_non_whitespace(s, ch); 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 = "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 exclusion list */ + 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); - if(strncmp(s-1, "exclude-file=", 13) == 0) { - options->exclude_file = - append_sl(options->exclude_file, s+12); - } - if(strncmp(s-1, "exclude-list=", 13) == 0) { - options->exclude_list = - append_sl(options->exclude_list, s+12); - } - - skip_non_whitespace(s, ch); - if(ch) { - err_extra = "extra text at end"; - goto err; /* should have gotten to end */ + while (ch != '\0') { + if(strncmp_const(s-1, "exclude-file=") == 0) { + qlist = unquote_string(s+12); + dle->exclude_file = + append_sl(dle->exclude_file, qlist); + amfree(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_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_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 = vstrallocf(_("Invalid parameter (%s)"), s-1); + goto err; /* should have gotten to end */ + } + skip_quoted_string(s, ch); + skip_whitespace(s, ch); /* find the inclusion list */ + amfree(qlist); } } } - else { - options = alloc(sizeof(option_t)); - init_options(options); - } } - add_diskest(disk, amdevice, level, spindle, prog, calcprog, options); - amfree(amdevice); + /*@ignore@*/ + dle_add_diskest(dle); + /*@end@*/ + } + if (g_options == NULL) { + 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; @@ -316,30 +430,24 @@ char **argv; 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. */ @@ -349,12 +457,13 @@ char **argv; } } 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); } } /* @@ -379,7 +488,7 @@ char **argv; /* * 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) { /* @@ -388,7 +497,7 @@ char **argv; */ continue; } - if(est1->spindle == est->spindle) { + if(est1->dle->spindle == est->dle->spindle) { break; /* oops -- they match */ } } @@ -404,17 +513,25 @@ char **argv; } } 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); @@ -425,104 +542,159 @@ char **argv; 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->str); - amfree(g_options->hostname); - amfree(g_options); - - malloc_size_2 = malloc_inuse(&malloc_hist_2); - - if(malloc_size_1 != malloc_size_2) { -#if defined(USE_DBMALLOC) - 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 : "")); + 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(disk, amdevice, level, spindle, prog, calcprog, options) -char *disk, *amdevice, *prog, *calcprog; -int level, spindle; -option_t *options; +void +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; + } + } + + 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->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; } } - newp = (disk_estimates_t *) alloc(sizeof(disk_estimates_t)); - memset(newp, 0, sizeof(*newp)); + newp = (disk_estimates_t *) alloc(SIZEOF(disk_estimates_t)); + memset(newp, 0, SIZEOF(*newp)); newp->next = est_list; est_list = newp; - newp->amname = stralloc(disk); - newp->amdevice = stralloc(amdevice); - newp->dirname = amname_to_dirname(newp->amdevice); - newp->program = stralloc(prog); - if(calcprog != NULL) - newp->calcprog = stralloc(calcprog); - else - newp->calcprog = NULL; - 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; } } } -void free_estimates(est) -disk_estimates_t *est; +void +free_estimates( + disk_estimates_t * est) { - amfree(est->amname); - amfree(est->amdevice); + amfree(est->qamname); + amfree(est->qamdevice); amfree(est->dirname); - 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); + amfree(est->qdirname); + if (est->dle) { + free_dle(est->dle); } } @@ -531,184 +703,475 @@ disk_estimates_t *est; * */ -void calc_estimates(est) -disk_estimates_t *est; +void +calc_estimates( + disk_estimates_t * est) { - dbprintf(("%s: calculating for amname '%s', dirname '%s', spindle %d\n", - debug_prefix_time(NULL), - est->amname, est->dirname, est->spindle)); + 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", - est->amname, est->dirname)); - 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(_("done with amname %s dirname %s spindle %d\n"), + est->qamname, est->qdirname, est->dle->spindle); +} + +/* + * ------------------------------------------------------------------------ + * + */ + +/* local functions */ +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 +application_api_calc_estimate( + disk_estimates_t * est) +{ + 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); + } + } + } - dbprintf(("%s: done with amname '%s', dirname '%s', spindle %d\n", - debug_prefix_time(NULL), - est->amname, est->dirname, est->spindle)); + amfree(bsu); } -void generic_calc_estimates(est) -disk_estimates_t *est; + +void +generic_calc_estimates( + disk_estimates_t * est) { int pipefd = -1, nullfd = -1; char *cmd; - char *my_argv[DUMP_LEVELS*2+20]; + char *cmdline; + char *command; + GPtrArray *argv_ptr = g_ptr_array_new(); char number[NUM_STR_SIZE]; - int i, level, my_argc, calcpid; + unsigned int i; + int level; + pid_t calcpid; int nb_exclude = 0; int nb_include = 0; char *file_exclude = NULL; char *file_include = NULL; times_t start_time; FILE *dumpout = NULL; - long size = 1; + 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); - - my_argc = 0; - my_argv[my_argc++] = stralloc("calcsize"); - 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; + cmd = vstralloc(amlibexecdir, "/", "calcsize", NULL); - 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("calcsize")); + if (g_options->config) + g_ptr_array_add(argv_ptr, stralloc(g_options->config)); + else + 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) { - ap_snprintf(number, sizeof(number), "%d", level); - my_argv[my_argc++] = stralloc(number); - dbprintf((" %s", number)); - ap_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); - nullfd = open("/dev/null", O_RDWR); - calcpid = pipespawnv(cmd, STDERR_PIPE, &nullfd, &nullfd, &pipefd, my_argv); + if ((nullfd = open("/dev/null", O_RDWR)) == -1) { + errmsg = vstrallocf(_("Cannot access /dev/null : %s"), + strerror(errno)); + dbprintf("%s\n", errmsg); + goto common_exit; + } + + calcpid = pipespawnv(cmd, STDERR_PIPE, 0, + &nullfd, &nullfd, &pipefd, (char **)argv_ptr->pdata); amfree(cmd); dumpout = fdopen(pipefd,"r"); - match_expr = vstralloc(est->amname," %d SIZE %ld", NULL); - for(size = -1; (line = agets(dumpout)) != NULL; free(line)) { - if(sscanf(line, match_expr, &level, &size) == 2) { - printf("%s\n", line); /* write to amandad */ - dbprintf(("%s: estimate size for %s level %d: %ld KB\n", - debug_prefix(NULL), - est->amname, + if (!dumpout) { + error(_("Can't fdopen: %s"), strerror(errno)); + /*NOTREACHED*/ + } + match_expr = vstralloc(" %d SIZE %lld", NULL); + len = strlen(est->qamname); + for(size = (off_t)-1; (line = agets(dumpout)) != NULL; free(line)) { + long long size_ = (long long)0; + if (line[0] == '\0' || (int)strlen(line) <= len) + continue; + /* 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\n", - debug_prefix_time(NULL), my_argv[0], est->amdevice)); - wait(NULL); - dbprintf(("%s: after %s \"%s\" wait\n", - debug_prefix_time(NULL), my_argv[0], est->amdevice)); + 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), - est->amname, - walltime_str(timessub(curclock(), start_time)))); + dbprintf(_(".....\n")); + dbprintf(_("estimate time for %s: %s\n"), + est->qamname, + walltime_str(timessub(curclock(), start_time))); - for(i = 0; i < my_argc; i++) { - amfree(my_argv[i]); +common_exit: + 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); } -/* - * ------------------------------------------------------------------------ - * - */ - -/* local functions */ -void dump_calc_estimates P((disk_estimates_t *est)); -long getsize_dump P((char *disk, char *amdevice, int level, option_t *options)); -long getsize_smbtar P((char *disk, char *amdevice, int level, option_t *options)); -long getsize_gnutar P((char *disk, char *amdevice, int level, - option_t *options, time_t dumpsince)); -long handle_dumpline P((char *str)); -double first_num P((char *str)); - -void dump_calc_estimates(est) -disk_estimates_t *est; +void +dump_calc_estimates( + disk_estimates_t * est) { int level; - long size; + 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->amname, 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"); - fseek(stdout, (off_t)0, SEEK_SET); - - printf("%s %d SIZE %ld\n", est->amname, level, 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"); @@ -717,23 +1180,35 @@ disk_estimates_t *est; } #ifdef SAMBA_CLIENT -void smbtar_calc_estimates(est) -disk_estimates_t *est; +void +smbtar_calc_estimates( + disk_estimates_t * est) { int level; - long size; + 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->amname, 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"); - fseek(stdout, (off_t)0, SEEK_SET); - - printf("%s %d SIZE %ld\n", est->amname, level, 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"); @@ -743,43 +1218,57 @@ disk_estimates_t *est; #endif #ifdef GNUTAR -void gnutar_calc_estimates(est) -disk_estimates_t *est; +void +gnutar_calc_estimates( + disk_estimates_t * est) { - int level; - long 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->amname, level)); - size = getsize_gnutar(est->amname, est->amdevice, level, - est->options, est->est[level].dumpsince); + int level; + off_t size; + char *errmsg = NULL, *qerrmsg; - amflock(1, "size"); + 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); - fseek(stdout, (off_t)0, SEEK_SET); + amflock(1, "size"); - printf("%s %d SIZE %ld\n", est->amname, level, size); - fflush(stdout); + 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"); - } - } + amfunlock(1, "size"); + } + } } #endif -typedef struct regex_s { +typedef struct regex_scale_s { char *regex; int scale; -} regex_t; +} regex_scale_t; -regex_t re_size[] = { +/*@ignore@*/ +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}, - {" DUMP: [Ee]stimated [0-9][0-9]* bytes", 1}, /* Ultrix 4.4 */ - {" UFSDUMP: estimated [0-9][0-9]* blocks", 512}, /* NEC EWS-UX */ + {" DUMP: [Ee]stimated [0-9][0-9]* bytes", 1}, /* Ultrix 4.4 */ + {" UFSDUMP: estimated [0-9][0-9]* blocks", 512}, /* NEC EWS-UX */ {"dump: Estimate: [0-9][0-9]* tape blocks", 1024}, /* OSF/1 */ {"backup: There are an estimated [0-9][0-9]* tape blocks.",1024}, /* AIX */ {"backup: estimated [0-9][0-9]* 1k blocks", 1024}, /* AIX */ @@ -787,37 +1276,33 @@ regex_t re_size[] = { {"backup: [0-9][0-9]* tape blocks on [0-9][0-9]* tape(s)",1024}, /* AIX */ {"backup: [0-9][0-9]* 1k blocks on [0-9][0-9]* volume(s)",1024}, /* AIX */ {"dump: Estimate: [0-9][0-9]* blocks being output to pipe",1024}, - /* DU 4.0 dump */ - {"dump: Dumping [0-9][0-9]* bytes, ", 1}, /* DU 4.0 vdump */ - {"DUMP: estimated [0-9][0-9]* KB output", 1024}, /* HPUX */ - {"DUMP: estimated [0-9][0-9]* KB\\.", 1024}, /* NetApp */ - {" UFSDUMP: estimated [0-9][0-9]* blocks", 512}, /* Sinix */ + /* DU 4.0 dump */ + {"dump: Dumping [0-9][0-9]* bytes, ", 1}, /* DU 4.0 vdump */ + {"DUMP: estimated [0-9][0-9]* KB output", 1024}, /* HPUX */ + {"DUMP: estimated [0-9][0-9]* KB\\.", 1024}, /* NetApp */ + {" UFSDUMP: estimated [0-9][0-9]* blocks", 512}, /* Sinix */ #ifdef HAVE_DUMP_ESTIMATE {"[0-9][0-9]* blocks, [0-9][0-9]*.[0-9][0-9]* volumes", 1024}, - /* DU 3.2g dump -E */ - {"^[0-9][0-9]* blocks$", 1024}, /* DU 4.0 dump -E */ - {"^[0-9][0-9]*$", 1}, /* Solaris ufsdump -S */ + /* DU 3.2g dump -E */ + {"^[0-9][0-9]* blocks$", 1024}, /* DU 4.0 dump -E */ + {"^[0-9][0-9]*$", 1}, /* Solaris ufsdump -S */ #endif #endif #ifdef VDUMP - {"vdump: Dumping [0-9][0-9]* bytes, ", 1}, /* OSF/1 vdump */ + {"vdump: Dumping [0-9][0-9]* bytes, ", 1}, /* OSF/1 vdump */ #endif #ifdef VXDUMP - {"vxdump: estimated [0-9][0-9]* blocks", 512}, /* HPUX's vxdump */ - {" VXDUMP: estimated [0-9][0-9]* blocks", 512}, /* Sinix */ + {"vxdump: estimated [0-9][0-9]* blocks", 512}, /* HPUX's vxdump */ + {" VXDUMP: estimated [0-9][0-9]* blocks", 512}, /* Sinix */ #endif #ifdef XFSDUMP {"xfsdump: estimated dump size: [0-9][0-9]* bytes", 1}, /* Irix 6.2 xfs */ #endif -#ifdef USE_QUICK_AND_DIRTY_ESTIMATES - {"amqde estimate: [0-9][0-9]* kb", 1024}, /* amqde */ -#endif - #ifdef GNUTAR {"Total bytes written: [0-9][0-9]*", 1}, /* Gnutar client */ #endif @@ -834,16 +1319,17 @@ regex_t re_size[] = { { NULL, 0 } }; +/*@end@*/ - -long getsize_dump(disk, amdevice, level, options) - char *disk, *amdevice; - int level; - option_t *options; +off_t +getsize_dump( + dle_t *dle, + int level, + char **errmsg) { int pipefd[2], nullfd, stdoutfd, killctl[2]; pid_t dumppid; - long size; + off_t size; FILE *dumpout; char *dumpkeys = NULL; char *device = NULL; @@ -855,21 +1341,57 @@ long getsize_dump(disk, amdevice, level, options) char level_str[NUM_STR_SIZE]; int s; times_t start_time; + char *qdisk = quote_string(dle->disk); + char *qdevice; + char *config; + amwait_t wait_status; +#if defined(DUMP) || defined(VDUMP) || defined(VXDUMP) || defined(XFSDUMP) + int is_rundump = 1; +#endif - ap_snprintf(level_str, sizeof(level_str), "%d", level); + if (level > 9) + return -2; /* planner will not even consider this level */ - device = amname_to_devname(amdevice); - fstype = amname_to_fstype(amdevice); + g_snprintf(level_str, SIZEOF(level_str), "%d", level); - dbprintf(("%s: calculating for device '%s' with '%s'\n", - debug_prefix_time(NULL), device, fstype)); + device = amname_to_devname(dle->device); + qdevice = quote_string(device); + fstype = amname_to_fstype(dle->device); - cmd = vstralloc(libexecdir, "/rundump", versionsuffix(), NULL); - rundump_cmd = stralloc(cmd); + dbprintf(_("calculating for device %s with %s\n"), + qdevice, fstype); - stdoutfd = nullfd = open("/dev/null", O_RDWR); + 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) { + *errmsg = vstrallocf(_("getsize_dump could not open /dev/null: %s"), + strerror(errno)); + dbprintf("%s\n", *errmsg); + amfree(cmd); + amfree(rundump_cmd); + amfree(fstype); + amfree(device); + amfree(qdevice); + amfree(qdisk); + return(-1); + } pipefd[0] = pipefd[1] = killctl[0] = killctl[1] = -1; - pipe(pipefd); + if (pipe(pipefd) < 0) { + *errmsg = vstrallocf(_("getsize_dump could create data pipes: %s"), + strerror(errno)); + dbprintf("%s\n", *errmsg); + amfree(cmd); + amfree(rundump_cmd); + amfree(fstype); + amfree(device); + amfree(qdevice); + amfree(qdisk); + return(-1); + } #ifdef XFSDUMP /* { */ #ifdef DUMP /* { */ @@ -878,9 +1400,9 @@ long getsize_dump(disk, amdevice, level, options) if (1) #endif /* } */ { - name = stralloc(" (xfsdump)"); - dbprintf(("%s: running \"%s%s -F -J -l %s - %s\"\n", - debug_prefix_time(NULL), cmd, name, level_str, device)); + name = stralloc(" (xfsdump)"); + dbprintf(_("running \"%s%s -F -J -l %s - %s\"\n"), + cmd, name, level_str, qdevice); } else #endif /* } */ @@ -892,14 +1414,16 @@ long getsize_dump(disk, amdevice, level, options) #endif /* } */ { #ifdef USE_RUNDUMP - name = stralloc(" (vxdump)"); + name = stralloc(" (vxdump)"); #else name = stralloc(""); cmd = newstralloc(cmd, VXDUMP); + config = skip_argument; + 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, device)); + dbprintf(_("running \"%s%s %s 1048576 - %s\"\n"), + cmd, name, dumpkeys, qdevice); } else #endif /* } */ @@ -911,11 +1435,9 @@ long getsize_dump(disk, amdevice, level, options) #endif /* } */ { name = stralloc(" (vdump)"); - amfree(device); - device = amname_to_dirname(amdevice); dumpkeys = vstralloc(level_str, "b", "f", NULL); - dbprintf(("%s: running \"%s%s %s 60 - %s\"\n", - debug_prefix_time(NULL), cmd, name, dumpkeys, device)); + dbprintf(_("running \"%s%s %s 60 - %s\"\n"), + cmd, name, dumpkeys, qdevice); } else #endif /* } */ @@ -930,20 +1452,28 @@ long getsize_dump(disk, amdevice, level, options) # else /* } { */ name = stralloc(""); cmd = newstralloc(cmd, DUMP); + config = skip_argument; + is_rundump = 0; # endif /* } */ # ifdef AIX_BACKUP /* { */ dumpkeys = vstralloc("-", level_str, "f", NULL); - dbprintf(("%s: running \"%s%s %s - %s\"\n", - debug_prefix_time(NULL), cmd, name, dumpkeys, device)); + 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 @@ -951,32 +1481,41 @@ long getsize_dump(disk, amdevice, level, options) # endif # ifdef HAVE_HONOR_NODUMP /* { */ - dbprintf(("%s: running \"%s%s %s 0 1048576 - %s\"\n", - debug_prefix_time(NULL), cmd, name, dumpkeys, device)); + 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, device)); + 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*/ } - pipe(killctl); + if (pipe(killctl) < 0) { + dbprintf(_("Could not create pipe: %s\n"), strerror(errno)); + /* Message will be printed later... */ + killctl[0] = killctl[1] = -1; + } 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); amfree(device); + amfree(qdevice); + amfree(qdisk); amfree(name); + amfree(fstype); return -1; default: break; @@ -984,21 +1523,18 @@ long getsize_dump(disk, amdevice, level, options) if(SETPGRP == -1) SETPGRP_FAILED(); else if (killctl[0] == -1 || killctl[1] == -1) - dbprintf(("%s: pipe for killpgrp failed, 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 *killpgrp_cmd = vstralloc(libexecdir, "/killpgrp", - versionsuffix(), NULL); - dbprintf(("%s: running %s\n", - debug_prefix_time(NULL), killpgrp_cmd)); + char *config; + char *killpgrp_cmd = vstralloc(amlibexecdir, "/killpgrp", NULL); + dbprintf(_("running %s\n"), killpgrp_cmd); dup2(killctl[0], 0); dup2(nullfd, 1); dup2(nullfd, 2); @@ -1006,9 +1542,15 @@ long getsize_dump(disk, amdevice, level, options) close(pipefd[1]); close(killctl[1]); close(nullfd); - execle(killpgrp_cmd, killpgrp_cmd, (char *)0, safe_env()); - dbprintf(("%s: cannot execute %s: %s\n", - debug_prefix(NULL), killpgrp_cmd, strerror(errno))); + if (g_options->config) + config = g_options->config; + else + config = "NOCONFIG"; + safe_fd(-1, 0); + execle(killpgrp_cmd, killpgrp_cmd, config, (char *)0, + safe_env()); + dbprintf(_("cannot execute %s: %s\n"), + killpgrp_cmd, strerror(errno)); exit(-1); } @@ -1025,6 +1567,7 @@ long getsize_dump(disk, amdevice, level, options) aclose(killctl[0]); if (killctl[1] != -1) aclose(killctl[1]); + safe_fd(-1, 0); #ifdef XFSDUMP #ifdef DUMP @@ -1032,8 +1575,12 @@ long getsize_dump(disk, amdevice, level, options) #else if (1) #endif - execle(cmd, "xfsdump", "-F", "-J", "-l", level_str, "-", device, - (char *)0, safe_env()); + if (is_rundump) + execle(cmd, "rundump", config, "xfsdump", "-F", "-J", "-l", + level_str, "-", device, (char *)0, safe_env()); + else + execle(cmd, "xfsdump", "-F", "-J", "-l", + level_str, "-", device, (char *)0, safe_env()); else #endif #ifdef VXDUMP @@ -1042,8 +1589,12 @@ long getsize_dump(disk, amdevice, level, options) #else if (1) #endif - execle(cmd, "vxdump", dumpkeys, "1048576", "-", device, (char *)0, - safe_env()); + if (is_rundump) + execle(cmd, "rundump", config, "vxdump", dumpkeys, "1048576", + "-", device, (char *)0, safe_env()); + else + execle(cmd, "vxdump", dumpkeys, "1048576", "-", + device, (char *)0, safe_env()); else #endif #ifdef VDUMP @@ -1052,24 +1603,42 @@ long getsize_dump(disk, amdevice, level, options) #else if (1) #endif - execle(cmd, "vdump", dumpkeys, "60", "-", device, (char *)0, - safe_env()); + if (is_rundump) + execle(cmd, "rundump", config, "vdump", dumpkeys, "60", "-", + device, (char *)0, safe_env()); + else + execle(cmd, "vdump", dumpkeys, "60", "-", + device, (char *)0, safe_env()); else #endif #ifdef DUMP # ifdef AIX_BACKUP - execle(cmd, "backup", dumpkeys, "-", device, (char *)0, safe_env()); + if (is_rundump) + execle(cmd, "rundump", config, "backup", dumpkeys, "-", + device, (char *)0, safe_env()); + else + execle(cmd, "backup", dumpkeys, "-", + device, (char *)0, safe_env()); # else - execle(cmd, "dump", dumpkeys, + if (is_rundump) { + execle(cmd, "rundump", config, "dump", dumpkeys, +#ifdef HAVE_HONOR_NODUMP + "0", +#endif + "1048576", "-", device, (char *)0, safe_env()); + } else { + execle(cmd, "dump", dumpkeys, #ifdef HAVE_HONOR_NODUMP - "0", + "0", #endif - "1048576", "-", device, (char *)0, safe_env()); + "1048576", "-", device, (char *)0, safe_env()); + } # 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*/ } } @@ -1080,44 +1649,58 @@ long getsize_dump(disk, amdevice, level, options) if (killctl[0] != -1) aclose(killctl[0]); dumpout = fdopen(pipefd[0],"r"); + if (!dumpout) { + error(_("Can't fdopen: %s"), strerror(errno)); + /*NOTREACHED*/ + } - for(size = -1; (line = agets(dumpout)) != NULL; free(line)) { - dbprintf(("%s: %s\n", debug_prefix_time(NULL), line)); + for(size = (off_t)-1; (line = agets(dumpout)) != NULL; free(line)) { + if (line[0] == '\0') + continue; + dbprintf("%s\n", line); size = handle_dumpline(line); - if(size > -1) { + if(size > (off_t)-1) { amfree(line); - if((line = agets(dumpout)) != NULL) { - dbprintf(("%s: %s\n", debug_prefix_time(NULL), line)); + while ((line = agets(dumpout)) != NULL) { + if (line[0] != '\0') + break; + amfree(line); + } + if (line != NULL) { + 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), - disk, + dbprintf(".....\n"); + dbprintf(_("estimate time for %s level %d: %s\n"), + qdisk, level, - walltime_str(timessub(curclock(), start_time)))); - if(size == -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))); - } else if(size == 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(("%s: estimate size for %s level %d: %ld KB\n", - debug_prefix(NULL), - disk, + walltime_str(timessub(curclock(), start_time))); + if(size == (off_t)-1) { + *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(_("possible %s%s problem -- is \"%s\" really empty?\n"), + cmd, name, dle->disk); + dbprintf(".....\n"); + } else { + 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); @@ -1130,11 +1713,9 @@ long getsize_dump(disk, amdevice, level, options) * 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) { @@ -1143,11 +1724,9 @@ long getsize_dump(disk, amdevice, level, options) 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); @@ -1155,11 +1734,23 @@ long getsize_dump(disk, amdevice, level, options) goto terminated; } - dbprintf(("%s: waiting for %s%s \"%s\" child\n", - debug_prefix_time(NULL), cmd, name, disk)); - wait(NULL); - dbprintf(("%s: after %s%s \"%s\" wait\n", - debug_prefix_time(NULL), cmd, name, disk)); + 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: @@ -1167,6 +1758,8 @@ long getsize_dump(disk, amdevice, level, options) afclose(dumpout); amfree(device); + amfree(qdevice); + amfree(qdisk); amfree(fstype); amfree(cmd); @@ -1176,41 +1769,49 @@ long getsize_dump(disk, amdevice, level, options) } #ifdef SAMBA_CLIENT -long getsize_smbtar(disk, amdevice, level, optionns) - char *disk, *amdevice; - int level; - option_t *optionns; +off_t +getsize_smbtar( + dle_t *dle, + int level, + char **errmsg) { int pipefd = -1, nullfd = -1, passwdfd = -1; - int dumppid; - long size; + pid_t dumppid; + off_t size; FILE *dumpout; char *tarkeys, *sharename, *user_and_password = NULL, *domain = NULL; char *share = NULL, *subdir = NULL; - int lpass; + size_t lpass; char *pwtext; - int pwtext_len; + size_t pwtext_len; char *line; char *pw_fd_env; times_t start_time; char *error_pn = NULL; + 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", disk); + error(_("cannot parse disk entry %s for share/subdir"), qdisk); + /*NOTREACHED*/ } if ((subdir) && (SAMBA_VERSION < 2)) { amfree(share); amfree(subdir); set_pname(error_pn); amfree(error_pn); - error("subdirectory specified for share '%s' but samba not v2 or better", disk); + error(_("subdirectory specified for share %s but samba not v2 or better"), qdisk); + /*NOTREACHED*/ } if ((user_and_password = findpass(share, &domain)) == NULL) { @@ -1220,11 +1821,12 @@ long getsize_smbtar(disk, amdevice, level, optionns) } 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); if ((pwtext = strchr(user_and_password, '%')) == NULL) { - memset(user_and_password, '\0', lpass); + memset(user_and_password, '\0', (size_t)lpass); amfree(user_and_password); if(domain) { memset(domain, '\0', strlen(domain)); @@ -1232,12 +1834,25 @@ long getsize_smbtar(disk, amdevice, level, optionns) } 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'; pwtext_len = strlen(pwtext); if ((sharename = makesharename(share, 0)) == NULL) { - memset(user_and_password, '\0', lpass); + memset(user_and_password, '\0', (size_t)lpass); + amfree(user_and_password); + if(domain) { + memset(domain, '\0', strlen(domain)); + amfree(domain); + } + set_pname(error_pn); + amfree(error_pn); + error(_("cannot make share name of %s"), share); + /*NOTREACHED*/ + } + if ((nullfd = open("/dev/null", O_RDWR)) == -1) { + memset(user_and_password, '\0', (size_t)lpass); amfree(user_and_password); if(domain) { memset(domain, '\0', strlen(domain)); @@ -1245,9 +1860,11 @@ long getsize_smbtar(disk, amdevice, level, optionns) } set_pname(error_pn); amfree(error_pn); - error("cannot make share name of %s", share); + amfree(sharename); + error(_("could not open /dev/null: %s\n"), + strerror(errno)); + /*NOTREACHED*/ } - nullfd = open("/dev/null", O_RDWR); #if SAMBA_VERSION >= 2 if (level == 0) @@ -1268,7 +1885,7 @@ long getsize_smbtar(disk, amdevice, level, optionns) } 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", @@ -1290,17 +1907,18 @@ long getsize_smbtar(disk, amdevice, level, optionns) amfree(domain); } aclose(nullfd); - if(pwtext_len > 0 && fullwrite(passwdfd, pwtext, pwtext_len) < 0) { + if(pwtext_len > 0 && full_write(passwdfd, pwtext, pwtext_len) < pwtext_len) { int save_errno = errno; - memset(user_and_password, '\0', lpass); + memset(user_and_password, '\0', (size_t)lpass); amfree(user_and_password); 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', lpass); + memset(user_and_password, '\0', (size_t)lpass); amfree(user_and_password); aclose(passwdfd); amfree(sharename); @@ -1308,67 +1926,94 @@ long getsize_smbtar(disk, amdevice, level, optionns) amfree(subdir); amfree(error_pn); dumpout = fdopen(pipefd,"r"); + if (!dumpout) { + error(_("Can't fdopen: %s"), strerror(errno)); + /*NOTREACHED*/ + } - for(size = -1; (line = agets(dumpout)) != NULL; free(line)) { - dbprintf(("%s: %s\n", debug_prefix_time(NULL), line)); + for(size = (off_t)-1; (line = agets(dumpout)) != NULL; free(line)) { + if (line[0] == '\0') + continue; + dbprintf("%s\n", line); size = handle_dumpline(line); if(size > -1) { amfree(line); - if((line = agets(dumpout)) != NULL) { - dbprintf(("%s: %s\n", debug_prefix_time(NULL), line)); + while ((line = agets(dumpout)) != NULL) { + if (line[0] != '\0') + break; + amfree(line); + } + if(line != NULL) { + 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), - disk, + dbprintf(".....\n"); + dbprintf(_("estimate time for %s level %d: %s\n"), + qdisk, level, - walltime_str(timessub(curclock(), start_time)))); - if(size == -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))); - } else if(size == 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(("%s: estimate size for %s level %d: %ld KB\n", - debug_prefix(NULL), - disk, + walltime_str(timessub(curclock(), start_time))); + if(size == (off_t)-1) { + *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(_("possible %s problem -- is \"%s\" really empty?\n"), + SAMBA_CLIENT, dle->disk); + dbprintf(".....\n"); + } + 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, disk)); - wait(NULL); - dbprintf(("%s: after %s \"%s\" wait\n", - debug_prefix_time(NULL), SAMBA_CLIENT, disk)); + 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; amfree(error_pn); + amfree(qdisk); return size; } #endif #ifdef GNUTAR -long getsize_gnutar(disk, amdevice, level, options, dumpsince) -char *disk, *amdevice; -int level; -option_t *options; -time_t dumpsince; +off_t +getsize_gnutar( + dle_t *dle, + int level, + time_t dumpsince, + char **errmsg) { - int pipefd = -1, nullfd = -1, dumppid; - long size = -1; + int pipefd = -1, nullfd = -1; + pid_t dumppid; + off_t size = (off_t)-1; FILE *dumpout = NULL; char *incrname = NULL; char *basename = NULL; @@ -1378,49 +2023,50 @@ time_t dumpsince; 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; - - 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(nb_exclude > 0) file_exclude = build_exclude(disk, amdevice, options, 0); - if(nb_include > 0) file_include = build_include(disk, amdevice, options, 0); - - my_argv = alloc(sizeof(char *) * 21); - i = 0; - -#ifdef GNUTAR_LISTED_INCREMENTAL_DIR - { + int infd, outfd; + ssize_t nb; + char buf[32768]; + char *qdisk = quote_string(dle->disk); + char *gnutar_list_dir; + amwait_t wait_status; + char tmppath[PATH_MAX]; + + if (level > 9) + return -2; /* planner will not even consider this level */ + + 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; + + if(nb_exclude > 0) file_exclude = build_exclude(dle, 0); + if(nb_include > 0) file_include = build_include(dle, 0); + + 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_LISTED_INCREMENTAL_DIR, + 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 + sizeof(GNUTAR_LISTED_INCREMENTAL_DIR); - while((ch = *s++) != '\0') { - if(ch == '/' || isspace(ch)) s[-1] = '_'; - } + amfree(sdisk); - ap_snprintf(number, sizeof(number), "%d", level); + g_snprintf(number, SIZEOF(number), "%d", level); incrname = vstralloc(basename, "_", number, ".new", NULL); unlink(incrname); @@ -1430,193 +2076,215 @@ time_t dumpsince; * be true for a level 0), arrange to read from /dev/null. */ baselevel = level; - while (in == NULL) { + infd = -1; + while (infd == -1) { if (--baselevel >= 0) { - ap_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 ((in = fopen(inputname, "r")) == NULL) { - int save_errno = errno; + if ((infd = open(inputname, O_RDONLY)) == -1) { - 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); } } /* * Copy the previous listed incremental file to the new one. */ - if ((out = fopen(incrname, "w")) == NULL) { - dbprintf(("%s: opening %s: %s\n", - debug_prefix(NULL), incrname, strerror(errno))); + if ((outfd = open(incrname, O_WRONLY|O_CREAT, 0600)) == -1) { + *errmsg = vstrallocf(_("opening %s: %s"), + incrname, strerror(errno)); + dbprintf("%s\n", *errmsg); goto common_exit; } - for (; (line = agets(in)) != NULL; free(line)) { - if (fputs(line, out) == EOF || putc('\n', out) == EOF) { - dbprintf(("%s: writing to %s: %s\n", - debug_prefix(NULL), incrname, strerror(errno))); + while ((nb = read(infd, &buf, SIZEOF(buf))) > 0) { + 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; } } - amfree(line); - if (ferror(in)) { - dbprintf(("%s: reading from %s: %s\n", - debug_prefix(NULL), inputname, strerror(errno))); + if (nb < 0) { + *errmsg = vstrallocf(_("reading from %s: %s"), + inputname, strerror(errno)); + dbprintf("%s\n", *errmsg); goto common_exit; } - if (fclose(in) == EOF) { - dbprintf(("%s: closing %s: %s\n", - debug_prefix(NULL), inputname, strerror(errno))); - in = NULL; + + if (close(infd) != 0) { + *errmsg = vstrallocf(_("closing %s: %s"), + inputname, strerror(errno)); + dbprintf("%s\n", *errmsg); goto common_exit; } - in = NULL; - if (fclose(out) == EOF) { - dbprintf(("%s: closing %s: %s\n", - debug_prefix(NULL), incrname, strerror(errno))); - out = NULL; + if (close(outfd) != 0) { + *errmsg = vstrallocf(_("closing %s: %s"), + incrname, strerror(errno)); + dbprintf("%s\n", *errmsg); goto common_exit; } - out = NULL; amfree(inputname); amfree(basename); } -#endif gmtm = gmtime(&dumpsince); - ap_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(amlibexecdir, "/", "runtar", NULL); + g_ptr_array_add(argv_ptr, stralloc("runtar")); + if (g_options->config) + g_ptr_array_add(argv_ptr, stralloc(g_options->config)); + else + g_ptr_array_add(argv_ptr, stralloc("NOCONFIG")); - -#ifdef USE_QUICK_AND_DIRTY_ESTIMATES - ap_snprintf(dumptimestr, sizeof(dumptimestr), "%ld", dumpsince); - - cmd = vstralloc(libexecdir, "/", "amqde", versionsuffix(), NULL); - - my_argv[i++] = vstralloc(libexecdir, "/", "amqde", versionsuffix(), NULL); - my_argv[i++] = "-s"; - my_argv[i++] = dumptimestr; - if(file_exclude) { /* at present, this is not used... */ - my_argv[i++] = "-x"; - my_argv[i++] = file_exclude; - } - /* [XXX] need to also consider implementation of --files-from */ - my_argv[i++] = dirname; - my_argv[i++] = NULL; -#else #ifdef GNUTAR - cmd = vstralloc(libexecdir, "/", "runtar", versionsuffix(), NULL); - - my_argv[i++] = GNUTAR; -#else - my_argv[i++] = "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"; -#ifdef GNUTAR_LISTED_INCREMENTAL_DIR - my_argv[i++] = "--listed-incremental"; - my_argv[i++] = incrname; + g_ptr_array_add(argv_ptr, stralloc(GNUTAR)); #else - my_argv[i++] = "--incremental"; - my_argv[i++] = "--newer"; - my_argv[i++] = dumptimestr; + g_ptr_array_add(argv_ptr, stralloc("tar")); #endif + 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) { + g_ptr_array_add(argv_ptr, stralloc("--listed-incremental")); + g_ptr_array_add(argv_ptr, stralloc(incrname)); + } else { + 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 * utime() after reading files in order to * 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(".")); } -#endif /* USE_QUICK_AND_DIRTY_ESTIMATES */ - my_argv[i++] = NULL; + g_ptr_array_add(argv_ptr, NULL); start_time = curclock(); - nullfd = open("/dev/null", O_RDWR); - dumppid = pipespawnv(cmd, STDERR_PIPE, &nullfd, &nullfd, &pipefd, my_argv); - amfree(cmd); - amfree(file_exclude); - amfree(file_include); + if ((nullfd = open("/dev/null", O_RDWR)) == -1) { + *errmsg = vstrallocf(_("Cannot access /dev/null : %s"), + strerror(errno)); + dbprintf("%s\n", *errmsg); + goto common_exit; + } + + 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)); + /*NOTREACHED*/ + } - for(size = -1; (line = agets(dumpout)) != NULL; free(line)) { - dbprintf(("%s: %s\n", debug_prefix_time(NULL), line)); + for(size = (off_t)-1; (line = agets(dumpout)) != NULL; free(line)) { + if (line[0] == '\0') + continue; + dbprintf("%s\n", line); size = handle_dumpline(line); - if(size > -1) { + if(size > (off_t)-1) { amfree(line); - if((line = agets(dumpout)) != NULL) { - dbprintf(("%s: %s\n", debug_prefix_time(NULL), line)); + while ((line = agets(dumpout)) != NULL) { + if (line[0] != '\0') { + break; + } + amfree(line); + } + if (line != NULL) { + dbprintf("%s\n", line); + break; } break; } } amfree(line); - dbprintf(("%s: .....\n", debug_prefix_time(NULL))); - dbprintf(("%s: estimate time for %s level %d: %s\n", - debug_prefix(NULL), - disk, + dbprintf(".....\n"); + dbprintf(_("estimate time for %s level %d: %s\n"), + qdisk, level, - walltime_str(timessub(curclock(), start_time)))); - if(size == -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))); - } else if(size == 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(("%s: estimate size for %s level %d: %ld KB\n", - debug_prefix(NULL), - disk, + walltime_str(timessub(curclock(), start_time))); + if(size == (off_t)-1) { + *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(_("possible %s problem -- is \"%s\" really empty?\n"), + command, dle->disk); + dbprintf(".....\n"); + } + 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], disk)); - wait(NULL); - dbprintf(("%s: after %s \"%s\" wait\n", - debug_prefix_time(NULL), my_argv[0], disk)); + 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: @@ -1627,7 +2295,11 @@ 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); + amfree(file_include); aclose(nullfd); afclose(dumpout); @@ -1638,12 +2310,276 @@ common_exit: } #endif +off_t +getsize_application_api( + disk_estimates_t *est, + int nb_level, + int *levels, + backup_support_option_t *bsu) +{ + 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 *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(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")); + } + + 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); + + 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; + } + + if (pipe(pipeinfd) < 0) { + errmsg = vstrallocf(_("getsize_application_api could not create data pipes: %s"), + strerror(errno)); + goto common_exit; + } + + if (pipe(pipeoutfd) < 0) { + errmsg = vstrallocf(_("getsize_application_api could not create data pipes: %s"), + strerror(errno)); + goto common_exit; + } + + start_time = curclock(); + + switch(dumppid = fork()) { + case -1: + size = (off_t)-1; + goto common_exit; + default: + break; /* parent */ + case 0: + 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(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)); + /*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\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; + } + 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; + } + } + 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); + + 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))); + } + + kill(-dumppid, SIGTERM); + + 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); + + 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; +} + -double first_num(str) -char *str; /* * Returns the value of the first integer in a string. */ + +double +first_num( + char * str) { char *start; int ch; @@ -1655,27 +2591,32 @@ char *str; while(isdigit(ch) || (ch == '.')) ch = *str++; str[-1] = '\0'; d = atof(start); - str[-1] = ch; + str[-1] = (char)ch; return d; } -long handle_dumpline(str) -char *str; /* * Checks the dump output line against the error and size regex tables. */ + +off_t +handle_dumpline( + char * str) { - regex_t *rp; + regex_scale_t *rp; double size; /* check for size match */ + /*@ignore@*/ for(rp = re_size; rp->regex != NULL; rp++) { if(match(rp->regex, str)) { size = ((first_num(str)*rp->scale+1023.0)/1024.0); - if(size < 0) size = 1; /* found on NeXT -- sigh */ - return (long) size; + if(size < 0.0) + size = 1.0; /* found on NeXT -- sigh */ + return (off_t)size; } } - return -1; + /*@end@*/ + return (off_t)-1; }