Imported Upstream version 2.5.1
[debian/amanda] / server-src / reporter.c
index 43cf3fe6f474f598e1f84a1151398817e48afc07..73acd3d183f1d79c8cdc095201f46691d0d39841 100644 (file)
  *                        University of Maryland at College Park
  */
 /*
- * $Id: reporter.c,v 1.105 2006/03/09 16:51:42 martinea Exp $
+ * $Id: reporter.c,v 1.132 2006/08/28 17:02:48 martinea Exp $
  *
  * nightly Amanda Report generator
  */
 /*
-report format
-    tape label message
-    error messages
-    summary stats
-    details for errors
-    notes
-    success summary
-*/
+ * report format
*     tape label message
*     error messages
*     summary stats
*     details for errors
*     notes
*     success summary
+ */
 
 #include "amanda.h"
 #include "conffile.h"
@@ -58,9 +58,9 @@ typedef struct line_s {
 
 typedef struct timedata_s {
     logtype_t result;
-    float origsize, outsize;
+    double origsize, outsize;
     char *datestamp;
-    float sec, kps;
+    double sec, kps;
     int filenum;
     char *tapelabel;
 } timedata_t;
@@ -68,6 +68,7 @@ typedef struct timedata_s {
 typedef struct repdata_s {
     disk_t *disk;
     char *datestamp;
+    double est_nsize, est_csize;
     timedata_t taper;
     timedata_t dumper;
     timedata_t chunker;
@@ -90,7 +91,7 @@ typedef struct taper_s {
     char *label;
     double taper_time;
     double coutsize, corigsize;
-  int tapedisks, tapechunks;
+    int tapedisks, tapechunks;
     struct taper_s *next;
 } taper_t;
 
@@ -107,13 +108,12 @@ typedef struct strange_s {
 
 static strange_t *first_strange=NULL, *last_strange=NULL;
 
-static float total_time, startup_time, planner_time;
+static double total_time, startup_time, planner_time;
 
 /* count files to tape */
 static int tapefcount = 0;
 
 static char *run_datestamp;
-static char *today_datestamp;
 static char *tape_labels = NULL;
 static int last_run_tapes = 0;
 static int degraded_mode = 0; /* defined in driverio too */
@@ -141,44 +141,54 @@ char *displayunit;
 long int unitdivisor;
 
 /* local functions */
-static int contline_next P((void));
-static void addline P((line_t **lp, char *str));
-static void usage P((void));
-int main P((int argc, char **argv));
-
-static void copy_template_file P((char *lbl_templ));
-static void do_postscript_output P((void));
-static void handle_start P((void));
-static void handle_finish P((void));
-static void handle_note P((void));
-static void handle_summary P((void));
-static void handle_stats P((void));
-static void handle_error P((void));
-static void handle_disk P((void));
-static repdata_t *handle_success P((logtype_t logtype));
-static repdata_t *handle_chunk P((void));
-static void handle_partial P((void));
-static void handle_strange P((void));
-static void handle_failed P((void));
-static void generate_missing P((void));
-static void output_tapeinfo P((void));
-static void output_lines P((line_t *lp, FILE *f));
-static void output_stats P((void));
-static void output_summary P((void));
-static void output_strange P((void));
-static void sort_disks P((void));
-static int sort_by_name P((disk_t *a, disk_t *b));
-static void bogus_line P((void));
-static char *nicedate P((int datestamp));
-static char *prefix P((char *host, char *disk, int level));
-static char *prefixstrange P((char *host, char *disk, int level, int len_host, int len_disk));
-static void addtostrange P((char *host, char *disk, int level, char *str));
-static repdata_t *find_repdata P((disk_t *dp, char *datestamp, int level));
-
+int main(int argc, char **argv);
+
+static char *  nicedate(const char * datestamp);
+static char *  prefix(char *host, char *disk, int level);
+static char *  prefixstrange(char *host, char *disk, int level,
+                       size_t len_host, size_t len_disk);
+static char *  Rule(int From, int To);
+static char *  sDivZero(double a, double b, int cn);
+static char *  TextRule(int From, int To, char *s);
+static int     ColWidth(int From, int To);
+static int     contline_next(void);
+static int     sort_by_name(disk_t *a, disk_t *b);
+static repdata_t *find_repdata(disk_t *dp, char *datestamp, int level);
+static repdata_t *handle_chunk(void);
+static repdata_t *handle_success(logtype_t logtype);
+static void    addline(line_t **lp, char *str);
+static void    addtostrange(char *host, char *disk, int level, char *str);
+static void    bogus_line(const char *);
+static void    CalcMaxWidth(void);
+static void    CheckFloatMax(ColumnInfo *cd, double d);
+static void    CheckIntMax(ColumnInfo *cd, int n);
+static void    CheckStringMax(ColumnInfo *cd, char *s);
+static void    copy_template_file(char *lbl_templ);
+static void    do_postscript_output(void);
+static void    generate_missing(void);
+static void    generate_bad_estimate(void);
+static void    handle_disk(void);
+static void    handle_error(void);
+static void    handle_failed(void);
+static void    handle_finish(void);
+static void    handle_note(void);
+static void    handle_partial(void);
+static void    handle_start(void);
+static void    handle_stats(void);
+static void    handle_strange(void);
+static void    handle_summary(void);
+static void    output_lines(line_t *lp, FILE *f);
+static void    output_stats(void);
+static void    output_strange(void);
+static void    output_summary(void);
+static void    output_tapeinfo(void);
+static void    sort_disks(void);
+static void    usage(void);
 
 static int
-ColWidth(From, To)
-    int From, To;
+ColWidth(
+    int                From,
+    int                To)
 {
     int i, Width= 0;
     for (i=From; i<=To && ColumnData[i].Name != NULL; i++) {
@@ -188,12 +198,13 @@ ColWidth(From, To)
 }
 
 static char *
-Rule(From, To)
-    int From, To;
+Rule(
+    int                From,
+    int                To)
 {
     int i, ThisLeng;
     int Leng= ColWidth(0, ColumnDataCount());
-    char *RuleSpace= alloc(Leng+1);
+    char *RuleSpace= alloc((size_t)(Leng+1));
     ThisLeng= ColWidth(From, To);
     for (i=0;i<ColumnData[From].PrefixSpace; i++)
        RuleSpace[i]= ' ';
@@ -204,19 +215,21 @@ Rule(From, To)
 }
 
 static char *
-TextRule(From, To, s)
-    int From, To;
-    char *s;
+TextRule(
+    int                From,
+    int                To,
+    char *     s)
 {
     ColumnInfo *cd= &ColumnData[From];
-    int leng, nbrules, i, txtlength;
+    int leng;
+    int nbrules, i, txtlength;
     int RuleSpaceSize= ColWidth(0, ColumnDataCount());
-    char *RuleSpace= alloc(RuleSpaceSize), *tmp;
+    char *RuleSpace= alloc((size_t)RuleSpaceSize), *tmp;
 
-    lengstrlen(s);
+    leng = (int)strlen(s);
     if(leng >= (RuleSpaceSize - cd->PrefixSpace))
        leng = RuleSpaceSize - cd->PrefixSpace - 1;
-    snprintf(RuleSpace, RuleSpaceSize, "%*s%*.*s ", cd->PrefixSpace, "", 
+    snprintf(RuleSpace, (size_t)RuleSpaceSize, "%*s%*.*s ", cd->PrefixSpace, "", 
             leng, leng, s);
     txtlength = cd->PrefixSpace + leng + 1;
     nbrules = ColWidth(From,To) - txtlength;
@@ -227,60 +240,74 @@ TextRule(From, To, s)
 }
 
 static char *
-sDivZero(a, b, cn)
-    double a, b;
-    int cn;
+sDivZero(
+    double     a,
+    double     b,
+    int                cn)
 {
     ColumnInfo *cd= &ColumnData[cn];
     static char PrtBuf[256];
-    if (b == 0.0)
-       snprintf(PrtBuf, sizeof(PrtBuf),
+    if (!isnormal(b))
+       snprintf(PrtBuf, SIZEOF(PrtBuf),
          "%*s", cd->Width, "-- ");
     else
-       snprintf(PrtBuf, sizeof(PrtBuf),
+       snprintf(PrtBuf, SIZEOF(PrtBuf),
          cd->Format, cd->Width, cd->Precision, a/b);
     return PrtBuf;
 }
 
 static int
-contline_next()
+contline_next(void)
 {
     int ch;
 
-    ch = getc(logfile);
-    ungetc(ch, logfile);
-
+    if ((ch = getc(logfile)) != EOF) {
+           if (ungetc(ch, logfile) == EOF) {
+               if (ferror(logfile)) {
+                   error("ungetc failed: %s\n", strerror(errno));
+                   /*NOTREACHED*/
+               }
+               error("ungetc failed: EOF\n");
+               /*NOTREACHED*/
+           }
+    }
     return ch == ' ';
 }
 
 static void
-addline(lp, str)
-    line_t **lp;
-    char *str;
+addline(
+    line_t **  lp,
+    char *     str)
 {
-    line_t *new, *p, *q;
+    line_t *new, *p;
 
     /* allocate new line node */
-    new = (line_t *) alloc(sizeof(line_t));
+    new = (line_t *) alloc(SIZEOF(line_t));
     new->next = NULL;
     new->str = stralloc(str);
 
     /* add to end of list */
-    for(p = *lp, q = NULL; p != NULL; q = p, p = p->next);
-    if(q == NULL) *lp = new;
-    else q->next = new;
+    p = *lp;
+    if (p == NULL) {
+       *lp = new;
+    } else {
+       while (p->next != NULL)
+           p = p->next;
+       p->next = new;  
+    }
 }
 
 static void
-usage()
+usage(void)
 {
-    error("Usage: amreport conf [-f output-file] [-l logfile] [-p postscript-file]");
+    error("Usage: amreport conf [-i] [-M address] [-f output-file] [-l logfile] [-p postscript-file] [-o configoption]*");
+    /*NOTREACHED*/
 }
 
 int
-main(argc, argv)
-    int argc;
-    char **argv;
+main(
+    int                argc,
+    char **    argv)
 {
     char *conffile;
     char *conf_diskfile;
@@ -297,11 +324,18 @@ main(argc, argv)
     char *ColumnSpec = "";
     char *errstr = NULL;
     int cn;
+    int mailout = 1;
+    char *mailto = NULL;
+    int    new_argc,   my_argc;
+    char **new_argv, **my_argv;
+    char *lbl_templ = NULL;
 
     safe_fd(-1, 0);
 
     set_pname("amreport");
 
+    dbopen(DBG_SUBDIR_SERVER);
+
     /* Don't die when child closes pipe */
     signal(SIGPIPE, SIG_IGN);
 
@@ -314,28 +348,48 @@ main(argc, argv)
     psfname = NULL;
     logfname = NULL;
 
-    if (getcwd(my_cwd, sizeof(my_cwd)) == NULL) {
+    if (getcwd(my_cwd, SIZEOF(my_cwd)) == NULL) {
        error("cannot determine current working directory");
+       /*NOTREACHED*/
     }
 
-    if (argc < 2) {
+    parse_server_conf(argc, argv, &new_argc, &new_argv);
+    my_argc = new_argc;
+    my_argv = new_argv;
+
+    if (my_argc < 2) {
        config_dir = stralloc2(my_cwd, "/");
        if ((config_name = strrchr(my_cwd, '/')) != NULL) {
            config_name = stralloc(config_name + 1);
        }
     } else {
-       if (argv[1][0] == '-') {
+       if (my_argv[1][0] == '-') {
            usage();
            return 1;
        }
-       config_name = stralloc(argv[1]);
+       config_name = stralloc(my_argv[1]);
        config_dir = vstralloc(CONFIG_DIR, "/", config_name, "/", NULL);
-       --argc; ++argv;
-       while((opt = getopt(argc, argv, "f:l:p:")) != EOF) {
+       --my_argc; ++my_argv;
+       while((opt = getopt(my_argc, my_argv, "M:f:l:p:i")) != EOF) {
            switch(opt) {
+           case 'i': 
+               mailout = 0;
+               break;
+            case 'M':
+               if (mailto != NULL) {
+                   error("you may specify at most one -M");
+                   /*NOTREACHED*/
+               }
+                mailto = stralloc(optarg);
+               if(!validate_mailto(mailto)) {
+                   error("mail address has invalid characters");
+                   /*NOTREACHED*/
+               }
+                break;
             case 'f':
                if (outfname != NULL) {
                    error("you may specify at most one -f");
+                   /*NOTREACHED*/
                }
                if (*optarg == '/') {
                     outfname = stralloc(optarg);
@@ -346,6 +400,7 @@ main(argc, argv)
             case 'l':
                if (logfname != NULL) {
                    error("you may specify at most one -l");
+                   /*NOTREACHED*/
                }
                if (*optarg == '/') {
                    logfname = stralloc(optarg);
@@ -356,6 +411,7 @@ main(argc, argv)
             case 'p':
                if (psfname != NULL) {
                    error("you may specify at most one -p");
+                   /*NOTREACHED*/
                }
                if (*optarg == '/') {
                     psfname = stralloc(optarg);
@@ -364,21 +420,22 @@ main(argc, argv)
                }
                 break;
             case '?':
-            default:
                usage();
                return 1;
+            default:
+               break;
            }
        }
 
-       argc -= optind;
-       argv += optind;
-
-       if (argc > 1) {
-           usage();
-           return 1;
-       }
+       my_argc -= optind;
+       my_argv += optind;
+    }
+    if( !mailout && mailto ){
+       printf("You cannot specify both -i & -M at the same time\n");
+       exit(1);
     }
 
+
 #if !defined MAILER
     if(!outfname) {
        printf("You must run amreport with '-f <output file>' because configure\n");
@@ -392,29 +449,38 @@ main(argc, argv)
     /* read configuration files */
 
     conffile = stralloc2(config_dir, CONFFILE_NAME);
-    if(read_conffile(conffile)) {
-        error("errors processing config file \"%s\"", conffile);
-    }
+    /* Ignore error from read_conffile */
+    read_conffile(conffile);
     amfree(conffile);
+
+    dbrename(config_name, DBG_SUBDIR_SERVER);
+
+    report_bad_conf_arg();
     conf_diskfile = getconf_str(CNF_DISKFILE);
     if (*conf_diskfile == '/') {
        conf_diskfile = stralloc(conf_diskfile);
     } else {
        conf_diskfile = stralloc2(config_dir, conf_diskfile);
     }
-    if(read_diskfile(conf_diskfile, &diskq) < 0) {
-       error("could not load disklist \"%s\"", conf_diskfile);
-    }
+    /* Ignore error from read_diskfile */
+    read_diskfile(conf_diskfile, &diskq);
     amfree(conf_diskfile);
+    if(mailout && !mailto && 
+       getconf_seen(CNF_MAILTO) && strlen(getconf_str(CNF_MAILTO)) > 0) {
+               mailto = getconf_str(CNF_MAILTO);
+                if(!validate_mailto(mailto)){
+                  mailto = NULL;
+                }
+    }
+    
     conf_tapelist = getconf_str(CNF_TAPELIST);
     if (*conf_tapelist == '/') {
        conf_tapelist = stralloc(conf_tapelist);
     } else {
        conf_tapelist = stralloc2(config_dir, conf_tapelist);
     }
-    if(read_tapelist(conf_tapelist)) {
-       error("could not read tapelist \"%s\"", conf_tapelist);
-    }
+    /* Ignore error from read_tapelist */
+    read_tapelist(conf_tapelist);
     amfree(conf_tapelist);
     conf_infofile = getconf_str(CNF_INFOFILE);
     if (*conf_infofile == '/') {
@@ -424,11 +490,10 @@ main(argc, argv)
     }
     if(open_infofile(conf_infofile)) {
        error("could not open info db \"%s\"", conf_infofile);
+       /*NOTREACHED*/
     }
     amfree(conf_infofile);
 
-    today_datestamp = construct_datestamp(NULL);
-
     displayunit = getconf_str(CNF_DISPLAYUNIT);
     unitdivisor = getconf_unit_divisor();
 
@@ -515,13 +580,15 @@ main(argc, argv)
     }
     afclose(logfile);
     close_infofile();
-    if(!amflush_run)
+    if(!amflush_run) {
        generate_missing();
+       generate_bad_estimate();
+    }
 
     subj_str = vstralloc(getconf_str(CNF_ORG),
                         " ", amflush_run ? "AMFLUSH" : "AMANDA",
                         " ", "MAIL REPORT FOR",
-                        " ", nicedate(run_datestamp ? atoi(run_datestamp) : 0),
+                        " ", nicedate(run_datestamp ? run_datestamp : "0"),
                         NULL);
        
     /* lookup the tapetype and printer type from the amanda.conf file. */
@@ -537,19 +604,30 @@ main(argc, argv)
        /* output to a file */
        if((mailf = fopen(outfname,"w")) == NULL) {
            error("could not open output file: %s %s", outfname, strerror(errno));
+           /*NOTREACHED*/
        }
-       fprintf(mailf, "To: %s\n", getconf_str(CNF_MAILTO));
+       fprintf(mailf, "To: %s\n", mailto);
        fprintf(mailf, "Subject: %s\n\n", subj_str);
 
     } else {
 #ifdef MAILER
-       mail_cmd = vstralloc(MAILER,
+       if(mailto) {
+               mail_cmd = vstralloc(MAILER,
                             " -s", " \"", subj_str, "\"",
-                            " ", getconf_str(CNF_MAILTO),
-                            NULL);
-       if((mailf = popen(mail_cmd, "w")) == NULL)
-           error("could not open pipe to \"%s\": %s",
-                 mail_cmd, strerror(errno));
+                            " ", mailto, NULL);
+               if((mailf = popen(mail_cmd, "w")) == NULL) {
+               error("could not open pipe to \"%s\": %s",
+                       mail_cmd, strerror(errno));
+               /*NOTREACHED*/
+               }
+       }
+       else {
+               if(mailout) {
+                   printf("No mail sent! ");
+                  printf("No valid mail address has been specified in amanda.conf or on the commmand line\n");
+               }
+               mailf = NULL;
+       }
 #endif
     }
 
@@ -559,7 +637,9 @@ main(argc, argv)
        /* if the postscript_label_template (tp->lbl_templ) field is not */
        /* the empty string (i.e. it is set to something), open the      */
        /* postscript debugging file for writing.                        */
-       if ((strcmp(tp->lbl_templ, "")) != 0) {
+       if (tp)
+           lbl_templ = tapetype_get_lbl_templ(tp);
+       if (tp && lbl_templ && strcmp(lbl_templ, "") != 0) {
            if ((postscript = fopen(psfname, "w")) == NULL) {
                curlog = L_ERROR;
                curprog = P_REPORTER;
@@ -585,8 +665,9 @@ main(argc, argv)
            /* print to the default printer */
            printer_cmd = vstralloc(LPRCMD, NULL);
 #endif
-
-       if ((strcmp(tp->lbl_templ, "")) != 0) {
+       if (tp)
+           lbl_templ = tapetype_get_lbl_templ(tp);
+       if (tp && lbl_templ && strcmp(lbl_templ, "") != 0) {
 #ifdef LPRCMD
            if ((postscript = popen(printer_cmd, "w")) == NULL) {
                curlog = L_ERROR;
@@ -611,35 +692,37 @@ main(argc, argv)
 
     amfree(subj_str);
 
+    if(mailf) {
 
-    if(!got_finish) fputs("*** THE DUMPS DID NOT FINISH PROPERLY!\n\n", mailf);
-
-    output_tapeinfo();
-
-    if(first_strange || errsum) {
-       fprintf(mailf,"\nFAILURE AND STRANGE DUMP SUMMARY:\n");
-       if(first_strange) output_strange();
-       if(errsum) output_lines(errsum, mailf);
-    }
-    fputs("\n\n", mailf);
+       if(!got_finish) fputs("*** THE DUMPS DID NOT FINISH PROPERLY!\n\n", mailf);
 
-    output_stats();
+       output_tapeinfo();
 
-    if(errdet) {
-       fprintf(mailf,"\n\014\nFAILED AND STRANGE DUMP DETAILS:\n");
-       output_lines(errdet, mailf);
-    }
-    if(notes) {
-       fprintf(mailf,"\n\014\nNOTES:\n");
-       output_lines(notes, mailf);
-    }
-    sort_disks();
-    if(sortq.head != NULL) {
-       fprintf(mailf,"\n\014\nDUMP SUMMARY:\n");
-       output_summary();
+       if(first_strange || errsum) {
+               fprintf(mailf,"\nFAILURE AND STRANGE DUMP SUMMARY:\n");
+               if(first_strange) output_strange();
+               if(errsum) output_lines(errsum, mailf);
+       }
+       fputs("\n\n", mailf);
+       
+       output_stats();
+       
+       if(errdet) {
+               fprintf(mailf,"\n\014\nFAILED AND STRANGE DUMP DETAILS:\n");
+               output_lines(errdet, mailf);
+       }
+       if(notes) {
+               fprintf(mailf,"\n\014\nNOTES:\n");
+               output_lines(notes, mailf);
+       }
+       sort_disks();
+       if(sortq.head != NULL) {
+               fprintf(mailf,"\n\014\nDUMP SUMMARY:\n");
+               output_summary();
+       }
+       fprintf(mailf,"\n(brought to you by Amanda version %s)\n",
+               version());
     }
-    fprintf(mailf,"\n(brought to you by Amanda version %s)\n",
-           version());
 
     if (postscript) {
        do_postscript_output();
@@ -652,8 +735,10 @@ main(argc, argv)
        afclose(postscript);
     }
     else {
-       if (postscript != NULL && pclose(postscript) != 0)
+       if (postscript != NULL && pclose(postscript) != 0) {
            error("printer command failed: %s", printer_cmd);
+           /*NOTREACHED*/
+       }
        postscript = NULL;
     }
 
@@ -661,12 +746,18 @@ main(argc, argv)
     if(outfname) {
         afclose(mailf);
     }
-    else {
-        if(pclose(mailf) != 0)
+    else if(mailf) {
+        if(pclose(mailf) != 0) {
             error("mail command failed: %s", mail_cmd);
+           /*NOTREACHED*/
+       }
         mailf = NULL;
     }
 
+    clear_tapelist();
+    free_disklist(&diskq);
+    free_new_argv(new_argc, new_argv);
+    free_server_config();
     amfree(run_datestamp);
     amfree(tape_labels);
     amfree(config_dir);
@@ -681,6 +772,7 @@ main(argc, argv)
        malloc_list(fileno(stderr), malloc_hist_1, malloc_hist_2);
     }
 
+    dbclose();
     return 0;
 }
 
@@ -695,33 +787,40 @@ main(argc, argv)
 #define divzero(fp,a,b)                            \
     do {                                           \
        double q = (b);                     \
-       if (q == 0.0)                       \
+       if (!isnormal(q))                   \
            fprintf((fp),"  -- ");          \
        else if ((q = (a)/q) >= 999.95)     \
            fprintf((fp), "###.#");         \
        else                                \
-           fprintf((fp), "%5.1f",q);       \
+           fprintf((fp), "%5.1lf",q);      \
     } while(0)
 #define divzero_wide(fp,a,b)               \
     do {                                           \
        double q = (b);                     \
-       if (q == 0.0)                       \
+       if (!isnormal(q))                   \
            fprintf((fp),"    -- ");        \
        else if ((q = (a)/q) >= 99999.95)   \
            fprintf((fp), "#####.#");       \
        else                                \
-           fprintf((fp), "%7.1f",q);       \
+           fprintf((fp), "%7.1lf",q);      \
     } while(0)
 
 static void
-output_stats()
+output_stats(void)
 {
     double idle_time;
     tapetype_t *tp = lookup_tapetype(getconf_str(CNF_TAPETYPE));
-    int tapesize, marksize, lv, first;
+    off_t tapesize;
+    off_t marksize;
+    int lv, first;
 
-    tapesize = tp->length;
-    marksize = tp->filemark;
+    if (tp) {
+       tapesize = tapetype_get_length(tp);
+       marksize = tapetype_get_filemark(tp);
+    } else {
+       tapesize = 100 * 1024 * 1024;
+       marksize = 1   * 1024 * 1024;
+    }
 
     stats[2].dumpdisks   = stats[0].dumpdisks   + stats[1].dumpdisks;
     stats[2].tapedisks   = stats[0].tapedisks   + stats[1].tapedisks;
@@ -758,11 +857,11 @@ output_stats()
            hrmn(stats[1].dumper_time));
 
     fprintf(mailf,
-           "Output Size (meg)      %8.1f   %8.1f   %8.1f\n",
+           "Output Size (meg)      %8.1lf   %8.1lf   %8.1lf\n",
            mb(stats[2].outsize), mb(stats[0].outsize), mb(stats[1].outsize));
 
     fprintf(mailf,
-           "Original Size (meg)    %8.1f   %8.1f   %8.1f\n",
+           "Original Size (meg)    %8.1lf   %8.1lf   %8.1lf\n",
            mb(stats[2].origsize), mb(stats[0].origsize),
            mb(stats[1].origsize));
 
@@ -806,16 +905,16 @@ output_stats()
            hrmn(stats[1].taper_time));
 
     fprintf(mailf,
-           "Tape Size (meg)        %8.1f   %8.1f   %8.1f\n",
+           "Tape Size (meg)        %8.1lf   %8.1lf   %8.1lf\n",
            mb(stats[2].tapesize), mb(stats[0].tapesize),
            mb(stats[1].tapesize));
 
     fprintf(mailf, "Tape Used (%%)             ");
-    divzero(mailf, pct(stats[2].tapesize+marksize*(stats[2].tapedisks+stats[2].tapechunks)),tapesize);
+    divzero(mailf, pct(stats[2].tapesize+marksize*(stats[2].tapedisks+stats[2].tapechunks)),(double)tapesize);
     fputs("      ", mailf);
-    divzero(mailf, pct(stats[0].tapesize+marksize*(stats[0].tapedisks+stats[0].tapechunks)),tapesize);
+    divzero(mailf, pct(stats[0].tapesize+marksize*(stats[0].tapedisks+stats[0].tapechunks)),(double)tapesize);
     fputs("      ", mailf);
-    divzero(mailf, pct(stats[1].tapesize+marksize*(stats[1].tapedisks+stats[1].tapechunks)),tapesize);
+    divzero(mailf, pct(stats[1].tapesize+marksize*(stats[1].tapedisks+stats[1].tapechunks)),(double)tapesize);
 
     if(stats[1].tapedisks > 0) fputs("   (level:#disks ...)", mailf);
     putc('\n', mailf);
@@ -862,7 +961,7 @@ output_stats()
     putc('\n', mailf);
 
     if(stats_by_tape) {
-       int label_length = strlen(stats_by_tape->label) + 5;
+       int label_length = (int)strlen(stats_by_tape->label) + 5;
        fprintf(mailf,"\nUSAGE BY TAPE:\n");
        fprintf(mailf,"  %-*s  Time      Size      %%    Nb    Nc\n",
                label_length, "Label");
@@ -870,21 +969,20 @@ output_stats()
            current_tape = current_tape->next) {
            fprintf(mailf, "  %-*s", label_length, current_tape->label);
            fprintf(mailf, " %2d:%02d", hrmn(current_tape->taper_time));
-           fprintf(mailf, " %8.0f%s  ", du(current_tape->coutsize), displayunit);
-           divzero(mailf, pct(current_tape->coutsize + 
-                              marksize * (current_tape->tapedisks+current_tape->tapechunks)),
-                          tapesize);
+           fprintf(mailf, " %8.0lf%s  ", du(current_tape->coutsize), displayunit);
+           divzero(mailf, pct(current_tape->coutsize + marksize *
+                  (current_tape->tapedisks+current_tape->tapechunks)),
+                  (double)tapesize);
            fprintf(mailf, "  %4d", current_tape->tapedisks);
            fprintf(mailf, "  %4d\n", current_tape->tapechunks);
        }
     }
-
 }
 
 /* ----- */
 
 static void
-output_tapeinfo()
+output_tapeinfo(void)
 {
     tape_t *tp, *lasttp;
     int run_tapes;
@@ -921,10 +1019,15 @@ output_tapeinfo()
                run_tapes);
     
     while(run_tapes > 0) {
-       if(tp != NULL)
+       if(tp != NULL) {
            fprintf(mailf, "%s", tp->label);
-       else
-           fputs("a new tape", mailf);
+       } else {
+           if (run_tapes == 1)
+               fprintf(mailf, "a new tape");
+           else
+               fprintf(mailf, "%d new tapes", run_tapes);
+           run_tapes = 1;
+       }
 
        if(run_tapes > 1) fputs(", ", mailf);
 
@@ -936,9 +1039,9 @@ output_tapeinfo()
 
     lasttp = lookup_tapepos(lookup_nb_tape());
     run_tapes = getconf_int(CNF_RUNTAPES);
-    if(lasttp && run_tapes > 0 && lasttp->datestamp == 0) {
+    if(lasttp && run_tapes > 0 && strcmp(lasttp->datestamp,"0") == 0) {
        int c = 0;
-       while(lasttp && run_tapes > 0 && lasttp->datestamp == 0) {
+       while(lasttp && run_tapes > 0 && strcmp(lasttp->datestamp,"0") == 0) {
            c++;
            lasttp = lasttp->prev;
            run_tapes--;
@@ -953,7 +1056,7 @@ output_tapeinfo()
                    lasttp->label);
            lasttp = lasttp->prev;
            c--;
-           while(lasttp && c > 0 && lasttp->datestamp == 0) {
+           while(lasttp && c > 0 && strcmp(lasttp->datestamp,"0") == 0) {
                fprintf(mailf, ", %s", lasttp->label);
                lasttp = lasttp->prev;
                c--;
@@ -964,9 +1067,10 @@ output_tapeinfo()
 }
 
 /* ----- */
-static void output_strange()
+static void
+output_strange(void)
 {
-    int len_host=0, len_disk=0;
+    size_t len_host=0, len_disk=0;
     strange_t *strange;
     char *str = NULL;
 
@@ -980,13 +1084,14 @@ static void output_strange()
        str = vstralloc("  ", prefixstrange(strange->hostname, strange->diskname, strange->level, len_host, len_disk),
                        "  ", strange->str, NULL);
        fprintf(mailf, "%s\n", str);
+       amfree(str);
     }
 }
 
 static void
-output_lines(lp, f)
-    line_t *lp;
-    FILE *f;
+output_lines(
+    line_t *   lp,
+    FILE *     f)
 {
     line_t *next;
 
@@ -1003,8 +1108,9 @@ output_lines(lp, f)
 /* ----- */
 
 static int
-sort_by_name(a, b)
-    disk_t *a, *b;
+sort_by_name(
+    disk_t *   a,
+    disk_t *   b)
 {
     int rc;
 
@@ -1014,7 +1120,7 @@ sort_by_name(a, b)
 }
 
 static void
-sort_disks()
+sort_disks(void)
 {
     disk_t *dp;
 
@@ -1029,44 +1135,46 @@ sort_disks()
 }
 
 static void
-CheckStringMax(cd, s)
-    ColumnInfo *cd;
-    char *s;
+CheckStringMax(
+    ColumnInfo *cd,
+    char *     s)
 {
     if (cd->MaxWidth) {
-       int l= strlen(s);
+       int l = (int)strlen(s);
+
        if (cd->Width < l)
            cd->Width= l;
     }
 }
 
 static void
-CheckIntMax(cd, n)
-    ColumnInfo *cd;
-    int n;
+CheckIntMax(
+    ColumnInfo *cd,
+    int                n)
 {
     if (cd->MaxWidth) {
        char testBuf[200];
        int l;
-       snprintf(testBuf, sizeof(testBuf),
+
+       snprintf(testBuf, SIZEOF(testBuf),
          cd->Format, cd->Width, cd->Precision, n);
-       lstrlen(testBuf);
+       l = (int)strlen(testBuf);
        if (cd->Width < l)
            cd->Width= l;
     }
 }
 
 static void
-CheckFloatMax(cd, d)
-    ColumnInfo *cd;
-    double d;
+CheckFloatMax(
+    ColumnInfo *cd,
+    double     d)
 {
     if (cd->MaxWidth) {
        char testBuf[200];
        int l;
-       snprintf(testBuf, sizeof(testBuf),
+       snprintf(testBuf, SIZEOF(testBuf),
          cd->Format, cd->Width, cd->Precision, d);
-       lstrlen(testBuf);
+       l = (int)strlen(testBuf);
        if (cd->Width < l)
            cd->Width= l;
     }
@@ -1084,7 +1192,7 @@ static int TapeTime;
 static int TapeRate;
 
 static void
-CalcMaxWidth()
+CalcMaxWidth(void)
 {
     /* we have to look for columspec's, that require the recalculation.
      * we do here the same loops over the sortq as is done in
@@ -1093,12 +1201,11 @@ CalcMaxWidth()
      *                                                 ElB, 1999-02-24.
      */
     disk_t *dp;
-    float f;
+    double f;
     repdata_t *repdata;
     for(dp = sortq.head; dp != NULL; dp = dp->next) {
       if(dp->todo) {
        for(repdata = data(dp); repdata != NULL; repdata = repdata->next) {
-           ColumnInfo *cd;
            char TimeRateBuffer[40];
 
            CheckStringMax(&ColumnData[HostName], dp->host->hostname);
@@ -1109,8 +1216,10 @@ CalcMaxWidth()
            CheckIntMax(&ColumnData[Level], repdata->level);
             if(repdata->dumper.result == L_SUCCESS || 
                    repdata->dumper.result == L_CHUNKSUCCESS) {
-               CheckFloatMax(&ColumnData[OrigKB], du(repdata->dumper.origsize));
-               CheckFloatMax(&ColumnData[OutKB], du(repdata->dumper.outsize));
+               CheckFloatMax(&ColumnData[OrigKB],
+                             (double)du(repdata->dumper.origsize));
+               CheckFloatMax(&ColumnData[OutKB],
+                             (double)du(repdata->dumper.outsize));
                if(dp->compress == COMP_NONE)
                    f = 0.0;
                else 
@@ -1119,43 +1228,41 @@ CalcMaxWidth()
                        sDivZero(pct(repdata->dumper.outsize), f, Compress));
 
                if(!amflush_run)
-                   snprintf(TimeRateBuffer, sizeof(TimeRateBuffer),
+                   snprintf(TimeRateBuffer, SIZEOF(TimeRateBuffer),
                                "%3d:%02d", mnsc(repdata->dumper.sec));
                else
-                   snprintf(TimeRateBuffer, sizeof(TimeRateBuffer),
+                   snprintf(TimeRateBuffer, SIZEOF(TimeRateBuffer),
                                "N/A ");
                CheckStringMax(&ColumnData[DumpTime], TimeRateBuffer);
 
                CheckFloatMax(&ColumnData[DumpRate], repdata->dumper.kps); 
            }
 
-           cd= &ColumnData[TapeTime];
            if(repdata->taper.result == L_FAIL) {
-               CheckStringMax(cd, "FAILED");
+               CheckStringMax(&ColumnData[TapeTime], "FAILED");
                continue;
            }
            if(repdata->taper.result == L_SUCCESS ||
               repdata->taper.result == L_CHUNKSUCCESS)
-               snprintf(TimeRateBuffer, sizeof(TimeRateBuffer), 
+               snprintf(TimeRateBuffer, SIZEOF(TimeRateBuffer), 
                  "%3d:%02d", mnsc(repdata->taper.sec));
            else
-               snprintf(TimeRateBuffer, sizeof(TimeRateBuffer),
+               snprintf(TimeRateBuffer, SIZEOF(TimeRateBuffer),
                  "N/A ");
-           CheckStringMax(cd, TimeRateBuffer);
+           CheckStringMax(&ColumnData[TapeTime], TimeRateBuffer);
 
-           cd= &ColumnData[TapeRate];
            if(repdata->taper.result == L_SUCCESS ||
                    repdata->taper.result == L_CHUNKSUCCESS)
-               CheckFloatMax(cd, repdata->taper.kps);
+               CheckFloatMax(&ColumnData[TapeRate], repdata->taper.kps);
            else
-               CheckStringMax(cd, "N/A ");
+               CheckStringMax(&ColumnData[TapeRate], "N/A ");
        }
       }
     }
 }
 
 static void
-output_summary()
+output_summary(void)
 {
     disk_t *dp;
     repdata_t *repdata;
@@ -1164,8 +1271,8 @@ output_summary()
     char *tmp;
 
     int i, h, w1, wDump, wTape;
-    float outsize, origsize;
-    float f;
+    double outsize, origsize;
+    double f;
 
     HostName = StringToColumn("HostName");
     Disk = StringToColumn("Disk");
@@ -1188,19 +1295,19 @@ output_summary()
     wTape= ColWidth(TapeTime, TapeRate);
 
     /* print centered top titles */
-    hstrlen(ds);
+    h = (int)strlen(ds);
     if (h > wDump) {
-       h= 0;
+       h = 0;
     } else {
-       h= (wDump-h)/2;
+       h = (wDump-h)/2;
     }
     fprintf(mailf, "%*s", w1+h, "");
     fprintf(mailf, "%-*s", wDump-h, ds);
-    hstrlen(ts);
+    h = (int)strlen(ts);
     if (h > wTape) {
-       h= 0;
+       h = 0;
     } else {
-       h= (wTape-h)/2;
+       h = (wTape-h)/2;
     }
     fprintf(mailf, "%*s", h, "");
     fprintf(mailf, "%-*s", wTape-h, ts);
@@ -1240,7 +1347,8 @@ output_summary()
        ColumnInfo *cd;
        char TimeRateBuffer[40];
        for(repdata = data(dp); repdata != NULL; repdata = repdata->next) {
-           int devlen;
+           char *devname;
+           size_t devlen;
 
            cd= &ColumnData[HostName];
            fprintf(mailf, "%*s", cd->PrefixSpace, "");
@@ -1248,15 +1356,16 @@ output_summary()
 
            cd= &ColumnData[Disk];
            fprintf(mailf, "%*s", cd->PrefixSpace, "");
-           devlen= strlen(dp->name);
-           if (devlen > cd->Width) {
+           devname = sanitize_string(dp->name);
+           devlen = strlen(devname);
+           if (devlen > (size_t)cd->Width) {
                fputc('-', mailf); 
                fprintf(mailf, cd->Format, cd->Width-1, cd->Precision-1,
-                 dp->name+devlen - (cd->Width-1) );
+                 devname+devlen - (cd->Width-1) );
            }
            else
-               fprintf(mailf, cd->Format, cd->Width, cd->Width, dp->name);
-
+               fprintf(mailf, cd->Format, cd->Width, cd->Width, devname);
+           amfree(devname);
            cd= &ColumnData[Level];
            if (repdata->dumper.result == L_BOGUS &&
                repdata->taper.result  == L_BOGUS) {
@@ -1309,7 +1418,7 @@ output_summary()
 
            cd= &ColumnData[OrigKB];
            fprintf(mailf, "%*s", cd->PrefixSpace, "");
-           if(origsize != 0.0)
+           if(isnormal(origsize))
                fprintf(mailf, cd->Format, cd->Width, cd->Precision, du(origsize));
            else
                fprintf(mailf, "%*.*s", cd->Width, cd->Width, "N/A");
@@ -1335,10 +1444,10 @@ output_summary()
            fprintf(mailf, "%*s", cd->PrefixSpace, "");
            if(repdata->dumper.result == L_SUCCESS ||
               repdata->dumper.result == L_CHUNKSUCCESS)
-               snprintf(TimeRateBuffer, sizeof(TimeRateBuffer),
+               snprintf(TimeRateBuffer, SIZEOF(TimeRateBuffer),
                  "%3d:%02d", mnsc(repdata->dumper.sec));
            else
-               snprintf(TimeRateBuffer, sizeof(TimeRateBuffer),
+               snprintf(TimeRateBuffer, SIZEOF(TimeRateBuffer),
                  "N/A ");
            fprintf(mailf, cd->Format, cd->Width, cd->Width, TimeRateBuffer);
 
@@ -1362,10 +1471,10 @@ output_summary()
            if(repdata->taper.result == L_SUCCESS || 
               repdata->taper.result == L_PARTIAL ||
               repdata->taper.result == L_CHUNKSUCCESS)
-               snprintf(TimeRateBuffer, sizeof(TimeRateBuffer),
+               snprintf(TimeRateBuffer, SIZEOF(TimeRateBuffer),
                  "%3d:%02d", mnsc(repdata->taper.sec));
            else
-               snprintf(TimeRateBuffer, sizeof(TimeRateBuffer),
+               snprintf(TimeRateBuffer, SIZEOF(TimeRateBuffer),
                  "N/A ");
            fprintf(mailf, cd->Format, cd->Width, cd->Width, TimeRateBuffer);
 
@@ -1389,40 +1498,49 @@ output_summary()
 }
 
 static void
-bogus_line()
+bogus_line(
+    const char *err_text)
 {
-    printf("line %d of log is bogus\n", curlinenum);
+    printf("line %d of log is bogus: <%s>\n", curlinenum, curstr);
+    printf("  Scan failed at: <%s>\n", err_text);
 }
 
 
-static char *
-nicedate(datestamp)
-    int datestamp;
 /*
- * Formats an integer of the form YYYYMMDD into the string
+ * Formats an integer of the form YYYYMMDDHHMMSS into the string
  * "Monthname DD, YYYY".  A pointer to the statically allocated string
  * is returned, so it must be copied to other storage (or just printed)
  * before calling nicedate() again.
  */
+static char *
+nicedate(
+    const char *datestamp)
 {
     static char nice[64];
+    char date[9];
+    int  numdate;
     static char *months[13] = { "BogusMonth",
        "January", "February", "March", "April", "May", "June",
        "July", "August", "September", "October", "November", "December"
     };
     int year, month, day;
 
-    year  = datestamp / 10000;
-    day   = datestamp % 100;
-    month = (datestamp / 100) % 100;
+    strncpy(date, datestamp, 8);
+    date[8] = '\0';
+    numdate = atoi(date);
+    year  = numdate / 10000;
+    day   = numdate % 100;
+    month = (numdate / 100) % 100;
+    if (month > 12 )
+       month = 0;
 
-    snprintf(nice, sizeof(nice), "%s %d, %d", months[month], day, year);
+    snprintf(nice, SIZEOF(nice), "%s %d, %d", months[month], day, year);
 
     return nice;
 }
 
 static void
-handle_start()
+handle_start(void)
 {
     static int started = 0;
     char *label;
@@ -1436,36 +1554,36 @@ handle_start()
 
        skip_whitespace(s, ch);
 #define sc "datestamp"
-       if(ch == '\0' || strncmp(s - 1, sc, sizeof(sc)-1) != 0) {
-           bogus_line();
+       if(ch == '\0' || strncmp(s - 1, sc, SIZEOF(sc)-1) != 0) {
+           bogus_line(s - 1);
            return;
        }
-       s += sizeof(sc)-1;
+       s += SIZEOF(sc)-1;
        ch = s[-1];
 #undef sc
        skip_whitespace(s, ch);
        if(ch == '\0') {
-           bogus_line();
+           bogus_line(s - 1);
            return;
        }
        fp = s - 1;
        skip_non_whitespace(s, ch);
        s[-1] = '\0';
        run_datestamp = newstralloc(run_datestamp, fp);
-       s[-1] = ch;
+       s[-1] = (char)ch;
 
        skip_whitespace(s, ch);
 #define sc "label"
-       if(ch == '\0' || strncmp(s - 1, sc, sizeof(sc)-1) != 0) {
-           bogus_line();
+       if(ch == '\0' || strncmp(s - 1, sc, SIZEOF(sc)-1) != 0) {
+           bogus_line(s - 1);
            return;
        }
-       s += sizeof(sc)-1;
+       s += SIZEOF(sc)-1;
        ch = s[-1];
 #undef sc
        skip_whitespace(s, ch);
        if(ch == '\0') {
-           bogus_line();
+           bogus_line(s - 1);
            return;
        }
        fp = s - 1;
@@ -1473,7 +1591,7 @@ handle_start()
        s[-1] = '\0';
 
        label = stralloc(fp);
-       s[-1] = ch;
+       s[-1] = (char)ch;
 
        if(tape_labels) {
            fp = vstralloc(tape_labels, ", ", label, NULL);
@@ -1486,10 +1604,10 @@ handle_start()
        last_run_tapes++;
 
        if(stats_by_tape == NULL) {
-           stats_by_tape = current_tape = (taper_t *)alloc(sizeof(taper_t));
+           stats_by_tape = current_tape = (taper_t *)alloc(SIZEOF(taper_t));
        }
        else {
-           current_tape->next = (taper_t *)alloc(sizeof(taper_t));
+           current_tape->next = (taper_t *)alloc(SIZEOF(taper_t));
            current_tape = current_tape->next;
        }
        current_tape->label = label;
@@ -1520,22 +1638,22 @@ handle_start()
 
        skip_whitespace(s, ch);
 #define sc "date"
-       if(ch == '\0' || strncmp(s - 1, sc, sizeof(sc)-1) != 0) {
+       if(ch == '\0' || strncmp(s - 1, sc, SIZEOF(sc)-1) != 0) {
            return;                             /* ignore bogus line */
        }
-       s += sizeof(sc)-1;
+       s += SIZEOF(sc)-1;
        ch = s[-1];
 #undef sc
        skip_whitespace(s, ch);
        if(ch == '\0') {
-           bogus_line();
+           bogus_line(s - 1);
            return;
        }
        fp = s - 1;
        skip_non_whitespace(s, ch);
        s[-1] = '\0';
        run_datestamp = newstralloc(run_datestamp, fp);
-       s[-1] = ch;
+       s[-1] = (char)ch;
 
        started = 1;
     }
@@ -1548,11 +1666,11 @@ handle_start()
 
 
 static void
-handle_finish()
+handle_finish(void)
 {
     char *s;
     int ch;
-    float a_time;
+    double a_time;
 
     if(curprog == P_DRIVER || curprog == P_AMFLUSH || curprog == P_PLANNER) {
        s = curstr;
@@ -1560,40 +1678,40 @@ handle_finish()
 
        skip_whitespace(s, ch);
 #define sc "date"
-       if(ch == '\0' || strncmp(s - 1, sc, sizeof(sc)-1) != 0) {
-           bogus_line();
+       if(ch == '\0' || strncmp(s - 1, sc, SIZEOF(sc)-1) != 0) {
+           bogus_line(s - 1);
            return;
        }
-       s += sizeof(sc)-1;
+       s += SIZEOF(sc)-1;
        ch = s[-1];
 #undef sc
 
        skip_whitespace(s, ch);
        if(ch == '\0') {
-           bogus_line();
+           bogus_line(s - 1);
            return;
        }
        skip_non_whitespace(s, ch);     /* ignore the date string */
 
        skip_whitespace(s, ch);
 #define sc "time"
-       if(ch == '\0' || strncmp(s - 1, sc, sizeof(sc)-1) != 0) {
+       if(ch == '\0' || strncmp(s - 1, sc, SIZEOF(sc)-1) != 0) {
            /* older planner doesn't write time */
            if(curprog == P_PLANNER) return;
-           bogus_line();
+           bogus_line(s - 1);
            return;
        }
-       s += sizeof(sc)-1;
+       s += SIZEOF(sc)-1;
        ch = s[-1];
 #undef sc
 
        skip_whitespace(s, ch);
        if(ch == '\0') {
-           bogus_line();
+           bogus_line(s - 1);
            return;
        }
-       if(sscanf(s - 1, "%f", &a_time) != 1) {
-           bogus_line();
+       if(sscanf(s - 1, "%lf", &a_time) != 1) {
+           bogus_line(s - 1);
            return;
        }
        if(curprog == P_PLANNER) {
@@ -1607,10 +1725,15 @@ handle_finish()
 }
 
 static void
-handle_stats()
+handle_stats(void)
 {
-    char *s;
+    char *s, *fp;
     int ch;
+    char *hostname, *diskname, *datestamp;
+    int level = 0;
+    double sec, kps, nbytes, cbytes;
+    repdata_t *repdata;
+    disk_t *dp;
 
     if(curprog == P_DRIVER) {
        s = curstr;
@@ -1618,30 +1741,122 @@ handle_stats()
 
        skip_whitespace(s, ch);
 #define sc "startup time"
-       if(ch == '\0' || strncmp(s - 1, sc, sizeof(sc)-1) != 0) {
-           bogus_line();
-           return;
+       if(ch != '\0' && strncmp(s - 1, sc, sizeof(sc)-1) == 0) {
+           s += sizeof(sc)-1;
+           ch = s[-1];
+#undef sc
+
+           skip_whitespace(s, ch);
+           if(ch == '\0') {
+               bogus_line(s - 1);
+               return;
+           }
+           if(sscanf(s - 1, "%lf", &startup_time) != 1) {
+               bogus_line(s - 1);
+               return;
+           }
+           planner_time = startup_time;
        }
-       s += sizeof(sc)-1;
-       ch = s[-1];
+#define sc "estimate"
+       else if(ch != '\0' && strncmp(s - 1, sc, sizeof(sc)-1) == 0) {
+           s += sizeof(sc)-1;
+           ch = s[-1];
 #undef sc
 
-       skip_whitespace(s, ch);
-       if(ch == '\0') {
-           bogus_line();
-           return;
+           skip_whitespace(s, ch);
+           if(ch == '\0') {
+               bogus_line(s - 1);
+               return;
+           }
+           fp = s - 1;
+           skip_non_whitespace(s, ch);
+           s[-1] = '\0';
+           hostname = stralloc(fp);
+           s[-1] = (char)ch;
+
+           skip_whitespace(s, ch);
+           if(ch == '\0') {
+               bogus_line(s - 1);
+               amfree(hostname);
+               return;
+           }
+           fp = s - 1;
+           skip_non_whitespace(s, ch);
+           s[-1] = '\0';
+           diskname = stralloc(fp);
+           s[-1] = (char)ch;
+
+           skip_whitespace(s, ch);
+           if(ch == '\0') {
+               bogus_line(s - 1);
+               amfree(hostname);
+               amfree(diskname);
+               return;
+           }
+           fp = s - 1;
+           skip_non_whitespace(s, ch);
+           s[-1] = '\0';
+           datestamp = stralloc(fp);
+           s[-1] = (char)ch;
+
+           skip_whitespace(s, ch);
+           if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
+               bogus_line(s - 1);
+               amfree(hostname);
+               amfree(diskname);
+               amfree(datestamp);
+               return;
+           }
+           skip_integer(s, ch);
+           if(level < 0 || level > 9) {
+               amfree(hostname);
+               amfree(diskname);
+               amfree(datestamp);
+               return;
+           }
+
+           skip_whitespace(s, ch);
+
+           if(sscanf(s - 1,"[sec %lf nkb %lf ckb %lf kps %lf",
+                     &sec, &nbytes, &cbytes, &kps) != 4)  {
+               bogus_line(s - 1);
+               amfree(hostname);
+               amfree(diskname);
+               amfree(datestamp);
+               return;
+           }
+
+           dp = lookup_disk(hostname, diskname);
+           if(dp == NULL) {
+               addtostrange(hostname, diskname, level,
+                            "ERROR [not in disklist]");
+               amfree(hostname);
+               amfree(diskname);
+               amfree(datestamp);
+               return;
+           }
+
+           repdata = find_repdata(dp, datestamp, level);
+
+           repdata->est_nsize = nbytes;
+           repdata->est_csize = cbytes;
+
+           amfree(hostname);
+           amfree(diskname);
+           amfree(datestamp);
        }
-       if(sscanf(s - 1, "%f", &startup_time) != 1) {
-           bogus_line();
+       else {
+           bogus_line(s - 1);
            return;
        }
-       planner_time = startup_time;
+#undef sc
+
     }
 }
 
 
 static void
-handle_note()
+handle_note(void)
 {
     char *str = NULL;
 
@@ -1654,7 +1869,7 @@ handle_note()
 /* ----- */
 
 static void
-handle_error()
+handle_error(void)
 {
     char *s = NULL, *nl;
     int ch;
@@ -1665,8 +1880,8 @@ handle_error()
 
        skip_whitespace(s, ch);
 #define sc "no-tape"
-       if(ch != '\0' && strncmp(s - 1, sc, sizeof(sc)-1) == 0) {
-           s += sizeof(sc)-1;
+       if(ch != '\0' && strncmp(s - 1, sc, SIZEOF(sc)-1) == 0) {
+           s += SIZEOF(sc)-1;
            ch = s[-1];
 #undef sc
 
@@ -1693,24 +1908,24 @@ handle_error()
 /* ----- */
 
 static void
-handle_summary()
+handle_summary(void)
 {
-    bogus_line();
+    bogus_line(curstr);
 }
 
 /* ----- */
 
 static int nb_disk=0;
 static void
-handle_disk()
+handle_disk(void)
 {
     disk_t *dp;
-    char *s, *fp;
+    char *s, *fp, *qdiskname;
     int ch;
     char *hostname = NULL, *diskname = NULL;
 
     if(curprog != P_PLANNER && curprog != P_AMFLUSH) {
-       bogus_line();
+       bogus_line(curstr);
        return;
     }
 
@@ -1725,26 +1940,26 @@ handle_disk()
 
     skip_whitespace(s, ch);
     if(ch == '\0') {
-       bogus_line();
+       bogus_line(s - 1);
        return;
     }
     fp = s - 1;
     skip_non_whitespace(s, ch);
     s[-1] = '\0';
     hostname = newstralloc(hostname, fp);
-    s[-1] = ch;
+    s[-1] = (char)ch;
 
     skip_whitespace(s, ch);
     if(ch == '\0') {
-       bogus_line();
+       bogus_line(s - 1);
        amfree(hostname);
        return;
     }
-    fp = s - 1;
-    skip_non_whitespace(s, ch);
+    qdiskname = s - 1;
+    skip_quoted_string(s, ch);
     s[-1] = '\0';
-    diskname = newstralloc(diskname, fp);
-    s[-1] = ch;
+    diskname = unquote_string(qdiskname);
+    s[-1] = (char)ch;
 
     dp = lookup_disk(hostname, diskname);
     if(dp == NULL) {
@@ -1761,10 +1976,10 @@ handle_disk()
  * for a split chunk of the overall dumpfile.
  */
 static repdata_t *
-handle_chunk()
+handle_chunk(void)
 {
     disk_t *dp;
-    float sec, kps, kbytes;
+    double sec, kps, kbytes;
     timedata_t *sp;
     int i;
     char *s, *fp;
@@ -1776,7 +1991,7 @@ handle_chunk()
     char *datestamp;
     
     if(curprog != P_TAPER) {
-       bogus_line();
+       bogus_line(curstr);
        return NULL;
     }
     
@@ -1785,30 +2000,30 @@ handle_chunk()
     
     skip_whitespace(s, ch);
     if(ch == '\0') {
-       bogus_line();
+       bogus_line(s - 1);
        return NULL;
     }
     fp = s - 1;
     skip_non_whitespace(s, ch);
     s[-1] = '\0';
     hostname = stralloc(fp);
-    s[-1] = ch;
+    s[-1] = (char)ch;
     
     skip_whitespace(s, ch);
     if(ch == '\0') {
-       bogus_line();
+       bogus_line(s - 1);
        amfree(hostname);
        return NULL;
     }
     fp = s - 1;
-    skip_non_whitespace(s, ch);
+    skip_quoted_string(s, ch);
     s[-1] = '\0';
-    diskname = stralloc(fp);
-    s[-1] = ch;
+    diskname = unquote_string(fp);
+    s[-1] = (char)ch;
     
     skip_whitespace(s, ch);
     if(ch == '\0') {
-       bogus_line();
+       bogus_line(s - 1);
        amfree(hostname);
        amfree(diskname);
        return NULL;
@@ -1817,44 +2032,40 @@ handle_chunk()
     skip_non_whitespace(s, ch);
     s[-1] = '\0';
     datestamp = stralloc(fp);
-    s[-1] = ch;
-    
-    level = atoi(datestamp);
-    if(level < 100)  {
-       datestamp = newstralloc(datestamp, run_datestamp);
-    }
-    else {
-       skip_whitespace(s, ch);
-       if(ch == '\0' || sscanf(s - 1, "%d", &chunk) != 1) {
-           bogus_line();
-           amfree(hostname);
-           amfree(diskname);
-           amfree(datestamp);
-           return NULL;
-       }
-       skip_integer(s, ch);
-       
-       skip_whitespace(s, ch);
-       if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
-           bogus_line();
-           amfree(hostname);
-           amfree(diskname);
-           amfree(datestamp);
-           return NULL;
-       }
-       skip_integer(s, ch);
+    s[-1] = (char)ch;
+    skip_whitespace(s, ch);
+    if(ch == '\0' || sscanf(s - 1, "%d", &chunk) != 1) {
+       bogus_line(s - 1);
+       amfree(hostname);
+       amfree(diskname);
+       amfree(datestamp);
+       return NULL;
     }
+    skip_integer(s, ch);
+
     skip_whitespace(s, ch);
+    if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
+       bogus_line(s - 1);
+       amfree(hostname);
+       amfree(diskname);
+       amfree(datestamp);
+       return NULL;
+    }
+    skip_integer(s, ch);
     
+    /*@ignore@*/
     if(level < 0 || level > 9) {
        amfree(hostname);
        amfree(diskname);
        amfree(datestamp);
        return NULL;
     }
-    
-    if(sscanf(s - 1,"[sec %f kb %f kps %f", &sec, &kbytes, &kps) != 3)  {
-       bogus_line();
+    /*@end@*/
+    skip_whitespace(s, ch);
+    if(sscanf(s - 1,"[sec %lf kb %lf kps %lf", &sec, &kbytes, &kps) != 3)  {
+       bogus_line(s - 1);
        amfree(hostname);
        amfree(diskname);
        amfree(datestamp);
@@ -1903,23 +2114,27 @@ handle_chunk()
 }
 
 static repdata_t *
-handle_success(logtype_t logtype)
+handle_success(
+    logtype_t  logtype)
 {
     disk_t *dp;
-    float sec, kps, kbytes, origkb;
+    double sec = 0.0;
+    double kps = 0.0;
+    double kbytes = 0.0;
+    double origkb = 0.0;
     timedata_t *sp;
     int i;
-    char *s, *fp;
+    char *s, *fp, *qdiskname;
     int ch;
     char *hostname = NULL;
     char *diskname = NULL;
     repdata_t *repdata;
-    int level;
+    int level = 0;
     char *datestamp;
 
     if(curprog != P_TAPER && curprog != P_DUMPER && curprog != P_PLANNER &&
        curprog != P_CHUNKER) {
-       bogus_line();
+       bogus_line(curstr);
        return NULL;
     }
 
@@ -1928,30 +2143,29 @@ handle_success(logtype_t logtype)
 
     skip_whitespace(s, ch);
     if(ch == '\0') {
-       bogus_line();
+       bogus_line(s - 1);
        return NULL;
     }
     fp = s - 1;
     skip_non_whitespace(s, ch);
     s[-1] = '\0';
     hostname = stralloc(fp);
-    s[-1] = ch;
+    s[-1] = (char)ch;
 
     skip_whitespace(s, ch);
     if(ch == '\0') {
-       bogus_line();
+       bogus_line(s - 1);
        amfree(hostname);
        return NULL;
     }
-    fp = s - 1;
-    skip_non_whitespace(s, ch);
+    qdiskname = s - 1;
+    skip_quoted_string(s, ch);
     s[-1] = '\0';
-    diskname = stralloc(fp);
-    s[-1] = ch;
+    diskname = unquote_string(qdiskname);
 
     skip_whitespace(s, ch);
     if(ch == '\0') {
-       bogus_line();
+       bogus_line(s - 1);
        amfree(hostname);
        amfree(diskname);
        return NULL;
@@ -1960,16 +2174,16 @@ handle_success(logtype_t logtype)
     skip_non_whitespace(s, ch);
     s[-1] = '\0';
     datestamp = stralloc(fp);
-    s[-1] = ch;
+    s[-1] = (char)ch;
 
-    level = atoi(datestamp);
-    if(level < 100)  {
+    if(strlen(datestamp) < 3) {
+       level = atoi(datestamp);
        datestamp = newstralloc(datestamp, run_datestamp);
     }
     else {
        skip_whitespace(s, ch);
        if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
-           bogus_line();
+           bogus_line(s - 1);
            amfree(hostname);
            amfree(diskname);
            amfree(datestamp);
@@ -1977,6 +2191,7 @@ handle_success(logtype_t logtype)
        }
        skip_integer(s, ch);
     }
+
     if(level < 0 || level > 9) {
        amfree(hostname);
        amfree(diskname);
@@ -1988,13 +2203,15 @@ handle_success(logtype_t logtype)
                                /* Planner success messages (for skipped
                                   dumps) do not contain statistics */
     if(curprog != P_PLANNER) {
-       if(curprog != P_DUMPER ||
-          sscanf(s - 1,"[sec %f kb %f kps %f orig-kb %f", 
-                 &sec, &kbytes, &kps, &origkb) != 4)  {
+       if(*(s - 1) == '"')
+           s++;
+       if((curprog != P_DUMPER)
+           || (sscanf(s - 1,"[sec %lf kb %lf kps %lf orig-kb %lf", 
+                 &sec, &kbytes, &kps, &origkb) != 4))  {
            origkb = -1;
-           if(sscanf(s - 1,"[sec %f kb %f kps %f",
+           if(sscanf(s - 1,"[sec %lf kb %lf kps %lf",
                      &sec, &kbytes, &kps) != 3) {
-               bogus_line();
+               bogus_line(s - 1);
                amfree(hostname);
                amfree(diskname);
                amfree(datestamp);
@@ -2002,14 +2219,15 @@ handle_success(logtype_t logtype)
            }
        }
        else {
-           if(origkb == 0.0) origkb = 0.1;
+           if(!isnormal(origkb))
+               origkb = 0.1;
        }
     }
 
 
     dp = lookup_disk(hostname, diskname);
     if(dp == NULL) {
-       addtostrange(hostname, diskname, level, "ERROR [not in disklist]");
+       addtostrange(hostname, qdiskname, level, "ERROR [not in disklist]");
        amfree(hostname);
        amfree(diskname);
        amfree(datestamp);
@@ -2034,15 +2252,19 @@ handle_success(logtype_t logtype)
 
     i = level > 0;
 
-    if(origkb == -1) {
+    if(origkb < 0.0) {
        info_t inf;
        struct tm *tm;
        int Idatestamp;
 
        get_info(hostname, diskname, &inf);
         tm = localtime(&inf.inf[level].date);
-        Idatestamp = 10000*(tm->tm_year+1900) +
-                      100*(tm->tm_mon+1) + tm->tm_mday;
+       if (tm) {
+            Idatestamp = 10000*(tm->tm_year+1900) +
+                        100*(tm->tm_mon+1) + tm->tm_mday;
+       } else {
+           Idatestamp = 19000101;
+       }
 
        if(atoi(datestamp) == Idatestamp) {
            /* grab original size from record */
@@ -2051,6 +2273,12 @@ handle_success(logtype_t logtype)
        else
            origkb = 0.0;
     }
+
+    if (curprog == P_DUMPER &&
+       (sp->result == L_FAIL || sp->result == L_PARTIAL)) {
+       addtostrange(hostname, qdiskname, level, "was successfully retried");
+    }
+
     amfree(hostname);
     amfree(diskname);
     amfree(datestamp);
@@ -2065,6 +2293,7 @@ handle_success(logtype_t logtype)
     if(curprog == P_TAPER) {
        if(current_tape == NULL) {
            error("current_tape == NULL");
+           /*NOTREACHED*/
        }
        stats[i].taper_time += sec;
        sp->filenum = ++tapefcount;
@@ -2073,7 +2302,7 @@ handle_success(logtype_t logtype)
        stats[i].tapedisks +=1;
        stats[i].tapesize += kbytes;
        sp->outsize = kbytes;
-       if(repdata->chunker.outsize == 0.0 && repdata->dumper.outsize != 0.0) { /* dump to tape */
+       if(!isnormal(repdata->chunker.outsize) && isnormal(repdata->dumper.outsize)) { /* dump to tape */
            stats[i].outsize += kbytes;
            if(dp->compress != COMP_NONE) {
                stats[i].coutsize += kbytes;
@@ -2111,12 +2340,14 @@ handle_success(logtype_t logtype)
 }
 
 static void
-handle_partial()
+handle_partial(void)
 {
     repdata_t *repdata;
     timedata_t *sp;
 
     repdata = handle_success(L_PARTIAL);
+    if (!repdata)
+       return;
 
     if(curprog == P_TAPER)
        sp = &(repdata->taper);
@@ -2128,17 +2359,22 @@ handle_partial()
 }
 
 static void
-handle_strange()
+handle_strange(void)
 {
     char *str = NULL;
     char *strangestr = NULL;
     repdata_t *repdata;
+    char *qdisk;
 
     repdata = handle_success(L_SUCCESS);
+    if (!repdata)
+       return;
+
+    qdisk = quote_string(repdata->disk->name);
 
     addline(&errdet,"");
     str = vstralloc("/-- ", prefix(repdata->disk->host->hostname, 
-                                  repdata->disk->name, repdata->level),
+                                  qdisk, repdata->level),
                    " ", "STRANGE",
                    NULL);
     addline(&errdet, str);
@@ -2147,30 +2383,30 @@ handle_strange()
     while(contline_next()) {
        get_logline(logfile);
 #define sc "sendbackup: warning "
-       if(strncmp(curstr, sc, sizeof(sc)-1) == 0) {
-           strangestr = newstralloc(strangestr, curstr+sizeof(sc)-1);
+       if(strncmp(curstr, sc, SIZEOF(sc)-1) == 0) {
+           strangestr = newstralloc(strangestr, curstr+SIZEOF(sc)-1);
        }
        addline(&errdet, curstr);
     }
     addline(&errdet,"\\--------");
 
     str = vstralloc("STRANGE", " ", strangestr, NULL);
-    addtostrange(repdata->disk->host->hostname, repdata->disk->name, repdata->level,
-                str);
+    addtostrange(repdata->disk->host->hostname, qdisk, repdata->level, str);
+    amfree(qdisk);
     amfree(str);
     amfree(strangestr);
 }
 
 static void
-handle_failed()
+handle_failed(void)
 {
     disk_t *dp;
     char *hostname;
     char *diskname;
     char *datestamp;
     char *errstr;
-    int level;
-    char *s, *fp;
+    int level = 0;
+    char *s, *fp, *qdiskname;
     int ch;
     char *str = NULL;
     repdata_t *repdata;
@@ -2184,7 +2420,7 @@ handle_failed()
 
     skip_whitespace(s, ch);
     if(ch == '\0') {
-       bogus_line();
+       bogus_line(s - 1);
        return;
     }
     hostname = s - 1;
@@ -2193,16 +2429,18 @@ handle_failed()
 
     skip_whitespace(s, ch);
     if(ch == '\0') {
-       bogus_line();
+       bogus_line(s - 1);
        return;
     }
-    diskname = s - 1;
-    skip_non_whitespace(s, ch);
+    qdiskname = s - 1;
+    skip_quoted_string(s, ch);
     s[-1] = '\0';
+    diskname = unquote_string(qdiskname);
 
     skip_whitespace(s, ch);
     if(ch == '\0') {
-       bogus_line();
+       bogus_line(s - 1);
+       amfree(diskname);
        return;
     }
     fp = s - 1;
@@ -2217,8 +2455,9 @@ handle_failed()
     else { /* read the level */
        skip_whitespace(s, ch);
        if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
-           bogus_line();
+           bogus_line(s - 1);
            amfree(datestamp);
+           amfree(diskname);
            return;
        }
        skip_integer(s, ch);
@@ -2226,8 +2465,9 @@ handle_failed()
 
     skip_whitespace(s, ch);
     if(ch == '\0') {
-       bogus_line();
+       bogus_line(s - 1);
        amfree(datestamp);
+       amfree(diskname);
        return;
     }
     errstr = s - 1;
@@ -2236,8 +2476,9 @@ handle_failed()
     }
 
     dp = lookup_disk(hostname, diskname);
+    amfree(diskname);
     if(dp == NULL) {
-       addtostrange(hostname, diskname, level, "ERROR [not in disklist]");
+       addtostrange(hostname, qdiskname, level, "ERROR [not in disklist]");
     } else {
        repdata = find_repdata(dp, datestamp, level);
 
@@ -2251,12 +2492,12 @@ handle_failed()
     amfree(datestamp);
 
     str = vstralloc("FAILED", " ", errstr, NULL);
-    addtostrange(hostname, diskname, level, str);
+    addtostrange(hostname, qdiskname, level, str);
     amfree(str);
 
     if(curprog == P_DUMPER) {
        addline(&errdet,"");
-       str = vstralloc("/-- ", prefix(hostname, diskname, level),
+       str = vstralloc("/-- ", prefix(hostname, qdiskname, level),
                        " ", "FAILED",
                        " ", errstr,
                        NULL);
@@ -2273,28 +2514,89 @@ handle_failed()
 
 
 static void
-generate_missing()
+generate_missing(void)
 {
     disk_t *dp;
+    char *qdisk;
 
     for(dp = diskq.head; dp != NULL; dp = dp->next) {
        if(dp->todo && data(dp) == NULL) {
-           addtostrange(dp->host->hostname, dp->name, -987, "RESULTS MISSING");
+           qdisk = quote_string(dp->name);
+           addtostrange(dp->host->hostname, qdisk, -987, "RESULTS MISSING");
+           amfree(qdisk);
        }
     }
 }
 
+static void
+generate_bad_estimate(void)
+{
+    disk_t *dp;
+    repdata_t *repdata;
+    char s[1000];
+    double outsize;
+
+    for(dp = diskq.head; dp != NULL; dp = dp->next) {
+       if(dp->todo) {
+           for(repdata = data(dp); repdata != NULL; repdata = repdata->next) {
+               if(repdata->est_csize >= 0.1) {
+                   if(repdata->taper.result == L_SUCCESS ||
+                      repdata->taper.result == L_PARTIAL ||
+                      repdata->taper.result == L_CHUNKSUCCESS)
+                       outsize  = repdata->taper.outsize;
+                   else if(repdata->chunker.result == L_SUCCESS ||
+                           repdata->chunker.result == L_PARTIAL ||
+                           repdata->chunker.result == L_CHUNKSUCCESS)
+                       outsize  = repdata->chunker.outsize;
+                   else
+                       outsize  = repdata->dumper.outsize;
+
+                   if(repdata->est_csize * 0.9 > outsize) {
+                       snprintf(s, 1000,
+                               "  big estimate: %s %s %d",
+                                repdata->disk->host->hostname,
+                                repdata->disk->name,
+                                repdata->level);
+                       s[999] = '\0';
+                       addline(&notes, s);
+                       snprintf(s, 1000,
+                                "                est: %.0lf%s    out %.0lf%s",
+                                du(repdata->est_csize), displayunit,
+                                du(outsize), displayunit);
+                       s[999] = '\0';
+                       addline(&notes, s);
+                   }
+                   else if(repdata->est_csize * 1.1 < outsize) {
+                       snprintf(s, 1000,
+                               "  small estimate: %s %s %d",
+                                repdata->disk->host->hostname,
+                                repdata->disk->name,
+                                repdata->level);
+                       s[999] = '\0';
+                       addline(&notes, s);
+                       snprintf(s, 1000,
+                                "                  est: %.0lf%s    out %.0lf%s",
+                                du(repdata->est_csize), displayunit,
+                                du(outsize), displayunit);
+                       s[999] = '\0';
+                       addline(&notes, s);
+                   }
+               }
+           }
+       }
+    }
+}
 
 static char *
-prefix (host, disk, level)
-    char *host;
-    char *disk;
-    int level;
+prefix (
+    char *     host,
+    char *     disk,
+    int                level)
 {
     char number[NUM_STR_SIZE];
     static char *str = NULL;
 
-    snprintf(number, sizeof(number), "%d", level);
+    snprintf(number, SIZEOF(number), "%d", level);
     str = newvstralloc(str,
                       " ", host ? host : "(host?)",
                       " ", disk ? disk : "(disk?)",
@@ -2306,19 +2608,20 @@ prefix (host, disk, level)
 
 
 static char *
-prefixstrange (host, disk, level, len_host, len_disk)
-    char *host;
-    char *disk;
-    int level;
-    int len_host, len_disk;
+prefixstrange (
+    char *     host,
+    char *     disk,
+    int                level,
+    size_t     len_host,
+    size_t     len_disk)
 {
     char *h, *d;
-    int l;
+    size_t l;
     char number[NUM_STR_SIZE];
     static char *str = NULL;
 
-    snprintf(number, sizeof(number), "%d", level);
-    h=malloc(len_host+1);
+    snprintf(number, SIZEOF(number), "%d", level);
+    h=alloc(len_host+1);
     if(host) {
        strncpy(h, host, len_host);
     } else {
@@ -2328,7 +2631,7 @@ prefixstrange (host, disk, level, len_host, len_disk)
     for(l = strlen(h); l < len_host; l++) {
        h[l] = ' ';
     }
-    d=malloc(len_disk+1);
+    d=alloc(len_disk+1);
     if(disk) {
        strncpy(d, disk, len_disk);
     } else {
@@ -2351,15 +2654,15 @@ prefixstrange (host, disk, level, len_host, len_disk)
 
 
 static void
-addtostrange (host, disk, level, str)
-    char *host;
-    char *disk;
-    int  level;
-    char *str;
+addtostrange (
+    char *     host,
+    char *     disk,
+    int                level,
+    char *     str)
 {
     strange_t *strange;
 
-    strange = malloc(sizeof(strange_t));
+    strange = alloc(SIZEOF(strange_t));
     strange->hostname = stralloc(host);
     strange->diskname = stralloc(disk);
     strange->level    = level;
@@ -2376,12 +2679,12 @@ addtostrange (host, disk, level, str)
 
 
 static void
-copy_template_file(lbl_templ)
-    char *lbl_templ;
+copy_template_file(
+    char *     lbl_templ)
 {
   char buf[BUFSIZ];
   int fd;
-  int numread;
+  ssize_t numread;
 
   if (strchr(lbl_templ, '/') == NULL) {
     lbl_templ = stralloc2(config_dir, lbl_templ);
@@ -2402,8 +2705,8 @@ copy_template_file(lbl_templ)
     afclose(postscript);
     return;
   }
-  while ((numread = read(fd, buf, sizeof(buf))) > 0) {
-    if (fwrite(buf, numread, 1, postscript) != 1) {
+  while ((numread = read(fd, buf, SIZEOF(buf))) > 0) {
+    if (fwrite(buf, (size_t)numread, 1, postscript) != 1) {
       curlog = L_ERROR;
       curprog = P_REPORTER;
       curstr = vstralloc("error copying PostScript template file ",
@@ -2437,10 +2740,10 @@ copy_template_file(lbl_templ)
 }
 
 static repdata_t *
-find_repdata(dp, datestamp, level)
-    disk_t *dp;
-    char *datestamp;
-    int level;
+find_repdata(
+    /*@keep@*/ disk_t *dp,
+               char *  datestamp,
+               int     level)
 {
     repdata_t *repdata, *prev;
 
@@ -2451,8 +2754,8 @@ find_repdata(dp, datestamp, level)
        prev = repdata;
     }
     if(!repdata) {
-       repdata = (repdata_t *)alloc(sizeof(repdata_t));
-       memset(repdata, '\0',sizeof(repdata_t));
+       repdata = (repdata_t *)alloc(SIZEOF(repdata_t));
+       memset(repdata, '\0', SIZEOF(repdata_t));
        repdata->disk = dp;
        repdata->datestamp = stralloc(datestamp ? datestamp : "");
        repdata->level = level;
@@ -2468,16 +2771,21 @@ find_repdata(dp, datestamp, level)
 }
 
 
-static void do_postscript_output()
+static void
+do_postscript_output(void)
 {
     tapetype_t *tp = lookup_tapetype(getconf_str(CNF_TAPETYPE));
     disk_t *dp;
     repdata_t *repdata;
-    float outsize, origsize;
-    int tapesize, marksize;
+    double outsize, origsize;
+    off_t tapesize;
+    off_t marksize;
+
+    if (!tp)
+       return;
 
-    tapesize = tp->length;
-    marksize = tp->filemark;
+    tapesize = tapetype_get_length(tp);
+    marksize = tapetype_get_filemark(tp);
 
     for(current_tape = stats_by_tape; current_tape != NULL;
            current_tape = current_tape->next) {
@@ -2486,21 +2794,21 @@ static void do_postscript_output()
            break;
        }
 
-       copy_template_file(tp->lbl_templ);
+       copy_template_file(tapetype_get_lbl_templ(tp));
 
        /* generate a few elements */
        fprintf(postscript,"(%s) DrawDate\n\n",
-                   nicedate(run_datestamp ? atoi(run_datestamp) : 0));
+                   nicedate(run_datestamp ? run_datestamp : "0"));
        fprintf(postscript,"(Amanda Version %s) DrawVers\n",version());
        fprintf(postscript,"(%s) DrawTitle\n", current_tape->label);
 
        /* Stats */
-       fprintf(postscript, "(Total Size:        %6.1f MB) DrawStat\n",
+       fprintf(postscript, "(Total Size:        %6.1lf MB) DrawStat\n",
              mb(current_tape->coutsize));
        fprintf(postscript, "(Tape Used (%%)       ");
        divzero(postscript, pct(current_tape->coutsize + 
                                marksize * (current_tape->tapedisks + current_tape->tapechunks)),
-                               tapesize);
+                               (double)tapesize);
        fprintf(postscript," %%) DrawStat\n");
        fprintf(postscript, "(Compression Ratio:  ");
        divzero(postscript, pct(current_tape->coutsize),current_tape->corigsize);
@@ -2538,14 +2846,14 @@ static void do_postscript_output()
 
                if (repdata->taper.result == L_SUCCESS ||
                    repdata->taper.result == L_PARTIAL) {
-                   if(origsize != 0.0) {
-                       fprintf(postscript,"(%s) (%s) (%d) (%3.0d) (%8.0f) (%8.0f) DrawHost\n",
+                   if(isnormal(origsize)) {
+                       fprintf(postscript,"(%s) (%s) (%d) (%3.0d) (%8.0lf) (%8.0lf) DrawHost\n",
                            dp->host->hostname, dp->name, repdata->level,
                            repdata->taper.filenum, origsize, 
                            outsize);
                    }
                    else {
-                       fprintf(postscript,"(%s) (%s) (%d) (%3.0d) (%8s) (%8.0f) DrawHost\n",
+                       fprintf(postscript,"(%s) (%s) (%d) (%3.0d) (%8s) (%8.0lf) DrawHost\n",
                            dp->host->hostname, dp->name, repdata->level,
                            repdata->taper.filenum, "N/A", 
                            outsize);