Imported Upstream version 2.6.0p2
[debian/amanda] / server-src / chunker.c
index fc783ba23acb5390b6f96da809c41e37037cabd5..5e6c1ef45c7619ec9bb761fe871494d8714a5e5f 100644 (file)
@@ -23,7 +23,7 @@
  * Authors: the Amanda Development Team.  Its members are listed in a
  * file named AUTHORS, in the root directory of this distribution.
  */
-/* $Id: chunker.c,v 1.25 2006/03/21 13:23:35 martinea Exp $
+/* $Id: chunker.c,v 1.36 2006/08/24 11:23:32 martinea Exp $
  *
  * requests remote amandad processes to dump filesystems
  */
 #include "server_util.h"
 #include "util.h"
 #include "holding.h"
+#include "timestamp.h"
+
+#define chunker_debug(i, ...) do {     \
+       if ((i) <= debug_chunker) {     \
+           dbprintf(__VA_ARGS__);      \
+       }                               \
+} while (0)
 
 #ifndef SEEK_SET
 #define SEEK_SET 0
@@ -61,9 +68,9 @@ struct databuf {
     int fd;                    /* file to flush to */
     char *filename;            /* name of what fd points to */
     int filename_seq;          /* for chunking */
-    long split_size;           /* when to chunk */
-    long chunk_size;           /* size of each chunk */
-    long use;                  /* size to use on this disk */
+    off_t split_size;          /* when to chunk */
+    off_t chunk_size;          /* size of each chunk */
+    off_t use;                 /* size to use on this disk */
     char buf[DISK_BLOCK_BYTES];
     char *datain;              /* data buffer markers */
     char *dataout;
@@ -74,100 +81,108 @@ static char *handle = NULL;
 
 static char *errstr = NULL;
 static int abort_pending;
-static long dumpsize, headersize;
-static long dumpbytes;
-static long filesize;
+static off_t dumpsize;
+static unsigned long headersize;
+static off_t dumpbytes;
+static off_t filesize;
 
 static char *hostname = NULL;
 static char *diskname = NULL;
+static char *qdiskname = NULL;
 static char *options = NULL;
 static char *progname = NULL;
 static int level;
 static char *dumpdate = NULL;
-static char *datestamp;
 static int command_in_transit;
+static char *chunker_timestamp = NULL;
 
 static dumpfile_t file;
 
 /* local functions */
-int main P((int, char **));
-static int write_tapeheader P((int, dumpfile_t *));
-static void databuf_init P((struct databuf *, int, char *, long, long));
-static int databuf_flush P((struct databuf *));
+int main(int, char **);
+static ssize_t write_tapeheader(int, dumpfile_t *);
+static void databuf_init(struct databuf *, int, char *, off_t, off_t);
+static int databuf_flush(struct databuf *);
 
-static int startup_chunker P((char *, long, long, struct databuf *));
-static int do_chunk P((int, struct databuf *));
+static int startup_chunker(char *, off_t, off_t, struct databuf *);
+static int do_chunk(int, struct databuf *);
 
 
 int
-main(main_argc, main_argv)
-    int main_argc;
-    char **main_argv;
+main(
+    int                argc,
+    char **    argv)
 {
     static struct databuf db;
     struct cmdargs cmdargs;
     cmd_t cmd;
     int infd;
-    unsigned long malloc_hist_1, malloc_size_1;
-    unsigned long malloc_hist_2, malloc_size_2;
-    char *conffile;
     char *q = NULL;
-    char *filename;
-    long chunksize, use;
+    char *filename = NULL;
+    char *qfilename = NULL;
+    off_t chunksize, use;
     times_t runtime;
     am_feature_t *their_features = NULL;
     int a;
+    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);
 
     set_pname("chunker");
 
+    dbopen(DBG_SUBDIR_SERVER);
+
     /* Don't die when child closes pipe */
     signal(SIGPIPE, SIG_IGN);
 
-    malloc_size_1 = malloc_inuse(&malloc_hist_1);
-
     erroutput_type = (ERR_AMANDALOG|ERR_INTERACTIVE);
     set_logerror(logerror);
 
-    if (main_argc > 1) {
-       config_name = stralloc(main_argv[1]);
-       config_dir = vstralloc(CONFIG_DIR, "/", config_name, "/", NULL);
-    } else {
-       char my_cwd[STR_SIZE];
+    cfg_ovr = extract_commandline_config_overwrites(&argc, &argv);
 
-       if (getcwd(my_cwd, sizeof(my_cwd)) == NULL) {
-           error("cannot determine current working directory");
-       }
-       config_dir = stralloc2(my_cwd, "/");
-       if ((config_name = strrchr(my_cwd, '/')) != NULL) {
-           config_name = stralloc(config_name + 1);
-       }
-    }
+    if (argc > 1) 
+       cfg_opt = argv[1];
 
-    safe_cd();
+    config_init(CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_USE_CWD | CONFIG_INIT_FATAL,
+               cfg_opt);
+    apply_config_overwrites(cfg_ovr);
 
-    conffile = stralloc2(config_dir, CONFFILE_NAME);
-    if(read_conffile(conffile)) {
-       error("errors processing config file \"%s\"", conffile);
-    }
-    amfree(conffile);
+    safe_cd(); /* do this *after* config_init() */
+
+    check_running_as(RUNNING_AS_DUMPUSER);
+
+    dbrename(config_name, DBG_SUBDIR_SERVER);
 
-    fprintf(stderr,
-           "%s: pid %ld executable %s version %s\n",
+    g_fprintf(stderr,
+           _("%s: pid %ld executable %s version %s\n"),
            get_pname(), (long) getpid(),
-           main_argv[0], version());
+           argv[0], version());
     fflush(stderr);
 
     /* now, make sure we are a valid user */
 
-    if (getpwuid(getuid()) == NULL)
-       error("can't get login name for my uid %ld", (long)getuid());
-
     signal(SIGPIPE, SIG_IGN);
     signal(SIGCHLD, SIG_IGN);
 
-    datestamp = construct_datestamp(NULL);
+    cmd = getcmd(&cmdargs);
+    if(cmd == START) {
+       if(cmdargs.argc <= 1)
+           error(_("error [dumper START: not enough args: timestamp]"));
+       chunker_timestamp = newstralloc(chunker_timestamp, cmdargs.argv[2]);
+    }
+    else {
+       error(_("Didn't get START command"));
+    }
 
 /*    do {*/
        cmd = getcmd(&cmdargs);
@@ -195,69 +210,88 @@ main(main_argc, main_argv)
            a = 2;
 
            if(a >= cmdargs.argc) {
-               error("error [chunker PORT-WRITE: not enough args: handle]");
+               error(_("error [chunker PORT-WRITE: not enough args: handle]"));
+               /*NOTREACHED*/
            }
            handle = newstralloc(handle, cmdargs.argv[a++]);
 
            if(a >= cmdargs.argc) {
-               error("error [chunker PORT-WRITE: not enough args: filename]");
+               error(_("error [chunker PORT-WRITE: not enough args: filename]"));
+               /*NOTREACHED*/
            }
-           filename = cmdargs.argv[a++];
+           qfilename = newstralloc(qfilename, cmdargs.argv[a++]);
+           if (filename != NULL)
+               amfree(filename);
+           filename = unquote_string(qfilename);
+           amfree(qfilename);
 
            if(a >= cmdargs.argc) {
-               error("error [chunker PORT-WRITE: not enough args: hostname]");
+               error(_("error [chunker PORT-WRITE: not enough args: hostname]"));
+               /*NOTREACHED*/
            }
            hostname = newstralloc(hostname, cmdargs.argv[a++]);
 
            if(a >= cmdargs.argc) {
-               error("error [chunker PORT-WRITE: not enough args: features]");
+               error(_("error [chunker PORT-WRITE: not enough args: features]"));
+               /*NOTREACHED*/
            }
            am_release_feature_set(their_features);
            their_features = am_string_to_feature(cmdargs.argv[a++]);
 
            if(a >= cmdargs.argc) {
-               error("error [chunker PORT-WRITE: not enough args: diskname]");
+               error(_("error [chunker PORT-WRITE: not enough args: diskname]"));
+               /*NOTREACHED*/
            }
-           diskname = newstralloc(diskname, cmdargs.argv[a++]);
+           qdiskname = newstralloc(qdiskname, cmdargs.argv[a++]);
+           if (diskname != NULL)
+               amfree(diskname);
+           diskname = unquote_string(qdiskname);
 
            if(a >= cmdargs.argc) {
-               error("error [chunker PORT-WRITE: not enough args: level]");
+               error(_("error [chunker PORT-WRITE: not enough args: level]"));
+               /*NOTREACHED*/
            }
            level = atoi(cmdargs.argv[a++]);
 
            if(a >= cmdargs.argc) {
-               error("error [chunker PORT-WRITE: not enough args: dumpdate]");
+               error(_("error [chunker PORT-WRITE: not enough args: dumpdate]"));
+               /*NOTREACHED*/
            }
            dumpdate = newstralloc(dumpdate, cmdargs.argv[a++]);
 
            if(a >= cmdargs.argc) {
-               error("error [chunker PORT-WRITE: not enough args: chunksize]");
+               error(_("error [chunker PORT-WRITE: not enough args: chunksize]"));
+               /*NOTREACHED*/
            }
-           chunksize = atoi(cmdargs.argv[a++]);
-           chunksize = am_floor(chunksize, DISK_BLOCK_KB);
+           chunksize = OFF_T_ATOI(cmdargs.argv[a++]);
+           chunksize = am_floor(chunksize, (off_t)DISK_BLOCK_KB);
 
            if(a >= cmdargs.argc) {
-               error("error [chunker PORT-WRITE: not enough args: progname]");
+               error(_("error [chunker PORT-WRITE: not enough args: progname]"));
+               /*NOTREACHED*/
            }
            progname = newstralloc(progname, cmdargs.argv[a++]);
 
            if(a >= cmdargs.argc) {
-               error("error [chunker PORT-WRITE: not enough args: use]");
+               error(_("error [chunker PORT-WRITE: not enough args: use]"));
+               /*NOTREACHED*/
            }
-           use = am_floor(atoi(cmdargs.argv[a++]), DISK_BLOCK_KB);
+           use = am_floor(OFF_T_ATOI(cmdargs.argv[a++]), DISK_BLOCK_KB);
 
            if(a >= cmdargs.argc) {
-               error("error [chunker PORT-WRITE: not enough args: options]");
+               error(_("error [chunker PORT-WRITE: not enough args: options]"));
+               /*NOTREACHED*/
            }
            options = newstralloc(options, cmdargs.argv[a++]);
 
            if(a != cmdargs.argc) {
-               error("error [chunker PORT-WRITE: too many args: %d != %d]",
+               error(_("error [chunker PORT-WRITE: too many args: %d != %d]"),
                      cmdargs.argc, a);
+               /*NOTREACHED*/
            }
 
            if((infd = startup_chunker(filename, use, chunksize, &db)) < 0) {
-               q = squotef("[chunker startup failed: %s]", errstr);
+               q = squotef(_("[chunker startup failed: %s]"), errstr);
                putresult(TRYAGAIN, "%s %s\n", handle, q);
                error("startup_chunker failed");
            }
@@ -268,15 +302,13 @@ main(main_argc, main_argv)
                double rt;
 
                runtime = stopclock();
-               rt = runtime.r.tv_sec+runtime.r.tv_usec/1000000.0;
-               snprintf(kb_str, sizeof(kb_str), "%ld", dumpsize - headersize);
-               snprintf(kps_str, sizeof(kps_str), "%3.1f",
-                               rt ? dumpsize / rt : 0.0);
-               errstr = newvstralloc(errstr,
-                                     "sec ", walltime_str(runtime),
-                                     " kb ", kb_str,
-                                     " kps ", kps_str,
-                                     NULL);
+                rt = g_timeval_to_double(runtime);
+               g_snprintf(kb_str, SIZEOF(kb_str), "%lld",
+                        (long long)(dumpsize - (off_t)headersize));
+               g_snprintf(kps_str, SIZEOF(kps_str), "%3.1lf",
+                               isnormal(rt) ? (double)dumpsize / rt : 0.0);
+               errstr = newvstrallocf(errstr, "sec %s kb %s kps %s",
+                               walltime_str(runtime), kb_str, kps_str);
                q = squotef("[%s]", errstr);
                if(command_in_transit != -1)
                    cmd = command_in_transit;
@@ -284,31 +316,30 @@ main(main_argc, main_argv)
                    cmd = getcmd(&cmdargs);
                switch(cmd) {
                case DONE:
-                   putresult(DONE, "%s %ld %s\n",
-                             handle, dumpsize - headersize, q);
+                   putresult(DONE, "%s %lld %s\n", handle,
+                            (long long)(dumpsize - (off_t)headersize), q);
                    log_add(L_SUCCESS, "%s %s %s %d [%s]",
-                           hostname, diskname, datestamp, level, errstr);
+                           hostname, qdiskname, chunker_timestamp, level, errstr);
                    break;
                case BOGUS:
                case TRYAGAIN:
                case FAILED:
                case ABORT_FINISHED:
-                   if(dumpsize > DISK_BLOCK_KB) {
-                       putresult(PARTIAL, "%s %ld %s\n",
-                                 handle, dumpsize - headersize, q);
+                   if(dumpsize > (off_t)DISK_BLOCK_KB) {
+                       putresult(PARTIAL, "%s %lld %s\n", handle,
+                                (long long)(dumpsize - (off_t)headersize),
+                                q);
                        log_add(L_PARTIAL, "%s %s %s %d [%s]",
-                               hostname, diskname, datestamp, level, errstr);
+                               hostname, qdiskname, chunker_timestamp, level, errstr);
                    }
                    else {
-                       errstr = newvstralloc(errstr,
-                                             "dumper returned ",
-                                             cmdstr[cmd],
-                                             NULL);
+                       errstr = newvstrallocf(errstr,
+                                       _("dumper returned %s"), cmdstr[cmd]);
                        amfree(q);
                        q = squotef("[%s]",errstr);
                        putresult(FAILED, "%s %s\n", handle, q);
                        log_add(L_FAIL, "%s %s %s %d [%s]",
-                               hostname, diskname, datestamp, level, errstr);
+                               hostname, qdiskname, chunker_timestamp, level, errstr);
                    }
                default: break;
                }
