* Eric Nelson <[EMAIL PROTECTED]> (Fri, Sep 07, 2001 at 09:26:08AM -0600)
> Hello all,

> Has anyone ever worked around the problem of having too large of disk partitions
> to fit onto a backup tape, thus the partitions had to be broken down into
> smaller file systems to be backed up, but after breaking them down, the estimate
> time took too long because of this and the backups never occur?

use calcsize iso gnutar to make the estimates.

I had promised to write a patch for his, but have never gotten farther then
downloading the CVS ....

A simpler version is in the attched file
(compile and reinstall)
Make sure to define USE_GENERIC_CALCSIZE before compiling.

> If anyone has ever had to deal with a situation like this, please advise.  Your
> help would be greatly appreciated!



        Gerhard,  <@jasongeo.com>   == The Acoustic Motorbiker ==       
-- 
   __O  If your watch is wound, wound to run, it will
 =`\<,  If your time is due, due to come, it will
(=)/(=) Living this life, is like trying to learn latin
                in a chines firedrill

/*
 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
 * Copyright (c) 1991-1998 University of Maryland at College Park
 * All Rights Reserved.
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of U.M. not be used in advertising or
 * publicity pertaining to distribution of the software without specific,
 * written prior permission.  U.M. makes no representations about the
 * suitability of this software for any purpose.  It is provided "as is"
 * without express or implied warranty.
 *
 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 * Authors: the Amanda Development Team.  Its members are listed in a
 * file named AUTHORS, in the root directory of this distribution.
 */
/* 
 * $Id: sendsize.c,v 1.97.2.13 2000/10/11 02:08:26 martinea Exp $
 *
 * send estimated backup sizes using dump
 */

#include "amanda.h"
#include "pipespawn.h"
#include "amandates.h"
#include "getfsent.h"
#include "version.h"

#ifdef SAMBA_CLIENT
#include "findpass.h"
#endif

#ifdef HAVE_SETPGID
#  define SETPGRP       setpgid(getpid(), getpid())
#  define SETPGRP_FAILED() do {                                         \
    dbprintf(("setpgid(%ld,%ld) failed: %s\n",                          \
              (long)getpid(), (long)getpid(), strerror(errno)));        \
} while(0)

#else /* () line 0 */
#if defined(SETPGRP_VOID)
#  define SETPGRP       setpgrp()
#  define SETPGRP_FAILED() do {                                         \
    dbprintf(("setpgrp() failed: %s\n", strerror(errno)));              \
} while(0)

#else
#  define SETPGRP       setpgrp(0, getpid())
#  define SETPGRP_FAILED() do {                                         \
    dbprintf(("setpgrp(0,%ld) failed: %s\n",                            \
              (long)getpid(), strerror(errno)));                        \
} while(0)

#endif
#endif

typedef struct level_estimates_s {
    time_t dumpsince;
    int estsize;
    int needestimate;
} level_estimate_t;

typedef struct disk_estimates_s {
    struct disk_estimates_s *next;
    char *amname;
    char *dirname;
    char *exclude;
    char *program;
    int spindle;
    level_estimate_t est[DUMP_LEVELS];
} disk_estimates_t;

disk_estimates_t *est_list;

#define MAXMAXDUMPS 16

int maxdumps = 1, dumpsrunning = 0;
char *host;                             /* my hostname from the server */

/* local functions */
int main P((int argc, char **argv));
void add_diskest P((char *disk, int level, char *exclude, int spindle, char *prog));
void calc_estimates P((disk_estimates_t *est));
void free_estimates P((disk_estimates_t *est));
void dump_calc_estimates P((disk_estimates_t *));
void smbtar_calc_estimates P((disk_estimates_t *));
void gnutar_calc_estimates P((disk_estimates_t *));
void generic_calc_estimates P((disk_estimates_t *));



int main(argc, argv)
int argc;
char **argv;
{
    int level, new_maxdumps, spindle;
    char *prog, *disk, *dumpdate, *exclude = NULL;
    disk_estimates_t *est;
    disk_estimates_t *est_prev;
    char *line = NULL;
    char *s, *fp;
    int ch;
    char *err_extra = NULL;
    int fd;
    unsigned long malloc_hist_1, malloc_size_1;
    unsigned long malloc_hist_2, malloc_size_2;

    /* initialize */

    for(fd = 3; fd < FD_SETSIZE; fd++) {
        /*
         * Make sure nobody spoofs us with a lot of extra open files
         * that would cause an open we do to get a very high file
         * descriptor, which in turn might be used as an index into
         * an array (e.g. an fd_set).
         */
        close(fd);
    }

    safe_cd();

    set_pname("sendsize");

    malloc_size_1 = malloc_inuse(&malloc_hist_1);

    erroutput_type = (ERR_INTERACTIVE|ERR_SYSLOG);
    dbopen();
    dbprintf(("%s: version %s\n", argv[0], version()));

    host = alloc(MAX_HOSTNAME_LENGTH+1);
    gethostname(host, MAX_HOSTNAME_LENGTH);
    host[MAX_HOSTNAME_LENGTH] = '\0';

    /* handle all service requests */

    start_amandates(0);

    for(; (line = agets(stdin)) != NULL; free(line)) {
#define sc "OPTIONS"
        if(strncmp(line, sc, sizeof(sc)-1) == 0) {
#undef sc
#define sc "maxdumps="
            s = strstr(line, sc);
            if(s != NULL) {
                s += sizeof(sc)-1;
#undef sc
                if(sscanf(s, "%d;", &new_maxdumps) != 1) {
                    err_extra = "bad maxdumps value";
                    goto err;
                }
                if (new_maxdumps > MAXMAXDUMPS) {
                    maxdumps = MAXMAXDUMPS;
                } else if (new_maxdumps > 0) {
                    maxdumps = new_maxdumps;
                }
            }

#define sc "hostname="
            s = strstr(line, sc);
            if(s != NULL) {
                s += sizeof(sc)-1;
                ch = *s++;
#undef sc
                fp = s-1;
                while(ch != '\0' && ch != ';') ch = *s++;
                s[-1] = '\0';
                host = newstralloc(host, fp);
            }

            printf("OPTIONS maxdumps=%d;\n", maxdumps);
            fflush(stdout);
            continue;
        }

        s = line;
        ch = *s++;

        skip_whitespace(s, ch);                 /* find the program name */
        if(ch == '\0') {
            err_extra = "no program name";
            goto err;                           /* no program name */
        }
        prog = s - 1;
        skip_non_whitespace(s, ch);
        s[-1] = '\0';

        skip_whitespace(s, ch);                 /* find the disk name */
        if(ch == '\0') {
            err_extra = "no disk name";
            goto err;                           /* no disk name */
        }
        disk = s - 1;
        skip_non_whitespace(s, ch);
        s[-1] = '\0';

        skip_whitespace(s, ch);                 /* find the level number */
        if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
            err_extra = "bad level";
            goto err;                           /* bad level */
        }
        skip_integer(s, ch);

        skip_whitespace(s, ch);                 /* find the dump date */
        if(ch == '\0') {
            err_extra = "no dumpdate";
            goto err;                           /* no dumpdate */
        }
        dumpdate = s - 1;
        skip_non_whitespace(s, ch);
        s[-1] = '\0';

        spindle = 0;                            /* default spindle */
        amfree(exclude);                                /* default is no exclude */

        skip_whitespace(s, ch);                 /* find the spindle */
        if(ch != '\0') {
            if(sscanf(s - 1, "%d", &spindle) != 1) {
                err_extra = "bad spindle";
                goto err;                       /* bad spindle */
            }
            skip_integer(s, ch);

            skip_whitespace(s, ch);             /* find the exclusion list */
            if(ch != '\0') {
                exclude = newstralloc2(exclude, "--", s - 1);
                skip_non_whitespace(s, ch);
                if(ch) {
                    err_extra = "extra text at end";
                    goto err;                   /* should have gotten to end */
                }
            }
        }

        add_diskest(disk, level, exclude, spindle, prog);
    }
    amfree(line);

    finish_amandates();
    free_amandates();

    for(est = est_list; est != NULL; est = est->next)
        calc_estimates(est);

    while(dumpsrunning > 0) {
      wait(NULL);
      --dumpsrunning;
    }

    est_prev = NULL;
    for(est = est_list; est != NULL; est = est->next) {
        free_estimates(est);
        amfree(est_prev);
        est_prev = est;
    }
    amfree(est_prev);
    amfree(host);

    malloc_size_2 = malloc_inuse(&malloc_hist_2);

    if(malloc_size_1 != malloc_size_2) {
#if defined(USE_DBMALLOC)
        extern int db_fd;

        malloc_list(db_fd, malloc_hist_1, malloc_hist_2);
#endif
    }

    dbclose();
    return 0;
 err:
    printf("FORMAT ERROR IN REQUEST PACKET\n");
    if(err_extra) {
        dbprintf(("REQ packet is bogus: %s\n", err_extra));
    } else {
        dbprintf(("REQ packet is bogus\n"));
    }
    dbclose();
    return 1;
}


void add_diskest(disk, level, exclude, spindle, prog)
char *disk, *prog;
char *exclude;
int level, spindle;
{
    disk_estimates_t *newp, *curp;
    amandates_t *amdp;
    int dumplev, estlev;
    time_t dumpdate;

    for(curp = est_list; curp != NULL; curp = curp->next) {
        if(strcmp(curp->amname, disk) == 0) {
            /* already have disk info, just note the level request */
            curp->est[level].needestimate = 1;
            return;
        }
    }

    newp = (disk_estimates_t *) alloc(sizeof(disk_estimates_t));
    memset(newp, 0, sizeof(*newp));
    newp->next = est_list;
    est_list = newp;
    newp->amname = stralloc(disk);
    newp->dirname = amname_to_dirname(newp->amname);
    newp->exclude = exclude ? stralloc(exclude) : NULL;
    newp->program = stralloc(prog);
    newp->spindle = spindle;
    newp->est[level].needestimate = 1;

    /* fill in dump-since dates */

    amdp = amandates_lookup(newp->amname);

    newp->est[0].dumpsince = EPOCH;
    for(dumplev = 0; dumplev < DUMP_LEVELS; dumplev++) {
        dumpdate = amdp->dates[dumplev];
        for(estlev = dumplev+1; estlev < DUMP_LEVELS; estlev++) {
            if(dumpdate > newp->est[estlev].dumpsince)
                newp->est[estlev].dumpsince = dumpdate;
        }
    }
}


void free_estimates(est)
disk_estimates_t *est;
{
    amfree(est->amname);
    amfree(est->dirname);
    amfree(est->exclude);
    amfree(est->program);
}

/*
 * ------------------------------------------------------------------------
 *
 */

void calc_estimates(est)
disk_estimates_t *est;
{
    dbprintf(("calculating for amname '%s', dirname '%s'\n", est->amname,
              est->dirname));
    if (maxdumps > 1) {
      while(dumpsrunning >= maxdumps) {
        wait(NULL);
        --dumpsrunning;
      }
      ++dumpsrunning;
      switch(fork()) {
      case 0:
        break;
      case -1:
        error("calc_estimates: fork returned: %s", strerror(errno));
      default:
        return;
      }
    }

    /* Now in the child process */
    if(strcmp(est->program, "DUMP") == 0)
        dump_calc_estimates(est);
    else
#ifndef USE_GENERIC_CALCSIZE
# ifdef SAMBA_CLIENT
      if (strcmp(est->program, "GNUTAR") == 0 &&
          est->amname[0] == '/' && est->amname[1] == '/')
        smbtar_calc_estimates(est);
      else
# endif
# ifdef GNUTAR
        if (strcmp(est->program, "GNUTAR") == 0)
          gnutar_calc_estimates(est);
        else
# endif
#endif
          generic_calc_estimates(est);
    if (maxdumps > 1)
      exit(0);
}

void generic_calc_estimates(est)
disk_estimates_t *est;
{
    char *cmd;
    char *argv[DUMP_LEVELS*2+10];
    char number[NUM_STR_SIZE];
    int i, level, argc, calcpid;

    cmd = vstralloc(libexecdir, "/", "calcsize", versionsuffix(), NULL);

    argc = 0;
    argv[argc++] = stralloc("calcsize");
    argv[argc++] = stralloc(est->program);
#ifdef BUILTIN_EXCLUDE_SUPPORT
    if(est->exclude && *est->exclude) {
        argv[argc++] = stralloc("-X");
        argv[argc++] = stralloc(est->exclude);
    }
#endif
    argv[argc++] = stralloc(est->amname);
    argv[argc++] = stralloc(est->dirname);

    dbprintf(("%s: running cmd:", argv[0]));
    for(i=0; i<argc; ++i)
        dbprintf((" %s", argv[i]));

    for(level = 0; level < DUMP_LEVELS; level++) {
        if(est->est[level].needestimate) {
            ap_snprintf(number, sizeof(number), "%d", level);
            argv[argc++] = stralloc(number); 
            dbprintf((" %s", number));
            ap_snprintf(number, sizeof(number),
                        "%ld", (long)est->est[level].dumpsince);
            argv[argc++] = stralloc(number); 
            dbprintf((" %s", number));
        }
    }
    argv[argc] = NULL;
    dbprintf(("\n"));

    fflush(stderr); fflush(stdout);

    switch(calcpid = fork()) {
    case -1:
        error("%s: fork returned: %s", cmd, strerror(errno));
    default:
        break;
    case 0:
        execve(cmd, argv, safe_env());
        dbprintf(("%s: execve %s returned: %s",
                  get_pname(), cmd, strerror(errno)));
        exit(1);
    }
    for(i = 0; i < argc; i++) {
        amfree(argv[i]);
    }
    amfree(cmd);

    wait(NULL);
}


/*
 * ------------------------------------------------------------------------
 *
 */

/* local functions */
void dump_calc_estimates P((disk_estimates_t *est));
long getsize_dump P((char *disk, int level));
long getsize_smbtar P((char *disk, int level, char* exclude));
long getsize_gnutar P((char *disk, int level,
                       char *exclude, time_t dumpsince));
long handle_dumpline P((char *str));
double first_num P((char *str));

void dump_calc_estimates(est)
disk_estimates_t *est;
{
    int level;
    long size;

    for(level = 0; level < DUMP_LEVELS; level++) {
        if(est->est[level].needestimate) {
            dbprintf(("%s: getting size via dump for %s level %d\n",
                      get_pname(), est->amname, level));
            size = getsize_dump(est->amname, level);

            amflock(1, "size");

            fseek(stdout, (off_t)0, SEEK_SET);

            printf("%s %d SIZE %ld\n", est->amname, level, size);
            fflush(stdout);

            amfunlock(1, "size");
        }
    }
}

#ifdef SAMBA_CLIENT
void smbtar_calc_estimates(est)
disk_estimates_t *est;
{
    int level;
    long size;

    for(level = 0; level < DUMP_LEVELS; level++) {
        if(est->est[level].needestimate) {
            dbprintf(("%s: getting size via smbclient for %s level %d\n",
                      get_pname(), est->amname, level));
            size = getsize_smbtar(est->amname, level, est->exclude);

            amflock(1, "size");

            fseek(stdout, (off_t)0, SEEK_SET);

            printf("%s %d SIZE %ld\n", est->amname, level, size);
            fflush(stdout);

            amfunlock(1, "size");
        }
    }
}
#endif

#ifdef GNUTAR
void gnutar_calc_estimates(est)
disk_estimates_t *est;
{
  int level;
  long size;

  for(level = 0; level < DUMP_LEVELS; level++) {
      if (est->est[level].needestimate) {
          dbprintf(("%s: getting size via gnutar for %s level %d\n",
                    get_pname(), est->amname, level));
          size = getsize_gnutar(est->amname, level,
                                est->exclude, est->est[level].dumpsince);

          amflock(1, "size");

          fseek(stdout, (off_t)0, SEEK_SET);

          printf("%s %d SIZE %ld\n", est->amname, level, size);
          fflush(stdout);

          amfunlock(1, "size");
      }
  }
}
#endif

typedef struct regex_s {
    char *regex;
    int scale;
} regex_t;

regex_t re_size[] = {
#ifdef DUMP
    {"  DUMP: estimated -*[0-9][0-9]* tape blocks", 1024},
    {"  DUMP: [Ee]stimated [0-9][0-9]* blocks", 512},
    {"  DUMP: [Ee]stimated [0-9][0-9]* bytes", 1},             /* Ultrix 4.4 */
    {" UFSDUMP: estimated [0-9][0-9]* blocks", 512},           /* NEC EWS-UX */
    {"dump: Estimate: [0-9][0-9]* tape blocks", 1024},              /* OSF/1 */
    {"backup: There are an estimated [0-9][0-9]* tape blocks.",1024}, /* AIX */
    {"backup: estimated [0-9][0-9]* 1k blocks", 1024},                /* AIX */
    {"backup: estimated [0-9][0-9]* tape blocks", 1024},              /* AIX */
    {"backup: [0-9][0-9]* tape blocks on [0-9][0-9]* tape(s)",1024},  /* AIX */
    {"backup: [0-9][0-9]* 1k blocks on [0-9][0-9]* volume(s)",1024},  /* AIX */
    {"dump: Estimate: [0-9][0-9]* blocks being output to pipe",1024},
                                                              /* DU 4.0 dump */
    {"dump: Dumping [0-9][0-9]* bytes, ", 1},                /* DU 4.0 vdump */
    {"DUMP: estimated [0-9][0-9]* KB output", 1024},                 /* HPUX */
    {"  UFSDUMP: estimated [0-9][0-9]* blocks", 512},               /* Sinix */

#ifdef HAVE_DUMP_ESTIMATE
    {"[0-9][0-9]* blocks, [0-9][0-9]*.[0-9][0-9]* volumes", 1024},
                                                          /* DU 3.2g dump -E */
    {"^[0-9][0-9]* blocks$", 1024},                       /* DU 4.0 dump  -E */
    {"^[0-9][0-9]*$", 1},                              /* Solaris ufsdump -S */
#endif
#endif

#ifdef VDUMP
    {"vdump: Dumping [0-9][0-9]* bytes, ", 1},                /* OSF/1 vdump */
#endif
    
#ifdef VXDUMP
    {"vxdump: estimated [0-9][0-9]* blocks", 512},          /* HPUX's vxdump */
    {"  VXDUMP: estimated [0-9][0-9]* blocks", 512},                /* Sinix */
#endif

#ifdef XFSDUMP
    {"xfsdump: estimated dump size: [0-9][0-9]* bytes", 1},  /* Irix 6.2 xfs */
#endif
    
#ifdef GNUTAR
    {"Total bytes written: [0-9][0-9]*", 1},                /* Gnutar client */
#endif

#ifdef SAMBA_CLIENT
#if SAMBA_VERSION >= 2
#define SAMBA_DEBUG_LEVEL "0"
    {"Total number of bytes: [0-9][0-9]*", 1},                   /* Samba du */
#else
#define SAMBA_DEBUG_LEVEL "3"
    {"Total bytes listed: [0-9][0-9]*", 1},                     /* Samba dir */
#endif
#endif

    { NULL, 0 }
};


long getsize_dump(disk, level)
    char *disk;
    int level;
{
    int pipefd[2], nullfd, stdoutfd, killctl[2];
    pid_t dumppid;
    long size;
    FILE *dumpout;
    char *dumpkeys = NULL;
    char *device = NULL;
    char *fstype = NULL;
    char *cmd = NULL;
    char *line = NULL;
    char *rundump_cmd = NULL;
    char level_str[NUM_STR_SIZE];
    int s;

    ap_snprintf(level_str, sizeof(level_str), "%d", level);

    device = amname_to_devname(disk);
    fstype = amname_to_fstype(disk);

    cmd = vstralloc(libexecdir, "/rundump", versionsuffix(), NULL);
    rundump_cmd = stralloc(cmd);

    stdoutfd = nullfd = open("/dev/null", O_RDWR);
    pipefd[0] = pipefd[1] = killctl[0] = killctl[1] = -1;
    pipe(pipefd);

#ifdef XFSDUMP                                          /* { */
#ifdef DUMP                                             /* { */
    if (strcmp(fstype, "xfs") == 0)
#else                                                   /* } { */
    if (1)
#endif                                                  /* } */
    {
        char *name = " (xfsdump)";
        dbprintf(("%s: running \"%s%s -F -J -l %s - %s\"\n",
                  get_pname(), cmd, name, level_str, device));
    }
    else
#endif                                                  /* } */
#ifdef VXDUMP                                           /* { */
#ifdef DUMP                                             /* { */
    if (strcmp(fstype, "vxfs") == 0)
#else                                                   /* } { */
    if (1)
#endif                                                  /* } */
    {
#ifdef USE_RUNDUMP
        char *name = " (vxdump)";
#else
        char *name = "";

        cmd = newstralloc(cmd, VXDUMP);
#endif
        dumpkeys = vstralloc(level_str, "s", "f", NULL);
        dbprintf(("%s: running \"%s%s %s 1048576 - %s\"\n",
                  get_pname(), cmd, name, dumpkeys, device));
    }
    else
#endif                                                  /* } */
#ifdef VDUMP                                            /* { */
#ifdef DUMP                                             /* { */
    if (strcmp(fstype, "advfs") == 0)
#else                                                   /* } { */
    if (1)
#endif                                                  /* } */
    {
        char *name = " (vdump)";
        amfree(device);
        device = amname_to_dirname(disk);
        dumpkeys = vstralloc(level_str, "b", "f", NULL);
        dbprintf(("%s: running \"%s%s %s 60 - %s\"\n",
                  get_pname(), cmd, name, dumpkeys, device));
    }
    else
#endif                                                  /* } */
#ifdef DUMP                                             /* { */
    if (1) {
        char *name = NULL;

# ifdef USE_RUNDUMP                                     /* { */
#  ifdef AIX_BACKUP                                     /* { */
        name = stralloc(" (backup)");
#  else                                                 /* } { */
        name = vstralloc(" (", DUMP, ")", NULL);
#  endif                                                /* } */
# else                                                  /* } { */
        name = stralloc("");
        cmd = newstralloc(cmd, DUMP);
# endif                                                 /* } */

# ifdef AIX_BACKUP                                      /* { */
        dumpkeys = vstralloc("-", level_str, "f", NULL);
        dbprintf(("%s: running \"%s%s %s - %s\"\n",
                  get_pname(), cmd, name, dumpkeys, device));
# else                                                  /* } { */
        dumpkeys = vstralloc(level_str,
#  ifdef HAVE_DUMP_ESTIMATE                             /* { */
                             HAVE_DUMP_ESTIMATE,
#  endif                                                /* } */
#  ifdef HAVE_HONOR_NODUMP                              /* { */
                             "h",
#  endif                                                /* } */
                             "s", "f", NULL);

#  ifdef HAVE_DUMP_ESTIMATE
        stdoutfd = pipefd[1];
#  endif

#  ifdef HAVE_HONOR_NODUMP                              /* { */
        dbprintf(("%s: running \"%s%s %s 0 1048576 - %s\"\n",
                  get_pname(), cmd, name, dumpkeys, device));
#  else                                                 /* } { */
        dbprintf(("%s: running \"%s%s %s 1048576 - %s\"\n",
                  get_pname(), cmd, name, dumpkeys, device));
#  endif                                                /* } */
# endif                                                 /* } */
        amfree(name);
    }
    else
#endif                                                  /* } */
    {
        dbprintf(("%s: no dump program available", get_pname()));
        error("%s: no dump program available", get_pname());
    }

    pipe(killctl);

    switch(dumppid = fork()) {
    case -1:
        dbprintf(("cannot fork for killpgrp: %s\n", strerror(errno)));
        amfree(dumpkeys);
        amfree(cmd);
        amfree(rundump_cmd);
        amfree(device);
        return -1;
    default:
        break; 
    case 0:     /* child process */
        if(SETPGRP == -1)
            SETPGRP_FAILED();
        else if (killctl[0] == -1 || killctl[1] == -1)
            dbprintf(("pipe for killpgrp failed, trying without killpgrp\n"));
        else {
            switch(fork()) {
            case -1:
                dbprintf(("fork failed, trying without killpgrp\n"));
                break;

            default:
            {
                char *killpgrp_cmd = vstralloc(libexecdir, "/killpgrp",
                                               versionsuffix(), NULL);
                dbprintf(("running %s\n",killpgrp_cmd));
                dup2(killctl[0], 0);
                dup2(nullfd, 1);
                dup2(nullfd, 2);
                close(pipefd[0]);
                close(pipefd[1]);
                close(killctl[1]);
                close(nullfd);
                execle(killpgrp_cmd, killpgrp_cmd, (char *)0, safe_env());
                dbprintf(("cannot execute %s: %s\n", killpgrp_cmd,
                    strerror(errno)));
                exit(-1);
            }

            case 0:  /* child process */
                break;
            }
        }

        dup2(nullfd, 0);
        dup2(stdoutfd, 1);
        dup2(pipefd[1], 2);
        aclose(pipefd[0]);
        if (killctl[0] != -1)
            aclose(killctl[0]);
        if (killctl[1] != -1)
            aclose(killctl[1]);

#ifdef XFSDUMP
#ifdef DUMP
        if (strcmp(fstype, "xfs") == 0)
#else
        if (1)
#endif
            execle(cmd, "xfsdump", "-F", "-J", "-l", level_str, "-", device,
                   (char *)0, safe_env());
        else
#endif
#ifdef VXDUMP
#ifdef DUMP
        if (strcmp(fstype, "vxfs") == 0)
#else
        if (1)
#endif
            execle(cmd, "vxdump", dumpkeys, "1048576", "-", device, (char *)0,
                   safe_env());
        else
#endif
#ifdef VDUMP
#ifdef DUMP
        if (strcmp(fstype, "advfs") == 0)
#else
        if (1)
#endif
            execle(cmd, "vdump", dumpkeys, "60", "-", device, (char *)0,
                   safe_env());
        else
#endif
#ifdef DUMP
# ifdef AIX_BACKUP
            execle(cmd, "backup", dumpkeys, "-", device, (char *)0, safe_env());
# else
            execle(cmd, "dump", dumpkeys, 
#ifdef HAVE_HONOR_NODUMP
                   "0",
#endif
                   "1048576", "-", device, (char *)0, safe_env());
# endif
#endif
        {
          char *e;

          e = strerror(errno);
          dbprintf(("%s: exec %s failed or no dump program available: %s\n",
                    get_pname(), cmd, e));
          error("%s: exec %s failed or no dump program available: %s",
                get_pname(), cmd, e);
          exit(1);
        }
    }

    amfree(dumpkeys);
    amfree(cmd);
    amfree(rundump_cmd);

    aclose(pipefd[1]);
    if (killctl[0] != -1)
        aclose(killctl[0]);
    dumpout = fdopen(pipefd[0],"r");

    for(size = -1; (line = agets(dumpout)) != NULL; free(line)) {
        dbprintf(("%s\n",line));
        size = handle_dumpline(line);
        if(size > -1) {
            amfree(line);
            if((line = agets(dumpout)) != NULL) {
                dbprintf(("%s\n",line));
            }
            break;
        }
    }
    amfree(line);

    dbprintf((".....\n"));
    if(size == -1)
        dbprintf(("(no size line match in above dump output)\n.....\n"));
    if(size == 0 && level == 0)
        dbprintf(("(PC SHARE connection problem, is this disk really 
empty?)\n.....\n"));

    if (killctl[1] != -1) {
        dbprintf(("asking killpgrp to terminate\n"));
        aclose(killctl[1]);
        for(s = 5; s > 0; --s) {
            sleep(1);
            if (waitpid(dumppid, NULL, WNOHANG) != -1)
                goto terminated;
        }
    }
    
    /*
     * First, try to kill the dump process nicely.  If it ignores us
     * for several seconds, hit it harder.
     */
    dbprintf(("sending SIGTERM to process group %ld\n", (long) dumppid));
    if (kill(-dumppid, SIGTERM) == -1) {
        dbprintf(("kill failed: %s\n", strerror(errno)));
    }
    /* Now check whether it dies */
    for(s = 5; s > 0; --s) {
        sleep(1);
        if (waitpid(dumppid, NULL, WNOHANG) != -1)
            goto terminated;
    }

    dbprintf(("sending SIGKILL to process group %ld\n", (long) dumppid));
    if (kill(-dumppid, SIGKILL) == -1) {
        dbprintf(("kill failed: %s\n", strerror(errno)));
    }
    for(s = 5; s > 0; --s) {
        sleep(1);
        if (waitpid(dumppid, NULL, WNOHANG) != -1)
            goto terminated;
    }

    dbprintf(("cannot kill it, waiting for normal termination\n"));
    wait(NULL);

 terminated:

    aclose(nullfd);
    afclose(dumpout);

    amfree(device);
    amfree(fstype);

    return size;
}

#ifdef SAMBA_CLIENT
long getsize_smbtar(disk, level, exclude_spec)
     char *disk;
     int level;
     char *exclude_spec;
{
    int pipefd, nullfd, dumppid;
    long size;
    FILE *dumpout;
    char *tarkeys, *sharename, *pass, *domain = NULL;
    char *line;

    if ((pass = findpass(disk, &domain)) == NULL) {
        error("[sendsize : error in smbtar diskline, unable to find password]");
    }
    if ((sharename = makesharename(disk, 0)) == NULL) {
        memset(pass, '\0', strlen(pass));
        amfree(pass);
        if(domain) {
            memset(domain, '\0', strlen(domain));
            amfree(domain);
        }
        error("[sendsize : can't make share name of %s]", disk);
    }
    nullfd = open("/dev/null", O_RDWR);

#if SAMBA_VERSION >= 2
    if (level == 0)
        tarkeys = "archive 0;recurse;du";
    else
        tarkeys = "archive 1;recurse;du";
#else
    if (level == 0)
        tarkeys = "archive 0;recurse;dir";
    else
        tarkeys = "archive 1;recurse;dir";
#endif

    dbprintf(("%s: running \"%s \'%s\' -d %s -U %s -E%s%s -c \'%s\'\"\n",
              get_pname(), SAMBA_CLIENT, sharename,
              SAMBA_DEBUG_LEVEL, "(see amandapass)", domain ? " -W " : "",
              domain ? domain : "", tarkeys));

    dumppid = pipespawn(SAMBA_CLIENT, STDERR_PIPE, &nullfd, &nullfd, &pipefd, 
              "smbclient", sharename,
              "-d", SAMBA_DEBUG_LEVEL,
              "-U", pass,
              "-E",
              domain ? "-W" : skip_argument,
              domain ? domain : skip_argument,
              "-c", tarkeys,
              (char *)0);
    memset(pass, '\0', strlen(pass));
    amfree(pass);
    if(domain) {
        memset(domain, '\0', strlen(domain));
        amfree(domain);
    }
    amfree(sharename);
    dumpout = fdopen(pipefd,"r");

    for(size = -1; (line = agets(dumpout)) != NULL; free(line)) {
        dbprintf(("%s\n",line));
        size = handle_dumpline(line);
        if(size > -1) {
            amfree(line);
            if((line = agets(dumpout)) != NULL) {
                dbprintf(("%s",line));
            }
            break;
        }
    }
    amfree(line);

    dbprintf((".....\n"));
    if(size == -1)
        dbprintf(("(no size line match in above smbclient output)\n.....\n"));
    if(size==0 && level ==0)
        size=-1;

    kill(-dumppid, SIGTERM);

    wait(NULL);

    aclose(nullfd);
    afclose(dumpout);

    return size;
}
#endif

#ifdef GNUTAR
long getsize_gnutar(disk, level, exclude_spec, dumpsince)
char *disk;
int level;
char *exclude_spec;
time_t dumpsince;
{
    int pipefd, nullfd, dumppid;
    long size;
    FILE *dumpout;
    char *incrname = NULL;
    char *dirname = NULL;
    char *exclude_arg = NULL;
    char *efile = NULL, *estr = NULL;
    char *line = NULL;
    char *cmd = NULL;
    char *cmd_line;
    char dumptimestr[80];
    struct tm *gmtm;

#ifdef GNUTAR_LISTED_INCREMENTAL_DIR
    {
      char *basename = NULL;
      char number[NUM_STR_SIZE];
      char *s;
      int ch;

      basename = vstralloc(GNUTAR_LISTED_INCREMENTAL_DIR,
                           "/",
                           host,
                           disk,
                           NULL);
      /*
       * The loop starts at the first character of the host name,
       * not the '/'.
       */
      s = basename + sizeof(GNUTAR_LISTED_INCREMENTAL_DIR);
      while((ch = *s++) != '\0') {
        if(ch == '/' || isspace(ch)) s[-1] = '_';
      }

      ap_snprintf(number, sizeof(number), "%d", level);
      incrname = vstralloc(basename, "_", number, ".new", NULL);
      unlink(incrname);

      if (level == 0) {
        FILE *out;

notincremental:

        out = fopen(incrname, "w");
        if (out == NULL) {
          dbprintf(("error [opening %s: %s]\n", incrname, strerror(errno)));
          amfree(incrname);
          amfree(basename);
          amfree(dirname);
          return -1;
        }

        if (fclose(out) == EOF) {
          dbprintf(("error [closing %s: %s]\n", incrname, strerror(errno)));
          out = NULL;
          amfree(incrname);
          amfree(basename);
          amfree(dirname);
          return -1;
        }
        out = NULL;

      } else {
        FILE *in = NULL, *out;
        char *inputname = NULL;
        char buf[BUFSIZ];
        int baselevel = level;

        while (in == NULL && --baselevel >= 0) {
          ap_snprintf(number, sizeof(number), "%d", baselevel);
          inputname = newvstralloc(inputname, basename, "_", number, NULL);
          in = fopen(inputname, "r");
        }

        if (in == NULL) {
          amfree(inputname);
          goto notincremental;
        }

        out = fopen(incrname, "w");
        if (out == NULL) {
          dbprintf(("error [opening %s: %s]\n", incrname, strerror(errno)));
          amfree(incrname);
          amfree(basename);
          amfree(inputname);
          amfree(dirname);
          return -1;
        }

        while(fgets(buf, sizeof(buf), in) != NULL)
          if (fputs(buf, out) == EOF) {
            dbprintf(("error [writing to %s: %s]\n", incrname,
                      strerror(errno)));
            amfree(incrname);
            amfree(basename);
            amfree(inputname);
            amfree(dirname);
            return -1;
          }

        if (ferror(in)) {
          dbprintf(("error [reading from %s: %s]\n", inputname,
                    strerror(errno)));
          amfree(incrname);
          amfree(basename);
          amfree(inputname);
          amfree(dirname);
          return -1;
        }

        if (fclose(in) == EOF) {
          dbprintf(("error [closing %s: %s]\n", inputname, strerror(errno)));
          in = NULL;
          amfree(incrname);
          amfree(basename);
          amfree(inputname);
          amfree(dirname);
          return -1;
        }
        in = NULL;

        if (fclose(out) == EOF) {
          dbprintf(("error [closing %s: %s]\n", incrname, strerror(errno)));
          out = NULL;
          amfree(incrname);
          amfree(basename);
          amfree(inputname);
          amfree(dirname);
          return -1;
        }
        out = NULL;

        amfree(inputname);
      }
      amfree(basename);
    }
#endif

    gmtm = gmtime(&dumpsince);
    ap_snprintf(dumptimestr, sizeof(dumptimestr),
                "%04d-%02d-%02d %2d:%02d:%02d GMT",
                gmtm->tm_year + 1900, gmtm->tm_mon+1, gmtm->tm_mday,
                gmtm->tm_hour, gmtm->tm_min, gmtm->tm_sec);

    dirname = amname_to_dirname(disk);

    cmd = vstralloc(libexecdir, "/", "runtar", versionsuffix(), NULL);

    if (exclude_spec == NULL) {
        amfree(exclude_arg);
        estr = NULL;
        efile = NULL;
        /* do nothing */
#define sc "--exclude-list="
    } else if (strncmp(exclude_spec, sc, sizeof(sc)-1)==0) {
        char *file = exclude_spec + sizeof(sc)-1;
/* BEGIN HPS */
        if(*file != '/')
          file = vstralloc(dirname,"/",file, NULL);
/* END HPS */
        estr = NULL;
        if (access(file, F_OK) == 0)
            efile = newstralloc(efile, file);
        else {
            dbprintf(("%s: missing exclude list file \"%s\" discarded\n",
                      get_pname(), file));
            amfree(efile);
        }
#undef sc
#define sc "--exclude-file="
    } else if (strncmp(exclude_spec, sc, sizeof(sc)-1)==0) {
      efile = NULL;
      estr = newstralloc(estr, exclude_spec+sizeof(sc)-1);
#undef sc
    } else {
        dbprintf(("error [exclude_spec is neither --exclude-list nor --exclude-file: 
%s]\n", exclude_spec));
        error("error: exclude_spec is neither --exclude-list nor --exclude-file: %s]", 
exclude_spec);
    }

    cmd_line = vstralloc(cmd,
                         " --create",
                         " --directory ", dirname,
#ifdef GNUTAR_LISTED_INCREMENTAL_DIR
                         " --listed-incremental ", incrname,
#else
                         " --incremental",
                         " --newer ", dumptimestr,
#endif
                         " --sparse",
                         " --one-file-system",
#ifdef ENABLE_GNUTAR_ATIME_PRESERVE
                         " --atime-preserve",
#endif
                         " --ignore-failed-read",
                         " --totals",
                         " --file", " /dev/null",
                         " ", 
                         efile ? "--exclude-from" : "",
                         efile ? efile : "",
                         estr ? "--exclude" : "",
                         estr ? estr : "",
                         NULL);

    dbprintf(("%s: running \"%s\"\n", get_pname(), cmd_line));

    nullfd = open("/dev/null", O_RDWR);
    dumppid = pipespawn(cmd, STDERR_PIPE, &nullfd, &nullfd, &pipefd,
#ifdef GNUTAR
              GNUTAR,
#else
              "tar",
#endif
              "--create",
              "--directory", dirname,
#ifdef GNUTAR_LISTED_INCREMENTAL_DIR
              "--listed-incremental", incrname,
#else
              "--incremental", "--newer", dumptimestr,
#endif
              "--sparse",
              "--one-file-system",
#ifdef ENABLE_GNUTAR_ATIME_PRESERVE
              "--atime-preserve",
#endif
              "--ignore-failed-read",
              "--totals",
              "--file", "/dev/null",
              efile ? "--exclude-from" : skip_argument,
              efile ? efile : skip_argument,
              estr ? "--exclude" : skip_argument,
              estr ? estr : skip_argument,
              ".",
              (char *)0);
    if (efile != NULL)
      amfree(efile);
    if (estr != NULL)
      amfree(estr);
    amfree(cmd);

    dumpout = fdopen(pipefd,"r");

    for(size = -1; (line = agets(dumpout)) != NULL; free(line)) {
        dbprintf(("%s\n",line));
        size = handle_dumpline(line);
        if(size > -1) {
            amfree(line);
            if((line = agets(dumpout)) != NULL) {
                dbprintf(("%s\n",line));
            }
            break;
        }
    }
    amfree(line);

    dbprintf((".....\n"));
    if(size == -1)
        dbprintf(("(no size line match in above gnutar output)\n.....\n"));
    if(size==0 && level ==0)
        size=-1;

    kill(-dumppid, SIGTERM);

    unlink(incrname);
    amfree(incrname);
    amfree(dirname);

    wait(NULL);

    aclose(nullfd);
    afclose(dumpout);

    return size;
}
#endif


double first_num(str)
char *str;
/*
 * Returns the value of the first integer in a string.
 */
{
    char *start;
    int ch;
    double d;

    ch = *str++;
    while(ch && !isdigit(ch)) ch = *str++;
    start = str-1;
    while(isdigit(ch) || (ch == '.')) ch = *str++;
    str[-1] = '\0';
    d = atof(start);
    str[-1] = ch;
    return d;
}


long handle_dumpline(str)
char *str;
/*
 * Checks the dump output line against the error and size regex tables.
 */
{
    regex_t *rp;
    double size;

    /* check for size match */
    for(rp = re_size; rp->regex != NULL; rp++) {
        if(match(rp->regex, str)) {
            size = ((first_num(str)*rp->scale+1023.0)/1024.0);
            if(size < 0) size = 1;              /* found on NeXT -- sigh */
            return (long) size;
        }
    }
    return -1;
}

Reply via email to