2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1998 University of Maryland at College Park
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of U.M. not be used in advertising or
11 * publicity pertaining to distribution of the software without specific,
12 * written prior permission. U.M. makes no representations about the
13 * suitability of this software for any purpose. It is provided "as is"
14 * without express or implied warranty.
16 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 * Authors: the Amanda Development Team. Its members are listed in a
24 * file named AUTHORS, in the root directory of this distribution.
27 * $Id: sendsize.c,v 1.171 2006/08/24 01:57:15 paddy_s Exp $
29 * send estimated backup sizes using dump
33 #include "pipespawn.h"
34 #include "amfeatures.h"
35 #include "amandates.h"
40 #include "client_util.h"
48 #define sendsize_debug(i, ...) do { \
49 if ((i) <= debug_sebdsize) { \
50 dbprintf(__VA_ARGS__); \
55 # define SETPGRP setpgid(getpid(), getpid())
56 # define SETPGRP_FAILED() do { \
57 dbprintf(_("setpgid(%ld,%ld) failed: %s\n"), \
58 (long)getpid(), (long)getpid(), strerror(errno)); \
62 #if defined(SETPGRP_VOID)
63 # define SETPGRP setpgrp()
64 # define SETPGRP_FAILED() do { \
65 dbprintf(_("setpgrp() failed: %s\n"), strerror(errno)); \
69 # define SETPGRP setpgrp(0, getpid())
70 # define SETPGRP_FAILED() do { \
71 dbprintf(_("setpgrp(0,%ld) failed: %s\n"), \
72 (long)getpid(), strerror(errno)); \
78 typedef struct level_estimates_s {
84 typedef struct disk_estimates_s {
85 struct disk_estimates_s *next;
94 int program_is_backup_api;
99 level_estimate_t est[DUMP_LEVELS];
102 disk_estimates_t *est_list;
104 static am_feature_t *our_features = NULL;
105 static char *our_feature_string = NULL;
106 static g_option_t *g_options = NULL;
108 /* local functions */
109 int main(int argc, char **argv);
110 void add_diskest(char *disk, char *amdevice, int level, int spindle,
111 int program_is_backup_api, char *prog, char *calcprog,
113 void calc_estimates(disk_estimates_t *est);
114 void free_estimates(disk_estimates_t *est);
115 void dump_calc_estimates(disk_estimates_t *);
116 void star_calc_estimates(disk_estimates_t *);
117 void smbtar_calc_estimates(disk_estimates_t *);
118 void gnutar_calc_estimates(disk_estimates_t *);
119 void backup_api_calc_estimate(disk_estimates_t *);
120 void generic_calc_estimates(disk_estimates_t *);
129 char *prog, *calcprog, *dumpdate;
130 option_t *options = NULL;
131 int program_is_backup_api;
132 disk_estimates_t *est;
133 disk_estimates_t *est1;
134 disk_estimates_t *est_prev;
138 char *err_extra = NULL;
145 char *amdevice = NULL;
146 char *qamdevice = NULL;
147 char *amandates_file;
148 int amandates_read = 0;
150 (void)argc; /* Quiet unused parameter warning */
151 (void)argv; /* Quiet unused parameter warning */
156 * Configure program for internationalization:
157 * 1) Only set the message locale for now.
158 * 2) Set textdomain for all amanda related programs to "amanda"
159 * We don't want to be forced to support dozens of message catalogs.
161 setlocale(LC_MESSAGES, "C");
162 textdomain("amanda");
167 set_pname("sendsize");
169 /* Don't die when child closes pipe */
170 signal(SIGPIPE, SIG_IGN);
172 #if defined(USE_DBMALLOC)
173 malloc_size_1 = malloc_inuse(&malloc_hist_1);
176 erroutput_type = (ERR_INTERACTIVE|ERR_SYSLOG);
177 dbopen(DBG_SUBDIR_CLIENT);
179 dbprintf(_("version %s\n"), version());
181 our_features = am_init_feature_set();
182 our_feature_string = am_feature_to_string(our_features);
184 config_init(CONFIG_INIT_CLIENT, NULL);
186 check_running_as(RUNNING_AS_CLIENT_LOGIN);
188 /* handle all service requests */
190 for(; (line = agets(stdin)) != NULL; free(line)) {
193 if(strncmp_const(line, "OPTIONS ") == 0) {
194 g_options = parse_g_options(line+8, 1);
195 if(!g_options->hostname) {
196 g_options->hostname = alloc(MAX_HOSTNAME_LENGTH+1);
197 gethostname(g_options->hostname, MAX_HOSTNAME_LENGTH);
198 g_options->hostname[MAX_HOSTNAME_LENGTH] = '\0';
201 g_printf("OPTIONS ");
202 if(am_has_feature(g_options->features, fe_rep_options_features)) {
203 g_printf("features=%s;", our_feature_string);
205 if(am_has_feature(g_options->features, fe_rep_options_maxdumps)) {
206 g_printf("maxdumps=%d;", g_options->maxdumps);
208 if(am_has_feature(g_options->features, fe_rep_options_hostname)) {
209 g_printf("hostname=%s;", g_options->hostname);
214 if (g_options->config) {
215 /* overlay this configuration on the existing (nameless) configuration */
216 config_init(CONFIG_INIT_CLIENT | CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_OVERLAY,
219 dbrename(config_name, DBG_SUBDIR_CLIENT);
225 if (amandates_read == 0) {
226 amandates_file = getconf_str(CNF_AMANDATES);
227 if(!start_amandates(amandates_file, 0))
228 error("error [opening %s: %s]", amandates_file,
236 skip_whitespace(s, ch); /* find the program name */
238 err_extra = stralloc(_("no program name"));
239 goto err; /* no program name */
242 skip_non_whitespace(s, ch);
245 program_is_backup_api=0;
246 if(strncmp_const(prog, "CALCSIZE") == 0) {
247 skip_whitespace(s, ch); /* find the program name */
249 err_extra = stralloc(_("no program name"));
253 skip_non_whitespace(s, ch);
255 if (strcmp(calcprog,"BACKUP") == 0) {
256 program_is_backup_api=1;
257 skip_whitespace(s, ch); /* find dumper name */
259 goto err; /* no program */
262 skip_non_whitespace(s, ch);
268 if (strcmp(prog,"BACKUP") == 0) {
269 program_is_backup_api=1;
270 skip_whitespace(s, ch); /* find dumper name */
272 goto err; /* no program */
275 skip_non_whitespace(s, ch);
280 skip_whitespace(s, ch); /* find the disk name */
282 err_extra = stralloc(_("no disk name"));
283 goto err; /* no disk name */
292 skip_quoted_string(s, ch);
293 s[-1] = '\0'; /* terminate the disk name */
294 qdisk = stralloc(fp);
295 disk = unquote_string(qdisk);
297 skip_whitespace(s, ch); /* find the device or level */
299 err_extra = stralloc(_("bad level"));
302 if(!isdigit((int)s[-1])) {
304 skip_quoted_string(s, ch);
306 qamdevice = stralloc(fp);
307 amdevice = unquote_string(qamdevice);
308 skip_whitespace(s, ch); /* find level number */
311 amdevice = stralloc(disk);
312 qamdevice = stralloc(qdisk);
315 /* find the level number */
316 if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
317 err_extra = stralloc(_("bad level"));
318 goto err; /* bad level */
320 if (level < 0 || level >= DUMP_LEVELS) {
321 err_extra = stralloc(_("bad level"));
326 skip_whitespace(s, ch); /* find the dump date */
328 err_extra = stralloc(_("no dumpdate"));
329 goto err; /* no dumpdate */
332 skip_non_whitespace(s, ch);
334 (void)dumpdate; /* XXX: Set but not used */
336 spindle = 0; /* default spindle */
338 skip_whitespace(s, ch); /* find the spindle */
340 if(sscanf(s - 1, "%d", &spindle) != 1) {
341 err_extra = stralloc(_("bad spindle"));
342 goto err; /* bad spindle */
346 skip_whitespace(s, ch); /* find the parameters */
348 if(strncmp_const(s-1, "OPTIONS |;") == 0) {
349 options = parse_options(s + 8,
356 options = alloc(SIZEOF(option_t));
357 init_options(options);
359 if(strncmp_const(s-1, "exclude-file=") == 0) {
360 qlist = unquote_string(s+12);
361 options->exclude_file =
362 append_sl(options->exclude_file, qlist);
364 } else if(strncmp_const(s-1, "exclude-list=") == 0) {
365 qlist = unquote_string(s+12);
366 options->exclude_list =
367 append_sl(options->exclude_list, qlist);
369 } else if(strncmp_const(s-1, "include-file=") == 0) {
370 qlist = unquote_string(s+12);
371 options->include_file =
372 append_sl(options->include_file, qlist);
374 } else if(strncmp_const(s-1, "include-list=") == 0) {
375 qlist = unquote_string(s+12);
376 options->include_list =
377 append_sl(options->include_list, qlist);
380 err_extra = vstrallocf(_("Invalid parameter (%s)"), s-1);
381 goto err; /* should have gotten to end */
383 skip_quoted_string(s, ch);
384 skip_whitespace(s, ch); /* find the inclusion list */
390 options = alloc(SIZEOF(option_t));
391 init_options(options);
395 options = alloc(SIZEOF(option_t));
396 init_options(options);
400 add_diskest(disk, amdevice, level, spindle, program_is_backup_api, prog, calcprog, options);
407 if (g_options == NULL) {
408 printf(_("ERROR [Missing OPTIONS line in sendsize input]\n"));
409 error(_("Missing OPTIONS line in sendsize input\n"));
423 * See if we need to wait for a child before we can do anything
428 amwait_t child_status;
431 dbprintf(_("waiting for any estimate child: %d running\n"),
433 child_pid = wait(&child_status);
434 if(child_pid == -1) {
435 error(_("wait failed: %s"), strerror(errno));
439 if (!WIFEXITED(child_status) || WEXITSTATUS(child_status) != 0) {
440 char *child_name = vstrallocf(_("child %ld"), (long)child_pid);
441 char *child_status_str = str_exit_status(child_name, child_status);
442 dbprintf("%s\n", child_status_str);
443 amfree(child_status_str);
448 * Find the child and mark it done.
450 for(est = est_list; est != NULL; est = est->next) {
451 if(est->child == child_pid) {
456 dbprintf(_("unexpected child %ld\n"), (long)child_pid);
464 * If we are already running the maximum number of children
465 * go back and wait until one of them finishes.
467 if(dumpsrunning >= g_options->maxdumps) {
470 continue; /* have to wait first */
473 * Find a new child to start.
475 for(est = est_list; est != NULL; est = est->next) {
477 done = 0; /* more to do */
479 if(est->child != 0 || est->done) {
480 continue; /* child is running or done */
483 * Make sure there is no spindle conflict.
485 if(est->spindle != -1) {
486 for(est1 = est_list; est1 != NULL; est1 = est1->next) {
487 if(est1->child == 0 || est == est1 || est1->done) {
489 * Ignore anything not yet started, ourself,
490 * and anything completed.
494 if(est1->spindle == est->spindle) {
495 break; /* oops -- they match */
499 continue; /* spindle conflict */
502 break; /* start this estimate */
505 if(dumpsrunning > 0) {
506 need_wait = 1; /* nothing to do but wait */
510 if((est->child = fork()) == 0) {
511 calc_estimates(est); /* child does the estimate */
513 } else if(est->child == -1) {
514 error(_("calc_estimates fork failed: %s"), strerror(errno));
517 dumpsrunning++; /* parent */
522 for(est = est_list; est != NULL; est = est->next) {
528 amfree(our_feature_string);
529 am_release_feature_set(our_features);
531 free_g_options(g_options);
536 g_printf(_("FORMAT ERROR IN REQUEST PACKET\n"));
538 dbprintf(_("REQ packet is bogus: %s\n"), err_extra);
541 dbprintf(_("REQ packet is bogus\n"));
554 int program_is_backup_api,
559 disk_estimates_t *newp, *curp;
566 if (level >= DUMP_LEVELS)
567 level = DUMP_LEVELS - 1;
569 for(curp = est_list; curp != NULL; curp = curp->next) {
570 if(strcmp(curp->amname, disk) == 0) {
571 /* already have disk info, just note the level request */
572 curp->est[level].needestimate = 1;
574 free_sl(options->exclude_file);
575 free_sl(options->exclude_list);
576 free_sl(options->include_file);
577 free_sl(options->include_list);
578 amfree(options->auth);
579 amfree(options->str);
586 newp = (disk_estimates_t *) alloc(SIZEOF(disk_estimates_t));
587 memset(newp, 0, SIZEOF(*newp));
588 newp->next = est_list;
590 newp->amname = stralloc(disk);
591 newp->qamname = quote_string(disk);
592 newp->amdevice = stralloc(amdevice);
593 newp->qamdevice = quote_string(amdevice);
594 newp->dirname = amname_to_dirname(newp->amdevice);
595 newp->qdirname = quote_string(newp->dirname);
596 newp->program = stralloc(prog);
598 newp->calcprog = stralloc(calcprog);
600 newp->calcprog = NULL;
601 newp->program_is_backup_api = program_is_backup_api;
602 newp->spindle = spindle;
603 newp->est[level].needestimate = 1;
604 newp->options = options;
606 /* fill in dump-since dates */
608 amdp = amandates_lookup(newp->amname);
610 newp->est[0].dumpsince = EPOCH;
611 for(dumplev = 0; dumplev < DUMP_LEVELS; dumplev++) {
612 dumpdate = amdp->dates[dumplev];
613 for(estlev = dumplev+1; estlev < DUMP_LEVELS; estlev++) {
614 if(dumpdate > newp->est[estlev].dumpsince)
615 newp->est[estlev].dumpsince = dumpdate;
623 disk_estimates_t * est)
626 amfree(est->qamname);
627 amfree(est->amdevice);
628 amfree(est->qamdevice);
629 amfree(est->dirname);
630 amfree(est->qdirname);
631 amfree(est->program);
633 free_sl(est->options->exclude_file);
634 free_sl(est->options->exclude_list);
635 free_sl(est->options->include_file);
636 free_sl(est->options->include_list);
637 amfree(est->options->str);
638 amfree(est->options->auth);
639 amfree(est->options);
644 * ------------------------------------------------------------------------
650 disk_estimates_t * est)
652 dbprintf(_("calculating for amname %s, dirname %s, spindle %d\n"),
653 est->qamname, est->qdirname, est->spindle);
655 if(est->program_is_backup_api == 1)
656 backup_api_calc_estimate(est);
658 #ifndef USE_GENERIC_CALCSIZE
659 if(strcmp(est->program, "DUMP") == 0)
660 dump_calc_estimates(est);
664 if (strcmp(est->program, "GNUTAR") == 0 &&
665 est->amdevice[0] == '/' && est->amdevice[1] == '/')
666 smbtar_calc_estimates(est);
670 if (strcmp(est->program, "GNUTAR") == 0)
671 gnutar_calc_estimates(est);
675 if (est->amdevice[0] == '/' && est->amdevice[1] == '/')
676 dbprintf(_("Can't use CALCSIZE for samba estimate: %s %s\n"),
677 est->qamname, est->qdirname);
680 generic_calc_estimates(est);
682 dbprintf(_("done with amname %s dirname %s spindle %d\n"),
683 est->qamname, est->qdirname, est->spindle);
687 * ------------------------------------------------------------------------
691 /* local functions */
692 off_t getsize_dump(char *disk, char *amdevice, int level, option_t *options,
694 off_t getsize_smbtar(char *disk, char *amdevice, int level, option_t *options,
696 off_t getsize_gnutar(char *disk, char *amdevice, int level,
697 option_t *options, time_t dumpsince, char **errmsg);
698 off_t getsize_backup_api(char *program, char *disk, char *amdevice, int level,
699 option_t *options, time_t dumpsince, char **errmsg);
700 off_t handle_dumpline(char *str);
701 double first_num(char *str);
704 backup_api_calc_estimate(
705 disk_estimates_t * est)
709 char *errmsg = NULL, *qerrmsg;
711 for(level = 0; level < DUMP_LEVELS; level++) {
712 if (est->est[level].needestimate) {
713 dbprintf(_("getting size via application API for %s %s level %d\n"),
714 est->qamname, est->qamdevice, level);
715 size = getsize_backup_api(est->program, est->amname, est->amdevice,
717 est->est[level].dumpsince, &errmsg);
721 g_printf(_("%s %d SIZE %lld\n"), est->qamname, level,
723 if (errmsg && errmsg[0] != '\0') {
724 if(am_has_feature(g_options->features,
725 fe_rep_sendsize_quoted_error)) {
726 qerrmsg = quote_string(errmsg);
727 dbprintf(_("errmsg is %s\n"), errmsg);
728 g_printf(_("%s %d ERROR %s\n"),
729 est->qamname, level, qerrmsg);
736 amfunlock(1, "size");
743 generic_calc_estimates(
744 disk_estimates_t * est)
746 int pipefd = -1, nullfd = -1;
749 char *my_argv[DUMP_LEVELS*2+22];
750 char number[NUM_STR_SIZE];
751 int i, level, my_argc;
755 char *file_exclude = NULL;
756 char *file_include = NULL;
758 FILE *dumpout = NULL;
759 off_t size = (off_t)1;
762 amwait_t wait_status;
763 char *errmsg = NULL, *qerrmsg;
764 char tmppath[PATH_MAX];
766 cmd = vstralloc(amlibexecdir, "/", "calcsize", versionsuffix(), NULL);
770 my_argv[my_argc++] = stralloc("calcsize");
771 if (g_options->config)
772 my_argv[my_argc++] = stralloc(g_options->config);
774 my_argv[my_argc++] = stralloc("NOCONFIG");
776 my_argv[my_argc++] = stralloc(est->calcprog);
778 my_argv[my_argc++] = stralloc(est->amname);
779 canonicalize_pathname(est->dirname, tmppath);
780 my_argv[my_argc++] = stralloc(tmppath);
783 if(est->options->exclude_file)
784 nb_exclude += est->options->exclude_file->nb_element;
785 if(est->options->exclude_list)
786 nb_exclude += est->options->exclude_list->nb_element;
787 if(est->options->include_file)
788 nb_include += est->options->include_file->nb_element;
789 if(est->options->include_list)
790 nb_include += est->options->include_list->nb_element;
793 file_exclude = build_exclude(est->amname,
794 est->amdevice, est->options, 0);
796 file_include = build_include(est->amname,
797 est->amdevice, est->options, 0);
800 my_argv[my_argc++] = stralloc("-X");
801 my_argv[my_argc++] = file_exclude;
805 my_argv[my_argc++] = stralloc("-I");
806 my_argv[my_argc++] = file_include;
808 start_time = curclock();
810 cmdline = stralloc(my_argv[0]);
811 for(i = 1; i < my_argc; i++)
812 cmdline = vstrextend(&cmdline, " ", my_argv[i], NULL);
813 dbprintf(_("running: \"%s\"\n"), cmdline);
816 for(level = 0; level < DUMP_LEVELS; level++) {
817 if(est->est[level].needestimate) {
818 g_snprintf(number, SIZEOF(number), "%d", level);
819 my_argv[my_argc++] = stralloc(number);
820 dbprintf(" %s", number);
821 g_snprintf(number, SIZEOF(number),
822 "%ld", (long)est->est[level].dumpsince);
823 my_argv[my_argc++] = stralloc(number);
824 dbprintf(" %s", number);
827 my_argv[my_argc] = NULL;
830 fflush(stderr); fflush(stdout);
832 if ((nullfd = open("/dev/null", O_RDWR)) == -1) {
833 errmsg = vstrallocf(_("Cannot access /dev/null : %s"),
835 dbprintf("%s\n", errmsg);
839 calcpid = pipespawnv(cmd, STDERR_PIPE, &nullfd, &nullfd, &pipefd, my_argv);
842 dumpout = fdopen(pipefd,"r");
844 error(_("Can't fdopen: %s"), strerror(errno));
847 match_expr = vstralloc(est->qamname," %d SIZE %lld", NULL);
848 for(size = (off_t)-1; (line = agets(dumpout)) != NULL; free(line)) {
849 long long size_ = (long long)0;
852 if(sscanf(line, match_expr, &level, &size_) == 2) {
853 g_printf("%s\n", line); /* write to amandad */
854 dbprintf(_("estimate size for %s level %d: %lld KB\n"),
863 dbprintf(_("waiting for %s %s child (pid=%d)\n"),
864 my_argv[0], est->qamdevice, (int)calcpid);
865 waitpid(calcpid, &wait_status, 0);
866 if (WIFSIGNALED(wait_status)) {
867 errmsg = vstrallocf(_("%s terminated with signal %d: see %s"),
868 "calcsize", WTERMSIG(wait_status),
870 } else if (WIFEXITED(wait_status)) {
871 if (WEXITSTATUS(wait_status) != 0) {
872 errmsg = vstrallocf(_("%s exited with status %d: see %s"),
873 "calcsize", WEXITSTATUS(wait_status),
879 errmsg = vstrallocf(_("%s got bad exit: see %s"),
882 dbprintf(_("after %s %s wait: child pid=%d status=%d\n"),
883 my_argv[0], est->qamdevice,
884 (int)calcpid, WEXITSTATUS(wait_status));
886 dbprintf(_(".....\n"));
887 dbprintf(_("estimate time for %s: %s\n"),
889 walltime_str(timessub(curclock(), start_time)));
892 if (errmsg && errmsg[0] != '\0') {
893 if(am_has_feature(g_options->features, fe_rep_sendsize_quoted_error)) {
894 qerrmsg = quote_string(errmsg);
895 dbprintf(_("errmsg is %s\n"), errmsg);
896 g_printf("%s %d ERROR %s\n",
897 est->qamname, 0, qerrmsg);
902 for(i = 0; i < my_argc; i++) {
911 disk_estimates_t * est)
915 char *errmsg=NULL, *qerrmsg;
917 for(level = 0; level < DUMP_LEVELS; level++) {
918 if(est->est[level].needestimate) {
919 dbprintf(_("getting size via dump for %s level %d\n"),
920 est->qamname, level);
921 size = getsize_dump(est->amname, est->amdevice,
922 level, est->options, &errmsg);
926 g_printf(_("%s %d SIZE %lld\n"),
927 est->qamname, level, (long long)size);
928 if (errmsg && errmsg[0] != '\0') {
929 if(am_has_feature(g_options->features,
930 fe_rep_sendsize_quoted_error)) {
931 qerrmsg = quote_string(errmsg);
932 dbprintf(_("errmsg is %s\n"), errmsg);
933 g_printf("%s %d ERROR %s\n",
934 est->qamname, level, qerrmsg);
941 amfunlock(1, "size");
948 smbtar_calc_estimates(
949 disk_estimates_t * est)
953 char *errmsg = NULL, *qerrmsg;
955 for(level = 0; level < DUMP_LEVELS; level++) {
956 if(est->est[level].needestimate) {
957 dbprintf(_("getting size via smbclient for %s level %d\n"),
958 est->qamname, level);
959 size = getsize_smbtar(est->amname, est->amdevice, level,
960 est->options, &errmsg);
964 g_printf(_("%s %d SIZE %lld\n"),
965 est->qamname, level, (long long)size);
966 if (errmsg && errmsg[0] != '\0') {
967 if(am_has_feature(g_options->features,
968 fe_rep_sendsize_quoted_error)) {
969 qerrmsg = quote_string(errmsg);
970 dbprintf(_("errmsg is %s\n"), errmsg);
971 g_printf("%s %d ERROR %s\n",
972 est->qamname, level, qerrmsg);
979 amfunlock(1, "size");
987 gnutar_calc_estimates(
988 disk_estimates_t * est)
992 char *errmsg = NULL, *qerrmsg;
994 for(level = 0; level < DUMP_LEVELS; level++) {
995 if (est->est[level].needestimate) {
996 dbprintf(_("getting size via gnutar for %s level %d\n"),
997 est->qamname, level);
998 size = getsize_gnutar(est->amname, est->amdevice, level,
999 est->options, est->est[level].dumpsince,
1004 g_printf(_("%s %d SIZE %lld\n"),
1005 est->qamname, level, (long long)size);
1006 if (errmsg && errmsg[0] != '\0') {
1007 if(am_has_feature(g_options->features,
1008 fe_rep_sendsize_quoted_error)) {
1009 qerrmsg = quote_string(errmsg);
1010 dbprintf(_("errmsg is %s\n"), errmsg);
1011 g_printf(_("%s %d ERROR %s\n"),
1012 est->qamname, level, qerrmsg);
1019 amfunlock(1, "size");
1025 typedef struct regex_s {
1031 regex_scale_t re_size[] = {
1033 {" DUMP: estimated -*[0-9][0-9]* tape blocks", 1024},
1034 {" DUMP: [Ee]stimated [0-9][0-9]* blocks", 512},
1035 {" DUMP: [Ee]stimated [0-9][0-9]* bytes", 1}, /* Ultrix 4.4 */
1036 {" UFSDUMP: estimated [0-9][0-9]* blocks", 512}, /* NEC EWS-UX */
1037 {"dump: Estimate: [0-9][0-9]* tape blocks", 1024}, /* OSF/1 */
1038 {"backup: There are an estimated [0-9][0-9]* tape blocks.",1024}, /* AIX */
1039 {"backup: estimated [0-9][0-9]* 1k blocks", 1024}, /* AIX */
1040 {"backup: estimated [0-9][0-9]* tape blocks", 1024}, /* AIX */
1041 {"backup: [0-9][0-9]* tape blocks on [0-9][0-9]* tape(s)",1024}, /* AIX */
1042 {"backup: [0-9][0-9]* 1k blocks on [0-9][0-9]* volume(s)",1024}, /* AIX */
1043 {"dump: Estimate: [0-9][0-9]* blocks being output to pipe",1024},
1045 {"dump: Dumping [0-9][0-9]* bytes, ", 1}, /* DU 4.0 vdump */
1046 {"DUMP: estimated [0-9][0-9]* KB output", 1024}, /* HPUX */
1047 {"DUMP: estimated [0-9][0-9]* KB\\.", 1024}, /* NetApp */
1048 {" UFSDUMP: estimated [0-9][0-9]* blocks", 512}, /* Sinix */
1050 #ifdef HAVE_DUMP_ESTIMATE
1051 {"[0-9][0-9]* blocks, [0-9][0-9]*.[0-9][0-9]* volumes", 1024},
1052 /* DU 3.2g dump -E */
1053 {"^[0-9][0-9]* blocks$", 1024}, /* DU 4.0 dump -E */
1054 {"^[0-9][0-9]*$", 1}, /* Solaris ufsdump -S */
1059 {"vdump: Dumping [0-9][0-9]* bytes, ", 1}, /* OSF/1 vdump */
1063 {"vxdump: estimated [0-9][0-9]* blocks", 512}, /* HPUX's vxdump */
1064 {" VXDUMP: estimated [0-9][0-9]* blocks", 512}, /* Sinix */
1068 {"xfsdump: estimated dump size: [0-9][0-9]* bytes", 1}, /* Irix 6.2 xfs */
1072 {"Total bytes written: [0-9][0-9]*", 1}, /* Gnutar client */
1076 #if SAMBA_VERSION >= 2
1077 #define SAMBA_DEBUG_LEVEL "0"
1078 {"Total number of bytes: [0-9][0-9]*", 1}, /* Samba du */
1080 #define SAMBA_DEBUG_LEVEL "3"
1081 {"Total bytes listed: [0-9][0-9]*", 1}, /* Samba dir */
1094 option_t *options G_GNUC_UNUSED,
1097 int pipefd[2], nullfd, stdoutfd, killctl[2];
1101 char *dumpkeys = NULL;
1102 char *device = NULL;
1103 char *fstype = NULL;
1107 char *rundump_cmd = NULL;
1108 char level_str[NUM_STR_SIZE];
1111 char *qdisk = quote_string(disk);
1114 amwait_t wait_status;
1115 #if defined(DUMP) || defined(VDUMP) || defined(VXDUMP) || defined(XFSDUMP)
1119 g_snprintf(level_str, SIZEOF(level_str), "%d", level);
1121 device = amname_to_devname(amdevice);
1122 qdevice = quote_string(device);
1123 fstype = amname_to_fstype(amdevice);
1125 dbprintf(_("calculating for device %s with %s\n"),
1128 cmd = vstralloc(amlibexecdir, "/rundump", versionsuffix(), NULL);
1129 rundump_cmd = stralloc(cmd);
1130 if (g_options->config)
1131 config = g_options->config;
1133 config = "NOCONFIG";
1134 if ((stdoutfd = nullfd = open("/dev/null", O_RDWR)) == -1) {
1135 *errmsg = vstrallocf(_("getsize_dump could not open /dev/null: %s"),
1137 dbprintf("%s\n", *errmsg);
1139 amfree(rundump_cmd);
1146 pipefd[0] = pipefd[1] = killctl[0] = killctl[1] = -1;
1147 if (pipe(pipefd) < 0) {
1148 *errmsg = vstrallocf(_("getsize_dump could create data pipes: %s"),
1150 dbprintf("%s\n", *errmsg);
1152 amfree(rundump_cmd);
1160 #ifdef XFSDUMP /* { */
1162 if (strcmp(fstype, "xfs") == 0)
1167 name = stralloc(" (xfsdump)");
1168 dbprintf(_("running \"%s%s -F -J -l %s - %s\"\n"),
1169 cmd, name, level_str, qdevice);
1173 #ifdef VXDUMP /* { */
1175 if (strcmp(fstype, "vxfs") == 0)
1181 name = stralloc(" (vxdump)");
1183 name = stralloc("");
1184 cmd = newstralloc(cmd, VXDUMP);
1185 config = skip_argument;
1188 dumpkeys = vstralloc(level_str, "s", "f", NULL);
1189 dbprintf(_("running \"%s%s %s 1048576 - %s\"\n"),
1190 cmd, name, dumpkeys, qdevice);
1194 #ifdef VDUMP /* { */
1196 if (strcmp(fstype, "advfs") == 0)
1201 name = stralloc(" (vdump)");
1204 device = amname_to_dirname(amdevice);
1205 qdevice = quote_string(device);
1206 dumpkeys = vstralloc(level_str, "b", "f", NULL);
1207 dbprintf(_("running \"%s%s %s 60 - %s\"\n"),
1208 cmd, name, dumpkeys, qdevice);
1214 # ifdef USE_RUNDUMP /* { */
1215 # ifdef AIX_BACKUP /* { */
1216 name = stralloc(" (backup)");
1218 name = vstralloc(" (", DUMP, ")", NULL);
1221 name = stralloc("");
1222 cmd = newstralloc(cmd, DUMP);
1223 config = skip_argument;
1227 # ifdef AIX_BACKUP /* { */
1228 dumpkeys = vstralloc("-", level_str, "f", NULL);
1229 dbprintf(_("running \"%s%s %s - %s\"\n"),
1230 cmd, name, dumpkeys, qdevice);
1232 # ifdef HAVE_DUMP_ESTIMATE
1233 # define PARAM_DUMP_ESTIMATE HAVE_DUMP_ESTIMATE
1235 # define PARAM_DUMP_ESTIMATE ""
1237 # ifdef HAVE_HONOR_NODUMP
1238 # define PARAM_HONOR_NODUMP "h"
1240 # define PARAM_HONOR_NODUMP ""
1242 dumpkeys = vstralloc(level_str,
1243 PARAM_DUMP_ESTIMATE,
1247 # ifdef HAVE_DUMP_ESTIMATE
1248 stdoutfd = pipefd[1];
1251 # ifdef HAVE_HONOR_NODUMP /* { */
1252 dbprintf(_("running \"%s%s %s 0 1048576 - %s\"\n"),
1253 cmd, name, dumpkeys, qdevice);
1255 dbprintf(_("running \"%s%s %s 1048576 - %s\"\n"),
1256 cmd, name, dumpkeys, qdevice);
1263 error(_("no dump program available"));
1267 if (pipe(killctl) < 0) {
1268 dbprintf(_("Could not create pipe: %s\n"), strerror(errno));
1269 /* Message will be printed later... */
1270 killctl[0] = killctl[1] = -1;
1273 start_time = curclock();
1274 switch(dumppid = fork()) {
1276 *errmsg = vstrallocf(_("cannot fork for killpgrp: %s"),
1278 dbprintf("%s\n", *errmsg);
1281 amfree(rundump_cmd);
1290 case 0: /* child process */
1293 else if (killctl[0] == -1 || killctl[1] == -1)
1294 dbprintf(_("Trying without killpgrp\n"));
1298 dbprintf(_("fork failed, trying without killpgrp\n"));
1304 char *killpgrp_cmd = vstralloc(amlibexecdir, "/killpgrp",
1305 versionsuffix(), NULL);
1306 dbprintf(_("running %s\n"), killpgrp_cmd);
1307 dup2(killctl[0], 0);
1314 if (g_options->config)
1315 config = g_options->config;
1317 config = "NOCONFIG";
1319 execle(killpgrp_cmd, killpgrp_cmd, config, (char *)0,
1321 dbprintf(_("cannot execute %s: %s\n"),
1322 killpgrp_cmd, strerror(errno));
1326 case 0: /* child process */
1335 if (killctl[0] != -1)
1337 if (killctl[1] != -1)
1343 if (strcmp(fstype, "xfs") == 0)
1348 execle(cmd, "rundump", config, "xfsdump", "-F", "-J", "-l",
1349 level_str, "-", device, (char *)0, safe_env());
1351 execle(cmd, "xfsdump", "-F", "-J", "-l",
1352 level_str, "-", device, (char *)0, safe_env());
1357 if (strcmp(fstype, "vxfs") == 0)
1362 execle(cmd, "rundump", config, "vxdump", dumpkeys, "1048576",
1363 "-", device, (char *)0, safe_env());
1365 execle(cmd, "vxdump", dumpkeys, "1048576", "-",
1366 device, (char *)0, safe_env());
1371 if (strcmp(fstype, "advfs") == 0)
1376 execle(cmd, "rundump", config, "vdump", dumpkeys, "60", "-",
1377 device, (char *)0, safe_env());
1379 execle(cmd, "vdump", dumpkeys, "60", "-",
1380 device, (char *)0, safe_env());
1386 execle(cmd, "rundump", config, "backup", dumpkeys, "-",
1387 device, (char *)0, safe_env());
1389 execle(cmd, "backup", dumpkeys, "-",
1390 device, (char *)0, safe_env());
1393 execle(cmd, "rundump", config, "dump", dumpkeys,
1394 #ifdef HAVE_HONOR_NODUMP
1397 "1048576", "-", device, (char *)0, safe_env());
1399 execle(cmd, "dump", dumpkeys,
1400 #ifdef HAVE_HONOR_NODUMP
1403 "1048576", "-", device, (char *)0, safe_env());
1408 error(_("exec %s failed or no dump program available: %s"),
1409 cmd, strerror(errno));
1415 amfree(rundump_cmd);
1418 if (killctl[0] != -1)
1420 dumpout = fdopen(pipefd[0],"r");
1422 error(_("Can't fdopen: %s"), strerror(errno));
1426 for(size = (off_t)-1; (line = agets(dumpout)) != NULL; free(line)) {
1427 if (line[0] == '\0')
1429 dbprintf("%s\n", line);
1430 size = handle_dumpline(line);
1431 if(size > (off_t)-1) {
1433 while ((line = agets(dumpout)) != NULL) {
1434 if (line[0] != '\0')
1439 dbprintf("%s\n", line);
1446 dbprintf(".....\n");
1447 dbprintf(_("estimate time for %s level %d: %s\n"),
1450 walltime_str(timessub(curclock(), start_time)));
1451 if(size == (off_t)-1) {
1452 *errmsg = vstrallocf(_("no size line match in %s%s output"),
1454 dbprintf(_("%s for %s\n"),
1457 dbprintf(".....\n");
1458 dbprintf(_("Run %s%s manually to check for errors\n"),
1460 } else if(size == (off_t)0 && level == 0) {
1461 dbprintf(_("possible %s%s problem -- is \"%s\" really empty?\n"),
1463 dbprintf(".....\n");
1465 dbprintf(_("estimate size for %s level %d: %lld KB\n"),
1471 if (killctl[1] != -1) {
1472 dbprintf(_("asking killpgrp to terminate\n"));
1474 for(s = 5; s > 0; --s) {
1476 if (waitpid(dumppid, NULL, WNOHANG) != -1)
1482 * First, try to kill the dump process nicely. If it ignores us
1483 * for several seconds, hit it harder.
1485 dbprintf(_("sending SIGTERM to process group %ld\n"), (long)dumppid);
1486 if (kill(-dumppid, SIGTERM) == -1) {
1487 dbprintf(_("kill failed: %s\n"), strerror(errno));
1489 /* Now check whether it dies */
1490 for(s = 5; s > 0; --s) {
1492 if (waitpid(dumppid, NULL, WNOHANG) != -1)
1496 dbprintf(_("sending SIGKILL to process group %ld\n"), (long)dumppid);
1497 if (kill(-dumppid, SIGKILL) == -1) {
1498 dbprintf(_("kill failed: %s\n"), strerror(errno));
1500 for(s = 5; s > 0; --s) {
1502 if (waitpid(dumppid, NULL, WNOHANG) != -1)
1506 dbprintf(_("waiting for %s%s \"%s\" child\n"), cmd, name, qdisk);
1507 waitpid(dumppid, &wait_status, 0);
1508 if (WIFSIGNALED(wait_status)) {
1509 *errmsg = vstrallocf(_("%s terminated with signal %d: see %s"),
1510 cmd, WTERMSIG(wait_status), dbfn());
1511 } else if (WIFEXITED(wait_status)) {
1512 if (WEXITSTATUS(wait_status) != 0) {
1513 *errmsg = vstrallocf(_("%s exited with status %d: see %s"),
1514 cmd, WEXITSTATUS(wait_status), dbfn());
1519 *errmsg = vstrallocf(_("%s got bad exit: see %s"),
1522 dbprintf(_("after %s%s %s wait\n"), cmd, name, qdisk);
1549 int pipefd = -1, nullfd = -1, passwdfd = -1;
1553 char *tarkeys, *sharename, *user_and_password = NULL, *domain = NULL;
1554 char *share = NULL, *subdir = NULL;
1561 char *error_pn = NULL;
1562 char *qdisk = quote_string(disk);
1563 amwait_t wait_status;
1565 (void)options; /* Quiet unused parameter warning */
1567 error_pn = stralloc2(get_pname(), "-smbclient");
1569 parsesharename(amdevice, &share, &subdir);
1573 set_pname(error_pn);
1575 error(_("cannot parse disk entry %s for share/subdir"), qdisk);
1578 if ((subdir) && (SAMBA_VERSION < 2)) {
1581 set_pname(error_pn);
1583 error(_("subdirectory specified for share %s but samba not v2 or better"), qdisk);
1586 if ((user_and_password = findpass(share, &domain)) == NULL) {
1589 memset(domain, '\0', strlen(domain));
1592 set_pname(error_pn);
1594 error(_("cannot find password for %s"), disk);
1597 lpass = strlen(user_and_password);
1598 if ((pwtext = strchr(user_and_password, '%')) == NULL) {
1599 memset(user_and_password, '\0', (size_t)lpass);
1600 amfree(user_and_password);
1602 memset(domain, '\0', strlen(domain));
1605 set_pname(error_pn);
1607 error(_("password field not \'user%%pass\' for %s"), disk);
1611 pwtext_len = strlen(pwtext);
1612 if ((sharename = makesharename(share, 0)) == NULL) {
1613 memset(user_and_password, '\0', (size_t)lpass);
1614 amfree(user_and_password);
1616 memset(domain, '\0', strlen(domain));
1619 set_pname(error_pn);
1621 error(_("cannot make share name of %s"), share);
1624 if ((nullfd = open("/dev/null", O_RDWR)) == -1) {
1625 memset(user_and_password, '\0', (size_t)lpass);
1626 amfree(user_and_password);
1628 memset(domain, '\0', strlen(domain));
1631 set_pname(error_pn);
1634 error(_("could not open /dev/null: %s\n"),
1639 #if SAMBA_VERSION >= 2
1641 tarkeys = "archive 0;recurse;du";
1643 tarkeys = "archive 1;recurse;du";
1646 tarkeys = "archive 0;recurse;dir";
1648 tarkeys = "archive 1;recurse;dir";
1651 start_time = curclock();
1653 if (pwtext_len > 0) {
1654 pw_fd_env = "PASSWD_FD";
1656 pw_fd_env = "dummy_PASSWD_FD";
1658 dumppid = pipespawn(SAMBA_CLIENT, STDERR_PIPE|PASSWD_PIPE,
1659 &nullfd, &nullfd, &pipefd,
1660 pw_fd_env, &passwdfd,
1663 "-d", SAMBA_DEBUG_LEVEL,
1664 *user_and_password ? "-U" : skip_argument,
1665 *user_and_password ? user_and_password : skip_argument,
1667 domain ? "-W" : skip_argument,
1668 domain ? domain : skip_argument,
1669 #if SAMBA_VERSION >= 2
1670 subdir ? "-D" : skip_argument,
1671 subdir ? subdir : skip_argument,
1676 memset(domain, '\0', strlen(domain));
1680 if(pwtext_len > 0 && fullwrite(passwdfd, pwtext, (size_t)pwtext_len) < 0) {
1681 int save_errno = errno;
1683 memset(user_and_password, '\0', (size_t)lpass);
1684 amfree(user_and_password);
1686 set_pname(error_pn);
1688 error(_("password write failed: %s"), strerror(save_errno));
1691 memset(user_and_password, '\0', (size_t)lpass);
1692 amfree(user_and_password);
1698 dumpout = fdopen(pipefd,"r");
1700 error(_("Can't fdopen: %s"), strerror(errno));
1704 for(size = (off_t)-1; (line = agets(dumpout)) != NULL; free(line)) {
1705 if (line[0] == '\0')
1707 dbprintf("%s\n", line);
1708 size = handle_dumpline(line);
1711 while ((line = agets(dumpout)) != NULL) {
1712 if (line[0] != '\0')
1717 dbprintf("%s\n", line);
1724 dbprintf(".....\n");
1725 dbprintf(_("estimate time for %s level %d: %s\n"),
1728 walltime_str(timessub(curclock(), start_time)));
1729 if(size == (off_t)-1) {
1730 *errmsg = vstrallocf(_("no size line match in %s output"),
1732 dbprintf(_("%s for %s\n"),
1734 dbprintf(".....\n");
1735 } else if(size == (off_t)0 && level == 0) {
1736 dbprintf(_("possible %s problem -- is \"%s\" really empty?\n"),
1737 SAMBA_CLIENT, disk);
1738 dbprintf(".....\n");
1740 dbprintf(_("estimate size for %s level %d: %lld KB\n"),
1745 kill(-dumppid, SIGTERM);
1747 dbprintf(_("waiting for %s \"%s\" child\n"), SAMBA_CLIENT, qdisk);
1748 waitpid(dumppid, &wait_status, 0);
1749 if (WIFSIGNALED(wait_status)) {
1750 *errmsg = vstrallocf(_("%s terminated with signal %d: see %s"),
1751 SAMBA_CLIENT, WTERMSIG(wait_status), dbfn());
1752 } else if (WIFEXITED(wait_status)) {
1753 if (WEXITSTATUS(wait_status) != 0) {
1754 *errmsg = vstrallocf(_("%s exited with status %d: see %s"),
1755 SAMBA_CLIENT, WEXITSTATUS(wait_status),
1761 *errmsg = vstrallocf(_("%s got bad exit: see %s"),
1762 SAMBA_CLIENT, dbfn());
1764 dbprintf(_("after %s %s wait\n"), SAMBA_CLIENT, qdisk);
1786 int pipefd = -1, nullfd = -1;
1788 off_t size = (off_t)-1;
1789 FILE *dumpout = NULL;
1790 char *incrname = NULL;
1791 char *basename = NULL;
1792 char *dirname = NULL;
1793 char *inputname = NULL;
1798 char dumptimestr[80];
1804 char *file_exclude = NULL;
1805 char *file_include = NULL;
1810 char *qdisk = quote_string(disk);
1811 char *gnutar_list_dir;
1812 amwait_t wait_status;
1813 char tmppath[PATH_MAX];
1815 if(options->exclude_file) nb_exclude += options->exclude_file->nb_element;
1816 if(options->exclude_list) nb_exclude += options->exclude_list->nb_element;
1817 if(options->include_file) nb_include += options->include_file->nb_element;
1818 if(options->include_list) nb_include += options->include_list->nb_element;
1820 if(nb_exclude > 0) file_exclude = build_exclude(disk, amdevice, options, 0);
1821 if(nb_include > 0) file_include = build_include(disk, amdevice, options, 0);
1823 my_argv = alloc(SIZEOF(char *) * 22);
1826 gnutar_list_dir = getconf_str(CNF_GNUTAR_LIST_DIR);
1827 if (strlen(gnutar_list_dir) == 0)
1828 gnutar_list_dir = NULL;
1829 if (gnutar_list_dir) {
1830 char number[NUM_STR_SIZE];
1832 char *sdisk = sanitise_filename(disk);
1834 basename = vstralloc(gnutar_list_dir,
1836 g_options->hostname,
1841 g_snprintf(number, SIZEOF(number), "%d", level);
1842 incrname = vstralloc(basename, "_", number, ".new", NULL);
1846 * Open the listed incremental file from the previous level. Search
1847 * backward until one is found. If none are found (which will also
1848 * be true for a level 0), arrange to read from /dev/null.
1852 while (infd == -1) {
1853 if (--baselevel >= 0) {
1854 g_snprintf(number, SIZEOF(number), "%d", baselevel);
1855 inputname = newvstralloc(inputname,
1856 basename, "_", number, NULL);
1858 inputname = newstralloc(inputname, "/dev/null");
1860 if ((infd = open(inputname, O_RDONLY)) == -1) {
1862 *errmsg = vstrallocf(_("gnutar: error opening %s: %s"),
1863 inputname, strerror(errno));
1864 dbprintf("%s\n", *errmsg);
1865 if (baselevel < 0) {
1873 * Copy the previous listed incremental file to the new one.
1875 if ((outfd = open(incrname, O_WRONLY|O_CREAT, 0600)) == -1) {
1876 *errmsg = vstrallocf(_("opening %s: %s"),
1877 incrname, strerror(errno));
1878 dbprintf("%s\n", *errmsg);
1882 while ((nb = read(infd, &buf, SIZEOF(buf))) > 0) {
1883 if (fullwrite(outfd, &buf, (size_t)nb) < nb) {
1884 *errmsg = vstrallocf(_("writing to %s: %s"),
1885 incrname, strerror(errno));
1886 dbprintf("%s\n", *errmsg);
1892 *errmsg = vstrallocf(_("reading from %s: %s"),
1893 inputname, strerror(errno));
1894 dbprintf("%s\n", *errmsg);
1898 if (close(infd) != 0) {
1899 *errmsg = vstrallocf(_("closing %s: %s"),
1900 inputname, strerror(errno));
1901 dbprintf("%s\n", *errmsg);
1904 if (close(outfd) != 0) {
1905 *errmsg = vstrallocf(_("closing %s: %s"),
1906 incrname, strerror(errno));
1907 dbprintf("%s\n", *errmsg);
1915 gmtm = gmtime(&dumpsince);
1916 g_snprintf(dumptimestr, SIZEOF(dumptimestr),
1917 "%04d-%02d-%02d %2d:%02d:%02d GMT",
1918 gmtm->tm_year + 1900, gmtm->tm_mon+1, gmtm->tm_mday,
1919 gmtm->tm_hour, gmtm->tm_min, gmtm->tm_sec);
1921 dirname = amname_to_dirname(amdevice);
1923 cmd = vstralloc(amlibexecdir, "/", "runtar", versionsuffix(), NULL);
1924 my_argv[i++] = "runtar";
1925 if (g_options->config)
1926 my_argv[i++] = g_options->config;
1928 my_argv[i++] = "NOCONFIG";
1931 my_argv[i++] = GNUTAR;
1933 my_argv[i++] = "tar";
1935 my_argv[i++] = "--create";
1936 my_argv[i++] = "--file";
1937 my_argv[i++] = "/dev/null";
1938 my_argv[i++] = "--directory";
1939 canonicalize_pathname(dirname, tmppath);
1940 my_argv[i++] = tmppath;
1941 my_argv[i++] = "--one-file-system";
1942 if (gnutar_list_dir) {
1943 my_argv[i++] = "--listed-incremental";
1944 my_argv[i++] = incrname;
1946 my_argv[i++] = "--incremental";
1947 my_argv[i++] = "--newer";
1948 my_argv[i++] = dumptimestr;
1950 #ifdef ENABLE_GNUTAR_ATIME_PRESERVE
1951 /* --atime-preserve causes gnutar to call
1952 * utime() after reading files in order to
1953 * adjust their atime. However, utime()
1954 * updates the file's ctime, so incremental
1955 * dumps will think the file has changed. */
1956 my_argv[i++] = "--atime-preserve";
1958 my_argv[i++] = "--sparse";
1959 my_argv[i++] = "--ignore-failed-read";
1960 my_argv[i++] = "--totals";
1963 my_argv[i++] = "--exclude-from";
1964 my_argv[i++] = file_exclude;
1968 my_argv[i++] = "--files-from";
1969 my_argv[i++] = file_include;
1974 my_argv[i++] = NULL;
1976 start_time = curclock();
1978 if ((nullfd = open("/dev/null", O_RDWR)) == -1) {
1979 *errmsg = vstrallocf(_("Cannot access /dev/null : %s"),
1981 dbprintf("%s\n", *errmsg);
1985 dumppid = pipespawnv(cmd, STDERR_PIPE, &nullfd, &nullfd, &pipefd, my_argv);
1987 dumpout = fdopen(pipefd,"r");
1989 error(_("Can't fdopen: %s"), strerror(errno));
1993 for(size = (off_t)-1; (line = agets(dumpout)) != NULL; free(line)) {
1994 if (line[0] == '\0')
1996 dbprintf("%s\n", line);
1997 size = handle_dumpline(line);
1998 if(size > (off_t)-1) {
2000 while ((line = agets(dumpout)) != NULL) {
2001 if (line[0] != '\0') {
2007 dbprintf("%s\n", line);
2015 dbprintf(".....\n");
2016 dbprintf(_("estimate time for %s level %d: %s\n"),
2019 walltime_str(timessub(curclock(), start_time)));
2020 if(size == (off_t)-1) {
2021 *errmsg = vstrallocf(_("no size line match in %s output"), my_argv[0]);
2022 dbprintf(_("%s for %s\n"), *errmsg, qdisk);
2023 dbprintf(".....\n");
2024 } else if(size == (off_t)0 && level == 0) {
2025 dbprintf(_("possible %s problem -- is \"%s\" really empty?\n"),
2027 dbprintf(".....\n");
2029 dbprintf(_("estimate size for %s level %d: %lld KB\n"),
2034 kill(-dumppid, SIGTERM);
2036 dbprintf(_("waiting for %s \"%s\" child\n"), my_argv[0], qdisk);
2037 waitpid(dumppid, &wait_status, 0);
2038 if (WIFSIGNALED(wait_status)) {
2039 *errmsg = vstrallocf(_("%s terminated with signal %d: see %s"),
2040 cmd, WTERMSIG(wait_status), dbfn());
2041 } else if (WIFEXITED(wait_status)) {
2042 if (WEXITSTATUS(wait_status) != 0) {
2043 *errmsg = vstrallocf(_("%s exited with status %d: see %s"),
2044 cmd, WEXITSTATUS(wait_status), dbfn());
2049 *errmsg = vstrallocf(_("%s got bad exit: see %s"),
2052 dbprintf(_("after %s %s wait\n"), my_argv[0], qdisk);
2066 amfree(file_exclude);
2067 amfree(file_include);
2088 int pipeinfd[2], pipeoutfd[2], nullfd;
2090 off_t size = (off_t)-1;
2091 FILE *dumpout, *toolin;
2095 char dumptimestr[80];
2098 char *argvchild[10];
2099 char *newoptstr = NULL;
2102 char *qdisk = quote_string(disk);
2103 char *qamdevice = quote_string(amdevice);
2104 amwait_t wait_status;
2105 char levelstr[NUM_STR_SIZE];
2106 backup_support_option_t *bsu;
2109 gmtm = gmtime(&dumpsince);
2110 g_snprintf(dumptimestr, SIZEOF(dumptimestr),
2111 "%04d-%02d-%02d %2d:%02d:%02d GMT",
2112 gmtm->tm_year + 1900, gmtm->tm_mon+1, gmtm->tm_mday,
2113 gmtm->tm_hour, gmtm->tm_min, gmtm->tm_sec);
2115 cmd = vstralloc(DUMPER_DIR, "/", program, NULL);
2117 bsu = backup_support_option(program, g_options, disk, amdevice);
2120 argvchild[i++] = program;
2121 argvchild[i++] = "estimate";
2122 if (bsu->message_line == 1) {
2123 argvchild[i++] = "--message";
2124 argvchild[i++] = "line";
2126 if (g_options->config && bsu->config == 1) {
2127 argvchild[i++] = "--config";
2128 argvchild[i++] = g_options->config;
2130 if (g_options->hostname && bsu->host == 1) {
2131 argvchild[i++] = "--host";
2132 argvchild[i++] = g_options->hostname;
2134 argvchild[i++] = "--device";
2135 argvchild[i++] = amdevice;
2136 if (disk && bsu->disk == 1) {
2137 argvchild[i++] = "--disk";
2138 argvchild[i++] = disk;
2140 if (level <= bsu->max_level) {
2141 argvchild[i++] = "--level";
2142 g_snprintf(levelstr,SIZEOF(levelstr),"%d",level);
2143 argvchild[i++] = levelstr;
2146 argvchild[i] = NULL;
2148 cmdline = stralloc(cmd);
2149 for(j = 1; j < i; j++)
2150 cmdline = vstrextend(&cmdline, " ", argvchild[i], NULL);
2151 dbprintf("running: \"%s\"\n", cmdline);
2154 if ((nullfd = open("/dev/null", O_RDWR)) == -1) {
2155 *errmsg = vstrallocf(_("Cannot access /dev/null : %s"),
2157 dbprintf("%s\n", *errmsg);
2161 if (pipe(pipeinfd) < 0) {
2162 *errmsg = vstrallocf(_("getsize_backup_api could create data pipes: %s"),
2164 dbprintf("%s\n", *errmsg);
2168 if (pipe(pipeoutfd) < 0) {
2169 *errmsg = vstrallocf(_("getsize_backup_api could create data pipes: %s"),
2171 dbprintf("%s\n", *errmsg);
2175 start_time = curclock();
2177 switch(dumppid = fork()) {
2184 dup2(pipeinfd[0], 0);
2185 dup2(pipeoutfd[1], 1);
2187 aclose(pipeinfd[1]);
2188 aclose(pipeoutfd[0]);
2191 execve(cmd, argvchild, safe_env());
2192 error(_("exec %s failed: %s"), cmd, strerror(errno));
2197 aclose(pipeinfd[0]);
2198 aclose(pipeoutfd[1]);
2200 toolin = fdopen(pipeinfd[1],"w");
2202 error("Can't fdopen: %s", strerror(errno));
2206 output_tool_property(toolin, options);
2210 dumpout = fdopen(pipeoutfd[0],"r");
2212 error(_("Can't fdopen: %s"), strerror(errno));
2216 for(size = (off_t)-1; (line = agets(dumpout)) != NULL; free(line)) {
2217 long long size1_ = (long long)0;
2218 long long size2_ = (long long)0;
2219 if (line[0] == '\0')
2221 dbprintf("%s\n", line);
2222 i = sscanf(line, "%lld %lld", &size1_, &size2_);
2223 size1 = (off_t)size1_;
2224 size2 = (off_t)size2_;
2226 size = size1 * size2;
2230 while ((line = agets(dumpout)) != NULL) {
2231 if (line[0] != '\0')
2236 dbprintf(_("%s\n"), line);
2243 dbprintf(".....\n");
2244 dbprintf(_("estimate time for %s level %d: %s\n"), qamdevice, level,
2245 walltime_str(timessub(curclock(), start_time)));
2246 if(size == (off_t)-1) {
2247 *errmsg = vstrallocf(_("no size line match in %s output"), cmd);
2248 dbprintf(_("%s for %s\n"), cmd, qdisk);
2249 dbprintf(".....\n");
2250 } else if(size == (off_t)0 && level == 0) {
2251 dbprintf(_("possible %s problem -- is \"%s\" really empty?\n"),
2253 dbprintf(".....\n");
2255 dbprintf(_("estimate size for %s level %d: %lld KB\n"),
2260 kill(-dumppid, SIGTERM);
2262 dbprintf(_("waiting for %s \"%s\" child\n"), cmd, qdisk);
2263 waitpid(dumppid, &wait_status, 0);
2264 if (WIFSIGNALED(wait_status)) {
2265 *errmsg = vstrallocf(_("%s terminated with signal %d: see %s"),
2266 cmd, WTERMSIG(wait_status), dbfn());
2267 } else if (WIFEXITED(wait_status)) {
2268 if (WEXITSTATUS(wait_status) != 0) {
2269 *errmsg = vstrallocf(_("%s exited with status %d: see %s"), cmd,
2270 WEXITSTATUS(wait_status), dbfn());
2275 *errmsg = vstrallocf(_("%s got bad exit: see %s"),
2278 dbprintf(_("after %s %s wait\n"), cmd, qdisk);
2294 * Returns the value of the first integer in a string.
2306 while(ch && !isdigit(ch)) ch = *str++;
2308 while(isdigit(ch) || (ch == '.')) ch = *str++;
2317 * Checks the dump output line against the error and size regex tables.
2327 /* check for size match */
2329 for(rp = re_size; rp->regex != NULL; rp++) {
2330 if(match(rp->regex, str)) {
2331 size = ((first_num(str)*rp->scale+1023.0)/1024.0);
2333 size = 1.0; /* found on NeXT -- sigh */