@@ -320,10 +351,12 @@ main(main_argc, main_argv)
                    }
                    putresult(FAILED, "%s %s\n", handle, q);
                    log_add(L_FAIL, "%s %s %s %d [%s]",
-                           hostname, diskname, datestamp, level, errstr);
+                           hostname, qdiskname, chunker_timestamp, level, errstr);
                    amfree(q);
                }
            }
+           amfree(filename);
+           amfree(db.filename);
            break;
 
        default:
@@ -332,7 +365,7 @@ main(main_argc, main_argv)
            } else if(cmdargs.argc >= 0) {
                q = squote(cmdargs.argv[0]);
            } else {
-               q = stralloc("(no input?)");
+               q = stralloc(_("(no input?)"));
            }
            putresult(BAD_COMMAND, "%s\n", q);
            amfree(q);
@@ -342,24 +375,20 @@ main(main_argc, main_argv)
 /*    } while(cmd != QUIT); */
 
     amfree(errstr);
-    amfree(datestamp);
+    amfree(chunker_timestamp);
     amfree(handle);
     amfree(hostname);
     amfree(diskname);
+    amfree(qdiskname);
     amfree(dumpdate);
     amfree(progname);
     amfree(options);
-    amfree(config_dir);
-    amfree(config_name);
     am_release_feature_set(their_features);
     their_features = NULL;
 
