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.4 2006/12/22 14:42:42 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 int amandates_read = 0;
144 #if defined(USE_DBMALLOC)
145 unsigned long malloc_hist_1, malloc_size_1;
146 unsigned long malloc_hist_2, malloc_size_2;
149 (void)argc; /* Quiet unused parameter warning */
150 (void)argv; /* Quiet unused parameter warning */
157 set_pname("sendsize");
159 /* Don't die when child closes pipe */
160 signal(SIGPIPE, SIG_IGN);
162 #if defined(USE_DBMALLOC)
163 malloc_size_1 = malloc_inuse(&malloc_hist_1);
166 erroutput_type = (ERR_INTERACTIVE|ERR_SYSLOG);
167 dbopen(DBG_SUBDIR_CLIENT);
169 dbprintf(("%s: version %s\n", get_pname(), version()));
171 our_features = am_init_feature_set();
172 our_feature_string = am_feature_to_string(our_features);
174 set_debug_prefix_pid(getpid());
176 conffile = vstralloc(CONFIG_DIR, "/", "amanda-client.conf", NULL);
177 if (read_clientconf(conffile) > 0) {
178 error("error reading conffile: %s", conffile);
183 /* handle all service requests */
185 for(; (line = agets(stdin)) != NULL; free(line)) {
188 #define sc "OPTIONS "
189 if(strncmp(line, sc, SIZEOF(sc)-1) == 0) {
191 g_options = parse_g_options(line+8, 1);
192 if(!g_options->hostname) {
193 g_options->hostname = alloc(MAX_HOSTNAME_LENGTH+1);
194 gethostname(g_options->hostname, MAX_HOSTNAME_LENGTH);
195 g_options->hostname[MAX_HOSTNAME_LENGTH] = '\0';
199 if(am_has_feature(g_options->features, fe_rep_options_features)) {
200 printf("features=%s;", our_feature_string);
202 if(am_has_feature(g_options->features, fe_rep_options_maxdumps)) {
203 printf("maxdumps=%d;", g_options->maxdumps);
205 if(am_has_feature(g_options->features, fe_rep_options_hostname)) {
206 printf("hostname=%s;", g_options->hostname);
211 if (g_options->config) {
212 conffile = vstralloc(CONFIG_DIR, "/", g_options->config, "/",
213 "amanda-client.conf", NULL);
214 if (read_clientconf(conffile) > 0) {
215 error("error reading conffile: %s", conffile);
220 dbrename(g_options->config, DBG_SUBDIR_CLIENT);
226 if (amandates_read == 0) {
227 amandates_file = client_getconf_str(CLN_AMANDATES);
228 if(!start_amandates(amandates_file, 0))
229 error("error [opening %s: %s]", amandates_file,
237 skip_whitespace(s, ch); /* find the program name */
239 err_extra = stralloc("no program name");
240 goto err; /* no program name */
243 skip_non_whitespace(s, ch);
246 program_is_wrapper=0;
247 if(strcmp(prog,"DUMPER")==0) {
248 program_is_wrapper=1;
249 skip_whitespace(s, ch); /* find dumper name */
251 goto err; /* no program */
254 skip_non_whitespace(s, ch);
258 if(strncmp(prog, "CALCSIZE", 8) == 0) {
259 skip_whitespace(s, ch); /* find the program name */
261 err_extra = stralloc("no program name");
265 skip_non_whitespace(s, ch);
272 skip_whitespace(s, ch); /* find the disk name */
274 err_extra = stralloc("no disk name");
275 goto err; /* no disk name */
284 skip_quoted_string(s, ch);
285 s[-1] = '\0'; /* terminate the disk name */
286 qdisk = stralloc(fp);
287 disk = unquote_string(qdisk);
289 skip_whitespace(s, ch); /* find the device or level */
291 err_extra = stralloc("bad level");
294 if(!isdigit((int)s[-1])) {
296 skip_quoted_string(s, ch);
298 qamdevice = stralloc(fp);
299 amdevice = unquote_string(qamdevice);
300 skip_whitespace(s, ch); /* find level number */
303 amdevice = stralloc(disk);
304 qamdevice = stralloc(qdisk);
307 /* find the level number */
308 if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
309 err_extra = stralloc("bad level");
310 goto err; /* bad level */
312 if (level < 0 || level >= DUMP_LEVELS) {
313 err_extra = stralloc("bad level");
318 skip_whitespace(s, ch); /* find the dump date */
320 err_extra = stralloc("no dumpdate");
321 goto err; /* no dumpdate */
324 skip_non_whitespace(s, ch);
326 (void)dumpdate; /* XXX: Set but not used */
328 spindle = 0; /* default spindle */
330 skip_whitespace(s, ch); /* find the spindle */
332 if(sscanf(s - 1, "%d", &spindle) != 1) {
333 err_extra = stralloc("bad spindle");
334 goto err; /* bad spindle */
338 skip_whitespace(s, ch); /* find the parameters */
340 if(strncmp(s-1, "OPTIONS |;",10) == 0) {
341 options = parse_options(s + 8,
348 options = alloc(SIZEOF(option_t));
349 init_options(options);
351 if(strncmp(s-1, "exclude-file=", 13) == 0) {
352 qlist = unquote_string(s+12);
353 options->exclude_file =
354 append_sl(options->exclude_file, qlist);
356 } else if(strncmp(s-1, "exclude-list=", 13) == 0) {
357 options->exclude_list =
358 append_sl(options->exclude_list, qlist);
359 qlist = unquote_string(s+12);
361 } else if(strncmp(s-1, "include-file=", 13) == 0) {
362 options->include_file =
363 append_sl(options->include_file, qlist);
364 qlist = unquote_string(s+12);
366 } else if(strncmp(s-1, "include-list=", 13) == 0) {
367 options->include_list =
368 append_sl(options->include_list, qlist);
369 qlist = unquote_string(s+12);
372 err_extra = vstralloc("Invalid parameter (",
374 goto err; /* should have gotten to end */
376 skip_quoted_string(s, ch);
377 skip_whitespace(s, ch); /* find the inclusion list */
383 options = alloc(SIZEOF(option_t));
384 init_options(options);
388 options = alloc(SIZEOF(option_t));
389 init_options(options);
393 add_diskest(disk, amdevice, level, spindle, program_is_wrapper, prog, calcprog, options);
400 if (g_options == NULL) {
401 error("Missing OPTIONS line in sendsize input\n");
415 * See if we need to wait for a child before we can do anything
420 amwait_t child_status;
424 dbprintf(("%s: waiting for any estimate child: %d running\n",
425 debug_prefix_time(NULL), dumpsrunning));
426 child_pid = wait(&child_status);
427 if(child_pid == -1) {
428 error("wait failed: %s", strerror(errno));
431 if(WIFSIGNALED(child_status)) {
432 dbprintf(("%s: child %ld terminated with signal %d\n",
433 debug_prefix_time(NULL),
434 (long) child_pid, WTERMSIG(child_status)));
436 exit_code = WEXITSTATUS(child_status);
438 dbprintf(("%s: child %ld terminated normally\n",
439 debug_prefix_time(NULL), (long) child_pid));
441 dbprintf(("%s: child %ld terminated with code %d\n",
442 debug_prefix_time(NULL),
443 (long) child_pid, exit_code));
447 * Find the child and mark it done.
449 for(est = est_list; est != NULL; est = est->next) {
450 if(est->child == child_pid) {
455 dbprintf(("%s: unexpected child %ld\n",
456 debug_prefix_time(NULL), (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 set_debug_prefix_pid(getpid());
512 calc_estimates(est); /* child does the estimate */
514 } else if(est->child == -1) {
515 error("calc_estimates fork failed: %s", strerror(errno));
518 dumpsrunning++; /* parent */
523 for(est = est_list; est != NULL; est = est->next) {
529 amfree(our_feature_string);
530 am_release_feature_set(our_features);
532 am_release_feature_set(g_options->features);
533 g_options->features = NULL;
534 amfree(g_options->hostname);
535 amfree(g_options->str);
538 #if defined(USE_DBMALLOC)
539 malloc_size_2 = malloc_inuse(&malloc_hist_2);
541 if(malloc_size_1 != malloc_size_2) {
542 malloc_list(dbfd(), malloc_hist_1, malloc_hist_2);
549 printf("FORMAT ERROR IN REQUEST PACKET\n");
550 dbprintf(("%s: REQ packet is bogus%s%s\n",
551 debug_prefix_time(NULL),
552 err_extra ? ": " : "",
553 err_extra ? err_extra : ""));
566 int program_is_wrapper,
571 disk_estimates_t *newp, *curp;
578 if (level >= DUMP_LEVELS)
579 level = DUMP_LEVELS - 1;
581 for(curp = est_list; curp != NULL; curp = curp->next) {
582 if(strcmp(curp->amname, disk) == 0) {
583 /* already have disk info, just note the level request */
584 curp->est[level].needestimate = 1;
586 free_sl(options->exclude_file);
587 free_sl(options->exclude_list);
588 free_sl(options->include_file);
589 free_sl(options->include_list);
590 amfree(options->auth);
591 amfree(options->str);
598 newp = (disk_estimates_t *) alloc(SIZEOF(disk_estimates_t));
599 memset(newp, 0, SIZEOF(*newp));
600 newp->next = est_list;
602 newp->amname = stralloc(disk);
603 newp->qamname = quote_string(disk);
604 newp->amdevice = stralloc(amdevice);
605 newp->qamdevice = quote_string(amdevice);
606 newp->dirname = amname_to_dirname(newp->amdevice);
607 newp->qdirname = quote_string(newp->dirname);
608 newp->program = stralloc(prog);
610 newp->calcprog = stralloc(calcprog);
612 newp->calcprog = NULL;
613 newp->program_is_wrapper = program_is_wrapper;
614 newp->spindle = spindle;
615 newp->est[level].needestimate = 1;
616 newp->options = options;
618 /* fill in dump-since dates */
620 amdp = amandates_lookup(newp->amname);
622 newp->est[0].dumpsince = EPOCH;
623 for(dumplev = 0; dumplev < DUMP_LEVELS; dumplev++) {
624 dumpdate = amdp->dates[dumplev];
625 for(estlev = dumplev+1; estlev < DUMP_LEVELS; estlev++) {
626 if(dumpdate > newp->est[estlev].dumpsince)
627 newp->est[estlev].dumpsince = dumpdate;
635 disk_estimates_t * est)
638 amfree(est->qamname);
639 amfree(est->amdevice);
640 amfree(est->qamdevice);
641 amfree(est->dirname);
642 amfree(est->qdirname);
643 amfree(est->program);
645 free_sl(est->options->exclude_file);
646 free_sl(est->options->exclude_list);
647 free_sl(est->options->include_file);
648 free_sl(est->options->include_list);
649 amfree(est->options->str);
650 amfree(est->options->auth);
651 amfree(est->options);
656 * ------------------------------------------------------------------------
662 disk_estimates_t * est)
664 dbprintf(("%s: calculating for amname %s, dirname %s, spindle %d\n",
665 debug_prefix_time(NULL),
666 est->qamname, est->qdirname, est->spindle));
668 if(est->program_is_wrapper == 1)
669 wrapper_calc_estimates(est);
671 #ifndef USE_GENERIC_CALCSIZE
672 if(strcmp(est->program, "DUMP") == 0)
673 dump_calc_estimates(est);
677 if (strcmp(est->program, "GNUTAR") == 0 &&
678 est->amdevice[0] == '/' && est->amdevice[1] == '/')
679 smbtar_calc_estimates(est);
683 if (strcmp(est->program, "GNUTAR") == 0)
684 gnutar_calc_estimates(est);
688 if (est->amdevice[0] == '/' && est->amdevice[1] == '/')
689 dbprintf(("%s: Can't use CALCSIZE for samba estimate: %s %s\n",
690 debug_prefix_time(NULL),
691 est->qamname, est->qdirname));
694 generic_calc_estimates(est);
696 dbprintf(("%s: done with amname %s dirname %s spindle %d\n",
697 debug_prefix_time(NULL),
698 est->qamname, est->qdirname, est->spindle));
702 * ------------------------------------------------------------------------
706 /* local functions */
707 off_t getsize_dump(char *disk, char *amdevice, int level, option_t *options);
708 off_t getsize_star(char *disk, char *amdevice, int level,
709 option_t *options, time_t dumpsince);
710 off_t getsize_smbtar(char *disk, char *amdevice, int level, option_t *options);
711 off_t getsize_gnutar(char *disk, char *amdevice, int level,
712 option_t *options, time_t dumpsince);
713 off_t getsize_wrapper(char *program, char *disk, char *amdevice, int level,
714 option_t *options, time_t dumpsince);
715 off_t handle_dumpline(char *str);
716 double first_num(char *str);
719 wrapper_calc_estimates(
720 disk_estimates_t * est)
725 for(level = 0; level < DUMP_LEVELS; level++) {
726 if (est->est[level].needestimate) {
727 dbprintf(("%s: getting size via wrapper for %s level %d\n",
728 debug_prefix_time(NULL), est->qamname, level));
729 size = getsize_wrapper(est->program, est->amname, est->amdevice,
730 level, est->options, est->est[level].dumpsince);
734 if (fseek(stdout, 0L, SEEK_END) < 0) {
735 dbprintf(("wrapper_calc_estimates: warning - seek failed: %s\n",
739 printf("%s %d SIZE " OFF_T_FMT "\n", est->qamname, level,
740 (OFF_T_FMT_TYPE)size);
743 amfunlock(1, "size");
750 generic_calc_estimates(
751 disk_estimates_t * est)
753 int pipefd = -1, nullfd = -1;
755 char *my_argv[DUMP_LEVELS*2+22];
756 char number[NUM_STR_SIZE];
757 int i, level, my_argc, status;
761 char *file_exclude = NULL;
762 char *file_include = NULL;
764 FILE *dumpout = NULL;
765 off_t size = (off_t)1;
769 cmd = vstralloc(libexecdir, "/", "calcsize", versionsuffix(), NULL);
773 my_argv[my_argc++] = stralloc("calcsize");
774 if (g_options->config)
775 my_argv[my_argc++] = stralloc(g_options->config);
777 my_argv[my_argc++] = stralloc("NOCONFIG");
779 my_argv[my_argc++] = stralloc(est->calcprog);
781 my_argv[my_argc++] = stralloc(est->amname);
782 my_argv[my_argc++] = stralloc(est->dirname);
785 if(est->options->exclude_file)
786 nb_exclude += est->options->exclude_file->nb_element;
787 if(est->options->exclude_list)
788 nb_exclude += est->options->exclude_list->nb_element;
789 if(est->options->include_file)
790 nb_include += est->options->include_file->nb_element;
791 if(est->options->include_list)
792 nb_include += est->options->include_list->nb_element;
795 file_exclude = build_exclude(est->amname,
796 est->amdevice, est->options, 0);
798 file_include = build_include(est->amname,
799 est->amdevice, est->options, 0);
802 my_argv[my_argc++] = stralloc("-X");
803 my_argv[my_argc++] = file_exclude;
807 my_argv[my_argc++] = stralloc("-I");
808 my_argv[my_argc++] = file_include;
810 start_time = curclock();
812 dbprintf(("%s: running cmd: %s", debug_prefix_time(NULL), my_argv[0]));
813 for(i=0; i<my_argc; ++i)
814 dbprintf((" %s", my_argv[i]));
816 for(level = 0; level < DUMP_LEVELS; level++) {
817 if(est->est[level].needestimate) {
818 snprintf(number, SIZEOF(number), "%d", level);
819 my_argv[my_argc++] = stralloc(number);
820 dbprintf((" %s", number));
821 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 dbprintf(("Cannot access /dev/null : %s\n", strerror(errno)));
837 calcpid = pipespawnv(cmd, STDERR_PIPE, &nullfd, &nullfd, &pipefd, my_argv);
840 dumpout = fdopen(pipefd,"r");
842 error("Can't fdopen: %s", strerror(errno));
845 match_expr = vstralloc(est->qamname," %d SIZE " OFF_T_FMT, NULL);
846 for(size = (off_t)-1; (line = agets(dumpout)) != NULL; free(line)) {
849 if(sscanf(line, match_expr, &level, &size) == 2) {
850 printf("%s\n", line); /* write to amandad */
851 dbprintf(("%s: estimate size for %s level %d: " OFF_T_FMT " KB\n",
860 dbprintf(("%s: waiting for %s %s child (pid=%d)\n",
861 debug_prefix_time(NULL), my_argv[0], est->qamdevice, calcpid));
863 dbprintf(("%s: after %s %s wait: child pid=%d status=%d\n",
864 debug_prefix_time(NULL), my_argv[0], est->qamdevice,
865 calcpid, WEXITSTATUS(status)));
867 dbprintf(("%s: .....\n", debug_prefix_time(NULL)));
868 dbprintf(("%s: estimate time for %s: %s\n",
871 walltime_str(timessub(curclock(), start_time))));
874 for(i = 0; i < my_argc; i++) {
883 disk_estimates_t * est)
888 for(level = 0; level < DUMP_LEVELS; level++) {
889 if(est->est[level].needestimate) {
890 dbprintf(("%s: getting size via dump for %s level %d\n",
891 debug_prefix_time(NULL), est->qamname, level));
892 size = getsize_dump(est->amname, est->amdevice,
893 level, est->options);
897 if (fseek(stdout, 0L, SEEK_END) < 0) {
898 dbprintf(("dump_calc_estimates: warning - seek failed: %s\n",
902 printf("%s %d SIZE " OFF_T_FMT "\n",
903 est->qamname, level, (OFF_T_FMT_TYPE)size);
906 amfunlock(1, "size");
913 smbtar_calc_estimates(
914 disk_estimates_t * est)
919 for(level = 0; level < DUMP_LEVELS; level++) {
920 if(est->est[level].needestimate) {
921 dbprintf(("%s: getting size via smbclient for %s level %d\n",
922 debug_prefix_time(NULL), est->qamname, level));
923 size = getsize_smbtar(est->amname, est->amdevice, level, est->options);
927 if (fseek(stdout, 0L, SEEK_END) < 0) {
928 dbprintf(("smbtar_calc_estimates: warning - seek failed: %s\n",
932 printf("%s %d SIZE " OFF_T_FMT "\n",
933 est->qamname, level, (OFF_T_FMT_TYPE)size);
936 amfunlock(1, "size");
944 gnutar_calc_estimates(
945 disk_estimates_t * est)
950 for(level = 0; level < DUMP_LEVELS; level++) {
951 if (est->est[level].needestimate) {
952 dbprintf(("%s: getting size via gnutar for %s level %d\n",
953 debug_prefix_time(NULL), est->qamname, level));
954 size = getsize_gnutar(est->amname, est->amdevice, level,
955 est->options, est->est[level].dumpsince);
959 if (fseek(stdout, 0L, SEEK_END) < 0) {
960 dbprintf(("gnutar_calc_estimates: warning - seek failed: %s\n",
964 printf("%s %d SIZE " OFF_T_FMT "\n",
965 est->qamname, level, (OFF_T_FMT_TYPE)size);
968 amfunlock(1, "size");
974 typedef struct regex_s {
980 regex_t re_size[] = {
982 {" DUMP: estimated -*[0-9][0-9]* tape blocks", 1024},
983 {" DUMP: [Ee]stimated [0-9][0-9]* blocks", 512},
984 {" DUMP: [Ee]stimated [0-9][0-9]* bytes", 1}, /* Ultrix 4.4 */
985 {" UFSDUMP: estimated [0-9][0-9]* blocks", 512}, /* NEC EWS-UX */
986 {"dump: Estimate: [0-9][0-9]* tape blocks", 1024}, /* OSF/1 */
987 {"backup: There are an estimated [0-9][0-9]* tape blocks.",1024}, /* AIX */
988 {"backup: estimated [0-9][0-9]* 1k blocks", 1024}, /* AIX */
989 {"backup: estimated [0-9][0-9]* tape blocks", 1024}, /* AIX */
990 {"backup: [0-9][0-9]* tape blocks on [0-9][0-9]* tape(s)",1024}, /* AIX */
991 {"backup: [0-9][0-9]* 1k blocks on [0-9][0-9]* volume(s)",1024}, /* AIX */
992 {"dump: Estimate: [0-9][0-9]* blocks being output to pipe",1024},
994 {"dump: Dumping [0-9][0-9]* bytes, ", 1}, /* DU 4.0 vdump */
995 {"DUMP: estimated [0-9][0-9]* KB output", 1024}, /* HPUX */
996 {"DUMP: estimated [0-9][0-9]* KB\\.", 1024}, /* NetApp */
997 {" UFSDUMP: estimated [0-9][0-9]* blocks", 512}, /* Sinix */
999 #ifdef HAVE_DUMP_ESTIMATE
1000 {"[0-9][0-9]* blocks, [0-9][0-9]*.[0-9][0-9]* volumes", 1024},
1001 /* DU 3.2g dump -E */
1002 {"^[0-9][0-9]* blocks$", 1024}, /* DU 4.0 dump -E */
1003 {"^[0-9][0-9]*$", 1}, /* Solaris ufsdump -S */
1008 {"vdump: Dumping [0-9][0-9]* bytes, ", 1}, /* OSF/1 vdump */
1012 {"vxdump: estimated [0-9][0-9]* blocks", 512}, /* HPUX's vxdump */
1013 {" VXDUMP: estimated [0-9][0-9]* blocks", 512}, /* Sinix */
1017 {"xfsdump: estimated dump size: [0-9][0-9]* bytes", 1}, /* Irix 6.2 xfs */
1021 {"Total bytes written: [0-9][0-9]*", 1}, /* Gnutar client */
1025 #if SAMBA_VERSION >= 2
1026 #define SAMBA_DEBUG_LEVEL "0"
1027 {"Total number of bytes: [0-9][0-9]*", 1}, /* Samba du */
1029 #define SAMBA_DEBUG_LEVEL "3"
1030 {"Total bytes listed: [0-9][0-9]*", 1}, /* Samba dir */
1045 int pipefd[2], nullfd, stdoutfd, killctl[2];
1049 char *dumpkeys = NULL;
1050 char *device = NULL;
1051 char *fstype = NULL;
1055 char *rundump_cmd = NULL;
1056 char level_str[NUM_STR_SIZE];
1059 char *qdisk = quote_string(disk);
1062 #if defined(DUMP) || defined(VDUMP) || defined(VXDUMP) || defined(XFSDUMP)
1066 (void)options; /* Quiet unused parameter warning */
1068 (void)getsize_smbtar; /* Quiet unused parameter warning */
1070 snprintf(level_str, SIZEOF(level_str), "%d", level);
1072 device = amname_to_devname(amdevice);
1073 qdevice = quote_string(device);
1074 fstype = amname_to_fstype(amdevice);
1076 dbprintf(("%s: calculating for device %s with %s\n",
1077 debug_prefix_time(NULL), qdevice, fstype));
1079 cmd = vstralloc(libexecdir, "/rundump", versionsuffix(), NULL);
1080 rundump_cmd = stralloc(cmd);
1081 if (g_options->config)
1082 config = g_options->config;
1084 config = "NOCONFIG";
1085 if ((stdoutfd = nullfd = open("/dev/null", O_RDWR)) == -1) {
1086 dbprintf(("getsize_dump could not open /dev/null: %s\n",
1089 amfree(rundump_cmd);
1096 pipefd[0] = pipefd[1] = killctl[0] = killctl[1] = -1;
1097 if (pipe(pipefd) < 0) {
1098 dbprintf(("getsize_dump could create data pipes: %s\n",
1101 amfree(rundump_cmd);
1109 #ifdef XFSDUMP /* { */
1111 if (strcmp(fstype, "xfs") == 0)
1116 name = stralloc(" (xfsdump)");
1117 dbprintf(("%s: running \"%s%s -F -J -l %s - %s\"\n",
1118 debug_prefix_time(NULL), cmd, name, level_str, qdevice));
1122 #ifdef VXDUMP /* { */
1124 if (strcmp(fstype, "vxfs") == 0)
1130 name = stralloc(" (vxdump)");
1132 name = stralloc("");
1133 cmd = newstralloc(cmd, VXDUMP);
1134 config = skip_argument;
1137 dumpkeys = vstralloc(level_str, "s", "f", NULL);
1138 dbprintf(("%s: running \"%s%s %s 1048576 - %s\"\n",
1139 debug_prefix_time(NULL), cmd, name, dumpkeys, qdevice));
1143 #ifdef VDUMP /* { */
1145 if (strcmp(fstype, "advfs") == 0)
1150 name = stralloc(" (vdump)");
1153 device = amname_to_dirname(amdevice);
1154 qdevice = quote_string(device);
1155 dumpkeys = vstralloc(level_str, "b", "f", NULL);
1156 dbprintf(("%s: running \"%s%s %s 60 - %s\"\n",
1157 debug_prefix_time(NULL), cmd, name, dumpkeys, qdevice));
1163 # ifdef USE_RUNDUMP /* { */
1164 # ifdef AIX_BACKUP /* { */
1165 name = stralloc(" (backup)");
1167 name = vstralloc(" (", DUMP, ")", NULL);
1170 name = stralloc("");
1171 cmd = newstralloc(cmd, DUMP);
1172 config = skip_argument;
1176 # ifdef AIX_BACKUP /* { */
1177 dumpkeys = vstralloc("-", level_str, "f", NULL);
1178 dbprintf(("%s: running \"%s%s %s - %s\"\n",
1179 debug_prefix_time(NULL), cmd, name, dumpkeys, qdevice));
1181 # ifdef HAVE_DUMP_ESTIMATE
1182 # define PARAM_DUMP_ESTIMATE HAVE_DUMP_ESTIMATE
1184 # define PARAM_DUMP_ESTIMATE ""
1186 # ifdef HAVE_HONOR_NODUMP
1187 # define PARAM_HONOR_NODUMP "h"
1189 # define PARAM_HONOR_NODUMP ""
1191 dumpkeys = vstralloc(level_str,
1192 PARAM_DUMP_ESTIMATE,
1193 PARAM_DUMP_ESTIMATE,
1196 # ifdef HAVE_DUMP_ESTIMATE
1197 stdoutfd = pipefd[1];
1200 # ifdef HAVE_HONOR_NODUMP /* { */
1201 dbprintf(("%s: running \"%s%s %s 0 1048576 - %s\"\n",
1202 debug_prefix_time(NULL), cmd, name, dumpkeys, qdevice));
1204 dbprintf(("%s: running \"%s%s %s 1048576 - %s\"\n",
1205 debug_prefix_time(NULL), cmd, name, dumpkeys, qdevice));
1212 error("no dump program available");
1216 if (pipe(killctl) < 0) {
1217 dbprintf(("%s: Could not create pipe: %s\n",
1218 debug_prefix(NULL), strerror(errno)));
1219 /* Message will be printed later... */
1220 killctl[0] = killctl[1] = -1;
1223 start_time = curclock();
1224 switch(dumppid = fork()) {
1226 dbprintf(("%s: cannot fork for killpgrp: %s\n",
1227 debug_prefix(NULL), strerror(errno)));
1230 amfree(rundump_cmd);
1239 case 0: /* child process */
1242 else if (killctl[0] == -1 || killctl[1] == -1)
1243 dbprintf(("%s: Trying without killpgrp\n", debug_prefix(NULL)));
1247 dbprintf(("%s: fork failed, trying without killpgrp\n",
1248 debug_prefix(NULL)));
1254 char *killpgrp_cmd = vstralloc(libexecdir, "/killpgrp",
1255 versionsuffix(), NULL);
1256 dbprintf(("%s: running %s\n",
1257 debug_prefix_time(NULL), killpgrp_cmd));
1258 dup2(killctl[0], 0);
1265 if (g_options->config)
1266 config = g_options->config;
1268 config = "NOCONFIG";
1269 execle(killpgrp_cmd, killpgrp_cmd, config, (char *)0,
1271 dbprintf(("%s: cannot execute %s: %s\n",
1272 debug_prefix(NULL), killpgrp_cmd, strerror(errno)));
1276 case 0: /* child process */
1285 if (killctl[0] != -1)
1287 if (killctl[1] != -1)
1292 if (strcmp(fstype, "xfs") == 0)
1297 execle(cmd, "rundump", config, "xfsdump", "-F", "-J", "-l",
1298 level_str, "-", device, (char *)0, safe_env());
1300 execle(cmd, "xfsdump", "-F", "-J", "-l",
1301 level_str, "-", device, (char *)0, safe_env());
1306 if (strcmp(fstype, "vxfs") == 0)
1311 execle(cmd, "rundump", config, "vxdump", dumpkeys, "1048576",
1312 "-", device, (char *)0, safe_env());
1314 execle(cmd, "vxdump", dumpkeys, "1048576", "-",
1315 device, (char *)0, safe_env());
1320 if (strcmp(fstype, "advfs") == 0)
1325 execle(cmd, "rundump", config, "vdump", dumpkeys, "60", "-",
1326 device, (char *)0, safe_env());
1328 execle(cmd, "vdump", dumpkeys, "60", "-",
1329 device, (char *)0, safe_env());
1335 execle(cmd, "rundump", config, "backup", dumpkeys, "-",
1336 device, (char *)0, safe_env());
1338 execle(cmd, "backup", dumpkeys, "-",
1339 device, (char *)0, safe_env());
1342 execle(cmd, "rundump", config, "dump", dumpkeys,
1343 #ifdef HAVE_HONOR_NODUMP
1346 "1048576", "-", device, (char *)0, safe_env());
1348 execle(cmd, "dump", dumpkeys,
1349 #ifdef HAVE_HONOR_NODUMP
1352 "1048576", "-", device, (char *)0, safe_env());
1357 error("exec %s failed or no dump program available: %s",
1358 cmd, strerror(errno));
1364 amfree(rundump_cmd);
1367 if (killctl[0] != -1)
1369 dumpout = fdopen(pipefd[0],"r");
1371 error("Can't fdopen: %s", strerror(errno));
1375 for(size = (off_t)-1; (line = agets(dumpout)) != NULL; free(line)) {
1376 if (line[0] == '\0')
1378 dbprintf(("%s: %s\n", debug_prefix_time(NULL), line));
1379 size = handle_dumpline(line);
1380 if(size > (off_t)-1) {
1382 while ((line = agets(dumpout)) != NULL) {
1383 if (line[0] != '\0')
1388 dbprintf(("%s: %s\n", debug_prefix_time(NULL), line));
1395 dbprintf(("%s: .....\n", debug_prefix_time(NULL)));
1396 dbprintf(("%s: estimate time for %s level %d: %s\n",
1400 walltime_str(timessub(curclock(), start_time))));
1401 if(size == (off_t)-1) {
1402 dbprintf(("%s: no size line match in %s%s output for \"%s\"\n",
1403 debug_prefix(NULL), cmd, name, disk));
1404 dbprintf(("%s: .....\n", debug_prefix(NULL)));
1405 dbprintf(("%s: Run %s%s manually to check for errors\n",
1406 debug_prefix(NULL), cmd, name));
1407 } else if(size == (off_t)0 && level == 0) {
1408 dbprintf(("%s: possible %s%s problem -- is \"%s\" really empty?\n",
1409 debug_prefix(NULL), cmd, name, disk));
1410 dbprintf(("%s: .....\n", debug_prefix(NULL)));
1412 dbprintf(("%s: estimate size for %s level %d: %ld KB\n",
1419 if (killctl[1] != -1) {
1420 dbprintf(("%s: asking killpgrp to terminate\n",
1421 debug_prefix_time(NULL)));
1423 for(s = 5; s > 0; --s) {
1425 if (waitpid(dumppid, NULL, WNOHANG) != -1)
1431 * First, try to kill the dump process nicely. If it ignores us
1432 * for several seconds, hit it harder.
1434 dbprintf(("%s: sending SIGTERM to process group %ld\n",
1435 debug_prefix_time(NULL), (long)dumppid));
1436 if (kill(-dumppid, SIGTERM) == -1) {
1437 dbprintf(("%s: kill failed: %s\n",
1438 debug_prefix(NULL), strerror(errno)));
1440 /* Now check whether it dies */
1441 for(s = 5; s > 0; --s) {
1443 if (waitpid(dumppid, NULL, WNOHANG) != -1)
1447 dbprintf(("%s: sending SIGKILL to process group %ld\n",
1448 debug_prefix_time(NULL), (long)dumppid));
1449 if (kill(-dumppid, SIGKILL) == -1) {
1450 dbprintf(("%s: kill failed: %s\n",
1451 debug_prefix(NULL), strerror(errno)));
1453 for(s = 5; s > 0; --s) {
1455 if (waitpid(dumppid, NULL, WNOHANG) != -1)
1459 dbprintf(("%s: waiting for %s%s \"%s\" child\n",
1460 debug_prefix_time(NULL), cmd, name, qdisk));
1462 dbprintf(("%s: after %s%s %s wait\n",
1463 debug_prefix_time(NULL), cmd, name, qdisk));
1489 int pipefd = -1, nullfd = -1, passwdfd = -1;
1493 char *tarkeys, *sharename, *user_and_password = NULL, *domain = NULL;
1494 char *share = NULL, *subdir = NULL;
1501 char *error_pn = NULL;
1502 char *qdisk = quote_string(disk);
1504 (void)options; /* Quiet unused parameter warning */
1506 error_pn = stralloc2(get_pname(), "-smbclient");
1508 parsesharename(amdevice, &share, &subdir);
1512 set_pname(error_pn);
1514 error("cannot parse disk entry %s for share/subdir", qdisk);
1517 if ((subdir) && (SAMBA_VERSION < 2)) {
1520 set_pname(error_pn);
1522 error("subdirectory specified for share %s but samba not v2 or better", qdisk);
1525 if ((user_and_password = findpass(share, &domain)) == NULL) {
1528 memset(domain, '\0', strlen(domain));
1531 set_pname(error_pn);
1533 error("cannot find password for %s", disk);
1536 lpass = strlen(user_and_password);
1537 if ((pwtext = strchr(user_and_password, '%')) == NULL) {
1538 memset(user_and_password, '\0', (size_t)lpass);
1539 amfree(user_and_password);
1541 memset(domain, '\0', strlen(domain));
1544 set_pname(error_pn);
1546 error("password field not \'user%%pass\' for %s", disk);
1550 pwtext_len = strlen(pwtext);
1551 if ((sharename = makesharename(share, 0)) == NULL) {
1552 memset(user_and_password, '\0', (size_t)lpass);
1553 amfree(user_and_password);
1555 memset(domain, '\0', strlen(domain));
1558 set_pname(error_pn);
1560 error("cannot make share name of %s", share);
1563 if ((nullfd = open("/dev/null", O_RDWR)) == -1) {
1564 memset(user_and_password, '\0', (size_t)lpass);
1565 amfree(user_and_password);
1567 memset(domain, '\0', strlen(domain));
1570 set_pname(error_pn);
1573 error("could not open /dev/null: %s\n",
1578 #if SAMBA_VERSION >= 2
1580 tarkeys = "archive 0;recurse;du";
1582 tarkeys = "archive 1;recurse;du";
1585 tarkeys = "archive 0;recurse;dir";
1587 tarkeys = "archive 1;recurse;dir";
1590 start_time = curclock();
1592 if (pwtext_len > 0) {
1593 pw_fd_env = "PASSWD_FD";
1595 pw_fd_env = "dummy_PASSWD_FD";
1597 dumppid = pipespawn(SAMBA_CLIENT, STDERR_PIPE|PASSWD_PIPE,
1598 &nullfd, &nullfd, &pipefd,
1599 pw_fd_env, &passwdfd,
1602 "-d", SAMBA_DEBUG_LEVEL,
1603 *user_and_password ? "-U" : skip_argument,
1604 *user_and_password ? user_and_password : skip_argument,
1606 domain ? "-W" : skip_argument,
1607 domain ? domain : skip_argument,
1608 #if SAMBA_VERSION >= 2
1609 subdir ? "-D" : skip_argument,
1610 subdir ? subdir : skip_argument,
1615 memset(domain, '\0', strlen(domain));
1619 if(pwtext_len > 0 && fullwrite(passwdfd, pwtext, (size_t)pwtext_len) < 0) {
1620 int save_errno = errno;
1622 memset(user_and_password, '\0', (size_t)lpass);
1623 amfree(user_and_password);
1625 set_pname(error_pn);
1627 error("password write failed: %s", strerror(save_errno));
1630 memset(user_and_password, '\0', (size_t)lpass);
1631 amfree(user_and_password);
1637 dumpout = fdopen(pipefd,"r");
1639 error("Can't fdopen: %s", strerror(errno));
1643 for(size = (off_t)-1; (line = agets(dumpout)) != NULL; free(line)) {
1644 if (line[0] == '\0')
1646 dbprintf(("%s: %s\n", debug_prefix_time(NULL), line));
1647 size = handle_dumpline(line);
1650 while ((line = agets(dumpout)) != NULL) {
1651 if (line[0] != '\0')
1656 dbprintf(("%s: %s\n", debug_prefix_time(NULL), line));
1663 dbprintf(("%s: .....\n", debug_prefix_time(NULL)));
1664 dbprintf(("%s: estimate time for %s level %d: %s\n",
1668 walltime_str(timessub(curclock(), start_time))));
1669 if(size == (off_t)-1) {
1670 dbprintf(("%s: no size line match in %s output for \"%s\"\n",
1671 debug_prefix(NULL), SAMBA_CLIENT, disk));
1672 dbprintf(("%s: .....\n", debug_prefix(NULL)));
1673 } else if(size == (off_t)0 && level == 0) {
1674 dbprintf(("%s: possible %s problem -- is \"%s\" really empty?\n",
1675 debug_prefix(NULL), SAMBA_CLIENT, disk));
1676 dbprintf(("%s: .....\n", debug_prefix(NULL)));
1678 dbprintf(("%s: estimate size for %s level %d: %ld KB\n",
1684 kill(-dumppid, SIGTERM);
1686 dbprintf(("%s: waiting for %s \"%s\" child\n",
1687 debug_prefix_time(NULL), SAMBA_CLIENT, qdisk));
1689 dbprintf(("%s: after %s %s wait\n",
1690 debug_prefix_time(NULL), SAMBA_CLIENT, qdisk));
1711 int pipefd = -1, nullfd = -1;
1713 off_t size = (off_t)-1;
1714 FILE *dumpout = NULL;
1715 char *incrname = NULL;
1716 char *basename = NULL;
1717 char *dirname = NULL;
1718 char *inputname = NULL;
1723 char dumptimestr[80];
1729 char *file_exclude = NULL;
1730 char *file_include = NULL;
1735 char *qdisk = quote_string(disk);
1736 char *gnutar_list_dir;
1738 if(options->exclude_file) nb_exclude += options->exclude_file->nb_element;
1739 if(options->exclude_list) nb_exclude += options->exclude_list->nb_element;
1740 if(options->include_file) nb_include += options->include_file->nb_element;
1741 if(options->include_list) nb_include += options->include_list->nb_element;
1743 if(nb_exclude > 0) file_exclude = build_exclude(disk, amdevice, options, 0);
1744 if(nb_include > 0) file_include = build_include(disk, amdevice, options, 0);
1746 my_argv = alloc(SIZEOF(char *) * 22);
1749 gnutar_list_dir = client_getconf_str(CLN_GNUTAR_LIST_DIR);
1750 if (strlen(gnutar_list_dir) == 0)
1751 gnutar_list_dir = NULL;
1752 if (gnutar_list_dir) {
1753 char number[NUM_STR_SIZE];
1758 basename = vstralloc(gnutar_list_dir,
1760 g_options->hostname,
1764 * The loop starts at the first character of the host name,
1767 s = basename + strlen(gnutar_list_dir) + 1;
1768 while((ch = *s++) != '\0') {
1769 if(ch == '/' || isspace(ch)) s[-1] = '_';
1772 snprintf(number, SIZEOF(number), "%d", level);
1773 incrname = vstralloc(basename, "_", number, ".new", NULL);
1777 * Open the listed incremental file from the previous level. Search
1778 * backward until one is found. If none are found (which will also
1779 * be true for a level 0), arrange to read from /dev/null.
1783 while (infd == -1) {
1784 if (--baselevel >= 0) {
1785 snprintf(number, SIZEOF(number), "%d", baselevel);
1786 inputname = newvstralloc(inputname,
1787 basename, "_", number, NULL);
1789 inputname = newstralloc(inputname, "/dev/null");
1791 if ((infd = open(inputname, O_RDONLY)) == -1) {
1792 int save_errno = errno;
1794 dbprintf(("%s: gnutar: error opening %s: %s\n",
1795 debug_prefix(NULL), inputname, strerror(save_errno)));
1796 if (baselevel < 0) {
1803 * Copy the previous listed incremental file to the new one.
1805 if ((outfd = open(incrname, O_WRONLY|O_CREAT, 0600)) == -1) {
1806 dbprintf(("%s: opening %s: %s\n",
1807 debug_prefix(NULL), incrname, strerror(errno)));
1811 while ((nb = read(infd, &buf, SIZEOF(buf))) > 0) {
1812 if (fullwrite(outfd, &buf, (size_t)nb) < nb) {
1813 dbprintf(("%s: writing to %s: %s\n",
1814 debug_prefix(NULL), incrname, strerror(errno)));
1820 dbprintf(("%s: reading from %s: %s\n",
1821 debug_prefix(NULL), inputname, strerror(errno)));
1825 if (close(infd) != 0) {
1826 dbprintf(("%s: closing %s: %s\n",
1827 debug_prefix(NULL), inputname, strerror(errno)));
1830 if (close(outfd) != 0) {
1831 dbprintf(("%s: closing %s: %s\n",
1832 debug_prefix(NULL), incrname, strerror(errno)));
1840 gmtm = gmtime(&dumpsince);
1841 snprintf(dumptimestr, SIZEOF(dumptimestr),
1842 "%04d-%02d-%02d %2d:%02d:%02d GMT",
1843 gmtm->tm_year + 1900, gmtm->tm_mon+1, gmtm->tm_mday,
1844 gmtm->tm_hour, gmtm->tm_min, gmtm->tm_sec);
1846 dirname = amname_to_dirname(amdevice);
1848 cmd = vstralloc(libexecdir, "/", "runtar", versionsuffix(), NULL);
1849 my_argv[i++] = "runtar";
1850 if (g_options->config)
1851 my_argv[i++] = g_options->config;
1853 my_argv[i++] = "NOCONFIG";
1856 my_argv[i++] = GNUTAR;
1858 my_argv[i++] = "tar";
1860 my_argv[i++] = "--create";
1861 my_argv[i++] = "--file";
1862 my_argv[i++] = "/dev/null";
1863 my_argv[i++] = "--directory";
1864 my_argv[i++] = dirname;
1865 my_argv[i++] = "--one-file-system";
1866 if (gnutar_list_dir) {
1867 my_argv[i++] = "--listed-incremental";
1868 my_argv[i++] = incrname;
1870 my_argv[i++] = "--incremental";
1871 my_argv[i++] = "--newer";
1872 my_argv[i++] = dumptimestr;
1874 #ifdef ENABLE_GNUTAR_ATIME_PRESERVE
1875 /* --atime-preserve causes gnutar to call
1876 * utime() after reading files in order to
1877 * adjust their atime. However, utime()
1878 * updates the file's ctime, so incremental
1879 * dumps will think the file has changed. */
1880 my_argv[i++] = "--atime-preserve";
1882 my_argv[i++] = "--sparse";
1883 my_argv[i++] = "--ignore-failed-read";
1884 my_argv[i++] = "--totals";
1887 my_argv[i++] = "--exclude-from";
1888 my_argv[i++] = file_exclude;
1892 my_argv[i++] = "--files-from";
1893 my_argv[i++] = file_include;
1898 my_argv[i++] = NULL;
1900 start_time = curclock();
1902 if ((nullfd = open("/dev/null", O_RDWR)) == -1) {
1903 dbprintf(("Cannot access /dev/null : %s\n", strerror(errno)));
1907 dumppid = pipespawnv(cmd, STDERR_PIPE, &nullfd, &nullfd, &pipefd, my_argv);
1909 dumpout = fdopen(pipefd,"r");
1911 error("Can't fdopen: %s", strerror(errno));
1915 for(size = (off_t)-1; (line = agets(dumpout)) != NULL; free(line)) {
1916 if (line[0] == '\0')
1918 dbprintf(("%s: %s\n", debug_prefix_time(NULL), line));
1919 size = handle_dumpline(line);
1920 if(size > (off_t)-1) {
1922 while ((line = agets(dumpout)) != NULL) {
1923 if (line[0] != '\0') {
1929 dbprintf(("%s: %s\n", debug_prefix_time(NULL), line));
1937 dbprintf(("%s: .....\n", debug_prefix_time(NULL)));
1938 dbprintf(("%s: estimate time for %s level %d: %s\n",
1942 walltime_str(timessub(curclock(), start_time))));
1943 if(size == (off_t)-1) {
1944 dbprintf(("%s: no size line match in %s output for \"%s\"\n",
1945 debug_prefix(NULL), my_argv[0], disk));
1946 dbprintf(("%s: .....\n", debug_prefix(NULL)));
1947 } else if(size == (off_t)0 && level == 0) {
1948 dbprintf(("%s: possible %s problem -- is \"%s\" really empty?\n",
1949 debug_prefix(NULL), my_argv[0], disk));
1950 dbprintf(("%s: .....\n", debug_prefix(NULL)));
1952 dbprintf(("%s: estimate size for %s level %d: %ld KB\n",
1958 kill(-dumppid, SIGTERM);
1960 dbprintf(("%s: waiting for %s \"%s\" child\n",
1961 debug_prefix_time(NULL), my_argv[0], qdisk));
1963 dbprintf(("%s: after %s %s wait\n",
1964 debug_prefix_time(NULL), my_argv[0], qdisk));
1978 amfree(file_exclude);
1979 amfree(file_include);
1999 int pipefd[2], nullfd;
2001 off_t size = (off_t)-1;
2005 char dumptimestr[80];
2008 char *argvchild[10];
2009 char *newoptstr = NULL;
2012 char *qdisk = quote_string(disk);
2013 char *qamdevice = quote_string(amdevice);
2015 gmtm = gmtime(&dumpsince);
2016 snprintf(dumptimestr, SIZEOF(dumptimestr),
2017 "%04d-%02d-%02d %2d:%02d:%02d GMT",
2018 gmtm->tm_year + 1900, gmtm->tm_mon+1, gmtm->tm_mday,
2019 gmtm->tm_hour, gmtm->tm_min, gmtm->tm_sec);
2021 cmd = vstralloc(DUMPER_DIR, "/", program, NULL);
2024 argvchild[i++] = program;
2025 argvchild[i++] = "estimate";
2027 argvchild[i++] = "full";
2029 char levelstr[NUM_STR_SIZE];
2030 snprintf(levelstr,SIZEOF(levelstr),"%d",level);
2031 argvchild[i++] = "level";
2032 argvchild[i++] = levelstr;
2034 argvchild[i++] = amdevice;
2035 newoptstr = vstralloc(options->str,"estimate-direct;", NULL);
2036 argvchild[i++] = newoptstr;
2037 argvchild[i] = NULL;
2039 dbprintf(("%s: running %s", debug_prefix_time(NULL), cmd));
2040 for(j = 1; j < i; j++) {
2041 dbprintf((" %s", argvchild[j]));
2045 if ((nullfd = open("/dev/null", O_RDWR)) == -1) {
2046 dbprintf(("Cannot access /dev/null : %s\n", strerror(errno)));
2050 if (pipe(pipefd) < 0) {
2051 dbprintf(("getsize_wrapper could create data pipes: %s\n",
2056 start_time = curclock();
2058 switch(dumppid = fork()) {
2070 execve(cmd, argvchild, safe_env());
2071 error("exec %s failed: %s", cmd, strerror(errno));
2077 dumpout = fdopen(pipefd[0],"r");
2079 error("Can't fdopen: %s", strerror(errno));
2083 for(size = (off_t)-1; (line = agets(dumpout)) != NULL; free(line)) {
2084 if (line[0] == '\0')
2086 dbprintf(("%s: %s\n", debug_prefix_time(NULL), line));
2087 i = sscanf(line, OFF_T_FMT " " OFF_T_FMT,
2088 (OFF_T_FMT_TYPE *)&size1,
2089 (OFF_T_FMT_TYPE *)&size2);
2091 size = size1 * size2;
2095 while ((line = agets(dumpout)) != NULL) {
2096 if (line[0] != '\0')
2101 dbprintf(("%s: %s\n", debug_prefix_time(NULL), line));
2108 dbprintf(("%s: .....\n", debug_prefix_time(NULL)));
2109 dbprintf(("%s: estimate time for %s level %d: %s\n",
2113 walltime_str(timessub(curclock(), start_time))));
2114 if(size == (off_t)-1) {
2115 dbprintf(("%s: no size line match in %s output for \"%s\"\n",
2116 debug_prefix(NULL), cmd, qdisk));
2117 dbprintf(("%s: .....\n", debug_prefix(NULL)));
2118 } else if(size == (off_t)0 && level == 0) {
2119 dbprintf(("%s: possible %s problem -- is \"%s\" really empty?\n",
2120 debug_prefix(NULL), cmd, qdisk));
2121 dbprintf(("%s: .....\n", debug_prefix(NULL)));
2123 dbprintf(("%s: estimate size for %s level %d: " OFF_T_FMT " KB\n",
2129 kill(-dumppid, SIGTERM);
2131 dbprintf(("%s: waiting for %s \"%s\" child\n",
2132 debug_prefix_time(NULL), cmd, qdisk));
2134 dbprintf(("%s: after %s %s wait\n",
2135 debug_prefix_time(NULL), cmd, qdisk));
2151 * Returns the value of the first integer in a string.
2163 while(ch && !isdigit(ch)) ch = *str++;
2165 while(isdigit(ch) || (ch == '.')) ch = *str++;
2174 * Checks the dump output line against the error and size regex tables.
2184 /* check for size match */
2186 for(rp = re_size; rp->regex != NULL; rp++) {
2187 if(match(rp->regex, str)) {
2188 size = ((first_num(str)*rp->scale+1023.0)/1024.0);
2190 size = 1.0; /* found on NeXT -- sigh */