Imported Upstream version 2.6.0
[debian/amanda] / server-src / reporter.c
index 21c171c057227705cb4b43c048108ae2fdc49dc5..17497f897e5c6eed0dd25ab4d09334d9b5cd6cc9 100644 (file)
  * report format
  *     tape label message
  *     error messages
+ *     strange messages
  *     summary stats
  *     details for errors
+ *     details for strange
  *     notes
  *     success summary
  */
 
 #include "amanda.h"
 #include "conffile.h"
+#include "columnar.h"
 #include "tapefile.h"
 #include "diskfile.h"
 #include "infofile.h"
 #include "logfile.h"
 #include "version.h"
 #include "util.h"
+#include "timestamp.h"
+#include "holding.h"
 
 /* don't have (or need) a skipped type except internally to reporter */
 #define L_SKIPPED      L_MARKER
@@ -69,6 +74,7 @@ typedef struct timedata_s {
     double sec, kps;
     int filenum;
     char *tapelabel;
+    int totpart;
 } timedata_t;
 
 typedef struct repdata_s {
@@ -104,15 +110,16 @@ typedef struct taper_s {
 static taper_t *stats_by_tape = NULL;
 static taper_t *current_tape = NULL;
 
-typedef struct strange_s {
+typedef struct X_summary_s {
     char *hostname;
     char *diskname;
     int  level;
     char *str;
-    struct strange_s *next;
-} strange_t;
+    struct X_summary_s *next;
+} X_summary_t;
 
-static strange_t *first_strange=NULL, *last_strange=NULL;
+static X_summary_t *first_strange=NULL, *last_strange=NULL;
+static X_summary_t *first_failed=NULL, *last_failed=NULL;
 
 static double total_time, startup_time, planner_time;
 
@@ -127,6 +134,7 @@ static int degraded_mode = 0; /* defined in driverio too */
 static int normal_run = 0;
 static int amflush_run = 0;
 static int got_finish = 0;
+static int cmdlogfname = 0;
 static char *ghostname = NULL;
 
 static char *tapestart_error = NULL;
@@ -141,12 +149,13 @@ static disklist_t sortq;
 
 static line_t *errsum = NULL;
 static line_t *errdet = NULL;
+static line_t *strangedet = NULL;
 static line_t *notes = NULL;
 
 static char MaxWidthsRequested = 0;    /* determined via config data */
 
-char *displayunit;
-long int unitdivisor;
+static char *displayunit;
+static long int unitdivisor;
 
 /* local functions */
 int main(int argc, char **argv);
@@ -162,10 +171,11 @@ 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_chunk(logtype_t logtype);
 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    addtoX_summary(X_summary_t **first, X_summary_t **last,
+                              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);
@@ -187,7 +197,7 @@ 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_X_summary(X_summary_t *first);
 static void    output_summary(void);
 static void    output_tapeinfo(void);
 static void    sort_disks(void);
@@ -237,7 +247,7 @@ TextRule(
     leng = (int)strlen(s);
     if(leng >= (RuleSpaceSize - cd->PrefixSpace))
        leng = RuleSpaceSize - cd->PrefixSpace - 1;
-    snprintf(RuleSpace, (size_t)RuleSpaceSize, "%*s%*.*s ", cd->PrefixSpace, "", 
+    g_snprintf(RuleSpace, (size_t)RuleSpaceSize, "%*s%*.*s ", cd->PrefixSpace, "", 
             leng, leng, s);
     txtlength = cd->PrefixSpace + leng + 1;
     nbrules = ColWidth(From,To) - txtlength;
@@ -256,10 +266,10 @@ sDivZero(
     ColumnInfo *cd= &ColumnData[cn];
     static char PrtBuf[256];
     if (!isnormal(b))
-       snprintf(PrtBuf, SIZEOF(PrtBuf),
+       g_snprintf(PrtBuf, SIZEOF(PrtBuf),
          "%*s", cd->Width, "-- ");
     else
-       snprintf(PrtBuf, SIZEOF(PrtBuf),
+       g_snprintf(PrtBuf, SIZEOF(PrtBuf),
          cd->Format, cd->Width, cd->Precision, a/b);
     return PrtBuf;
 }
@@ -272,10 +282,10 @@ contline_next(void)
     if ((ch = getc(logfile)) != EOF) {
            if (ungetc(ch, logfile) == EOF) {
                if (ferror(logfile)) {
-                   error("ungetc failed: %s\n", strerror(errno));
+                   error(_("ungetc failed: %s\n"), strerror(errno));
                    /*NOTREACHED*/
                }
-               error("ungetc failed: EOF\n");
+               error(_("ungetc failed: EOF\n"));
                /*NOTREACHED*/
            }
     }
@@ -308,7 +318,7 @@ addline(
 static void
 usage(void)
 {
-    error("Usage: amreport conf [-i] [-M address] [-f output-file] [-l logfile] [-p postscript-file] [-o configoption]*");
+    error(_("Usage: amreport conf [-i] [-M address] [-f output-file] [-l logfile] [-p postscript-file] [-o configoption]*"));
     /*NOTREACHED*/
 }
 
@@ -317,26 +327,32 @@ main(
     int                argc,
     char **    argv)
 {
-    char *conffile;
     char *conf_diskfile;
     char *conf_tapelist;
     char *conf_infofile;
     char *logfname, *psfname, *outfname, *subj_str = NULL;
     tapetype_t *tp;
     int opt;
-    unsigned long malloc_hist_1, malloc_size_1;
-    unsigned long malloc_hist_2, malloc_size_2;
     char *mail_cmd = NULL, *printer_cmd = NULL;
     extern int optind;
-    char my_cwd[STR_SIZE];
+    char * cwd = NULL;
     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;
+    config_overwrites_t *cfg_ovr = NULL;
+    char *cfg_opt = NULL;
+
+    /*
+     * Configure program for internationalization:
+     *   1) Only set the message locale for now.
+     *   2) Set textdomain for all amanda related programs to "amanda"
+     *      We don't want to be forced to support dozens of message catalogs.
+     */  
+    setlocale(LC_MESSAGES, "C");
+    textdomain("amanda"); 
 
     safe_fd(-1, 0);
 
@@ -347,86 +363,85 @@ main(
     /* Don't die when child closes pipe */
     signal(SIGPIPE, SIG_IGN);
 
-    malloc_size_1 = malloc_inuse(&malloc_hist_1);
-
     /* Process options */
     
     erroutput_type = ERR_INTERACTIVE;
     outfname = NULL;
     psfname = NULL;
     logfname = NULL;
+    cmdlogfname = 0;
 
-    if (getcwd(my_cwd, SIZEOF(my_cwd)) == NULL) {
-       error("cannot determine current working directory");
+    cwd = g_get_current_dir();
+    if (cwd == NULL) {
+       error(_("Cannot determine current working directory: %s"),
+             strerror(errno));
        /*NOTREACHED*/
     }
 
-    parse_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 (my_argv[1][0] == '-') {
+    if (argc >= 2) {
+       if (argv[1][0] == '-') {
            usage();
            return 1;
        }
-       config_name = stralloc(my_argv[1]);
-       config_dir = vstralloc(CONFIG_DIR, "/", config_name, "/", NULL);
-       --my_argc; ++my_argv;
-       while((opt = getopt(my_argc, my_argv, "M:f:l:p:i")) != EOF) {
+
+       /* get the config name and move past it */
+       cfg_opt = argv[1];
+       --argc; ++argv;
+
+       cfg_ovr = new_config_overwrites(argc/2);
+       while((opt = getopt(argc, argv, "o: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");
+                   error(_("you may specify at most one -M"));
                    /*NOTREACHED*/
                }
                 mailto = stralloc(optarg);
                if(!validate_mailto(mailto)) {
-                   error("mail address has invalid characters");
+                   error(_("mail address has invalid characters"));
                    /*NOTREACHED*/
                }
                 break;
             case 'f':
                if (outfname != NULL) {
-                   error("you may specify at most one -f");
+                   error(_("you may specify at most one -f"));
                    /*NOTREACHED*/
                }
                if (*optarg == '/') {
                     outfname = stralloc(optarg);
                } else {
-                    outfname = vstralloc(my_cwd, "/", optarg, NULL);
+                    outfname = vstralloc(cwd, "/", optarg, NULL);
                }
                 break;
             case 'l':
+               cmdlogfname = 1;
                if (logfname != NULL) {
-                   error("you may specify at most one -l");
+                   error(_("you may specify at most one -l"));
                    /*NOTREACHED*/
                }
                if (*optarg == '/') {
                    logfname = stralloc(optarg);
                } else {
-                    logfname = vstralloc(my_cwd, "/", optarg, NULL);
+                    logfname = vstralloc(cwd, "/", optarg, NULL);
                }
                 break;
             case 'p':
                if (psfname != NULL) {
-                   error("you may specify at most one -p");
+                   error(_("you may specify at most one -p"));
                    /*NOTREACHED*/
                }
                if (*optarg == '/') {
                     psfname = stralloc(optarg);
                } else {
-                    psfname = vstralloc(my_cwd, "/", optarg, NULL);
+                    psfname = vstralloc(cwd, "/", optarg, NULL);
                }
                 break;
+           case 'o':
+               add_config_overwrite_opt(cfg_ovr, optarg);
+               break;
             case '?':
                usage();
                return 1;
@@ -435,41 +450,37 @@ main(
            }
        }
 
-       my_argc -= optind;
-       my_argv += optind;
+       argc -= optind;
+       argv += optind;
     }
     if( !mailout && mailto ){
-       printf("You cannot specify both -i & -M at the same time\n");
+       g_printf(_("You cannot specify both -i & -M at the same time\n"));
        exit(1);
     }
 
+    amfree(cwd);
 
 #if !defined MAILER
     if(!outfname) {
-       printf("You must run amreport with '-f <output file>' because configure\n");
-       printf("didn't find a mailer.\n");
+       g_printf(_("You must run amreport with '-f <output file>' because configure\n"));
+       g_printf(_("didn't find a mailer.\n"));
        exit (1);
     }
 #endif
 
-    safe_cd();
-
     /* read configuration files */
 
-    conffile = stralloc2(config_dir, CONFFILE_NAME);
-    /* Ignore error from read_conffile */
-    read_conffile(conffile);
-    amfree(conffile);
+    /* ignore any errors reading the config file (amreport can run without a config) */
+    config_init(CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_USE_CWD, cfg_opt);
+    if (cfg_ovr) apply_config_overwrites(cfg_ovr);
+
+    check_running_as(RUNNING_AS_DUMPUSER);
 
     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);
-    }
+    safe_cd(); /* must be called *after* config_init() */
+
+    conf_diskfile = config_dir_relative(getconf_str(CNF_DISKFILE));
     /* Ignore error from read_diskfile */
     read_diskfile(conf_diskfile, &diskq);
     amfree(conf_diskfile);
@@ -481,23 +492,13 @@ main(
                 }
     }
     
-    conf_tapelist = getconf_str(CNF_TAPELIST);
-    if (*conf_tapelist == '/') {
-       conf_tapelist = stralloc(conf_tapelist);
-    } else {
-       conf_tapelist = stralloc2(config_dir, conf_tapelist);
-    }
+    conf_tapelist = config_dir_relative(getconf_str(CNF_TAPELIST));
     /* Ignore error from read_tapelist */
     read_tapelist(conf_tapelist);
     amfree(conf_tapelist);
-    conf_infofile = getconf_str(CNF_INFOFILE);
-    if (*conf_infofile == '/') {
-       conf_infofile = stralloc(conf_infofile);
-    } else {
-       conf_infofile = stralloc2(config_dir, conf_infofile);
-    }
+    conf_infofile = config_dir_relative(getconf_str(CNF_INFOFILE));
     if(open_infofile(conf_infofile)) {
-       error("could not open info db \"%s\"", conf_infofile);
+       error(_("could not open info db \"%s\""), conf_infofile);
        /*NOTREACHED*/
     }
     amfree(conf_infofile);
@@ -506,7 +507,7 @@ main(
     unitdivisor = getconf_unit_divisor();
 
     ColumnSpec = getconf_str(CNF_COLUMNSPEC);
-    if(SetColumDataFromString(ColumnData, ColumnSpec, &errstr) < 0) {
+    if(SetColumnDataFromString(ColumnData, ColumnSpec, &errstr) < 0) {
        curlog = L_ERROR;
        curprog = P_REPORTER;
        curstr = errstr;
@@ -514,7 +515,7 @@ main(
         amfree(errstr);
        curstr = NULL;
        ColumnSpec = "";                /* use the default */
-       if(SetColumDataFromString(ColumnData, ColumnSpec, &errstr) < 0) {
+       if(SetColumnDataFromString(ColumnData, ColumnSpec, &errstr) < 0) {
            curlog = L_ERROR;
            curprog = P_REPORTER;
            curstr = errstr;
@@ -533,12 +534,7 @@ main(
     if(!logfname) {
        char *conf_logdir;
 
-       conf_logdir = getconf_str(CNF_LOGDIR);
-       if (*conf_logdir == '/') {
-           conf_logdir = stralloc(conf_logdir);
-       } else {
-           conf_logdir = stralloc2(config_dir, conf_logdir);
-       }
+       conf_logdir = config_dir_relative(getconf_str(CNF_LOGDIR));
        logfname = vstralloc(conf_logdir, "/", "log", NULL);
        amfree(conf_logdir);
     }
@@ -546,7 +542,7 @@ main(
     if((logfile = fopen(logfname, "r")) == NULL) {
        curlog = L_ERROR;
        curprog = P_REPORTER;
-       curstr = vstralloc("could not open log ",
+       curstr = vstralloc(_("could not open log "),
                           logfname,
                           ": ",
                           strerror(errno),
@@ -557,31 +553,34 @@ main(
 
     while(logfile && get_logline(logfile)) {
        switch(curlog) {
-       case L_START:   handle_start(); break;
-       case L_FINISH:  handle_finish(); break;
+       case L_START:        handle_start(); break;
+       case L_FINISH:       handle_finish(); break;
 
-       case L_INFO:    handle_note(); break;
-       case L_WARNING: handle_note(); break;
+       case L_INFO:         handle_note(); break;
+       case L_WARNING:      handle_note(); break;
 
-       case L_SUMMARY: handle_summary(); break;
-       case L_STATS:   handle_stats(); break;
+       case L_SUMMARY:      handle_summary(); break;
+       case L_STATS:        handle_stats(); break;
 
-       case L_ERROR:   handle_error(); break;
-       case L_FATAL:   handle_error(); break;
+       case L_ERROR:        handle_error(); break;
+       case L_FATAL:        handle_error(); break;
 
-       case L_DISK:    handle_disk(); break;
+       case L_DISK:         handle_disk(); break;
 
-       case L_SUCCESS: handle_success(curlog); break;
+       case L_DONE:         handle_success(curlog); break;
+       case L_SUCCESS:      handle_success(curlog); break;
        case L_CHUNKSUCCESS: handle_success(curlog); break;
-       case L_CHUNK:   handle_chunk(); break;
-       case L_PARTIAL: handle_partial(); break;
-       case L_STRANGE: handle_strange(); break;
-       case L_FAIL:    handle_failed(); break;
+       case L_PART:         handle_chunk(curlog); break;
+       case L_PARTPARTIAL:  handle_chunk(curlog); break;
+       case L_CHUNK:        handle_chunk(curlog); break;
+       case L_PARTIAL:      handle_partial(); break;
+       case L_STRANGE:      handle_strange(); break;
+       case L_FAIL:         handle_failed(); break;
 
        default:
            curlog = L_ERROR;
            curprog = P_REPORTER;
-           curstr = stralloc2("unexpected log line: ", curstr);
+           curstr = vstrallocf(_("unexpected log line: %s"), curstr);
            handle_error();
            amfree(curstr);
        }
@@ -611,11 +610,13 @@ main(
     if(outfname) {
        /* output to a file */
        if((mailf = fopen(outfname,"w")) == NULL) {
-           error("could not open output file: %s %s", outfname, strerror(errno));
+           error(_("could not open output file: %s %s"), outfname, strerror(errno));
            /*NOTREACHED*/
        }
-       fprintf(mailf, "To: %s\n", mailto);
-       fprintf(mailf, "Subject: %s\n\n", subj_str);
+        if (mailto != NULL) {
+               g_fprintf(mailf, "To: %s\n", mailto);
+               g_fprintf(mailf, "Subject: %s\n\n", subj_str);
+       }
 
     } else {
 #ifdef MAILER
@@ -624,15 +625,15 @@ main(
                             " -s", " \"", subj_str, "\"",
                             " ", mailto, NULL);
                if((mailf = popen(mail_cmd, "w")) == NULL) {
-               error("could not open pipe to \"%s\": %s",
+               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");
+                   g_printf(_("No mail sent! "));
+                  g_printf(_("No valid mail address has been specified in amanda.conf or on the commmand line\n"));
                }
                mailf = NULL;
        }
@@ -651,11 +652,9 @@ main(
            if ((postscript = fopen(psfname, "w")) == NULL) {
                curlog = L_ERROR;
                curprog = P_REPORTER;
-               curstr = vstralloc("could not open ",
+               curstr = vstrallocf(_("could not open %s: %s"),
                                   psfname,
-                                  ": ",
-                                  strerror(errno),
-                                  NULL);
+                                  strerror(errno));
                handle_error();
                amfree(curstr);
            }
@@ -680,18 +679,15 @@ main(
            if ((postscript = popen(printer_cmd, "w")) == NULL) {
                curlog = L_ERROR;
                curprog = P_REPORTER;
-               curstr = vstralloc("could not open pipe to ",
-                                  printer_cmd,
-                                  ": ",
-                                  strerror(errno),
-                                  NULL);
+               curstr = vstrallocf(_("could not open pipe to %s: %s"),
+                                  printer_cmd, strerror(errno));
                handle_error();
                amfree(curstr);
            }
 #else
            curlog = L_ERROR;
            curprog = P_REPORTER;
-           curstr = stralloc("no printer command defined");
+           curstr = vstrallocf(_("no printer command defined"));
            handle_error();
            amfree(curstr);
 #endif
@@ -700,44 +696,57 @@ main(
 
     amfree(subj_str);
 
+    sort_disks();
+
     if(mailf) {
 
-       if(!got_finish) fputs("*** THE DUMPS DID NOT FINISH PROPERLY!\n\n", mailf);
+       if(!got_finish) fputs(_("*** THE DUMPS DID NOT FINISH PROPERLY!\n\n"), mailf);
 
        if (ghostname) {
-           fprintf(mailf, "Hostname: %s\n", ghostname);
-           fprintf(mailf, "Org     : %s\n", getconf_str(CNF_ORG));
-           fprintf(mailf, "Config  : %s\n", config_name);
-           fprintf(mailf, "Date    : %s\n",
+           g_fprintf(mailf, _("Hostname: %s\n"), ghostname);
+           g_fprintf(mailf, _("Org     : %s\n"), getconf_str(CNF_ORG));
+           g_fprintf(mailf, _("Config  : %s\n"), config_name);
+           g_fprintf(mailf, _("Date    : %s\n"),
                    nicedate(run_datestamp ? run_datestamp : "0"));
-           fprintf(mailf,"\n");
+           g_fprintf(mailf,"\n");
        }
 
        output_tapeinfo();
 
-       if(first_strange || errsum) {
-               fprintf(mailf,"\nFAILURE AND STRANGE DUMP SUMMARY:\n");
-               if(first_strange) output_strange();
+       if(first_failed || errsum) {
+               g_fprintf(mailf,_("\nFAILURE DUMP SUMMARY:\n"));
+               if(first_failed) output_X_summary(first_failed);
                if(errsum) output_lines(errsum, mailf);
        }
+       if(first_strange) {
+               g_fprintf(mailf,_("\nSTRANGE DUMP SUMMARY:\n"));
+               if(first_strange) output_X_summary(first_strange);
+       }
        fputs("\n\n", mailf);
        
        output_stats();
        
        if(errdet) {
-               fprintf(mailf,"\n\014\nFAILED AND STRANGE DUMP DETAILS:\n");
+               g_fprintf(mailf,"\n\f\n");
+               g_fprintf(mailf,_("FAILED DUMP DETAILS:\n"));
                output_lines(errdet, mailf);
        }
+       if(strangedet) {
+               g_fprintf(mailf,"\n\f\n");
+               g_fprintf(mailf,_("STRANGE DUMP DETAILS:\n"));
+               output_lines(strangedet, mailf);
+       }
        if(notes) {
-               fprintf(mailf,"\n\014\nNOTES:\n");
+               g_fprintf(mailf,"\n\f\n");
+               g_fprintf(mailf,_("NOTES:\n"));
                output_lines(notes, mailf);
        }
-       sort_disks();
        if(sortq.head != NULL) {
-               fprintf(mailf,"\n\014\nDUMP SUMMARY:\n");
+               g_fprintf(mailf,"\n\f\n");
+               g_fprintf(mailf,_("DUMP SUMMARY:\n"));
                output_summary();
        }
-       fprintf(mailf,"\n(brought to you by Amanda version %s)\n",
+       g_fprintf(mailf,_("\n(brought to you by Amanda version %s)\n"),
                version());
     }
 
@@ -753,7 +762,7 @@ main(
     }
     else {
        if (postscript != NULL && pclose(postscript) != 0) {
-           error("printer command failed: %s", printer_cmd);
+           error(_("printer command failed: %s"), printer_cmd);
            /*NOTREACHED*/
        }
        postscript = NULL;
@@ -764,8 +773,10 @@ main(
         afclose(mailf);
     }
     else if(mailf) {
-        if(pclose(mailf) != 0) {
-            error("mail command failed: %s", mail_cmd);
+       int exitcode;
+        if((exitcode = pclose(mailf)) != 0) {
+           char *exitstr = str_exit_status("mail command", exitcode);
+            error(exitstr);
            /*NOTREACHED*/
        }
         mailf = NULL;
@@ -773,22 +784,12 @@ main(
 
     clear_tapelist();
     free_disklist(&diskq);
-    free_new_argv(new_argc, new_argv);
-    free_server_config();
     amfree(run_datestamp);
     amfree(tape_labels);
-    amfree(config_dir);
-    amfree(config_name);
     amfree(printer_cmd);
     amfree(mail_cmd);
     amfree(logfname);
 
-    malloc_size_2 = malloc_inuse(&malloc_hist_2);
-
-    if(malloc_size_1 != malloc_size_2) {
-       malloc_list(fileno(stderr), malloc_hist_1, malloc_hist_2);
-    }
-
     dbclose();
     return exit_status;
 }
@@ -805,21 +806,21 @@ main(
     do {                                           \
        double q = (b);                     \
        if (!isnormal(q))                   \
-           fprintf((fp),"  -- ");          \
+           g_fprintf((fp),"  -- ");        \
        else if ((q = (a)/q) >= 999.95)     \
-           fprintf((fp), "###.#");         \
+           g_fprintf((fp), "###.#");       \
        else                                \
-           fprintf((fp), "%5.1lf",q);      \
+           g_fprintf((fp), "%5.1lf",q);            \
     } while(0)
 #define divzero_wide(fp,a,b)               \
     do {                                           \
        double q = (b);                     \
        if (!isnormal(q))                   \
-           fprintf((fp),"    -- ");        \
+           g_fprintf((fp),"    -- ");      \
        else if ((q = (a)/q) >= 99999.95)   \
-           fprintf((fp), "#####.#");       \
+           g_fprintf((fp), "#####.#");     \
        else                                \
-           fprintf((fp), "%7.1lf",q);      \
+           g_fprintf((fp), "%7.1lf",q);            \
     } while(0)
 
 static void
@@ -856,142 +857,142 @@ output_stats(void)
     idle_time = (total_time - startup_time) - stats[2].taper_time;
     if(idle_time < 0) idle_time = 0.0;
 
-    fprintf(mailf,"STATISTICS:\n");
-    fprintf(mailf,
-           "                          Total       Full      Incr.\n");
-    fprintf(mailf,
-           "                        --------   --------   --------\n");
+    g_fprintf(mailf,_("STATISTICS:\n"));
+    g_fprintf(mailf,
+           _("                          Total       Full      Incr.\n"));
+    g_fprintf(mailf,
+           _("                        --------   --------   --------\n"));
 
-    fprintf(mailf,
-           "Estimate Time (hrs:min)   %2d:%02d\n", hrmn(planner_time));
+    g_fprintf(mailf,
+           _("Estimate Time (hrs:min)   %2d:%02d\n"), hrmn(planner_time));
 
-    fprintf(mailf,
-           "Run Time (hrs:min)        %2d:%02d\n", hrmn(total_time));
+    g_fprintf(mailf,
+           _("Run Time (hrs:min)        %2d:%02d\n"), hrmn(total_time));
 
-    fprintf(mailf,
-           "Dump Time (hrs:min)       %2d:%02d      %2d:%02d      %2d:%02d\n",
+    g_fprintf(mailf,
+           _("Dump Time (hrs:min)       %2d:%02d      %2d:%02d      %2d:%02d\n"),
            hrmn(stats[2].dumper_time), hrmn(stats[0].dumper_time),
            hrmn(stats[1].dumper_time));
 
-    fprintf(mailf,
-           "Output Size (meg)      %8.1lf   %8.1lf   %8.1lf\n",
+    g_fprintf(mailf,
+           _("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.1lf   %8.1lf   %8.1lf\n",
+    g_fprintf(mailf,
+           _("Original Size (meg)    %8.1lf   %8.1lf   %8.1lf\n"),
            mb(stats[2].origsize), mb(stats[0].origsize),
            mb(stats[1].origsize));
 
-    fprintf(mailf, "Avg Compressed Size (%%)   ");
+    g_fprintf(mailf, _("Avg Compressed Size (%%)   "));
     divzero(mailf, pct(stats[2].coutsize),stats[2].corigsize);
-    fputs("      ", mailf);
+    fputs(_("      "), mailf);
     divzero(mailf, pct(stats[0].coutsize),stats[0].corigsize);
-    fputs("      ", mailf);
+    fputs(_("      "), mailf);
     divzero(mailf, pct(stats[1].coutsize),stats[1].corigsize);
 
-    if(stats[1].dumpdisks > 0) fputs("   (level:#disks ...)", mailf);
+    if(stats[1].dumpdisks > 0) fputs(_("   (level:#disks ...)"), mailf);
     putc('\n', mailf);
 
-    fprintf(mailf,
-           "Filesystems Dumped         %4d       %4d       %4d",
+    g_fprintf(mailf,
+           _("Filesystems Dumped         %4d       %4d       %4d"),
            stats[2].dumpdisks, stats[0].dumpdisks, stats[1].dumpdisks);
 
     if(stats[1].dumpdisks > 0) {
        first = 1;
        for(lv = 1; lv < 10; lv++) if(dumpdisks[lv]) {
-           fputs(first?"   (":" ", mailf);
+           fputs(first?_("   ("):_(" "), mailf);
            first = 0;
-           fprintf(mailf, "%d:%d", lv, dumpdisks[lv]);
+           g_fprintf(mailf, _("%d:%d"), lv, dumpdisks[lv]);
        }
        putc(')', mailf);
     }
     putc('\n', mailf);
 
-    fprintf(mailf, "Avg Dump Rate (k/s)     ");
+    g_fprintf(mailf, _("Avg Dump Rate (k/s)     "));
     divzero_wide(mailf, stats[2].outsize,stats[2].dumper_time);
-    fputs("    ", mailf);
+    fputs(_("    "), mailf);
     divzero_wide(mailf, stats[0].outsize,stats[0].dumper_time);
-    fputs("    ", mailf);
+    fputs(_("    "), mailf);
     divzero_wide(mailf, stats[1].outsize,stats[1].dumper_time);
     putc('\n', mailf);
 
     putc('\n', mailf);
-    fprintf(mailf,
-           "Tape Time (hrs:min)       %2d:%02d      %2d:%02d      %2d:%02d\n",
+    g_fprintf(mailf,
+           _("Tape Time (hrs:min)       %2d:%02d      %2d:%02d      %2d:%02d\n"),
            hrmn(stats[2].taper_time), hrmn(stats[0].taper_time),
            hrmn(stats[1].taper_time));
 
-    fprintf(mailf,
-           "Tape Size (meg)        %8.1lf   %8.1lf   %8.1lf\n",
+    g_fprintf(mailf,
+           _("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 (%%)             ");
+    g_fprintf(mailf, _("Tape Used (%%)             "));
     divzero(mailf, pct(stats[2].tapesize+marksize*(stats[2].tapedisks+stats[2].tapechunks)),(double)tapesize);
-    fputs("      ", mailf);
+    fputs(_("      "), mailf);
     divzero(mailf, pct(stats[0].tapesize+marksize*(stats[0].tapedisks+stats[0].tapechunks)),(double)tapesize);
-    fputs("      ", mailf);
+    fputs(_("      "), mailf);
     divzero(mailf, pct(stats[1].tapesize+marksize*(stats[1].tapedisks+stats[1].tapechunks)),(double)tapesize);
 
-    if(stats[1].tapedisks > 0) fputs("   (level:#disks ...)", mailf);
+    if(stats[1].tapedisks > 0) fputs(_("   (level:#disks ...)"), mailf);
     putc('\n', mailf);
 
-    fprintf(mailf,
-           "Filesystems Taped          %4d       %4d       %4d",
+    g_fprintf(mailf,
+           _("Filesystems Taped          %4d       %4d       %4d"),
            stats[2].tapedisks, stats[0].tapedisks, stats[1].tapedisks);
 
     if(stats[1].tapedisks > 0) {
        first = 1;
        for(lv = 1; lv < 10; lv++) if(tapedisks[lv]) {
-           fputs(first?"   (":" ", mailf);
+           fputs(first?_("   ("):_(" "), mailf);
            first = 0;
-           fprintf(mailf, "%d:%d", lv, tapedisks[lv]);
+           g_fprintf(mailf, _("%d:%d"), lv, tapedisks[lv]);
        }
        putc(')', mailf);
     }
     putc('\n', mailf);
 
-    if(stats[1].tapechunks > 0) fputs("   (level:#chunks ...)", mailf);
+    if(stats[1].tapechunks > 0) fputs(_("   (level:#chunks ...)"), mailf);
     putc('\n', mailf);
 
-    fprintf(mailf,
-           "Chunks Taped               %4d       %4d       %4d",
+    g_fprintf(mailf,
+           _("Chunks Taped               %4d       %4d       %4d"),
            stats[2].tapechunks, stats[0].tapechunks, stats[1].tapechunks);
 
     if(stats[1].tapechunks > 0) {
        first = 1;
        for(lv = 1; lv < 10; lv++) if(tapechunks[lv]) {
-           fputs(first?"   (":" ", mailf);
+           fputs(first?_("   ("):_(" "), mailf);
            first = 0;
-           fprintf(mailf, "%d:%d", lv, tapechunks[lv]);
+           g_fprintf(mailf, _("%d:%d"), lv, tapechunks[lv]);
        }
        putc(')', mailf);
     }
     putc('\n', mailf);
 
-    fprintf(mailf, "Avg Tp Write Rate (k/s) ");
+    g_fprintf(mailf, _("Avg Tp Write Rate (k/s) "));
     divzero_wide(mailf, stats[2].tapesize,stats[2].taper_time);
-    fputs("    ", mailf);
+    fputs(_("    "), mailf);
     divzero_wide(mailf, stats[0].tapesize,stats[0].taper_time);
-    fputs("    ", mailf);
+    fputs(_("    "), mailf);
     divzero_wide(mailf, stats[1].tapesize,stats[1].taper_time);
     putc('\n', mailf);
 
     if(stats_by_tape) {
        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");
+       g_fprintf(mailf,_("\nUSAGE BY TAPE:\n"));
+       g_fprintf(mailf,_("  %-*s  Time      Size      %%    Nb    Nc\n"),
+               label_length, _("Label"));
        for(current_tape = stats_by_tape; current_tape != NULL;
            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.0lf%s  ", du(current_tape->coutsize), displayunit);
+           g_fprintf(mailf, _("  %-*s"), label_length, current_tape->label);
+           g_fprintf(mailf, _(" %2d:%02d"), hrmn(current_tape->taper_time));
+           g_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);
+           g_fprintf(mailf, _("  %4d"), current_tape->tapedisks);
+           g_fprintf(mailf, _("  %4d\n"), current_tape->tapechunks);
        }
     }
 }
@@ -1007,22 +1008,55 @@ output_tapeinfo(void)
 
     if (last_run_tapes > 0) {
        if(amflush_run)
-           fprintf(mailf, "The dumps were flushed to tape%s %s.\n",
-                   last_run_tapes == 1 ? "" : "s",
+           g_fprintf(mailf,
+                   plural(_("The dumps were flushed to tape %s.\n"),
+                          _("The dumps were flushed to tapes %s.\n"),
+                          last_run_tapes),
                    tape_labels ? tape_labels : "");
        else
-           fprintf(mailf, "These dumps were to tape%s %s.\n",
-                   last_run_tapes == 1 ? "" : "s",
+           g_fprintf(mailf,
+                   plural(_("These dumps were to tape %s.\n"),
+                          _("These dumps were to tapes %s.\n"),
+                          last_run_tapes),
                    tape_labels ? tape_labels : "");
     }
 
     if(degraded_mode) {
-       fprintf(mailf,
-               "*** A TAPE ERROR OCCURRED: %s.\n", tapestart_error);
-       fputs("Some dumps may have been left in the holding disk.\n", mailf);
-       fprintf(mailf,
-               "Run amflush%s to flush them to tape.\n",
-               amflush_run ? " again" : "");
+       g_fprintf(mailf,
+               _("*** A TAPE ERROR OCCURRED: %s.\n"), tapestart_error);
+    }
+    if (cmdlogfname == 1) {
+       if(degraded_mode) {
+           fputs(_("Some dumps may have been left in the holding disk.\n"),
+                 mailf);
+           g_fprintf(mailf,"\n");
+       }
+    }  else {
+       GSList *holding_list, *holding_file;
+       off_t  h_size = 0, mh_size;
+
+       holding_list = holding_get_files_for_flush(NULL);
+       for(holding_file=holding_list; holding_file != NULL;
+                                      holding_file = holding_file->next) {
+           mh_size = holding_file_size((char *)holding_file->data, 1);
+           if (mh_size > 0)
+               h_size += mh_size;
+       }
+
+       if (h_size > 0) {
+           g_fprintf(mailf,
+                   _("There are %lld%s of dumps left in the holding disk.\n"),
+                   (long long)h_size, displayunit);
+           if (getconf_boolean(CNF_AUTOFLUSH)) {
+               g_fprintf(mailf, _("They will be flushed on the next run.\n"));
+           } else {
+               g_fprintf(mailf, _("Run amflush to flush them to tape.\n"));
+           }
+           g_fprintf(mailf,"\n");
+       } else if (degraded_mode) {
+           g_fprintf(mailf, _("No dumps are left in the holding disk. %lld%s\n"), (long long)h_size, displayunit);
+           g_fprintf(mailf,"\n");
+       }
     }
 
     tp = lookup_last_reusable_tape(skip);
@@ -1030,19 +1064,19 @@ output_tapeinfo(void)
     run_tapes = getconf_int(CNF_RUNTAPES);
 
     if (run_tapes == 1)
-       fputs("The next tape Amanda expects to use is: ", mailf);
+       fputs(_("The next tape Amanda expects to use is: "), mailf);
     else if(run_tapes > 1)
-       fprintf(mailf, "The next %d tapes Amanda expects to use are: ",
+       g_fprintf(mailf, _("The next %d tapes Amanda expects to use are: "),
                run_tapes);
     
     while(run_tapes > 0) {
        if(tp != NULL) {
-           fprintf(mailf, "%s", tp->label);
+           g_fprintf(mailf, "%s", tp->label);
        } else {
            if (run_tapes == 1)
-               fprintf(mailf, "a new tape");
+               g_fprintf(mailf, _("a new tape"));
            else
-               fprintf(mailf, "%d new tapes", run_tapes);
+               g_fprintf(mailf, _("%d new tapes"), run_tapes);
            run_tapes = 1;
        }
 
@@ -1065,42 +1099,43 @@ output_tapeinfo(void)
        }
        lasttp = lookup_tapepos(lookup_nb_tape());
        if(c == 1) {
-           fprintf(mailf, "The next new tape already labelled is: %s.\n",
+           g_fprintf(mailf, _("The next new tape already labelled is: %s.\n"),
                    lasttp->label);
        }
        else {
-           fprintf(mailf, "The next %d new tapes already labelled are: %s", c,
+           g_fprintf(mailf, _("The next %d new tapes already labelled are: %s"), c,
                    lasttp->label);
            lasttp = lasttp->prev;
            c--;
            while(lasttp && c > 0 && strcmp(lasttp->datestamp,"0") == 0) {
-               fprintf(mailf, ", %s", lasttp->label);
+               g_fprintf(mailf, ", %s", lasttp->label);
                lasttp = lasttp->prev;
                c--;
            }
-           fprintf(mailf, ".\n");
+           g_fprintf(mailf, ".\n");
        }
     }
 }
 
 /* ----- */
 static void
-output_strange(void)
+output_X_summary(
+    X_summary_t *first)
 {
     size_t len_host=0, len_disk=0;
-    strange_t *strange;
+    X_summary_t *strange;
     char *str = NULL;
 
-    for(strange=first_strange; strange != NULL; strange = strange->next) {
+    for(strange=first; strange != NULL; strange = strange->next) {
        if(strlen(strange->hostname) > len_host)
            len_host = strlen(strange->hostname);
        if(strlen(strange->diskname) > len_disk)
            len_disk = strlen(strange->diskname);
     }
-    for(strange=first_strange; strange != NULL; strange = strange->next) {
+    for(strange=first; strange != NULL; strange = strange->next) {
        str = vstralloc("  ", prefixstrange(strange->hostname, strange->diskname, strange->level, len_host, len_disk),
                        "  ", strange->str, NULL);
-       fprintf(mailf, "%s\n", str);
+       g_fprintf(mailf, "%s\n", str);
        amfree(str);
     }
 }
@@ -1173,7 +1208,7 @@ CheckIntMax(
        char testBuf[200];
        int l;
 
-       snprintf(testBuf, SIZEOF(testBuf),
+       g_snprintf(testBuf, SIZEOF(testBuf),
          cd->Format, cd->Width, cd->Precision, n);
        l = (int)strlen(testBuf);
        if (cd->Width < l)
@@ -1189,7 +1224,8 @@ CheckFloatMax(
     if (cd->MaxWidth) {
        char testBuf[200];
        int l;
-       snprintf(testBuf, SIZEOF(testBuf),
+
+       g_snprintf(testBuf, SIZEOF(testBuf),
          cd->Format, cd->Width, cd->Precision, d);
        l = (int)strlen(testBuf);
        if (cd->Width < l)
@@ -1221,6 +1257,15 @@ CalcMaxWidth(void)
     double f;
     repdata_t *repdata;
     char *qdevname;
+    int i, l;
+
+    for (i=0;ColumnData[i].Name != NULL; i++) {
+       if (ColumnData[i].MaxWidth) {
+           l = (int)strlen(ColumnData[i].Title);
+           if (ColumnData[i].Width < l)
+               ColumnData[i].Width= l;
+       }
+    }
 
     for(dp = sortq.head; dp != NULL; dp = dp->next) {
       if(dp->todo) {
@@ -1241,18 +1286,18 @@ CalcMaxWidth(void)
                              (double)du(repdata->dumper.origsize));
                CheckFloatMax(&ColumnData[OutKB],
                              (double)du(repdata->dumper.outsize));
-               if(dp->compress == COMP_NONE)
+               if(abs(repdata->dumper.outsize - repdata->dumper.origsize)< 32)
                    f = 0.0;
                else 
                    f = repdata->dumper.origsize;
-               CheckStringMax(&ColumnData[Disk], 
+               CheckStringMax(&ColumnData[Compress], 
                        sDivZero(pct(repdata->dumper.outsize), f, Compress));
 
                if(!amflush_run)
-                   snprintf(TimeRateBuffer, SIZEOF(TimeRateBuffer),
+                   g_snprintf(TimeRateBuffer, SIZEOF(TimeRateBuffer),
                                "%3d:%02d", mnsc(repdata->dumper.sec));
                else
-                   snprintf(TimeRateBuffer, SIZEOF(TimeRateBuffer),
+                   g_snprintf(TimeRateBuffer, SIZEOF(TimeRateBuffer),
                                "N/A ");
                CheckStringMax(&ColumnData[DumpTime], TimeRateBuffer);
 
@@ -1265,10 +1310,10 @@ CalcMaxWidth(void)
            }
            if(repdata->taper.result == L_SUCCESS ||
               repdata->taper.result == L_CHUNKSUCCESS)
-               snprintf(TimeRateBuffer, SIZEOF(TimeRateBuffer), 
+               g_snprintf(TimeRateBuffer, SIZEOF(TimeRateBuffer), 
                  "%3d:%02d", mnsc(repdata->taper.sec));
            else
-               snprintf(TimeRateBuffer, SIZEOF(TimeRateBuffer),
+               g_snprintf(TimeRateBuffer, SIZEOF(TimeRateBuffer),
                  "N/A ");
            CheckStringMax(&ColumnData[TapeTime], TimeRateBuffer);
 
@@ -1322,23 +1367,23 @@ output_summary(void)
     } else {
        h = (wDump-h)/2;
     }
-    fprintf(mailf, "%*s", w1+h, "");
-    fprintf(mailf, "%-*s", wDump-h, ds);
+    g_fprintf(mailf, "%*s", w1+h, "");
+    g_fprintf(mailf, "%-*s", wDump-h, ds);
     h = (int)strlen(ts);
     if (h > wTape) {
        h = 0;
     } else {
        h = (wTape-h)/2;
     }
-    fprintf(mailf, "%*s", h, "");
-    fprintf(mailf, "%-*s", wTape-h, ts);
+    g_fprintf(mailf, "%*s", h, "");
+    g_fprintf(mailf, "%-*s", wTape-h, ts);
     fputc('\n', mailf);
 
     /* print the titles */
     for (i=0; ColumnData[i].Name != NULL; i++) {
        char *fmt;
        ColumnInfo *cd= &ColumnData[i];
-       fprintf(mailf, "%*s", cd->PrefixSpace, "");
+       g_fprintf(mailf, "%*s", cd->PrefixSpace, "");
        if (cd->Format[1] == '-')
            fmt= "%-*s";
        else
@@ -1353,7 +1398,7 @@ output_summary(void)
            cd->Title = stralloc("OUT-KB");
            cd->Title[4] = displayunit[0];
        }
-       fprintf(mailf, fmt, cd->Width, cd->Title);
+       g_fprintf(mailf, fmt, cd->Width, cd->Title);
     }
     fputc('\n', mailf);
 
@@ -1373,48 +1418,48 @@ output_summary(void)
            size_t devlen;
 
            cd= &ColumnData[HostName];
-           fprintf(mailf, "%*s", cd->PrefixSpace, "");
-           fprintf(mailf, cd->Format, cd->Width, cd->Width, dp->host->hostname);
+           g_fprintf(mailf, "%*s", cd->PrefixSpace, "");
+           g_fprintf(mailf, cd->Format, cd->Width, cd->Width, dp->host->hostname);
 
            cd= &ColumnData[Disk];
-           fprintf(mailf, "%*s", cd->PrefixSpace, "");
+           g_fprintf(mailf, "%*s", cd->PrefixSpace, "");
            devname = sanitize_string(dp->name);
            qdevname = quote_string(devname);
            devlen = strlen(qdevname);
            if (devlen > (size_t)cd->Width) {
                fputc('-', mailf); 
-               fprintf(mailf, cd->Format, cd->Width-1, cd->Precision-1,
+               g_fprintf(mailf, cd->Format, cd->Width-1, cd->Precision-1,
                        qdevname+devlen - (cd->Width-1) );
            }
            else
-               fprintf(mailf, cd->Format, cd->Width, cd->Width, qdevname);
+               g_fprintf(mailf, cd->Format, cd->Width, cd->Width, qdevname);
            amfree(devname);
            amfree(qdevname);
            cd= &ColumnData[Level];
            if (repdata->dumper.result == L_BOGUS &&
                repdata->taper.result  == L_BOGUS) {
              if(amflush_run){
-               fprintf(mailf, "%*s%s\n", cd->PrefixSpace+cd->Width, "",
+               g_fprintf(mailf, "%*s%s\n", cd->PrefixSpace+cd->Width, "",
                        tmp=TextRule(OrigKB, TapeRate, "NO FILE TO FLUSH"));
              } else {
-               fprintf(mailf, "%*s%s\n", cd->PrefixSpace+cd->Width, "",
+               g_fprintf(mailf, "%*s%s\n", cd->PrefixSpace+cd->Width, "",
                        tmp=TextRule(OrigKB, TapeRate, "MISSING"));
              }
              amfree(tmp);
              continue;
            }
            
-           fprintf(mailf, "%*s", cd->PrefixSpace, "");
-           fprintf(mailf, cd->Format, cd->Width, cd->Precision,repdata->level);
+           g_fprintf(mailf, "%*s", cd->PrefixSpace, "");
+           g_fprintf(mailf, cd->Format, cd->Width, cd->Precision,repdata->level);
 
            if (repdata->dumper.result == L_SKIPPED) {
-               fprintf(mailf, "%s\n",
+               g_fprintf(mailf, "%s\n",
                        tmp=TextRule(OrigKB, TapeRate, "SKIPPED"));
                amfree(tmp);
                continue;
            }
            if (repdata->dumper.result == L_FAIL && (repdata->chunker.result != L_PARTIAL && repdata->taper.result  != L_PARTIAL)) {
-               fprintf(mailf, "%s\n",
+               g_fprintf(mailf, "%s\n",
                        tmp=TextRule(OrigKB, TapeRate, "FAILED"));
                amfree(tmp);
                exit_status |= STATUS_FAILED;
@@ -1443,21 +1488,21 @@ output_summary(void)
                outsize  = repdata->dumper.outsize;
 
            cd= &ColumnData[OrigKB];
-           fprintf(mailf, "%*s", cd->PrefixSpace, "");
+           g_fprintf(mailf, "%*s", cd->PrefixSpace, "");
            if(isnormal(origsize))
-               fprintf(mailf, cd->Format, cd->Width, cd->Precision, du(origsize));
+               g_fprintf(mailf, cd->Format, cd->Width, cd->Precision, du(origsize));
            else
-               fprintf(mailf, "%*.*s", cd->Width, cd->Width, "N/A");
+               g_fprintf(mailf, "%*.*s", cd->Width, cd->Width, "N/A");
 
            cd= &ColumnData[OutKB];
-           fprintf(mailf, "%*s", cd->PrefixSpace, "");
+           g_fprintf(mailf, "%*s", cd->PrefixSpace, "");
 
-           fprintf(mailf, cd->Format, cd->Width, cd->Precision, du(outsize));
+           g_fprintf(mailf, cd->Format, cd->Width, cd->Precision, du(outsize));
                
            cd= &ColumnData[Compress];
-           fprintf(mailf, "%*s", cd->PrefixSpace, "");
+           g_fprintf(mailf, "%*s", cd->PrefixSpace, "");
 
-           if(dp->compress == COMP_NONE)
+           if(abs(outsize - origsize) < 32)
                f = 0.0;
            else if(origsize < 1.0)
                f = 0.0;
@@ -1467,28 +1512,28 @@ output_summary(void)
            fputs(sDivZero(pct(outsize), f, Compress), mailf);
 
            cd= &ColumnData[DumpTime];
-           fprintf(mailf, "%*s", cd->PrefixSpace, "");
+           g_fprintf(mailf, "%*s", cd->PrefixSpace, "");
            if(repdata->dumper.result == L_SUCCESS ||
               repdata->dumper.result == L_CHUNKSUCCESS)
-               snprintf(TimeRateBuffer, SIZEOF(TimeRateBuffer),
+               g_snprintf(TimeRateBuffer, SIZEOF(TimeRateBuffer),
                  "%3d:%02d", mnsc(repdata->dumper.sec));
            else
-               snprintf(TimeRateBuffer, SIZEOF(TimeRateBuffer),
+               g_snprintf(TimeRateBuffer, SIZEOF(TimeRateBuffer),
                  "N/A ");
-           fprintf(mailf, cd->Format, cd->Width, cd->Width, TimeRateBuffer);
+           g_fprintf(mailf, cd->Format, cd->Width, cd->Width, TimeRateBuffer);
 
            cd= &ColumnData[DumpRate];
-           fprintf(mailf, "%*s", cd->PrefixSpace, "");
+           g_fprintf(mailf, "%*s", cd->PrefixSpace, "");
            if(repdata->dumper.result == L_SUCCESS ||
                    repdata->dumper.result == L_CHUNKSUCCESS)
-               fprintf(mailf, cd->Format, cd->Width, cd->Precision, repdata->dumper.kps);
+               g_fprintf(mailf, cd->Format, cd->Width, cd->Precision, repdata->dumper.kps);
            else
-               fprintf(mailf, "%*s", cd->Width, "N/A ");
+               g_fprintf(mailf, "%*s", cd->Width, "N/A ");
 
            cd= &ColumnData[TapeTime];
-           fprintf(mailf, "%*s", cd->PrefixSpace, "");
+           g_fprintf(mailf, "%*s", cd->PrefixSpace, "");
            if(repdata->taper.result == L_FAIL) {
-               fprintf(mailf, "%s\n",
+               g_fprintf(mailf, "%s\n",
                        tmp=TextRule(TapeTime, TapeRate, "FAILED "));
                amfree(tmp);
                continue;
@@ -1497,26 +1542,26 @@ output_summary(void)
            if(repdata->taper.result == L_SUCCESS || 
               repdata->taper.result == L_PARTIAL ||
               repdata->taper.result == L_CHUNKSUCCESS)
-               snprintf(TimeRateBuffer, SIZEOF(TimeRateBuffer),
+               g_snprintf(TimeRateBuffer, SIZEOF(TimeRateBuffer),
                  "%3d:%02d", mnsc(repdata->taper.sec));
            else
-               snprintf(TimeRateBuffer, SIZEOF(TimeRateBuffer),
+               g_snprintf(TimeRateBuffer, SIZEOF(TimeRateBuffer),
                  "N/A ");
-           fprintf(mailf, cd->Format, cd->Width, cd->Width, TimeRateBuffer);
+           g_fprintf(mailf, cd->Format, cd->Width, cd->Width, TimeRateBuffer);
 
            cd= &ColumnData[TapeRate];
-           fprintf(mailf, "%*s", cd->PrefixSpace, "");
+           g_fprintf(mailf, "%*s", cd->PrefixSpace, "");
            if(repdata->taper.result == L_SUCCESS || 
               repdata->taper.result == L_PARTIAL ||
               repdata->taper.result == L_CHUNKSUCCESS)
-               fprintf(mailf, cd->Format, cd->Width, cd->Precision, repdata->taper.kps);
+               g_fprintf(mailf, cd->Format, cd->Width, cd->Precision, repdata->taper.kps);
            else
-               fprintf(mailf, "%*s", cd->Width, "N/A ");
+               g_fprintf(mailf, "%*s", cd->Width, "N/A ");
 
            if (repdata->chunker.result == L_PARTIAL)
-               fprintf(mailf, " PARTIAL");
+               g_fprintf(mailf, " PARTIAL");
            else if(repdata->taper.result == L_PARTIAL)
-               fprintf(mailf, " TAPE-PARTIAL");
+               g_fprintf(mailf, " TAPE-PARTIAL");
 
            fputc('\n', mailf);
        }
@@ -1528,8 +1573,14 @@ static void
 bogus_line(
     const char *err_text)
 {
-    printf("line %d of log is bogus: <%s>\n", curlinenum, curstr);
-    printf("  Scan failed at: <%s>\n", err_text);
+    char * s;
+    s = g_strdup_printf(_("line %d of log is bogus: <%s %s %s>\n"),
+                        curlinenum, 
+                        logtype_str[curlog], program_str[curprog], curstr);
+    g_printf("%s\n", s);
+    g_printf(_("  Scan failed at: <%s>\n"), err_text);
+    addline(&errsum, s);
+    amfree(s);
 }
 
 
@@ -1546,9 +1597,20 @@ nicedate(
     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"
+    static char *months[13] = {
+               T_("BogusMonth"),
+               T_("January"),
+               T_("February"),
+               T_("March"),
+               T_("April"),
+               T_("May"),
+               T_("June"),
+               T_("July"),
+               T_("August"),
+               T_("September"),
+               T_("October"),
+               T_("November"),
+               T_("December")
     };
     int year, month, day;
 
@@ -1561,7 +1623,7 @@ nicedate(
     if (month > 12 )
        month = 0;
 
-    snprintf(nice, SIZEOF(nice), "%s %d, %d", months[month], day, year);
+    g_snprintf(nice, SIZEOF(nice), "%s %d, %d", _(months[month]), day, year);
 
     return nice;
 }
@@ -1678,7 +1740,7 @@ handle_start(void)
     if(amflush_run && normal_run) {
        amflush_run = 0;
        addline(&notes,
-     "  reporter: both amflush and planner output in log, ignoring amflush.");
+     _("  reporter: both amflush and planner output in log, ignoring amflush."));
     }
 }
 
@@ -1739,7 +1801,7 @@ handle_stats(void)
 {
     char *s, *fp;
     int ch;
-    char *hostname, *diskname, *datestamp;
+    char *hostname, *diskname, *datestamp, *qdiskname;
     int level = 0;
     double sec, kps, nbytes, cbytes;
     repdata_t *repdata;
@@ -1788,10 +1850,11 @@ handle_stats(void)
                amfree(hostname);
                return;
            }
-           fp = s - 1;
-           skip_non_whitespace(s, ch);
+
+           qdiskname = s - 1;
+           skip_quoted_string(s, ch);
            s[-1] = '\0';
-           diskname = stralloc(fp);
+           diskname = unquote_string(qdiskname);
            s[-1] = (char)ch;
 
            skip_whitespace(s, ch);
@@ -1806,8 +1869,8 @@ handle_stats(void)
            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);
@@ -1836,8 +1899,9 @@ handle_stats(void)
 
            dp = lookup_disk(hostname, diskname);
            if(dp == NULL) {
-               addtostrange(hostname, diskname, level,
-                            "ERROR [not in disklist]");
+               addtoX_summary(&first_failed, &last_failed,
+                              hostname, diskname, level,
+                              _("ERROR [not in disklist]"));
                exit_status |= STATUS_FAILED;
                amfree(hostname);
                amfree(diskname);
@@ -1869,7 +1933,7 @@ handle_note(void)
 {
     char *str = NULL;
 
-    str = vstralloc("  ", program_str[curprog], ": ", curstr, NULL);
+    str = vstrallocf("  %s: %s", program_str[curprog], curstr);
     addline(&notes, str);
     amfree(str);
 }
@@ -1904,8 +1968,8 @@ handle_error(void)
        }
        /* else some other tape error, handle like other errors */
     }
-    s = vstralloc("  ", program_str[curprog], ": ",
-                 logtype_str[curlog], " ", curstr, NULL);
+    s = vstrallocf("  %s: %s %s", program_str[curprog],
+                 logtype_str[curlog], curstr);
     addline(&errsum, s);
     amfree(s);
 }
@@ -1981,7 +2045,8 @@ handle_disk(void)
  * for a split chunk of the overall dumpfile.
  */
 static repdata_t *
-handle_chunk(void)
+handle_chunk(
+    logtype_t logtype)
 {
     disk_t *dp;
     double sec, kps, kbytes;
@@ -1994,6 +2059,9 @@ handle_chunk(void)
     repdata_t *repdata;
     int level, chunk;
     char *datestamp;
+    char *label = NULL;
+    int fileno;
+    int totpart;
     
     if(curprog != P_TAPER) {
        bogus_line(curstr);
@@ -2002,12 +2070,36 @@ handle_chunk(void)
     
     s = curstr;
     ch = *s++;
-    
+
     skip_whitespace(s, ch);
     if(ch == '\0') {
        bogus_line(s - 1);
        return NULL;
     }
+
+    if (logtype == L_PART || logtype == L_PARTPARTIAL) {
+       fp = s - 1;
+       skip_non_whitespace(s, ch);
+       s[-1] = '\0';
+       label = stralloc(fp);
+       s[-1] = (char)ch;
+    
+       skip_whitespace(s, ch);
+       if(ch == '\0' || sscanf(s - 1, "%d", &fileno) != 1) {
+           bogus_line(s - 1);
+           amfree(label);
+           return NULL;
+       }
+       skip_integer(s, ch);
+       skip_whitespace(s, ch);
+       if(ch == '\0') {
+           bogus_line(s - 1);
+           amfree(label);
+           return NULL;
+       }
+       amfree(label);
+    }
+
     fp = s - 1;
     skip_non_whitespace(s, ch);
     s[-1] = '\0';
@@ -2049,6 +2141,18 @@ handle_chunk(void)
     }
     skip_integer(s, ch);
 
+    if (ch != '\0' && s[-1] == '/') {
+       s++; ch = s[-1];
+       if (sscanf(s - 1, "%d", &totpart) != 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);
@@ -2082,9 +2186,8 @@ handle_chunk(void)
     if(dp == NULL) {
        char *str = NULL;
        
-       str = vstralloc("  ", prefix(hostname, diskname, level),
-                       " ", "ERROR [not in disklist]",
-                       NULL);
+       str = vstrallocf(_("  %s ERROR [not in disklist]"),
+                       prefix(hostname, diskname, level));
        addline(&errsum, str);
        amfree(str);
        amfree(hostname);
@@ -2135,8 +2238,11 @@ handle_success(
     char *diskname = NULL;
     repdata_t *repdata;
     int level = 0;
+    int totpart = 0;
     char *datestamp;
 
+    (void)logtype;
+
     if(curprog != P_TAPER && curprog != P_DUMPER && curprog != P_PLANNER &&
        curprog != P_CHUNKER) {
        bogus_line(curstr);
@@ -2181,12 +2287,32 @@ handle_success(
     datestamp = stralloc(fp);
     s[-1] = (char)ch;
 
-    if(strlen(datestamp) < 3) {
-       level = atoi(datestamp);
+    //datestamp is optional
+    if(strlen(datestamp) < 6) {
+       totpart = atoi(datestamp);
        datestamp = newstralloc(datestamp, run_datestamp);
     }
     else {
        skip_whitespace(s, ch);
+       if(ch == '\0' || sscanf(s - 1, "%d", &totpart) != 1) {
+           bogus_line(s - 1);
+           amfree(hostname);
+           amfree(diskname);
+           amfree(datestamp);
+           return NULL;
+       }
+       skip_integer(s, ch);
+    }
+
+    skip_whitespace(s, ch);
+
+    //totpart is optional
+    if (*(s-1) == '"')
+       s++;
+    if (*(s-1) == '[') {
+       level = totpart;
+       totpart = -1;
+    } else {
        if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
            bogus_line(s - 1);
            amfree(hostname);
@@ -2195,8 +2321,10 @@ handle_success(
            return NULL;
        }
        skip_integer(s, ch);
+       skip_whitespace(s, ch);
     }
 
+
     if(level < 0 || level > 9) {
        amfree(hostname);
        amfree(diskname);
@@ -2204,7 +2332,6 @@ handle_success(
        return NULL;
     }
 
-    skip_whitespace(s, ch);
                                /* Planner success messages (for skipped
                                   dumps) do not contain statistics */
     if(curprog != P_PLANNER) {
@@ -2232,7 +2359,8 @@ handle_success(
 
     dp = lookup_disk(hostname, diskname);
     if(dp == NULL) {
-       addtostrange(hostname, qdiskname, level, "ERROR [not in disklist]");
+       addtoX_summary(&first_failed, &last_failed, hostname, qdiskname, level,
+                      _("ERROR [not in disklist]"));
        exit_status |= STATUS_FAILED;
        amfree(hostname);
        amfree(diskname);
@@ -2282,7 +2410,8 @@ handle_success(
 
     if (curprog == P_DUMPER &&
        (sp->result == L_FAIL || sp->result == L_PARTIAL)) {
-       addtostrange(hostname, qdiskname, level, "was successfully retried");
+       addtoX_summary(&first_failed, &last_failed, hostname, qdiskname, level,
+                      _("was successfully retried"));
     }
 
     amfree(hostname);
@@ -2298,33 +2427,29 @@ handle_success(
 
     if(curprog == P_TAPER) {
        if(current_tape == NULL) {
-           error("current_tape == NULL");
+           error(_("current_tape == NULL"));
            /*NOTREACHED*/
        }
        stats[i].taper_time += sec;
        sp->filenum = ++tapefcount;
        sp->tapelabel = current_tape->label;
+       sp->totpart = totpart;
        tapedisks[level] +=1;
        stats[i].tapedisks +=1;
        stats[i].tapesize += kbytes;
        sp->outsize = kbytes;
        if(!isnormal(repdata->chunker.outsize) && isnormal(repdata->dumper.outsize)) { /* dump to tape */
            stats[i].outsize += kbytes;
-           if(dp->compress != COMP_NONE) {
+           if (abs(kbytes - origkb) >= 32) {
                stats[i].coutsize += kbytes;
            }
        }
-       if (logtype == L_SUCCESS || logtype== L_PARTIAL) {
-           current_tape->taper_time += sec;
-           current_tape->coutsize += kbytes;
-       }
-       current_tape->corigsize += origkb;
        current_tape->tapedisks += 1;
     }
 
     if(curprog == P_DUMPER) {
        stats[i].dumper_time += sec;
-       if(dp->compress == COMP_NONE) {
+       if (abs(kbytes - origkb) < 32) {
            sp->origsize = kbytes;
        }
        else {
@@ -2338,7 +2463,7 @@ handle_success(
     if(curprog == P_CHUNKER) {
        sp->outsize = kbytes;
        stats[i].outsize += kbytes;
-       if(dp->compress != COMP_NONE) {
+       if (abs(kbytes - origkb) >= 32) {
            stats[i].coutsize += kbytes;
        }
     }
@@ -2378,12 +2503,10 @@ handle_strange(void)
 
     qdisk = quote_string(repdata->disk->name);
 
-    addline(&errdet,"");
-    str = vstralloc("/-- ", prefix(repdata->disk->host->hostname, 
-                                  qdisk, repdata->level),
-                   " ", "STRANGE",
-                   NULL);
-    addline(&errdet, str);
+    addline(&strangedet,"");
+    str = vstrallocf("/-- %s STRANGE",
+               prefix(repdata->disk->host->hostname, qdisk, repdata->level));
+    addline(&strangedet, str);
     amfree(str);
 
     while(contline_next()) {
@@ -2393,12 +2516,13 @@ handle_strange(void)
        if(strncmp_const_skip(curstr, "sendbackup: warning ", s, ch) == 0) {
            strangestr = newstralloc(strangestr, s);
        }
-       addline(&errdet, curstr);
+       addline(&strangedet, curstr);
     }
-    addline(&errdet,"\\--------");
+    addline(&strangedet,"\\--------");
 
-    str = vstralloc("STRANGE", " ", strangestr, NULL);
-    addtostrange(repdata->disk->host->hostname, qdisk, repdata->level, str);
+    str = vstrallocf("STRANGE %s", strangestr? strangestr : _("(see below)"));
+    addtoX_summary(&first_strange, &last_strange,
+                  repdata->disk->host->hostname, qdisk, repdata->level, str);
     exit_status |= STATUS_STRANGE;
     amfree(qdisk);
     amfree(str);
@@ -2486,7 +2610,8 @@ handle_failed(void)
     dp = lookup_disk(hostname, diskname);
     amfree(diskname);
     if(dp == NULL) {
-       addtostrange(hostname, qdiskname, level, "ERROR [not in disklist]");
+       addtoX_summary(&first_failed, &last_failed, hostname, qdiskname, level,
+                      _("ERROR [not in disklist]"));
     } else {
        repdata = find_repdata(dp, datestamp, level);
 
@@ -2499,16 +2624,16 @@ handle_failed(void)
     }
     amfree(datestamp);
 
-    str = vstralloc("FAILED", " ", errstr, NULL);
-    addtostrange(hostname, qdiskname, level, str);
+    str = vstrallocf(_("FAILED %s"), errstr);
+    addtoX_summary(&first_failed, &last_failed, hostname, qdiskname, level,
+                  str);
     amfree(str);
 
     if(curprog == P_DUMPER) {
        addline(&errdet,"");
-       str = vstralloc("/-- ", prefix(hostname, qdiskname, level),
-                       " ", "FAILED",
-                       " ", errstr,
-                       NULL);
+       str = vstrallocf("/-- %s FAILED %s",
+                       prefix(hostname, qdiskname, level), 
+                       errstr);
        addline(&errdet, str);
        amfree(str);
        while(contline_next()) {
@@ -2531,7 +2656,8 @@ generate_missing(void)
     for(dp = diskq.head; dp != NULL; dp = dp->next) {
        if(dp->todo && data(dp) == NULL) {
            qdisk = quote_string(dp->name);
-           addtostrange(dp->host->hostname, qdisk, -987, "RESULTS MISSING");
+           addtoX_summary(&first_failed, &last_failed, dp->host->hostname,
+                          qdisk, -987, _("RESULTS MISSING"));
            exit_status |= STATUS_MISSING;
            amfree(qdisk);
        }
@@ -2563,30 +2689,30 @@ generate_bad_estimate(void)
                        outsize  = repdata->dumper.outsize;
 
                    if(repdata->est_csize * 0.9 > outsize) {
-                       snprintf(s, 1000,
-                               "  big estimate: %s %s %d",
+                       g_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",
+                       g_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",
+                       g_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",
+                       g_snprintf(s, 1000,
+                                _("                  est: %.0lf%s    out %.0lf%s"),
                                 du(repdata->est_csize), displayunit,
                                 du(outsize), displayunit);
                        s[999] = '\0';
@@ -2604,16 +2730,18 @@ prefix (
     char *     disk,
     int                level)
 {
-    char number[NUM_STR_SIZE];
     static char *str = NULL;
 
-    snprintf(number, SIZEOF(number), "%d", level);
-    str = newvstralloc(str,
-                      " ", host ? host : "(host?)",
-                      " ", disk ? disk : "(disk?)",
-                      level != -987 ? " lev " : "",
-                      level != -987 ? number : "",
-                      NULL);
+    if (level == -987) {
+       str = newvstrallocf(str, " %s %s",
+                       host ? host : _("(host?)"),
+                       disk ? disk : _("(disk?)"));
+    } else {
+       str = newvstrallocf(str, " %s %s lev %d",
+                       host ? host : _("(host?)"),
+                       disk ? disk : _("(disk?)"),
+                       level);
+    }
     return str;
 }
 
@@ -2628,15 +2756,13 @@ prefixstrange (
 {
     char *h, *d;
     size_t l;
-    char number[NUM_STR_SIZE];
     static char *str = NULL;
 
-    snprintf(number, SIZEOF(number), "%d", level);
     h=alloc(len_host+1);
     if(host) {
        strncpy(h, host, len_host);
     } else {
-       strncpy(h, "(host?)", len_host);
+       strncpy(h, _("(host?)"), len_host);
     }
     h[len_host] = '\0';
     for(l = strlen(h); l < len_host; l++) {
@@ -2646,18 +2772,17 @@ prefixstrange (
     if(disk) {
        strncpy(d, disk, len_disk);
     } else {
-       strncpy(d, "(disk?)", len_disk);
+       strncpy(d, _("(disk?)"), len_disk);
     }
     d[len_disk] = '\0';
     for(l = strlen(d); l < len_disk; l++) {
        d[l] = ' ';
     }
-    str = newvstralloc(str,
-                      h,
-                      "  ", d,
-                      level != -987 ? "  lev " : "",
-                      level != -987 ? number : "",
-                      NULL);
+    if (level == -987) {
+       str = newvstrallocf(str, " %s %s", h, d);
+    } else {
+       str = newvstrallocf(str, " %s %s lev %d", h, d, level);
+    }
     amfree(h);
     amfree(d);
     return str;
@@ -2665,30 +2790,31 @@ prefixstrange (
 
 
 static void
-addtostrange (
-    char *     host,
-    char *     disk,
-    int                level,
-    char *     str)
+addtoX_summary (
+    X_summary_t **first,
+    X_summary_t **last,
+    char        *host,
+    char        *disk,
+    int                  level,
+    char        *str)
 {
-    strange_t *strange;
+    X_summary_t *X_summary;
 
-    strange = alloc(SIZEOF(strange_t));
-    strange->hostname = stralloc(host);
-    strange->diskname = stralloc(disk);
-    strange->level    = level;
-    strange->str      = stralloc(str);
-    strange->next = NULL;
-    if(first_strange == NULL) {
-       first_strange = strange;
+    X_summary = alloc(SIZEOF(X_summary_t));
+    X_summary->hostname = stralloc(host);
+    X_summary->diskname = stralloc(disk);
+    X_summary->level    = level;
+    X_summary->str      = stralloc(str);
+    X_summary->next = NULL;
+    if (*first == NULL) {
+       *first = X_summary;
     }
     else {
-        last_strange->next = strange;
+        (*last)->next = X_summary;
     }
-    last_strange = strange;
+    *last = X_summary;
 }
 
-
 static void
 copy_template_file(
     char *     lbl_templ)
@@ -2697,19 +2823,12 @@ copy_template_file(
   int fd;
   ssize_t numread;
 
-  if (strchr(lbl_templ, '/') == NULL) {
-    lbl_templ = stralloc2(config_dir, lbl_templ);
-  } else {
-    lbl_templ = stralloc(lbl_templ);
-  }
+  lbl_templ = config_dir_relative(lbl_templ);
   if ((fd = open(lbl_templ, 0)) < 0) {
     curlog = L_ERROR;
     curprog = P_REPORTER;
-    curstr = vstralloc("could not open PostScript template file ",
-                      lbl_templ,
-                      ": ",
-                      strerror(errno),
-                      NULL);
+    curstr = vstrallocf(_("could not open PostScript template file %s: %s"),
+                      lbl_templ, strerror(errno));
     handle_error();
     amfree(curstr);
     amfree(lbl_templ);
@@ -2720,11 +2839,8 @@ copy_template_file(
     if (fwrite(buf, (size_t)numread, 1, postscript) != 1) {
       curlog = L_ERROR;
       curprog = P_REPORTER;
-      curstr = vstralloc("error copying PostScript template file ",
-                        lbl_templ,
-                        ": ",
-                        strerror(errno),
-                        NULL);
+      curstr = vstrallocf(_("error copying PostScript template file %s: %s"),
+                        lbl_templ, strerror(errno));
       handle_error();
       amfree(curstr);
       amfree(lbl_templ);
@@ -2735,11 +2851,8 @@ copy_template_file(
   if (numread < 0) {
     curlog = L_ERROR;
     curprog = P_REPORTER;
-    curstr = vstralloc("error reading PostScript template file ",
-                      lbl_templ,
-                      ": ",
-                      strerror(errno),
-                      NULL);
+    curstr = vstrallocf(_("error reading PostScript template file %s: %s"),
+                      lbl_templ, strerror(errno));
     handle_error();
     amfree(curstr);
     amfree(lbl_templ);
@@ -2811,28 +2924,28 @@ do_postscript_output(void)
            return;
 
        /* generate a few elements */
-       fprintf(postscript,"(%s) DrawDate\n\n",
+       g_fprintf(postscript,"(%s) DrawDate\n\n",
                    nicedate(run_datestamp ? run_datestamp : "0"));
-       fprintf(postscript,"(Amanda Version %s) DrawVers\n",version());
-       fprintf(postscript,"(%s) DrawTitle\n", current_tape->label);
+       g_fprintf(postscript,_("(Amanda Version %s) DrawVers\n"),version());
+       g_fprintf(postscript,"(%s) DrawTitle\n", current_tape->label);
 
        /* Stats */
-       fprintf(postscript, "(Total Size:        %6.1lf MB) DrawStat\n",
+       g_fprintf(postscript, "(Total Size:        %6.1lf MB) DrawStat\n",
              mb(current_tape->coutsize));
-       fprintf(postscript, "(Tape Used (%%)       ");
+       g_fprintf(postscript, _("(Tape Used (%%)       "));
        divzero(postscript, pct(current_tape->coutsize + 
                                marksize * (current_tape->tapedisks + current_tape->tapechunks)),
                                (double)tapesize);
-       fprintf(postscript," %%) DrawStat\n");
-       fprintf(postscript, "(Compression Ratio:  ");
+       g_fprintf(postscript," %%) DrawStat\n");
+       g_fprintf(postscript, _("(Compression Ratio:  "));
        divzero(postscript, pct(current_tape->coutsize),current_tape->corigsize);
-       fprintf(postscript," %%) DrawStat\n");
-       fprintf(postscript,"(Filesystems Taped: %4d) DrawStat\n",
+       g_fprintf(postscript," %%) DrawStat\n");
+       g_fprintf(postscript,_("(Filesystems Taped: %4d) DrawStat\n"),
                  current_tape->tapedisks);
 
        /* Summary */
 
-       fprintf(postscript,
+       g_fprintf(postscript,
              "(-) (%s) (-) (  0) (      32) (      32) DrawHost\n",
              current_tape->label);
 
@@ -2861,13 +2974,13 @@ do_postscript_output(void)
                if (repdata->taper.result == L_SUCCESS ||
                    repdata->taper.result == L_PARTIAL) {
                    if(isnormal(origsize)) {
-                       fprintf(postscript,"(%s) (%s) (%d) (%3.0d) (%8.0lf) (%8.0lf) DrawHost\n",
+                       g_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.0lf) DrawHost\n",
+                       g_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);
@@ -2876,6 +2989,6 @@ do_postscript_output(void)
            }
        }
        
-       fprintf(postscript,"\nshowpage\n");
+       g_fprintf(postscript,"\nshowpage\n");
     }
 }