-    malloc_size_2 = malloc_inuse(&malloc_hist_2);
+    dbclose();
 
-    if (malloc_size_1 != malloc_size_2)
-       malloc_list(fileno(stderr), malloc_hist_1, malloc_hist_2);
-
-    exit(0);
+    return (0); /* exit */
 }
 
 /*
@@ -367,29 +396,38 @@ main(main_argc, main_argv)
  * on success, or -1 on error.
  */
 static int
-startup_chunker(filename, use, chunksize, db)
-    char *filename;
-    long use;
-    long chunksize;
-    struct databuf *db;
+startup_chunker(
+    char *             filename,
+    off_t              use,
+    off_t              chunksize,
+    struct databuf *   db)
 {
     int infd, outfd;
     char *tmp_filename, *pc;
-    int data_port, data_socket;
+    in_port_t data_port;
+    int data_socket;
+    int result;
+    struct addrinfo *res;
 
     data_port = 0;
-    data_socket = stream_server(&data_port, -1, STREAM_BUFSIZE);
+    if ((result = resolve_hostname("localhost", 0, &res, NULL) != 0)) {
+       errstr = newvstrallocf(errstr, _("could not resolve localhost: %s"),
+                              gai_strerror(result));
+       return -1;
+    }
+    data_socket = stream_server(res->ai_family, &data_port, 0,
+                               STREAM_BUFSIZE, 0);
 
     if(data_socket < 0) {
-       errstr = stralloc2("error creating stream server: ", strerror(errno));
+       errstr = vstrallocf(_("error creating stream server: %s"), strerror(errno));
        return -1;
     }
 
     putresult(PORT, "%d\n", data_port);
 
-    infd = stream_accept(data_socket, CONNECT_TIMEOUT, -1, NETWORK_BLOCK_BYTES);
+    infd = stream_accept(data_socket, CONNECT_TIMEOUT, 0, STREAM_BUFSIZE);
     if(infd == -1) {
-       errstr = stralloc2("error accepting stream: ", strerror(errno));
+       errstr = vstrallocf(_("error accepting stream: %s"), strerror(errno));
        return -1;
     }
 
@@ -401,13 +439,14 @@ startup_chunker(filename, use, chunksize, db)
     if ((outfd = open(tmp_filename, O_RDWR|O_CREAT|O_TRUNC, 0600)) < 0) {
        int save_errno = errno;
 
-       errstr = squotef("holding file \"%s\": %s",
+       errstr = squotef(_("holding file \"%s\": %s"),
                         tmp_filename,
                         strerror(errno));
        amfree(tmp_filename);
        aclose(infd);
        if(save_errno == ENOSPC) {
-           putresult(NO_ROOM, "%s %lu", handle, use);
+           putresult(NO_ROOM, "%s %lld\n",
+                     handle, (long long)use);
            return -2;
        } else {
            return -1;
@@ -420,61 +459,57 @@ startup_chunker(filename, use, chunksize, db)
 }
 
 static int
-do_chunk(infd, db)
-    int infd;
-    struct databuf *db;
+do_chunk(
+    int                        infd,
+    struct databuf *   db)
 {
-    int nread;
+    ssize_t nread;
     char header_buf[DISK_BLOCK_BYTES];
 
     startclock();
 
-    dumpsize = headersize = dumpbytes = filesize = 0;
+    dumpsize = dumpbytes = filesize = (off_t)0;
+    headersize = 0;
+    memset(header_buf, 0, sizeof(header_buf));
 
     /*
      * The first thing we should receive is the file header, which we
      * need to save into "file", as well as write out.  Later, the
      * chunk code will rewrite it.
      */
-    nread = fullread(infd, header_buf, sizeof(header_buf));
+    nread = fullread(infd, header_buf, SIZEOF(header_buf));
     if (nread != DISK_BLOCK_BYTES) {
-       char number1[NUM_STR_SIZE];
-       char number2[NUM_STR_SIZE];
-
        if(nread < 0) {
-           errstr = stralloc2("cannot read header: ", strerror(errno));
+           errstr = vstrallocf(_("cannot read header: %s"), strerror(errno));
        } else {
-           snprintf(number1, sizeof(number1), "%d", nread);
-           snprintf(number2, sizeof(number2), "%d", DISK_BLOCK_BYTES);
-           errstr = vstralloc("cannot read header: got ",
-                              number1,
-                              " instead of ",
-                              number2,
-                              NULL);
+           errstr = vstrallocf(_("cannot read header: got %zd bytes instead of %d"),
+                               nread,
+                               DISK_BLOCK_BYTES);
        }
        return 0;
     }
-    parse_file_header(header_buf, &file, nread);
+    parse_file_header(header_buf, &file, (size_t)nread);
     if(write_tapeheader(db->fd, &file)) {
        int save_errno = errno;
 
-       errstr = squotef("write_tapeheader file \"%s\": %s",
+       errstr = squotef(_("write_tapeheader file %s: %s"),
                         db->filename, strerror(errno));
        if(save_errno == ENOSPC) {
-           putresult(NO_ROOM, "%s %lu\n", handle, 
-                     db->use+db->split_size-dumpsize);
+           putresult(NO_ROOM, "%s %lld\n", handle, 
+                     (long long)(db->use+db->split_size-dumpsize));
        }
        return 0;
     }
-    dumpsize += DISK_BLOCK_KB;
-    filesize = DISK_BLOCK_KB;
+    dumpsize += (off_t)DISK_BLOCK_KB;
+    filesize = (off_t)DISK_BLOCK_KB;
     headersize += DISK_BLOCK_KB;
 
     /*
      * We've written the file header.  Now, just write data until the
      * end.
      */
-    while ((nread = fullread(infd, db->buf, db->datalimit - db->datain)) > 0) {
+    while ((nread = fullread(infd, db->buf,
+                            (size_t)(db->datalimit - db->datain))) > 0) {
        db->datain += nread;
        while(db->dataout < db->datain) {
            if(!databuf_flush(db)) {
@@ -487,9 +522,9 @@ do_chunk(infd, db)
            return 0;
        }
     }
-    if(dumpbytes > 0) {
-       dumpsize++;                     /* count partial final KByte */
-       filesize++;
+    if(dumpbytes > (off_t)0) {
+       dumpsize += (off_t)1;                   /* count partial final KByte */
+       filesize += (off_t)1;
     }
     return 1;
 }
@@ -498,21 +533,21 @@ do_chunk(infd, db)
  * Initialize a databuf.  Takes a writeable file descriptor.
  */
 static void
-databuf_init(db, fd, filename, use, chunk_size)
-    struct databuf *db;
-    int fd;
-    char *filename;
-    long use;
-    long chunk_size;
+databuf_init(
+    struct databuf *   db,
+    int                        fd,
+    char *             filename,
+    off_t              use,
+    off_t              chunk_size)
 {
     db->fd = fd;
     db->filename = stralloc(filename);
-    db->filename_seq = 0;
+    db->filename_seq = (off_t)0;
     db->chunk_size = chunk_size;
     db->split_size = (db->chunk_size > use) ? use : db->chunk_size;
-    db->use = (use>db->split_size) ? use - db->split_size : 0;
+    db->use = (use > db->split_size) ? use - db->split_size : (off_t)0;
     db->datain = db->dataout = db->buf;
-    db->datalimit = db->buf + sizeof(db->buf);
+    db->datalimit = db->buf + SIZEOF(db->buf);
 }
 
 
@@ -520,14 +555,15 @@ databuf_init(db, fd, filename, use, chunk_size)
  * Write out the buffer to the backing file
  */
 static int
-databuf_flush(db)
-    struct databuf *db;
+databuf_flush(
+    struct databuf *   db)
 {
     struct cmdargs cmdargs;
     int rc = 1;
-    int written;
-    long left_in_chunk;
+    ssize_t written;
+    off_t left_in_chunk;
     char *arg_filename = NULL;
+    char *qarg_filename = NULL;
     char *new_filename = NULL;
     char *tmp_filename = NULL;
     char sequence[NUM_STR_SIZE];
@@ -547,8 +583,8 @@ databuf_flush(db)
     /*
      * See if we need to split this file.
      */
-    while (db->split_size > 0 && dumpsize >= db->split_size) {
-       if( db->use == 0 ) {
+    while (db->split_size > (off_t)0 && dumpsize >= db->split_size) {
+       if( db->use == (off_t)0 ) {
            /*
             * Probably no more space on this disk.  Request some more.
             */
@@ -573,24 +609,31 @@ databuf_flush(db)
                a = 3;
 
                if(a >= cmdargs.argc) {
-                   error("error [chunker CONTINUE: not enough args: filename]");
+                   error(_("error [chunker CONTINUE: not enough args: filename]"));
+                   /*NOTREACHED*/
                }
-               arg_filename = newstralloc(arg_filename, cmdargs.argv[a++]);
+               qarg_filename = newstralloc(qarg_filename, cmdargs.argv[a++]);
+               if (arg_filename != NULL)
+                   amfree(arg_filename);
+               arg_filename = unquote_string(qarg_filename);
 
                if(a >= cmdargs.argc) {
-                   error("error [chunker CONTINUE: not enough args: chunksize]");
+                   error(_("error [chunker CONTINUE: not enough args: chunksize]"));
+                   /*NOTREACHED*/
                }
-               db->chunk_size = atoi(cmdargs.argv[a++]);
-               db->chunk_size = am_floor(db->chunk_size, DISK_BLOCK_KB);
+               db->chunk_size = OFF_T_ATOI(cmdargs.argv[a++]);
+               db->chunk_size = am_floor(db->chunk_size, (off_t)DISK_BLOCK_KB);
 
                if(a >= cmdargs.argc) {
-                   error("error [chunker CONTINUE: not enough args: use]");
+                   error(_("error [chunker CONTINUE: not enough args: use]"));
+                   /*NOTREACHED*/
                }
-               db->use = atoi(cmdargs.argv[a++]);
+               db->use = OFF_T_ATOI(cmdargs.argv[a++]);
 
                if(a != cmdargs.argc) {
-                   error("error [chunker CONTINUE: too many args: %d != %d]",
+                   error(_("error [chunker CONTINUE: too many args: %d != %d]"),
                          cmdargs.argc, a);
+                   /*NOTREACHED*/
                }
 
                if(strcmp(db->filename, arg_filename) == 0) {
@@ -602,12 +645,12 @@ databuf_flush(db)
                    left_in_chunk = db->chunk_size - filesize;
                    if(left_in_chunk > db->use) {
                        db->split_size += db->use;
-                       db->use = 0;
+                       db->use = (off_t)0;
                    } else {
                        db->split_size += left_in_chunk;
                        db->use -= left_in_chunk;
                    }
-                   if(left_in_chunk > 0) {
+                   if(left_in_chunk > (off_t)0) {
                        /*
                         * We still have space in this chunk.
                         */
@@ -631,9 +674,10 @@ databuf_flush(db)
                } else if(cmdargs.argc >= 0) {
                    q = squote(cmdargs.argv[0]);
                } else {
-                   q = stralloc("(no input?)");
+                   q = stralloc(_("(no input?)"));
                }
-               error("error [bad command after RQ-MORE-DISK: \"%s\"]", q);
+               error(_("error [bad command after RQ-MORE-DISK: \"%s\"]"), q);
+               /*NOTREACHED*/
            }
        }
 
@@ -645,7 +689,7 @@ databuf_flush(db)
         * First, open the new chunk file, and give it a new header
         * that has no cont_filename pointer.
         */
-       snprintf(sequence, sizeof(sequence), "%d", db->filename_seq);
+       g_snprintf(sequence, SIZEOF(sequence), "%d", db->filename_seq);
        new_filename = newvstralloc(new_filename,
                                    db->filename,
                                    ".",
@@ -664,14 +708,13 @@ databuf_flush(db)
            int save_errno = errno;
 
            if(save_errno == ENOSPC) {
-               putresult(NO_ROOM, "%s %lu\n",
-                         handle, 
-                         db->use+db->split_size-dumpsize);
-               db->use = 0;                    /* force RQ_MORE_DISK */
+               putresult(NO_ROOM, "%s %lld\n", handle, 
+                         (long long)(db->use+db->split_size-dumpsize));
+               db->use = (off_t)0;                     /* force RQ_MORE_DISK */
                db->split_size = dumpsize;
                continue;
            }
-           errstr = squotef("creating chunk holding file \"%s\": %s",
+           errstr = squotef(_("creating chunk holding file \"%s\": %s"),
                             tmp_filename,
                             strerror(errno));
            aclose(db->fd);
@@ -686,14 +729,13 @@ databuf_flush(db)
 
            aclose(newfd);
            if(save_errno == ENOSPC) {
-               putresult(NO_ROOM, "%s %lu\n",
-                         handle, 
-                         db->use+db->split_size-dumpsize);
-               db->use = 0;                    /* force RQ_MORE DISK */
+               putresult(NO_ROOM, "%s %lld\n", handle, 
+                         (long long)(db->use+db->split_size-dumpsize));
+               db->use = (off_t)0;                     /* force RQ_MORE DISK */
                db->split_size = dumpsize;
                continue;
            }
-           errstr = squotef("write_tapeheader file \"%s\": %s",
+           errstr = squotef(_("write_tapeheader file %s: %s"),
                             tmp_filename,
                             strerror(errno));
            rc = 0;
@@ -704,8 +746,8 @@ databuf_flush(db)
         * Now, update the header of the current file to point
         * to the next chunk, and then close it.
         */
-       if (lseek(db->fd, (off_t)0, SEEK_SET) < 0) {
-           errstr = squotef("lseek holding file \"%s\": %s",
+       if (lseek(db->fd, (off_t)0, SEEK_SET) < (off_t)0) {
+           errstr = squotef(_("lseek holding file %s: %s"),
                             db->filename,
                             strerror(errno));
            aclose(newfd);
@@ -714,10 +756,10 @@ databuf_flush(db)
        }
 
        file.type = save_type;
-       strncpy(file.cont_filename, new_filename, sizeof(file.cont_filename));
-       file.cont_filename[sizeof(file.cont_filename)] = '\0';
+       strncpy(file.cont_filename, new_filename, SIZEOF(file.cont_filename));
+       file.cont_filename[SIZEOF(file.cont_filename)-1] = '\0';
        if(write_tapeheader(db->fd, &file)) {
-           errstr = squotef("write_tapeheader file \"%s\": %s",
+           errstr = squotef(_("write_tapeheader file \"%s\": %s"),
                             db->filename,
                             strerror(errno));
            aclose(newfd);
@@ -737,16 +779,16 @@ databuf_flush(db)
        /*
         * Update when we need to chunk again
         */
-       if(db->use <= DISK_BLOCK_KB) {
+       if(db->use <= (off_t)DISK_BLOCK_KB) {
            /*
             * Cheat and use one more block than allowed so we can make
             * some progress.
             */
-           db->split_size += 2 * DISK_BLOCK_KB;
-           db->use = 0;
+           db->split_size += (off_t)(2 * DISK_BLOCK_KB);
+           db->use = (off_t)0;
        } else if(db->chunk_size > db->use) {
            db->split_size += db->use;
-           db->use = 0;
+           db->use = (off_t)0;
        } else {
            db->split_size += db->chunk_size;
            db->use -= db->chunk_size;
@@ -755,8 +797,8 @@ databuf_flush(db)
 
        amfree(tmp_filename);
        amfree(new_filename);
-       dumpsize += DISK_BLOCK_KB;
-       filesize = DISK_BLOCK_KB;
+       dumpsize += (off_t)DISK_BLOCK_KB;
+       filesize = (off_t)DISK_BLOCK_KB;
        headersize += DISK_BLOCK_KB;
        db->filename_seq++;
     }
@@ -764,17 +806,18 @@ databuf_flush(db)
     /*
      * Write out the buffer
      */
-    written = fullwrite(db->fd, db->dataout, db->datain - db->dataout);
+    written = fullwrite(db->fd, db->dataout,
+                       (size_t)(db->datain - db->dataout));
     if (written > 0) {
        db->dataout += written;
-       dumpbytes += written;
+       dumpbytes += (off_t)written;
     }
-    dumpsize += (dumpbytes / 1024);
-    filesize += (dumpbytes / 1024);
+    dumpsize += (dumpbytes / (off_t)1024);
+    filesize += (dumpbytes / (off_t)1024);
     dumpbytes %= 1024;
     if (written < 0) {
        if (errno != ENOSPC) {
-           errstr = squotef("data write: %s", strerror(errno));
+           errstr = squotef(_("data write: %s"), strerror(errno));
            rc = 0;
            goto common_exit;
        }
@@ -783,8 +826,9 @@ databuf_flush(db)
         * NO-ROOM is informational only.  Later, RQ_MORE_DISK will be
         * issued to use another holding disk.
         */
-       putresult(NO_ROOM, "%s %lu\n", handle, db->use+db->split_size-dumpsize);
-       db->use = 0;                            /* force RQ_MORE_DISK */
+       putresult(NO_ROOM, "%s %lld\n", handle,
+                 (long long)(db->use+db->split_size-dumpsize));
+       db->use = (off_t)0;                             /* force RQ_MORE_DISK */
        db->split_size = dumpsize;
        goto common_exit;
     }
@@ -798,29 +842,31 @@ databuf_flush(db)
 common_exit:
 
     amfree(new_filename);
-    amfree(tmp_filename);
+    /*@i@*/ amfree(tmp_filename);
     amfree(arg_filename);
+    amfree(qarg_filename);
     return rc;
 }
 
 
 /*
- * Send an Amanda dump header to the output file.
+ * Send an Amanda dump header to the output file and set file->blocksize
  */
-static int
-write_tapeheader(outfd, file)
-    int outfd;
-    dumpfile_t *file;
+static ssize_t
+write_tapeheader(
+    int                outfd,
+    dumpfile_t *file)
 {
-    char buffer[DISK_BLOCK_BYTES];
-    int written;
+    char *buffer;
+    ssize_t written;
 
     file->blocksize = DISK_BLOCK_BYTES;
-    build_header(buffer, file, sizeof(buffer));
+    buffer = build_header(file, DISK_BLOCK_BYTES);
 
-    written = fullwrite(outfd, buffer, sizeof(buffer));
-    if(written == sizeof(buffer)) return 0;
+    written = fullwrite(outfd, buffer, DISK_BLOCK_BYTES);
+    amfree(buffer);
+    if(written == DISK_BLOCK_BYTES) return 0;
     if(written < 0) return written;
     errno = ENOSPC;
-    return -1;
+    return (ssize_t)-1;
 }