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.2.1 2006/09/22 11:51:32 martinea 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"
41 #include "clientconf.h"
49 # define SETPGRP setpgid(getpid(), getpid())
50 # define SETPGRP_FAILED() do { \
51 dbprintf(("setpgid(%ld,%ld) failed: %s\n", \
52 (long)getpid(), (long)getpid(), strerror(errno))); \
56 #if defined(SETPGRP_VOID)
57 # define SETPGRP setpgrp()
58 # define SETPGRP_FAILED() do { \
59 dbprintf(("setpgrp() failed: %s\n", strerror(errno))); \
63 # define SETPGRP setpgrp(0, getpid())
64 # define SETPGRP_FAILED() do { \
65 dbprintf(("setpgrp(0,%ld) failed: %s\n", \
66 (long)getpid(), strerror(errno))); \
72 typedef struct level_estimates_s {
78 typedef struct disk_estimates_s {
79 struct disk_estimates_s *next;
88 int program_is_wrapper;
93 level_estimate_t est[DUMP_LEVELS];
96 disk_estimates_t *est_list;
98 static am_feature_t *our_features = NULL;
99 static char *our_feature_string = NULL;
100 static g_option_t *g_options = NULL;
102 /* local functions */
103 int main(int argc, char **argv);
104 void add_diskest(char *disk, char *amdevice, int level, int spindle,
105 int program_is_wrapper, char *prog, char *calcprog,
107 void calc_estimates(disk_estimates_t *est);
108 void free_estimates(disk_estimates_t *est);
109 void dump_calc_estimates(disk_estimates_t *);
110 void star_calc_estimates(disk_estimates_t *);
111 void smbtar_calc_estimates(disk_estimates_t *);
112 void gnutar_calc_estimates(disk_estimates_t *);
113 void wrapper_calc_estimates(disk_estimates_t *);
114 void generic_calc_estimates(disk_estimates_t *);
123 char *prog, *calcprog, *dumpdate;
124 option_t *options = NULL;
125 int program_is_wrapper;
126 disk_estimates_t *est;
127 disk_estimates_t *est1;
128 disk_estimates_t *est_prev;
132 char *err_extra = NULL;
139 char *amdevice = NULL;
140 char *qamdevice = NULL;
142 char *amandates_file;
143 #if defined(USE_DBMALLOC)
144 unsigned long malloc_hist_1, malloc_size_1;
145 unsigned long malloc_hist_2, malloc_size_2;
148 (void)argc; /* Quiet unused parameter warning */
149 (void)argv; /* Quiet unused parameter warning */
156 set_pname("sendsize");
158 /* Don't die when child closes pipe */
159 signal(SIGPIPE, SIG_IGN);
161 #if defined(USE_DBMALLOC)
162 malloc_size_1 = malloc_inuse(&malloc_hist_1);
165 erroutput_type = (ERR_INTERACTIVE|ERR_SYSLOG);
166 dbopen(DBG_SUBDIR_CLIENT);
168 dbprintf(("%s: version %s\n", get_pname(), version()));
170 our_features = am_init_feature_set();
171 our_feature_string = am_feature_to_string(our_features);
173 set_debug_prefix_pid(getpid());
175 conffile = vstralloc(CONFIG_DIR, "/", "amanda-client.conf", NULL);
176 if (read_clientconf(conffile) > 0) {
177 error("error reading conffile: %s", conffile);
182 /* handle all service requests */
184 amandates_file = client_getconf_str(CLN_AMANDATES);
185 if(!start_amandates(amandates_file, 0))
186 error("error [opening %s: %s]", amandates_file, strerror(errno));
188 for(; (line = agets(stdin)) != NULL; free(line)) {
191 #define sc "OPTIONS "
192 if(strncmp(line, sc, SIZEOF(sc)-1) == 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';
202 if(am_has_feature(g_options->features, fe_rep_options_features)) {
203 printf("features=%s;", our_feature_string);
205 if(am_has_feature(g_options->features, fe_rep_options_maxdumps)) {
206 printf("maxdumps=%d;", g_options->maxdumps);
208 if(am_has_feature(g_options->features, fe_rep_options_hostname)) {
209 printf("hostname=%s;", g_options->hostname);
214 if (g_options->config) {
215 conffile = vstralloc(CONFIG_DIR, "/", g_options->config, "/",
216 "amanda-client.conf", NULL);
217 if (read_clientconf(conffile) > 0) {
218 error("error reading conffile: %s", conffile);
223 dbrename(g_options->config, DBG_SUBDIR_CLIENT);
232 skip_whitespace(s, ch); /* find the program name */
234 err_extra = stralloc("no program name");
235 goto err; /* no program name */
238 skip_non_whitespace(s, ch);
241 program_is_wrapper=0;
242 if(strcmp(prog,"DUMPER")==0) {
243 program_is_wrapper=1;
244 skip_whitespace(s, ch); /* find dumper name */
246 goto err; /* no program */
249 skip_non_whitespace(s, ch);
253 if(strncmp(prog, "CALCSIZE", 8) == 0) {
254 skip_whitespace(s, ch); /* find the program name */
256 err_extra = stralloc("no program name");
260 skip_non_whitespace(s, ch);
267 skip_whitespace(s, ch); /* find the disk name */
269 err_extra = stralloc("no disk name");
270 goto err; /* no disk name */
279 skip_quoted_string(s, ch);
280 s[-1] = '\0'; /* terminate the disk name */
281 qdisk = stralloc(fp);
282 disk = unquote_string(qdisk);
284 skip_whitespace(s, ch); /* find the device or level */
286 err_extra = stralloc("bad level");
289 if(!isdigit((int)s[-1])) {
291 skip_quoted_string(s, ch);
293 qamdevice = stralloc(fp);
294 amdevice = unquote_string(qamdevice);
295 skip_whitespace(s, ch); /* find level number */
298 amdevice = stralloc(disk);
299 qamdevice = stralloc(qdisk);
302 /* find the level number */
303 if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
304 err_extra = stralloc("bad level");
305 goto err; /* bad level */
307 if (level < 0 || level >= DUMP_LEVELS) {
308 err_extra = stralloc("bad level");
313 skip_whitespace(s, ch); /* find the dump date */
315 err_extra = stralloc("no dumpdate");
316 goto err; /* no dumpdate */
319 skip_non_whitespace(s, ch);
321 (void)dumpdate; /* XXX: Set but not used */
323 spindle = 0; /* default spindle */
325 skip_whitespace(s, ch); /* find the spindle */
327 if(sscanf(s - 1, "%d", &spindle) != 1) {
328 err_extra = stralloc("bad spindle");
329 goto err; /* bad spindle */
333 skip_whitespace(s, ch); /* find the parameters */
335 if(strncmp(s-1, "OPTIONS |;",10) == 0) {
336 options = parse_options(s + 8,
343 options = alloc(SIZEOF(option_t));
344 init_options(options);
346 if(strncmp(s-1, "exclude-file=", 13) == 0) {
347 qlist = unquote_string(s+12);
348 options->exclude_file =
349 append_sl(options->exclude_file, qlist);
351 } else if(strncmp(s-1, "exclude-list=", 13) == 0) {
352 options->exclude_list =
353 append_sl(options->exclude_list, qlist);
354 qlist = unquote_string(s+12);
356 } else if(strncmp(s-1, "include-file=", 13) == 0) {
357 options->include_file =
358 append_sl(options->include_file, qlist);
359 qlist = unquote_string(s+12);
361 } else if(strncmp(s-1, "include-list=", 13) == 0) {
362 options->include_list =
363 append_sl(options->include_list, qlist);
364 qlist = unquote_string(s+12);
367 err_extra = vstralloc("Invalid parameter (",
369 goto err; /* should have gotten to end */
371 skip_quoted_string(s, ch);
372 skip_whitespace(s, ch); /* find the inclusion list */
378 options = alloc(SIZEOF(option_t));
379 init_options(options);
383 options = alloc(SIZEOF(option_t));
384 init_options(options);
388 add_diskest(disk, amdevice, level, spindle, program_is_wrapper, prog, calcprog, options);
395 if (g_options == NULL) {
396 error("Missing OPTIONS line in sendsize input\n");
410 * See if we need to wait for a child before we can do anything
415 amwait_t child_status;
419 dbprintf(("%s: waiting for any estimate child: %d running\n",
420 debug_prefix_time(NULL), dumpsrunning));
421 child_pid = wait(&child_status);
422 if(child_pid == -1) {
423 error("wait failed: %s", strerror(errno));
426 if(WIFSIGNALED(child_status)) {
427 dbprintf(("%s: child %ld terminated with signal %d\n",
428 debug_prefix_time(NULL),
429 (long) child_pid, WTERMSIG(child_status)));
431 exit_code = WEXITSTATUS(child_status);
433 dbprintf(("%s: child %ld terminated normally\n",
434 debug_prefix_time(NULL), (long) child_pid));
436 dbprintf(("%s: child %ld terminated with code %d\n",
437 debug_prefix_time(NULL),
438 (long) child_pid, exit_code));
442 * Find the child and mark it done.
444 for(est = est_list; est != NULL; est = est->next) {
445 if(est->child == child_pid) {
450 dbprintf(("%s: unexpected child %ld\n",
451 debug_prefix_time(NULL), (long)child_pid));
459 * If we are already running the maximum number of children
460 * go back and wait until one of them finishes.
462 if(dumpsrunning >= g_options->maxdumps) {
465 continue; /* have to wait first */
468 * Find a new child to start.
470 for(est = est_list; est != NULL; est = est->next) {
472 done = 0; /* more to do */
474 if(est->child != 0 || est->done) {
475 continue; /* child is running or done */
478 * Make sure there is no spindle conflict.
480 if(est->spindle != -1) {
481 for(est1 = est_list; est1 != NULL; est1 = est1->next) {
482 if(est1->child == 0 || est == est1 || est1->done) {
484 * Ignore anything not yet started, ourself,
485 * and anything completed.
489 if(est1->spindle == est->spindle) {
490 break; /* oops -- they match */
494 continue; /* spindle conflict */
497 break; /* start this estimate */
500 if(dumpsrunning > 0) {
501 need_wait = 1; /* nothing to do but wait */
505 if((est->child = fork()) == 0) {
506 set_debug_prefix_pid(getpid());
507 calc_estimates(est); /* child does the estimate */
509 } else if(est->child == -1) {
510 error("calc_estimates fork failed: %s", strerror(errno));
513 dumpsrunning++; /* parent */
518 for(est = est_list; est != NULL; est = est->next) {
524 amfree(our_feature_string);
525 am_release_feature_set(our_features);
527 am_release_feature_set(g_options->features);
528 g_options->features = NULL;
529 amfree(g_options->hostname);
530 amfree(g_options->str);
533 #if defined(USE_DBMALLOC)
534 malloc_size_2 = malloc_inuse(&malloc_hist_2);
536 if(malloc_size_1 != malloc_size_2) {
537 malloc_list(dbfd(), malloc_hist_1, malloc_hist_2);
544 printf("FORMAT ERROR IN REQUEST PACKET\n");
545 dbprintf(("%s: REQ packet is bogus%s%s\n",
546 debug_prefix_time(NULL),
547 err_extra ? ": " : "",
548 err_extra ? err_extra : ""));
561 int program_is_wrapper,
566 disk_estimates_t *newp, *curp;
573 if (level >= DUMP_LEVELS)
574 level = DUMP_LEVELS - 1;
576 for(curp = est_list; curp != NULL; curp = curp->next) {
577 if(strcmp(curp->amname, disk) == 0) {
578 /* already have disk info, just note the level request */
579 curp->est[level].needestimate = 1;
581 free_sl(options->exclude_file);
582 free_sl(options->exclude_list);
583 free_sl(options->include_file);
584 free_sl(options->include_list);
585 amfree(options->auth);
586 amfree(options->str);
593 newp = (disk_estimates_t *) alloc(SIZEOF(disk_estimates_t));
594 memset(newp, 0, SIZEOF(*newp));
595 newp->next = est_list;
597 newp->amname = stralloc(disk);
598 newp->qamname = quote_string(disk);
599 newp->amdevice = stralloc(amdevice);
600 newp->qamdevice = quote_string(amdevice);
601 newp->dirname = amname_to_dirname(newp->amdevice);
602 newp->qdirname = quote_string(newp->dirname);
603 newp->program = stralloc(prog);
605 newp->calcprog = stralloc(calcprog);
607 newp->calcprog = NULL;
608 newp->program_is_wrapper = program_is_wrapper;
609 newp->spindle = spindle;
610 newp->est[level].needestimate = 1;
611 newp->options = options;
613 /* fill in dump-since dates */
615 amdp = amandates_lookup(newp->amname);
617 newp->est[0].dumpsince = EPOCH;
618 for(dumplev = 0; dumplev < DUMP_LEVELS; dumplev++) {
619 dumpdate = amdp->dates[dumplev];
620 for(estlev = dumplev+1; estlev < DUMP_LEVELS; estlev++) {
621 if(dumpdate > newp->est[estlev].dumpsince)
622 newp->est[estlev].dumpsince = dumpdate;
630 disk_estimates_t * est)
633 amfree(est->qamname);
634 amfree(est->amdevice);
635 amfree(est->qamdevice);
636 amfree(est->dirname);
637 amfree(est->qdirname);
638 amfree(est->program);
640 free_sl(est->options->exclude_file);
641 free_sl(est->options->exclude_list);
642 free_sl(est->options->include_file);
643 free_sl(est->options->include_list);
644 amfree(est->options->str);
645 amfree(est->options->auth);
646 amfree(est->options);
651 * ------------------------------------------------------------------------
657 disk_estimates_t * est)
659 dbprintf(("%s: calculating for amname %s, dirname %s, spindle %d\n",
660 debug_prefix_time(NULL),
661 est->qamname, est->qdirname, est->spindle));
663 if(est->program_is_wrapper == 1)
664 wrapper_calc_estimates(est);
666 #ifndef USE_GENERIC_CALCSIZE
667 if(strcmp(est->program, "DUMP") == 0)
668 dump_calc_estimates(est);
672 if (strcmp(est->program, "GNUTAR") == 0 &&
673 est->amdevice[0] == '/' && est->amdevice[1] == '/')
674 smbtar_calc_estimates(est);
678 if (strcmp(est->program, "GNUTAR") == 0)
679 gnutar_calc_estimates(est);
683 if (est->amdevice[0] == '/' && est->amdevice[1] == '/')
684 dbprintf(("%s: Can't use CALCSIZE for samba estimate: %s %s\n",
685 debug_prefix_time(NULL),
686 est->qamname, est->qdirname));
689 generic_calc_estimates(est);
691 dbprintf(("%s: done with amname %s dirname %s spindle %d\n",
692 debug_prefix_time(NULL),
693 est->qamname, est->qdirname, est->spindle));
697 * ------------------------------------------------------------------------
701 /* local functions */
702 off_t getsize_dump(char *disk, char *amdevice, int level, option_t *options);
703 off_t getsize_star(char *disk, char *amdevice, int level,
704 option_t *options, time_t dumpsince);
705 off_t getsize_smbtar(char *disk, char *amdevice, int level, option_t *options);
706 off_t getsize_gnutar(char *disk, char *amdevice, int level,
707 option_t *options, time_t dumpsince);
708 off_t getsize_wrapper(char *program, char *disk, char *amdevice, int level,
709 option_t *options, time_t dumpsince);
710 off_t handle_dumpline(char *str);
711 double first_num(char *str);
714 wrapper_calc_estimates(
715 disk_estimates_t * est)
720 for(level = 0; level < DUMP_LEVELS; level++) {
721 if (est->est[level].needestimate) {
722 dbprintf(("%s: getting size via wrapper for %s level %d\n",
723 debug_prefix_time(NULL), est->qamname, level));
724 size = getsize_wrapper(est->program, est->amname, est->amdevice,
725 level, est->options, est->est[level].dumpsince);
729 if (fseek(stdout, 0L, SEEK_END) < 0) {
730 dbprintf(("wrapper_calc_estimates: warning - seek failed: %s\n",
734 printf("%s %d SIZE " OFF_T_FMT "\n", est->qamname, level,
735 (OFF_T_FMT_TYPE)size);
738 amfunlock(1, "size");
745 generic_calc_estimates(
746 disk_estimates_t * est)
748 int pipefd = -1, nullfd = -1;
750 char *my_argv[DUMP_LEVELS*2+22];
751 char number[NUM_STR_SIZE];
752 int i, level, my_argc, status;
756 char *file_exclude = NULL;
757 char *file_include = NULL;
759 FILE *dumpout = NULL;
760 off_t size = (off_t)1;
764 cmd = vstralloc(libexecdir, "/", "calcsize", versionsuffix(), NULL);
768 my_argv[my_argc++] = stralloc("calcsize");
769 if (g_options->config)
770 my_argv[my_argc++] = stralloc(g_options->config);
772 my_argv[my_argc++] = stralloc("NOCONFIG");
774 my_argv[my_argc++] = stralloc(est->calcprog);
776 my_argv[my_argc++] = stralloc(est->amname);
777 my_argv[my_argc++] = stralloc(est->dirname);
780 if(est->options->exclude_file)
781 nb_exclude += est->options->exclude_file->nb_element;
782 if(est->options->exclude_list)
783 nb_exclude += est->options->exclude_list->nb_element;
784 if(est->options->include_file)
785 nb_include += est->options->include_file->nb_element;
786 if(est->options->include_list)
787 nb_include += est->options->include_list->nb_element;
790 file_exclude = build_exclude(est->amname,
791 est->amdevice, est->options, 0);
793 file_include = build_include(est->amname,
794 est->amdevice, est->options, 0);
797 my_argv[my_argc++] = stralloc("-X");
798 my_argv[my_argc++] = file_exclude;
802 my_argv[my_argc++] = stralloc("-I");
803 my_argv[my_argc++] = file_include;
805 start_time = curclock();
807 dbprintf(("%s: running cmd: %s", debug_prefix_time(NULL), my_argv[0]));
808 for(i=0; i<my_argc; ++i)
809 dbprintf((" %s", my_argv[i]));
811 for(level = 0; level < DUMP_LEVELS; level++) {
812 if(est->est[level].needestimate) {
813 snprintf(number, SIZEOF(number), "%d", level);
814 my_argv[my_argc++] = stralloc(number);
815 dbprintf((" %s", number));
816 snprintf(number, SIZEOF(number),
817 "%ld", (long)est->est[level].dumpsince);
818 my_argv[my_argc++] = stralloc(number);
819 dbprintf((" %s", number));
822 my_argv[my_argc] = NULL;
825 fflush(stderr); fflush(stdout);
827 if ((nullfd = open("/dev/null", O_RDWR)) == -1) {
828 dbprintf(("Cannot access /dev/null : %s\n", strerror(errno)));
832 calcpid = pipespawnv(cmd, STDERR_PIPE, &nullfd, &nullfd, &pipefd, my_argv);
835 dumpout = fdopen(pipefd,"r");
837 error("Can't fdopen: %s", strerror(errno));
840 match_expr = vstralloc(est->qamname," %d SIZE " OFF_T_FMT, NULL);
841 for(size = (off_t)-1; (line = agets(dumpout)) != NULL; free(line)) {
844 if(sscanf(line, match_expr, &level, &size) == 2) {
845 printf("%s\n", line); /* write to amandad */
846 dbprintf(("%s: estimate size for %s level %d: " OFF_T_FMT " KB\n",
855 dbprintf(("%s: waiting for %s %s child (pid=%d)\n",
856 debug_prefix_time(NULL), my_argv[0], est->qamdevice, calcpid));
858 dbprintf(("%s: after %s %s wait: child pid=%d status=%d\n",
859 debug_prefix_time(NULL), my_argv[0], est->qamdevice,
860 calcpid, WEXITSTATUS(status)));
862 dbprintf(("%s: .....\n", debug_prefix_time(NULL)));
863 dbprintf(("%s: estimate time for %s: %s\n",
866 walltime_str(timessub(curclock(), start_time))));
869 for(i = 0; i < my_argc; i++) {
878 disk_estimates_t * est)
883 for(level = 0; level < DUMP_LEVELS; level++) {
884 if(est->est[level].needestimate) {
885 dbprintf(("%s: getting size via dump for %s level %d\n",
886 debug_prefix_time(NULL), est->qamname, level));
887 size = getsize_dump(est->amname, est->amdevice,
888 level, est->options);
892 if (fseek(stdout, 0L, SEEK_END) < 0) {
893 dbprintf(("dump_calc_estimates: warning - seek failed: %s\n",
897 printf("%s %d SIZE " OFF_T_FMT "\n",
898 est->qamname, level, (OFF_T_FMT_TYPE)size);
901 amfunlock(1, "size");
908 smbtar_calc_estimates(
909 disk_estimates_t * est)
914 for(level = 0; level < DUMP_LEVELS; level++) {
915 if(est->est[level].needestimate) {
916 dbprintf(("%s: getting size via smbclient for %s level %d\n",
917 debug_prefix_time(NULL), est->qamname, level));
918 size = getsize_smbtar(est->amname, est->amdevice, level, est->options);
922 if (fseek(stdout, 0L, SEEK_END) < 0) {
923 dbprintf(("smbtar_calc_estimates: warning - seek failed: %s\n",
927 printf("%s %d SIZE " OFF_T_FMT "\n",
928 est->qamname, level, (OFF_T_FMT_TYPE)size);
931 amfunlock(1, "size");
939 gnutar_calc_estimates(
940 disk_estimates_t * est)
945 for(level = 0; level < DUMP_LEVELS; level++) {
946 if (est->est[level].needestimate) {
947 dbprintf(("%s: getting size via gnutar for %s level %d\n",
948 debug_prefix_time(NULL), est->qamname, level));
949 size = getsize_gnutar(est->amname, est->amdevice, level,
950 est->options, est->est[level].dumpsince);
954 if (fseek(stdout, 0L, SEEK_END) < 0) {
955 dbprintf(("gnutar_calc_estimates: warning - seek failed: %s\n",
959 printf("%s %d SIZE " OFF_T_FMT "\n",
960 est->qamname, level, (OFF_T_FMT_TYPE)size);
963 amfunlock(1, "size");
969 typedef struct regex_s {
975 regex_t re_size[] = {
977 {" DUMP: estimated -*[0-9][0-9]* tape blocks", 1024},
978 {" DUMP: [Ee]stimated [0-9][0-9]* blocks", 512},
979 {" DUMP: [Ee]stimated [0-9][0-9]* bytes", 1}, /* Ultrix 4.4 */
980 {" UFSDUMP: estimated [0-9][0-9]* blocks", 512}, /* NEC EWS-UX */
981 {"dump: Estimate: [0-9][0-9]* tape blocks", 1024}, /* OSF/1 */
982 {"backup: There are an estimated [0-9][0-9]* tape blocks.",1024}, /* AIX */
983 {"backup: estimated [0-9][0-9]* 1k blocks", 1024}, /* AIX */
984 {"backup: estimated [0-9][0-9]* tape blocks", 1024}, /* AIX */
985 {"backup: [0-9][0-9]* tape blocks on [0-9][0-9]* tape(s)",1024}, /* AIX */
986 {"backup: [0-9][0-9]* 1k blocks on [0-9][0-9]* volume(s)",1024}, /* AIX */
987 {"dump: Estimate: [0-9][0-9]* blocks being output to pipe",1024},
989 {"dump: Dumping [0-9][0-9]* bytes, ", 1}, /* DU 4.0 vdump */
990 {"DUMP: estimated [0-9][0-9]* KB output", 1024}, /* HPUX */
991 {"DUMP: estimated [0-9][0-9]* KB\\.", 1024}, /* NetApp */
992 {" UFSDUMP: estimated [0-9][0-9]* blocks", 512}, /* Sinix */
994 #ifdef HAVE_DUMP_ESTIMATE
995 {"[0-9][0-9]* blocks, [0-9][0-9]*.[0-9][0-9]* volumes", 1024},
996 /* DU 3.2g dump -E */
997 {"^[0-9][0-9]* blocks$", 1024}, /* DU 4.0 dump -E */
998 {"^[0-9][0-9]*$", 1}, /* Solaris ufsdump -S */
1003 {"vdump: Dumping [0-9][0-9]* bytes, ", 1}, /* OSF/1 vdump */
1007 {"vxdump: estimated [0-9][0-9]* blocks", 512}, /* HPUX's vxdump */
1008 {" VXDUMP: estimated [0-9][0-9]* blocks", 512}, /* Sinix */
1012 {"xfsdump: estimated dump size: [0-9][0-9]* bytes", 1}, /* Irix 6.2 xfs */
1016 {"Total bytes written: [0-9][0-9]*", 1}, /* Gnutar client */
1020 #if SAMBA_VERSION >= 2
1021 #define SAMBA_DEBUG_LEVEL "0"
1022 {"Total number of bytes: [0-9][0-9]*", 1}, /* Samba du */
1024 #define SAMBA_DEBUG_LEVEL "3"
1025 {"Total bytes listed: [0-9][0-9]*", 1}, /* Samba dir */
1040 int pipefd[2], nullfd, stdoutfd, killctl[2];
1044 char *dumpkeys = NULL;
1045 char *device = NULL;
1046 char *fstype = NULL;
1050 char *rundump_cmd = NULL;
1051 char level_str[NUM_STR_SIZE];
1054 char *qdisk = quote_string(disk);
1061 (void)options; /* Quiet unused parameter warning */
1063 (void)getsize_smbtar; /* Quiet unused parameter warning */
1065 snprintf(level_str, SIZEOF(level_str), "%d", level);
1067 device = amname_to_devname(amdevice);
1068 qdevice = quote_string(device);
1069 fstype = amname_to_fstype(amdevice);
1071 dbprintf(("%s: calculating for device %s with %s\n",
1072 debug_prefix_time(NULL), qdevice, fstype));
1074 cmd = vstralloc(libexecdir, "/rundump", versionsuffix(), NULL);
1075 rundump_cmd = stralloc(cmd);
1076 if (g_options->config)
1077 config = g_options->config;
1079 config = "NOCONFIG";
1080 if ((stdoutfd = nullfd = open("/dev/null", O_RDWR)) == -1) {
1081 dbprintf(("getsize_dump could not open /dev/null: %s\n",
1084 amfree(rundump_cmd);
1091 pipefd[0] = pipefd[1] = killctl[0] = killctl[1] = -1;
1092 if (pipe(pipefd) < 0) {
1093 dbprintf(("getsize_dump could create data pipes: %s\n",
1096 amfree(rundump_cmd);
1104 #ifdef XFSDUMP /* { */
1106 if (strcmp(fstype, "xfs") == 0)
1111 name = stralloc(" (xfsdump)");
1112 dbprintf(("%s: running \"%s%s -F -J -l %s - %s\"\n",
1113 debug_prefix_time(NULL), cmd, name, level_str, qdevice));
1117 #ifdef VXDUMP /* { */
1119 if (strcmp(fstype, "vxfs") == 0)
1125 name = stralloc(" (vxdump)");
1127 name = stralloc("");
1128 cmd = newstralloc(cmd, VXDUMP);
1129 config = skip_argument;
1132 dumpkeys = vstralloc(level_str, "s", "f", NULL);
1133 dbprintf(("%s: running \"%s%s %s 1048576 - %s\"\n",
1134 debug_prefix_time(NULL), cmd, name, dumpkeys, qdevice));
1138 #ifdef VDUMP /* { */
1140 if (strcmp(fstype, "advfs") == 0)
1145 name = stralloc(" (vdump)");
1148 device = amname_to_dirname(amdevice);
1149 qdevice = quote_string(device);
1150 dumpkeys = vstralloc(level_str, "b", "f", NULL);
1151 dbprintf(("%s: running \"%s%s %s 60 - %s\"\n",
1152 debug_prefix_time(NULL), cmd, name, dumpkeys, qdevice));
1158 # ifdef USE_RUNDUMP /* { */
1159 # ifdef AIX_BACKUP /* { */
1160 name = stralloc(" (backup)");
1162 name = vstralloc(" (", DUMP, ")", NULL);
1165 name = stralloc("");
1166 cmd = newstralloc(cmd, DUMP);
1167 config = skip_argument;
1171 # ifdef AIX_BACKUP /* { */
1172 dumpkeys = vstralloc("-", level_str, "f", NULL);
1173 dbprintf(("%s: running \"%s%s %s - %s\"\n",
1174 debug_prefix_time(NULL), cmd, name, dumpkeys, qdevice));
1176 dumpkeys = vstralloc(level_str,
1177 # ifdef HAVE_DUMP_ESTIMATE /* { */
1180 # ifdef HAVE_HONOR_NODUMP /* { */
1185 # ifdef HAVE_DUMP_ESTIMATE
1186 stdoutfd = pipefd[1];
1189 # ifdef HAVE_HONOR_NODUMP /* { */
1190 dbprintf(("%s: running \"%s%s %s 0 1048576 - %s\"\n",
1191 debug_prefix_time(NULL), cmd, name, dumpkeys, qdevice));
1193 dbprintf(("%s: running \"%s%s %s 1048576 - %s\"\n",
1194 debug_prefix_time(NULL), cmd, name, dumpkeys, qdevice));
1201 error("no dump program available");
1205 if (pipe(killctl) < 0) {
1206 dbprintf(("%s: Could not create pipe: %s\n",
1207 debug_prefix(NULL), strerror(errno)));
1208 /* Message will be printed later... */
1209 killctl[0] = killctl[1] = -1;
1212 start_time = curclock();
1213 switch(dumppid = fork()) {
1215 dbprintf(("%s: cannot fork for killpgrp: %s\n",
1216 debug_prefix(NULL), strerror(errno)));
1219 amfree(rundump_cmd);
1228 case 0: /* child process */
1231 else if (killctl[0] == -1 || killctl[1] == -1)
1232 dbprintf(("%s: Trying without killpgrp\n", debug_prefix(NULL)));
1236 dbprintf(("%s: fork failed, trying without killpgrp\n",
1237 debug_prefix(NULL)));
1243 char *killpgrp_cmd = vstralloc(libexecdir, "/killpgrp",
1244 versionsuffix(), NULL);
1245 dbprintf(("%s: running %s\n",
1246 debug_prefix_time(NULL), killpgrp_cmd));
1247 dup2(killctl[0], 0);
1254 if (g_options->config)
1255 config = g_options->config;
1257 config = "NOCONFIG";
1258 execle(killpgrp_cmd, killpgrp_cmd, config, (char *)0,
1260 dbprintf(("%s: cannot execute %s: %s\n",
1261 debug_prefix(NULL), killpgrp_cmd, strerror(errno)));
1265 case 0: /* child process */
1274 if (killctl[0] != -1)
1276 if (killctl[1] != -1)
1281 if (strcmp(fstype, "xfs") == 0)
1286 execle(cmd, "rundump", config, "xfsdump", "-F", "-J", "-l",
1287 level_str, "-", device, (char *)0, safe_env());
1289 execle(cmd, "xfsdump", "-F", "-J", "-l",
1290 level_str, "-", device, (char *)0, safe_env());
1295 if (strcmp(fstype, "vxfs") == 0)
1300 execle(cmd, "rundump", config, "vxdump", dumpkeys, "1048576",
1301 "-", device, (char *)0, safe_env());
1303 execle(cmd, "vxdump", dumpkeys, "1048576", "-",
1304 device, (char *)0, safe_env());
1309 if (strcmp(fstype, "advfs") == 0)
1314 execle(cmd, "rundump", config, "vdump", dumpkeys, "60", "-",
1315 device, (char *)0, safe_env());
1317 execle(cmd, "vdump", dumpkeys, "60", "-",
1318 device, (char *)0, safe_env());
1324 execle(cmd, "rundump", config, "backup", dumpkeys, "-",
1325 device, (char *)0, safe_env());
1327 execle(cmd, "backup", dumpkeys, "-",
1328 device, (char *)0, safe_env());
1331 execle(cmd, "rundump", config, "dump", dumpkeys,
1332 #ifdef HAVE_HONOR_NODUMP
1335 "1048576", "-", device, (char *)0, safe_env());
1337 execle(cmd, "dump", dumpkeys,
1338 #ifdef HAVE_HONOR_NODUMP
1341 "1048576", "-", device, (char *)0, safe_env());
1346 error("exec %s failed or no dump program available: %s",
1347 cmd, strerror(errno));
1353 amfree(rundump_cmd);
1356 if (killctl[0] != -1)
1358 dumpout = fdopen(pipefd[0],"r");
1360 error("Can't fdopen: %s", strerror(errno));
1364 for(size = (off_t)-1; (line = agets(dumpout)) != NULL; free(line)) {
1365 if (line[0] == '\0')
1367 dbprintf(("%s: %s\n", debug_prefix_time(NULL), line));
1368 size = handle_dumpline(line);
1369 if(size > (off_t)-1) {
1371 while ((line = agets(dumpout)) != NULL) {
1372 if (line[0] != '\0')
1377 dbprintf(("%s: %s\n", debug_prefix_time(NULL), line));
1384 dbprintf(("%s: .....\n", debug_prefix_time(NULL)));
1385 dbprintf(("%s: estimate time for %s level %d: %s\n",
1389 walltime_str(timessub(curclock(), start_time))));
1390 if(size == (off_t)-1) {
1391 dbprintf(("%s: no size line match in %s%s output for \"%s\"\n",
1392 debug_prefix(NULL), cmd, name, disk));
1393 dbprintf(("%s: .....\n", debug_prefix(NULL)));
1394 dbprintf(("%s: Run %s%s manually to check for errors\n",
1395 debug_prefix(NULL), cmd, name));
1396 } else if(size == (off_t)0 && level == 0) {
1397 dbprintf(("%s: possible %s%s problem -- is \"%s\" really empty?\n",
1398 debug_prefix(NULL), cmd, name, disk));
1399 dbprintf(("%s: .....\n", debug_prefix(NULL)));
1401 dbprintf(("%s: estimate size for %s level %d: %ld KB\n",
1408 if (killctl[1] != -1) {
1409 dbprintf(("%s: asking killpgrp to terminate\n",
1410 debug_prefix_time(NULL)));
1412 for(s = 5; s > 0; --s) {
1414 if (waitpid(dumppid, NULL, WNOHANG) != -1)
1420 * First, try to kill the dump process nicely. If it ignores us
1421 * for several seconds, hit it harder.
1423 dbprintf(("%s: sending SIGTERM to process group %ld\n",
1424 debug_prefix_time(NULL), (long)dumppid));
1425 if (kill(-dumppid, SIGTERM) == -1) {
1426 dbprintf(("%s: kill failed: %s\n",
1427 debug_prefix(NULL), strerror(errno)));
1429 /* Now check whether it dies */
1430 for(s = 5; s > 0; --s) {
1432 if (waitpid(dumppid, NULL, WNOHANG) != -1)
1436 dbprintf(("%s: sending SIGKILL to process group %ld\n",
1437 debug_prefix_time(NULL), (long)dumppid));
1438 if (kill(-dumppid, SIGKILL) == -1) {
1439 dbprintf(("%s: kill failed: %s\n",
1440 debug_prefix(NULL), strerror(errno)));
1442 for(s = 5; s > 0; --s) {
1444 if (waitpid(dumppid, NULL, WNOHANG) != -1)
1448 dbprintf(("%s: waiting for %s%s \"%s\" child\n",
1449 debug_prefix_time(NULL), cmd, name, qdisk));
1451 dbprintf(("%s: after %s%s %s wait\n",
1452 debug_prefix_time(NULL), cmd, name, qdisk));
1478 int pipefd = -1, nullfd = -1, passwdfd = -1;
1482 char *tarkeys, *sharename, *user_and_password = NULL, *domain = NULL;
1483 char *share = NULL, *subdir = NULL;
1490 char *error_pn = NULL;
1491 char *qdisk = quote_string(disk);
1493 (void)options; /* Quiet unused parameter warning */
1495 error_pn = stralloc2(get_pname(), "-smbclient");
1497 parsesharename(amdevice, &share, &subdir);
1501 set_pname(error_pn);
1503 error("cannot parse disk entry %s for share/subdir", qdisk);
1506 if ((subdir) && (SAMBA_VERSION < 2)) {
1509 set_pname(error_pn);
1511 error("subdirectory specified for share %s but samba not v2 or better", qdisk);
1514 if ((user_and_password = findpass(share, &domain)) == NULL) {
1517 memset(domain, '\0', strlen(domain));
1520 set_pname(error_pn);
1522 error("cannot find password for %s", disk);
1525 lpass = strlen(user_and_password);
1526 if ((pwtext = strchr(user_and_password, '%')) == NULL) {
1527 memset(user_and_password, '\0', (size_t)lpass);
1528 amfree(user_and_password);
1530 memset(domain, '\0', strlen(domain));
1533 set_pname(error_pn);
1535 error("password field not \'user%%pass\' for %s", disk);
1539 pwtext_len = strlen(pwtext);
1540 if ((sharename = makesharename(share, 0)) == NULL) {
1541 memset(user_and_password, '\0', (size_t)lpass);
1542 amfree(user_and_password);
1544 memset(domain, '\0', strlen(domain));
1547 set_pname(error_pn);
1549 error("cannot make share name of %s", share);
1552 if ((nullfd = open("/dev/null", O_RDWR)) == -1) {
1553 memset(user_and_password, '\0', (size_t)lpass);
1554 amfree(user_and_password);
1556 memset(domain, '\0', strlen(domain));
1559 set_pname(error_pn);
1562 error("could not open /dev/null: %s\n",
1567 #if SAMBA_VERSION >= 2
1569 tarkeys = "archive 0;recurse;du";
1571 tarkeys = "archive 1;recurse;du";
1574 tarkeys = "archive 0;recurse;dir";
1576 tarkeys = "archive 1;recurse;dir";
1579 start_time = curclock();
1581 if (pwtext_len > 0) {
1582 pw_fd_env = "PASSWD_FD";
1584 pw_fd_env = "dummy_PASSWD_FD";
1586 dumppid = pipespawn(SAMBA_CLIENT, STDERR_PIPE|PASSWD_PIPE,
1587 &nullfd, &nullfd, &pipefd,
1588 pw_fd_env, &passwdfd,
1591 "-d", SAMBA_DEBUG_LEVEL,
1592 *user_and_password ? "-U" : skip_argument,
1593 *user_and_password ? user_and_password : skip_argument,
1595 domain ? "-W" : skip_argument,
1596 domain ? domain : skip_argument,
1597 #if SAMBA_VERSION >= 2
1598 subdir ? "-D" : skip_argument,
1599 subdir ? subdir : skip_argument,
1604 memset(domain, '\0', strlen(domain));
1608 if(pwtext_len > 0 && fullwrite(passwdfd, pwtext, (size_t)pwtext_len) < 0) {
1609 int save_errno = errno;
1611 memset(user_and_password, '\0', (size_t)lpass);
1612 amfree(user_and_password);
1614 set_pname(error_pn);
1616 error("password write failed: %s", strerror(save_errno));
1619 memset(user_and_password, '\0', (size_t)lpass);
1620 amfree(user_and_password);
1626 dumpout = fdopen(pipefd,"r");
1628 error("Can't fdopen: %s", strerror(errno));
1632 for(size = (off_t)-1; (line = agets(dumpout)) != NULL; free(line)) {
1633 if (line[0] == '\0')
1635 dbprintf(("%s: %s\n", debug_prefix_time(NULL), line));
1636 size = handle_dumpline(line);
1639 while ((line = agets(dumpout)) != NULL) {
1640 if (line[0] != '\0')
1645 dbprintf(("%s: %s\n", debug_prefix_time(NULL), line));
1652 dbprintf(("%s: .....\n", debug_prefix_time(NULL)));
1653 dbprintf(("%s: estimate time for %s level %d: %s\n",
1657 walltime_str(timessub(curclock(), start_time))));
1658 if(size == (off_t)-1) {
1659 dbprintf(("%s: no size line match in %s output for \"%s\"\n",
1660 debug_prefix(NULL), SAMBA_CLIENT, disk));
1661 dbprintf(("%s: .....\n", debug_prefix(NULL)));
1662 } else if(size == (off_t)0 && level == 0) {
1663 dbprintf(("%s: possible %s problem -- is \"%s\" really empty?\n",
1664 debug_prefix(NULL), SAMBA_CLIENT, disk));
1665 dbprintf(("%s: .....\n", debug_prefix(NULL)));
1667 dbprintf(("%s: estimate size for %s level %d: %ld KB\n",
1673 kill(-dumppid, SIGTERM);
1675 dbprintf(("%s: waiting for %s \"%s\" child\n",
1676 debug_prefix_time(NULL), SAMBA_CLIENT, qdisk));
1678 dbprintf(("%s: after %s %s wait\n",
1679 debug_prefix_time(NULL), SAMBA_CLIENT, qdisk));
1700 int pipefd = -1, nullfd = -1;
1702 off_t size = (off_t)-1;
1703 FILE *dumpout = NULL;
1704 char *incrname = NULL;
1705 char *basename = NULL;
1706 char *dirname = NULL;
1707 char *inputname = NULL;
1712 char dumptimestr[80];
1718 char *file_exclude = NULL;
1719 char *file_include = NULL;
1724 char *qdisk = quote_string(disk);
1725 char *gnutar_list_dir;
1727 if(options->exclude_file) nb_exclude += options->exclude_file->nb_element;
1728 if(options->exclude_list) nb_exclude += options->exclude_list->nb_element;
1729 if(options->include_file) nb_include += options->include_file->nb_element;
1730 if(options->include_list) nb_include += options->include_list->nb_element;
1732 if(nb_exclude > 0) file_exclude = build_exclude(disk, amdevice, options, 0);
1733 if(nb_include > 0) file_include = build_include(disk, amdevice, options, 0);
1735 my_argv = alloc(SIZEOF(char *) * 22);
1738 gnutar_list_dir = client_getconf_str(CLN_GNUTAR_LIST_DIR);
1739 if (strlen(gnutar_list_dir) == 0)
1740 gnutar_list_dir = NULL;
1741 if (gnutar_list_dir) {
1742 char number[NUM_STR_SIZE];
1747 basename = vstralloc(gnutar_list_dir,
1749 g_options->hostname,
1753 * The loop starts at the first character of the host name,
1756 s = basename + strlen(gnutar_list_dir) + 1;
1757 while((ch = *s++) != '\0') {
1758 if(ch == '/' || isspace(ch)) s[-1] = '_';
1761 snprintf(number, SIZEOF(number), "%d", level);
1762 incrname = vstralloc(basename, "_", number, ".new", NULL);
1766 * Open the listed incremental file from the previous level. Search
1767 * backward until one is found. If none are found (which will also
1768 * be true for a level 0), arrange to read from /dev/null.
1772 while (infd == -1) {
1773 if (--baselevel >= 0) {
1774 snprintf(number, SIZEOF(number), "%d", baselevel);
1775 inputname = newvstralloc(inputname,
1776 basename, "_", number, NULL);
1778 inputname = newstralloc(inputname, "/dev/null");
1780 if ((infd = open(inputname, O_RDONLY)) == -1) {
1781 int save_errno = errno;
1783 dbprintf(("%s: gnutar: error opening %s: %s\n",
1784 debug_prefix(NULL), inputname, strerror(save_errno)));
1785 if (baselevel < 0) {
1792 * Copy the previous listed incremental file to the new one.
1794 if ((outfd = open(incrname, O_WRONLY|O_CREAT, 0600)) == -1) {
1795 dbprintf(("%s: opening %s: %s\n",
1796 debug_prefix(NULL), incrname, strerror(errno)));
1800 while ((nb = read(infd, &buf, SIZEOF(buf))) > 0) {
1801 if (fullwrite(outfd, &buf, (size_t)nb) < nb) {
1802 dbprintf(("%s: writing to %s: %s\n",
1803 debug_prefix(NULL), incrname, strerror(errno)));
1809 dbprintf(("%s: reading from %s: %s\n",
1810 debug_prefix(NULL), inputname, strerror(errno)));
1814 if (close(infd) != 0) {
1815 dbprintf(("%s: closing %s: %s\n",
1816 debug_prefix(NULL), inputname, strerror(errno)));
1819 if (close(outfd) != 0) {
1820 dbprintf(("%s: closing %s: %s\n",
1821 debug_prefix(NULL), incrname, strerror(errno)));
1829 gmtm = gmtime(&dumpsince);
1830 snprintf(dumptimestr, SIZEOF(dumptimestr),
1831 "%04d-%02d-%02d %2d:%02d:%02d GMT",
1832 gmtm->tm_year + 1900, gmtm->tm_mon+1, gmtm->tm_mday,
1833 gmtm->tm_hour, gmtm->tm_min, gmtm->tm_sec);
1835 dirname = amname_to_dirname(amdevice);
1837 cmd = vstralloc(libexecdir, "/", "runtar", versionsuffix(), NULL);
1838 my_argv[i++] = "runtar";
1839 if (g_options->config)
1840 my_argv[i++] = g_options->config;
1842 my_argv[i++] = "NOCONFIG";
1845 my_argv[i++] = GNUTAR;
1847 my_argv[i++] = "tar";
1849 my_argv[i++] = "--create";
1850 my_argv[i++] = "--file";
1851 my_argv[i++] = "/dev/null";
1852 my_argv[i++] = "--directory";
1853 my_argv[i++] = dirname;
1854 my_argv[i++] = "--one-file-system";
1855 if (gnutar_list_dir) {
1856 my_argv[i++] = "--listed-incremental";
1857 my_argv[i++] = incrname;
1859 my_argv[i++] = "--incremental";
1860 my_argv[i++] = "--newer";
1861 my_argv[i++] = dumptimestr;
1863 #ifdef ENABLE_GNUTAR_ATIME_PRESERVE
1864 /* --atime-preserve causes gnutar to call
1865 * utime() after reading files in order to
1866 * adjust their atime. However, utime()
1867 * updates the file's ctime, so incremental
1868 * dumps will think the file has changed. */
1869 my_argv[i++] = "--atime-preserve";
1871 my_argv[i++] = "--sparse";
1872 my_argv[i++] = "--ignore-failed-read";
1873 my_argv[i++] = "--totals";
1876 my_argv[i++] = "--exclude-from";
1877 my_argv[i++] = file_exclude;
1881 my_argv[i++] = "--files-from";
1882 my_argv[i++] = file_include;
1887 my_argv[i++] = NULL;
1889 start_time = curclock();
1891 if ((nullfd = open("/dev/null", O_RDWR)) == -1) {
1892 dbprintf(("Cannot access /dev/null : %s\n", strerror(errno)));
1896 dumppid = pipespawnv(cmd, STDERR_PIPE, &nullfd, &nullfd, &pipefd, my_argv);
1898 dumpout = fdopen(pipefd,"r");
1900 error("Can't fdopen: %s", strerror(errno));
1904 for(size = (off_t)-1; (line = agets(dumpout)) != NULL; free(line)) {
1905 if (line[0] == '\0')
1907 dbprintf(("%s: %s\n", debug_prefix_time(NULL), line));
1908 size = handle_dumpline(line);
1909 if(size > (off_t)-1) {
1911 while ((line = agets(dumpout)) != NULL) {
1912 if (line[0] != '\0') {
1918 dbprintf(("%s: %s\n", debug_prefix_time(NULL), line));
1926 dbprintf(("%s: .....\n", debug_prefix_time(NULL)));
1927 dbprintf(("%s: estimate time for %s level %d: %s\n",
1931 walltime_str(timessub(curclock(), start_time))));
1932 if(size == (off_t)-1) {
1933 dbprintf(("%s: no size line match in %s output for \"%s\"\n",
1934 debug_prefix(NULL), my_argv[0], disk));
1935 dbprintf(("%s: .....\n", debug_prefix(NULL)));
1936 } else if(size == (off_t)0 && level == 0) {
1937 dbprintf(("%s: possible %s problem -- is \"%s\" really empty?\n",
1938 debug_prefix(NULL), my_argv[0], disk));
1939 dbprintf(("%s: .....\n", debug_prefix(NULL)));
1941 dbprintf(("%s: estimate size for %s level %d: %ld KB\n",
1947 kill(-dumppid, SIGTERM);
1949 dbprintf(("%s: waiting for %s \"%s\" child\n",
1950 debug_prefix_time(NULL), my_argv[0], qdisk));
1952 dbprintf(("%s: after %s %s wait\n",
1953 debug_prefix_time(NULL), my_argv[0], qdisk));
1967 amfree(file_exclude);
1968 amfree(file_include);
1988 int pipefd[2], nullfd;
1990 off_t size = (off_t)-1;
1994 char dumptimestr[80];
1997 char *argvchild[10];
1998 char *newoptstr = NULL;
2001 char *qdisk = quote_string(disk);
2002 char *qamdevice = quote_string(amdevice);
2004 gmtm = gmtime(&dumpsince);
2005 snprintf(dumptimestr, SIZEOF(dumptimestr),
2006 "%04d-%02d-%02d %2d:%02d:%02d GMT",
2007 gmtm->tm_year + 1900, gmtm->tm_mon+1, gmtm->tm_mday,
2008 gmtm->tm_hour, gmtm->tm_min, gmtm->tm_sec);
2010 cmd = vstralloc(DUMPER_DIR, "/", program, NULL);
2013 argvchild[i++] = program;
2014 argvchild[i++] = "estimate";
2016 argvchild[i++] = "full";
2018 char levelstr[NUM_STR_SIZE];
2019 snprintf(levelstr,SIZEOF(levelstr),"%d",level);
2020 argvchild[i++] = "level";
2021 argvchild[i++] = levelstr;
2023 argvchild[i++] = amdevice;
2024 newoptstr = vstralloc(options->str,"estimate-direct;", NULL);
2025 argvchild[i++] = newoptstr;
2026 argvchild[i] = NULL;
2028 dbprintf(("%s: running %s", debug_prefix_time(NULL), cmd));
2029 for(j = 1; j < i; j++) {
2030 dbprintf((" %s", argvchild[j]));
2034 if ((nullfd = open("/dev/null", O_RDWR)) == -1) {
2035 dbprintf(("Cannot access /dev/null : %s\n", strerror(errno)));
2039 if (pipe(pipefd) < 0) {
2040 dbprintf(("getsize_wrapper could create data pipes: %s\n",
2045 start_time = curclock();
2047 switch(dumppid = fork()) {
2059 execve(cmd, argvchild, safe_env());
2060 error("exec %s failed: %s", cmd, strerror(errno));
2066 dumpout = fdopen(pipefd[0],"r");
2068 error("Can't fdopen: %s", strerror(errno));
2072 for(size = (off_t)-1; (line = agets(dumpout)) != NULL; free(line)) {
2073 if (line[0] == '\0')
2075 dbprintf(("%s: %s\n", debug_prefix_time(NULL), line));
2076 i = sscanf(line, OFF_T_FMT " " OFF_T_FMT,
2077 (OFF_T_FMT_TYPE *)&size1,
2078 (OFF_T_FMT_TYPE *)&size2);
2080 size = size1 * size2;
2084 while ((line = agets(dumpout)) != NULL) {
2085 if (line[0] != '\0')
2090 dbprintf(("%s: %s\n", debug_prefix_time(NULL), line));
2097 dbprintf(("%s: .....\n", debug_prefix_time(NULL)));
2098 dbprintf(("%s: estimate time for %s level %d: %s\n",
2102 walltime_str(timessub(curclock(), start_time))));
2103 if(size == (off_t)-1) {
2104 dbprintf(("%s: no size line match in %s output for \"%s\"\n",
2105 debug_prefix(NULL), cmd, qdisk));
2106 dbprintf(("%s: .....\n", debug_prefix(NULL)));
2107 } else if(size == (off_t)0 && level == 0) {
2108 dbprintf(("%s: possible %s problem -- is \"%s\" really empty?\n",
2109 debug_prefix(NULL), cmd, qdisk));
2110 dbprintf(("%s: .....\n", debug_prefix(NULL)));
2112 dbprintf(("%s: estimate size for %s level %d: " OFF_T_FMT " KB\n",
2118 kill(-dumppid, SIGTERM);
2120 dbprintf(("%s: waiting for %s \"%s\" child\n",
2121 debug_prefix_time(NULL), cmd, qdisk));
2123 dbprintf(("%s: after %s %s wait\n",
2124 debug_prefix_time(NULL), cmd, qdisk));
2140 * Returns the value of the first integer in a string.
2152 while(ch && !isdigit(ch)) ch = *str++;
2154 while(isdigit(ch) || (ch == '.')) ch = *str++;
2163 * Checks the dump output line against the error and size regex tables.
2173 /* check for size match */
2175 for(rp = re_size; rp->regex != NULL; rp++) {
2176 if(match(rp->regex, str)) {
2177 size = ((first_num(str)*rp->scale+1023.0)/1024.0);
2179 size = 1.0; /* found on NeXT -- sigh */