Imported Upstream version 2.6.0
[debian/amanda] / server-src / dumper.c
index 49982b2ffcb9755570d7ce5af24421143efe29b4..6d20b8a4adbe5b43fcd5df6d9eb1c7a4c108a2b6 100644 (file)
@@ -44,6 +44,7 @@
 #include "amfeatures.h"
 #include "server_util.h"
 #include "util.h"
+#include "timestamp.h"
 
 #define dumper_debug(i,x) do {         \
        if ((i) <= debug_dumper) {      \
@@ -88,6 +89,7 @@ char *srv_encrypt = NULL;
 char *clnt_encrypt = NULL;
 char *srv_decrypt_opt = NULL;
 char *clnt_decrypt_opt = NULL;
+static kencrypt_type dumper_kencrypt;
 
 static FILE *errf = NULL;
 static char *hostname = NULL;
@@ -230,13 +232,19 @@ check_options(
        *decryptend = ';';
       }
     }
+
+    if (strstr(options, "kencrypt;") != NULL) {
+       dumper_kencrypt = KENCRYPT_WILL_DO;
+    } else {
+       dumper_kencrypt = KENCRYPT_NONE;
+    }
 }
 
 
 int
 main(
-    int                main_argc,
-    char **    main_argv)
+    int                argc,
+    char **    argv)
 {
     static struct databuf db;
     struct cmdargs cmdargs;
@@ -244,17 +252,25 @@ main(
     int outfd = -1;
     int rc;
     in_port_t taper_port;
-    unsigned long malloc_hist_1, malloc_size_1;
-    unsigned long malloc_hist_2, malloc_size_2;
-    char *conffile;
     char *q = NULL;
     int a;
-    uid_t ruid;
-    int    new_argc,   my_argc;
-    char **new_argv, **my_argv;
-    struct addrinfo hints;
     int res;
-    struct addrinfo *gaires = 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"); 
+
+    /* drop root privileges */
+    if (!set_root_privs(0)) {
+       error(_("dumper must be run setuid root"));
+    }
 
     safe_fd(-1, 0);
 
@@ -265,75 +281,33 @@ main(
     /* 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);
 
-    parse_conf(main_argc, main_argv, &new_argc, &new_argv);
-    my_argc = new_argc;
-    my_argv = new_argv;
+    cfg_ovr = extract_commandline_config_overwrites(&argc, &argv);
+    if (argc > 1)
+       cfg_opt = argv[1];
+    config_init(CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_USE_CWD | CONFIG_INIT_FATAL,
+               cfg_opt);
+    apply_config_overwrites(cfg_ovr);
 
-    if (my_argc > 1) {
-       config_name = stralloc(my_argv[1]);
-       config_dir = vstralloc(CONFIG_DIR, "/", config_name, "/", NULL);
-    } else {
-       char my_cwd[STR_SIZE];
+    safe_cd(); /* do this *after* config_init() */
 
-       if (getcwd(my_cwd, SIZEOF(my_cwd)) == NULL) {
-           error("cannot determine current working directory");
-           /*NOTREACHED*/
-       }
-       config_dir = stralloc2(my_cwd, "/");
-       if ((config_name = strrchr(my_cwd, '/')) != NULL) {
-           config_name = stralloc(config_name + 1);
-       }
-    }
+    check_running_as(RUNNING_AS_DUMPUSER);
 
-    safe_cd();
+    dbrename(config_name, DBG_SUBDIR_SERVER);
 
     our_features = am_init_feature_set();
     our_feature_string = am_feature_to_string(our_features);
 
-    conffile = stralloc2(config_dir, CONFFILE_NAME);
-    if(read_conffile(conffile)) {
-       error("errors processing config file \"%s\"", conffile);
-       /*NOTREACHED*/
-    }
-    amfree(conffile);
-
-    dbrename(config_name, DBG_SUBDIR_SERVER);
-
-    report_bad_conf_arg();
-    /*
-     * Make our effective uid nonprivlidged, keeping save uid as root
-     * in case we need to get back (to bind privlidged ports, etc).
-     */
-    ruid = getuid();
-    if(geteuid() == 0) {
-       seteuid(ruid);
-       setgid(getgid());
-    }
-#if defined BSD_SECURITY && !defined SSH_SECURITY
-    else {
-       error("must be run setuid root to communicate correctly");
-       /*NOTREACHED*/
-    }
-#endif
-
-    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(),
-           my_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());
-       /*NOTREACHED*/
-    }
-
     signal(SIGPIPE, SIG_IGN);
 
     conf_dtimeout = (time_t)getconf_int(CNF_DTIMEOUT);
@@ -346,7 +320,7 @@ main(
        switch(cmd) {
        case START:
            if(cmdargs.argc <  2)
-               error("error [dumper START: not enough args: timestamp]");
+               error(_("error [dumper START: not enough args: timestamp]"));
            dumper_timestamp = newstralloc(dumper_timestamp, cmdargs.argv[2]);
            break;
 
@@ -377,32 +351,32 @@ main(
            a = 2;
 
            if(a >= cmdargs.argc) {
-               error("error [dumper PORT-DUMP: not enough args: handle]");
+               error(_("error [dumper PORT-DUMP: not enough args: handle]"));
                /*NOTREACHED*/
            }
            handle = newstralloc(handle, cmdargs.argv[a++]);
 
            if(a >= cmdargs.argc) {
-               error("error [dumper PORT-DUMP: not enough args: port]");
+               error(_("error [dumper PORT-DUMP: not enough args: port]"));
                /*NOTREACHED*/
            }
            taper_port = (in_port_t)atoi(cmdargs.argv[a++]);
 
            if(a >= cmdargs.argc) {
-               error("error [dumper PORT-DUMP: not enough args: hostname]");
+               error(_("error [dumper PORT-DUMP: not enough args: hostname]"));
                /*NOTREACHED*/
            }
            hostname = newstralloc(hostname, cmdargs.argv[a++]);
 
            if(a >= cmdargs.argc) {
-               error("error [dumper PORT-DUMP: not enough args: features]");
+               error(_("error [dumper PORT-DUMP: 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 [dumper PORT-DUMP: not enough args: diskname]");
+               error(_("error [dumper PORT-DUMP: not enough args: diskname]"));
                /*NOTREACHED*/
            }
            qdiskname = newstralloc(qdiskname, cmdargs.argv[a++]);
@@ -411,7 +385,7 @@ main(
            diskname = unquote_string(qdiskname);
 
            if(a >= cmdargs.argc) {
-               error("error [dumper PORT-DUMP: not enough args: device]");
+               error(_("error [dumper PORT-DUMP: not enough args: device]"));
                /*NOTREACHED*/
            }
            device = newstralloc(device, cmdargs.argv[a++]);
@@ -419,76 +393,55 @@ main(
                amfree(device);
 
            if(a >= cmdargs.argc) {
-               error("error [dumper PORT-DUMP: not enough args: level]");
+               error(_("error [dumper PORT-DUMP: not enough args: level]"));
                /*NOTREACHED*/
            }
            level = atoi(cmdargs.argv[a++]);
 
            if(a >= cmdargs.argc) {
-               error("error [dumper PORT-DUMP: not enough args: dumpdate]");
+               error(_("error [dumper PORT-DUMP: not enough args: dumpdate]"));
                /*NOTREACHED*/
            }
            dumpdate = newstralloc(dumpdate, cmdargs.argv[a++]);
 
            if(a >= cmdargs.argc) {
-               error("error [dumper PORT-DUMP: not enough args: program]");
+               error(_("error [dumper PORT-DUMP: not enough args: program]"));
                /*NOTREACHED*/
            }
            progname = newstralloc(progname, cmdargs.argv[a++]);
 
            if(a >= cmdargs.argc) {
-               error("error [dumper PORT-DUMP: not enough args: amandad_path]");
+               error(_("error [dumper PORT-DUMP: not enough args: amandad_path]"));
                /*NOTREACHED*/
            }
            amandad_path = newstralloc(amandad_path, cmdargs.argv[a++]);
 
            if(a >= cmdargs.argc) {
-               error("error [dumper PORT-DUMP: not enough args: client_username]");
+               error(_("error [dumper PORT-DUMP: not enough args: client_username]"));
            }
            client_username = newstralloc(client_username, cmdargs.argv[a++]);
 
            if(a >= cmdargs.argc) {
-               error("error [dumper PORT-DUMP: not enough args: ssh_keys]");
+               error(_("error [dumper PORT-DUMP: not enough args: ssh_keys]"));
            }
            ssh_keys = newstralloc(ssh_keys, cmdargs.argv[a++]);
 
            if(a >= cmdargs.argc) {
-               error("error [dumper PORT-DUMP: not enough args: options]");
+               error(_("error [dumper PORT-DUMP: not enough args: options]"));
            }
            options = newstralloc(options, cmdargs.argv[a++]);
 
            if(a != cmdargs.argc) {
-               error("error [dumper PORT-DUMP: too many args: %d != %d]",
+               error(_("error [dumper PORT-DUMP: too many args: %d != %d]"),
                      cmdargs.argc, a);
                /*NOTREACHED*/
            }
 
            /* Double-check that 'localhost' resolves properly */
-#ifdef WORKING_IPV6
-           hints.ai_flags = AI_CANONNAME | AI_V4MAPPED | AI_ALL;
-           hints.ai_family = AF_UNSPEC;
-#else
-           hints.ai_flags = AI_CANONNAME;
-           hints.ai_family = AF_INET;
-#endif
-           hints.ai_socktype = 0;
-           hints.ai_protocol = 0;
-           hints.ai_addrlen = 0;
-           hints.ai_addr = NULL;
-           hints.ai_canonname = NULL;
-           hints.ai_next = NULL;
-           res = getaddrinfo("localhost", NULL, &hints, &gaires);
-#ifdef WORKING_IPV6
-           if (res != 0) {
-               hints.ai_flags = AI_CANONNAME;
-               hints.ai_family = AF_UNSPEC;
-               res = getaddrinfo("localhost", NULL, &hints, &gaires);
-           }
-#endif
-           if (res != 0) {
-               errstr = newvstralloc(errstr,
-                                    _("could not resolve localhost: "),
-                                    gai_strerror(res), NULL);
+           if ((res = resolve_hostname("localhost", 0, NULL, NULL) != 0)) {
+               errstr = newvstrallocf(errstr,
+                                    _("could not resolve localhost: %s"),
+                                    gai_strerror(res));
                q = squotef(errstr);
                putresult(FAILED, "%s %s\n", handle, q);
                log_add(L_FAIL, "%s %s %s %d [%s]", hostname, qdiskname,
@@ -496,7 +449,6 @@ main(
                amfree(q);
                break;
            }
-           if (gaires) freeaddrinfo(gaires);
 
            /* connect outf to chunker/taper port */
 
@@ -504,8 +456,8 @@ main(
                                  STREAM_BUFSIZE, 0, NULL, 0);
            if (outfd == -1) {
                
-               errstr = newvstralloc(errstr, "port open: ",
-                                     strerror(errno), NULL);
+               errstr = newvstrallocf(errstr, _("port open: %s"),
+                                     strerror(errno));
                q = squotef(errstr);
                putresult(FAILED, "%s %s\n", handle, q);
                log_add(L_FAIL, "%s %s %s %d [%s]", hostname, qdiskname,
@@ -537,6 +489,9 @@ main(
                amfree(q);
            } else {
                do_dump(&db);
+               /* try to clean up any defunct processes, since Amanda doesn't
+                  wait() for them explicitly */
+               while(waitpid(-1, NULL, WNOHANG)> 0);
            }
 
            amfree(amandad_path);
@@ -550,7 +505,7 @@ main(
            } 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);
@@ -561,14 +516,6 @@ main(
            aclose(outfd);
     } while(cmd != QUIT);
 
-    /* make sure root privilege is dropped */
-    if ( geteuid() == 0 ) {
-      setuid(ruid);
-      seteuid(ruid);
-    }
-
-    free_new_argv(new_argc, new_argv);
-    free_server_config();
     am_release_feature_set(our_features);
     amfree(our_feature_string);
     amfree(errstr);
@@ -587,14 +534,6 @@ main(
     amfree(srv_decrypt_opt);
     amfree(clnt_decrypt_opt);
     amfree(options);
-    amfree(config_dir);
-    amfree(config_name);
-
-    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 (0); /* exit */
@@ -665,7 +604,7 @@ databuf_flush(
        dumpbytes %= (off_t)1024;
     }
     if (written < 0) {
-       errstr = squotef("data write: %s", strerror(errno));
+       errstr = squotef(_("data write: %s"), strerror(errno));
        return -1;
     }
     db->datain = db->dataout = db->buf;
@@ -687,21 +626,21 @@ process_dumpeof(void)
     add_msg_data(NULL, 0);
     if(!ISSET(status, GOT_SIZELINE) && dump_result < 2) {
        /* make a note if there isn't already a failure */
-       fprintf(errf,
-               "? %s: strange [missing size line from sendbackup]\n",
+       g_fprintf(errf,
+               _("? %s: strange [missing size line from sendbackup]\n"),
                get_pname());
        if(errstr == NULL) {
-           errstr = stralloc("missing size line from sendbackup");
+           errstr = stralloc(_("missing size line from sendbackup"));
        }
        dump_result = max(dump_result, 2);
     }
 
     if(!ISSET(status, GOT_ENDLINE) && dump_result < 2) {
-       fprintf(errf,
-               "? %s: strange [missing end line from sendbackup]\n",
+       g_fprintf(errf,
+               _("? %s: strange [missing end line from sendbackup]\n"),
                get_pname());
        if(errstr == NULL) {
-           errstr = stralloc("missing end line from sendbackup");
+           errstr = stralloc(_("missing end line from sendbackup"));
        }
        dump_result = max(dump_result, 2);
     }
@@ -811,7 +750,7 @@ process_dumpline(
 
            tok = strtok(NULL, "");
            if (tok == NULL || *tok != '[') {
-               errstr = newvstralloc(errstr, "bad remote error: ", str, NULL);
+               errstr = newvstrallocf(errstr, _("bad remote error: %s"), str);
            } else {
                char *enderr;
 
@@ -833,11 +772,11 @@ process_dumpline(
     default:
 bad_line:
        /* prefix with ?? */
-       fprintf(errf, "??");
+       g_fprintf(errf, "??");
        dump_result = max(dump_result, 1);
        break;
     }
-    fprintf(errf, "%s\n", str);
+    g_fprintf(errf, "%s\n", str);
     amfree(buf);
 }
 
@@ -852,7 +791,6 @@ add_msg_data(
     } msg = { NULL, 0 };
     char *line, *ch;
     size_t buflen;
-    int        in_quotes = 0;
 
     if (msg.buf != NULL)
        buflen = strlen(msg.buf);
@@ -866,10 +804,9 @@ add_msg_data(
     if (str == NULL) {
        if (buflen == 0)
            return;
-       fprintf(errf,"? %s: error [partial line in msgbuf: "
-                               SIZE_T_FMT " bytes]\n", get_pname(),
-                               (SIZE_T_FMT_TYPE)buflen);
-       fprintf(errf,"? %s: error [partial line in msgbuf: \"%s\"]\n",
+       g_fprintf(errf,_("? %s: error [partial line in msgbuf: %zu bytes]\n"),
+           get_pname(), buflen);
+       g_fprintf(errf,_("? %s: error [partial line in msgbuf: \"%s\"]\n"),
            get_pname(), msg.buf);
        msg.buf[0] = '\0';
        return;
@@ -908,13 +845,9 @@ add_msg_data(
      * scanning line for unqouted newline.
      */
     for (ch = line = msg.buf; *ch != '\0'; ch++) {
-       if (*ch == '"') {
-           in_quotes = !in_quotes;
-       } else if ((*ch == '\\') && (*(ch + 1) == '"')) {
-               ch++;
-       } else if (!in_quotes && (*ch == '\n')) {
+       if (*ch == '\n') {
            /*
-            * Found an unqouted newline.  Terminate and process line.
+            * Found a newline.  Terminate and process line.
             */
            *ch = '\0';
            process_dumpline(line);
@@ -943,7 +876,7 @@ log_msgout(
 
     fflush(errf);
     if (fseek(errf, 0L, SEEK_SET) < 0) {
-       dbprintf(("log_msgout: warning - seek failed: %s\n", strerror(errno)));
+       dbprintf(_("log_msgout: warning - seek failed: %s\n"), strerror(errno));
     }
     while ((line = agets(errf)) != NULL) {
        if (line[0] != '\0') {
@@ -983,21 +916,21 @@ finish_tapeheader(
 #define        UNCOMPRESS_OPT  ""
 #endif
        if (srvcompress == COMP_SERVER_CUST) {
-           snprintf(file->uncompress_cmd, SIZEOF(file->uncompress_cmd),
+           g_snprintf(file->uncompress_cmd, SIZEOF(file->uncompress_cmd),
                     " %s %s |", srvcompprog, "-d");
            strncpy(file->comp_suffix, "cust", SIZEOF(file->comp_suffix) - 1);
            file->comp_suffix[SIZEOF(file->comp_suffix) - 1] = '\0';
            strncpy(file->srvcompprog, srvcompprog, SIZEOF(file->srvcompprog) - 1);
            file->srvcompprog[SIZEOF(file->srvcompprog) - 1] = '\0';
        } else if ( srvcompress == COMP_CUST ) {
-           snprintf(file->uncompress_cmd, SIZEOF(file->uncompress_cmd),
+           g_snprintf(file->uncompress_cmd, SIZEOF(file->uncompress_cmd),
                     " %s %s |", clntcompprog, "-d");
            strncpy(file->comp_suffix, "cust", SIZEOF(file->comp_suffix) - 1);
            file->comp_suffix[SIZEOF(file->comp_suffix) - 1] = '\0';
            strncpy(file->clntcompprog, clntcompprog, SIZEOF(file->clntcompprog));
            file->clntcompprog[SIZEOF(file->clntcompprog) - 1] = '\0';
        } else {
-           snprintf(file->uncompress_cmd, SIZEOF(file->uncompress_cmd),
+           g_snprintf(file->uncompress_cmd, SIZEOF(file->uncompress_cmd),
                " %s %s |", UNCOMPRESS_PATH, UNCOMPRESS_OPT);
            strncpy(file->comp_suffix, COMPRESS_SUFFIX,SIZEOF(file->comp_suffix) - 1);
            file->comp_suffix[SIZEOF(file->comp_suffix) - 1] = '\0';
@@ -1016,7 +949,7 @@ finish_tapeheader(
     if (srvencrypt != ENCRYPT_NONE) {
       file->encrypted= 1;
       if (srvencrypt == ENCRYPT_SERV_CUST) {
-       snprintf(file->decrypt_cmd, SIZEOF(file->decrypt_cmd),
+       g_snprintf(file->decrypt_cmd, SIZEOF(file->decrypt_cmd),
                 " %s %s |", srv_encrypt, srv_decrypt_opt); 
        strncpy(file->encrypt_suffix, "enc", SIZEOF(file->encrypt_suffix) - 1);
        file->encrypt_suffix[SIZEOF(file->encrypt_suffix) - 1] = '\0';
@@ -1025,7 +958,7 @@ finish_tapeheader(
        strncpy(file->srv_decrypt_opt, srv_decrypt_opt, SIZEOF(file->srv_decrypt_opt) - 1);
        file->srv_decrypt_opt[SIZEOF(file->srv_decrypt_opt) - 1] = '\0';
       } else if ( srvencrypt == ENCRYPT_CUST ) {
-       snprintf(file->decrypt_cmd, SIZEOF(file->decrypt_cmd),
+       g_snprintf(file->decrypt_cmd, SIZEOF(file->decrypt_cmd),
                 " %s %s |", clnt_encrypt, clnt_decrypt_opt);
        strncpy(file->encrypt_suffix, "enc", SIZEOF(file->encrypt_suffix) - 1);
        file->encrypt_suffix[SIZEOF(file->encrypt_suffix) - 1] = '\0';
@@ -1054,16 +987,17 @@ write_tapeheader(
     int                outfd,
     dumpfile_t *file)
 {
-    char buffer[DISK_BLOCK_BYTES];
+    char * buffer;
     ssize_t written;
 
-    build_header(buffer, file, SIZEOF(buffer));
+    buffer = build_header(file, DISK_BLOCK_BYTES);
 
-    written = fullwrite(outfd, buffer, SIZEOF(buffer));
-    if(written == (ssize_t)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;
+        return written;
 
     return -1;
 }
@@ -1090,7 +1024,7 @@ do_dump(
     dumpbytes = dumpsize = headersize = origsize = (off_t)0;
     fh_init(&file);
 
-    snprintf(level_str, SIZEOF(level_str), "%d", level);
+    g_snprintf(level_str, SIZEOF(level_str), "%d", level);
     fn = sanitise_filename(diskname);
     errfname = newvstralloc(errfname,
                            AMANDA_TMPDIR,
@@ -1101,10 +1035,8 @@ do_dump(
                            NULL);
     amfree(fn);
     if((errf = fopen(errfname, "w+")) == NULL) {
-       errstr = newvstralloc(errstr,
-                             "errfile open \"", errfname, "\": ",
-                             strerror(errno),
-                             NULL);
+       errstr = newvstrallocf(errstr, "errfile open \"%s\": %s",
+                             errfname, strerror(errno));
        amfree(errfname);
        goto failed;
     }
@@ -1116,20 +1048,18 @@ do_dump(
        indexfile_tmp = stralloc2(indexfile_real, ".tmp");
 
        if (mkpdir(indexfile_tmp, 02755, (uid_t)-1, (gid_t)-1) == -1) {
-          errstr = newvstralloc(errstr,
-                                "err create ",
+          errstr = newvstrallocf(errstr,
+                                _("err create %s: %s"),
                                 indexfile_tmp,
-                                ": ",
-                                strerror(errno),
-                                NULL);
+                                strerror(errno));
           amfree(indexfile_real);
           amfree(indexfile_tmp);
           goto failed;
        }
        indexout = open(indexfile_tmp, O_WRONLY | O_CREAT | O_TRUNC, 0600);
        if (indexout == -1) {
-           errstr = newvstralloc(errstr, "err open ", indexfile_tmp, ": ",
-               strerror(errno), NULL);
+           errstr = newvstrallocf(errstr, _("err open %s: %s"),
+                       indexfile_tmp, strerror(errno));
            goto failed;
        } else {
            if (runcompress(indexout, &indexpid, COMP_BEST) < 0) {
@@ -1162,28 +1092,35 @@ do_dump(
      */
     event_loop(0);
 
+    if (!ISSET(status, HEADER_DONE)) {
+       dump_result = max(dump_result, 2);
+       if (!errstr) errstr = stralloc(_("got no header information"));
+    }
+
+    dumpsize -= headersize;            /* don't count the header */
+    if (dumpsize <= (off_t)0) {
+       dumpsize = (off_t)0;
+       dump_result = max(dump_result, 2);
+       if (!errstr) errstr = stralloc(_("got no data"));
+    }
+
     if (dump_result > 1)
        goto failed;
 
     runtime = stopclock();
-    dumptime = (double)(runtime.r.tv_sec) +
-              ((double)(runtime.r.tv_usec) / 1000000.0);
-
-    dumpsize -= headersize;            /* don't count the header */
-    if (dumpsize < (off_t)0)           /* XXX - maybe this should be fatal? */
-       dumpsize = (off_t)0;
+    dumptime = g_timeval_to_double(runtime);
 
     amfree(errstr);
     errstr = alloc(128);
-    snprintf(errstr, 128, "sec %s kb " OFF_T_FMT " kps %3.1lf orig-kb " OFF_T_FMT "",
+    g_snprintf(errstr, 128, _("sec %s kb %lld kps %3.1lf orig-kb %lld"),
        walltime_str(runtime),
-       (OFF_T_FMT_TYPE)dumpsize,
+       (long long)dumpsize,
        (isnormal(dumptime) ? ((double)dumpsize / (double)dumptime) : 0.0),
-       (OFF_T_FMT_TYPE)origsize);
+       (long long)origsize);
     q = squotef("[%s]", errstr);
-    putresult(DONE, "%s " OFF_T_FMT " " OFF_T_FMT " %lu %s\n", handle,
-               (OFF_T_FMT_TYPE)origsize,
-               (OFF_T_FMT_TYPE)dumpsize,
+    putresult(DONE, _("%s %lld %lld %lu %s\n"), handle,
+               (long long)origsize,
+               (long long)dumpsize,
                (unsigned long)((double)dumptime+0.5), q);
     amfree(q);
 
@@ -1211,7 +1148,7 @@ do_dump(
        /*@i@*/ aclose(indexout);
        waitpid(indexpid,&index_status,0);
        if (rename(indexfile_tmp, indexfile_real) != 0) {
-           log_add(L_WARNING, "could not rename \"%s\" to \"%s\": %s",
+           log_add(L_WARNING, _("could not rename \"%s\" to \"%s\": %s"),
                    indexfile_tmp, indexfile_real, strerror(errno));
        }
        amfree(indexfile_tmp);
@@ -1237,10 +1174,10 @@ failed:
     aclose(db->fd);
     /* kill all child process */
     if (db->compresspid != -1) {
-       fprintf(stderr,"%s: kill compress command\n",get_pname());
+       g_fprintf(stderr,_("%s: kill compress command\n"),get_pname());
        if (kill(db->compresspid, SIGTERM) < 0) {
            if (errno != ESRCH)
-               fprintf(stderr,"%s: can't kill compress command: %s\n"
+               g_fprintf(stderr,_("%s: can't kill compress command: %s\n")
                    get_pname(), strerror(errno));
        }
        else {
@@ -1249,10 +1186,10 @@ failed:
     }
 
     if (db->encryptpid != -1) {
-       fprintf(stderr,"%s: kill encrypt command\n",get_pname());
+       g_fprintf(stderr,_("%s: kill encrypt command\n"),get_pname());
        if (kill(db->encryptpid, SIGTERM) < 0) {
            if (errno != ESRCH)
-               fprintf(stderr,"%s: can't kill encrypt command: %s\n"
+               g_fprintf(stderr,_("%s: can't kill encrypt command: %s\n")
                    get_pname(), strerror(errno));
        }
        else {
@@ -1261,10 +1198,10 @@ failed:
     }
 
     if (indexpid != -1) {
-       fprintf(stderr,"%s: kill index command\n",get_pname());
+       g_fprintf(stderr,_("%s: kill index command\n"),get_pname());
        if (kill(indexpid, SIGTERM) < 0) {
            if (errno != ESRCH)
-               fprintf(stderr,"%s: can't kill index command: %s\n"
+               g_fprintf(stderr,_("%s: can't kill index command: %s\n")
                    get_pname(),strerror(errno));
        }
        else {
@@ -1273,7 +1210,7 @@ failed:
     }
 
     log_start_multiline();
-    log_add(L_FAIL, "%s %s %s %d [%s]", hostname, qdiskname, dumper_timestamp,
+    log_add(L_FAIL, _("%s %s %s %d [%s]"), hostname, qdiskname, dumper_timestamp,
            level, errstr);
     if (errf) {
        log_msgout(L_FAIL);
@@ -1306,7 +1243,7 @@ read_mesgfd(
 
     switch (size) {
     case -1:
-       errstr = newstralloc2(errstr, "mesg read: ",
+       errstr = newvstrallocf(errstr, _("mesg read: %s"),
            security_stream_geterror(streams[MESGFD].fd));
        dump_result = 2;
        stop_dump();
@@ -1339,7 +1276,7 @@ read_mesgfd(
        /* time to do the header */
        finish_tapeheader(&file);
        if (write_tapeheader(db->fd, &file)) {
-           errstr = newstralloc2(errstr, "write_tapeheader: "
+           errstr = newvstrallocf(errstr, _("write_tapeheader: %s")
                                  strerror(errno));
            dump_result = 2;
            stop_dump();
@@ -1393,7 +1330,7 @@ read_datafd(
      * The read failed.  Error out
      */
     if (size < 0) {
-       errstr = newstralloc2(errstr, "data read: ",
+       errstr = newvstrallocf(errstr, _("data read: %s"),
            security_stream_geterror(streams[DATAFD].fd));
        dump_result = 2;
        stop_dump();
@@ -1427,7 +1364,7 @@ read_datafd(
      */
     assert(buf != NULL);
     if (databuf_write(db, buf, (size_t)size) < 0) {
-       errstr = newstralloc2(errstr, "data write: ", strerror(errno));
+       errstr = newvstrallocf(errstr, _("data write: %s"), strerror(errno));
        dump_result = 2;
        stop_dump();
        return;
@@ -1456,7 +1393,7 @@ read_indexfd(
     fd = *(int *)cookie;
 
     if (size < 0) {
-       errstr = newstralloc2(errstr, "index read: ",
+       errstr = newvstrallocf(errstr, _("index read: %s"),
            security_stream_geterror(streams[INDEXFD].fd));
        dump_result = 2;
        stop_dump();
@@ -1487,7 +1424,7 @@ read_indexfd(
        /* Ignore error, but schedule another read. */
        if(indexfderror == 0) {
            indexfderror = 1;
-           log_add(L_INFO, "Index corrupted for %s:%s", hostname, qdiskname);
+           log_add(L_INFO, _("Index corrupted for %s:%s"), hostname, qdiskname);
        }
     }
     security_stream_read(streams[INDEXFD].fd, read_indexfd, cookie);
@@ -1529,7 +1466,7 @@ timeout_callback(
     (void)unused;      /* Quiet unused parameter warning */
 
     assert(unused == NULL);
-    errstr = newstralloc(errstr, "data timeout");
+    errstr = newstralloc(errstr, _("data timeout"));
     dump_result = 2;
     stop_dump();
 }
@@ -1572,41 +1509,41 @@ runcompress(
 
     /* outpipe[0] is pipe's stdin, outpipe[1] is stdout. */
     if (pipe(outpipe) < 0) {
-       errstr = newstralloc2(errstr, "pipe: ", strerror(errno));
+       errstr = newvstrallocf(errstr, _("pipe: %s"), strerror(errno));
        return (-1);
     }
 
     switch (*pid = fork()) {
     case -1:
-       errstr = newstralloc2(errstr, "couldn't fork: ", strerror(errno));
+       errstr = newvstrallocf(errstr, _("couldn't fork: %s"), strerror(errno));
        aclose(outpipe[0]);
        aclose(outpipe[1]);
        return (-1);
     default:
        rval = dup2(outpipe[1], outfd);
        if (rval < 0)
-           errstr = newstralloc2(errstr, "couldn't dup2: ", strerror(errno));
+           errstr = newvstrallocf(errstr, _("couldn't dup2: %s"), strerror(errno));
        aclose(outpipe[1]);
        aclose(outpipe[0]);
        return (rval);
     case 0:
        if (dup2(outpipe[0], 0) < 0) {
-           error("err dup2 in: %s", strerror(errno));
+           error(_("err dup2 in: %s"), strerror(errno));
            /*NOTREACHED*/
        }
        if (dup2(outfd, 1) == -1) {
-           error("err dup2 out: %s", strerror(errno));
+           error(_("err dup2 out: %s"), strerror(errno));
            /*NOTREACHED*/
        }
        safe_fd(-1, 0);
        if (comptype != COMP_SERVER_CUST) {
            execlp(COMPRESS_PATH, COMPRESS_PATH, (  comptype == COMP_BEST ?
                COMPRESS_BEST_OPT : COMPRESS_FAST_OPT), (char *)NULL);
-           error("error: couldn't exec %s: %s", COMPRESS_PATH, strerror(errno));
+           error(_("error: couldn't exec %s: %s"), COMPRESS_PATH, strerror(errno));
            /*NOTREACHED*/
        } else if (*srvcompprog) {
            execlp(srvcompprog, srvcompprog, (char *)0);
-           error("error: couldn't exec server custom filter%s.\n", srvcompprog);
+           error(_("error: couldn't exec server custom filter%s.\n"), srvcompprog);
            /*NOTREACHED*/
        }
     }
@@ -1633,36 +1570,36 @@ runencrypt(
 
     /* outpipe[0] is pipe's stdin, outpipe[1] is stdout. */
     if (pipe(outpipe) < 0) {
-       errstr = newstralloc2(errstr, "pipe: ", strerror(errno));
+       errstr = newvstrallocf(errstr, _("pipe: %s"), strerror(errno));
        return (-1);
     }
 
     switch (*pid = fork()) {
     case -1:
-       errstr = newstralloc2(errstr, "couldn't fork: ", strerror(errno));
+       errstr = newvstrallocf(errstr, _("couldn't fork: %s"), strerror(errno));
        aclose(outpipe[0]);
        aclose(outpipe[1]);
        return (-1);
     default:
        rval = dup2(outpipe[1], outfd);
        if (rval < 0)
-           errstr = newstralloc2(errstr, "couldn't dup2: ", strerror(errno));
+           errstr = newvstrallocf(errstr, _("couldn't dup2: %s"), strerror(errno));
        aclose(outpipe[1]);
        aclose(outpipe[0]);
        return (rval);
     case 0:
        if (dup2(outpipe[0], 0) < 0) {
-           error("err dup2 in: %s", strerror(errno));
+           error(_("err dup2 in: %s"), strerror(errno));
            /*NOTREACHED*/
        }
        if (dup2(outfd, 1) < 0 ) {
-           error("err dup2 out: %s", strerror(errno));
+           error(_("err dup2 out: %s"), strerror(errno));
            /*NOTREACHED*/
        }
        safe_fd(-1, 0);
        if ((encrypttype == ENCRYPT_SERV_CUST) && *srv_encrypt) {
            execlp(srv_encrypt, srv_encrypt, (char *)0);
-           error("error: couldn't exec server encryption%s.\n", srv_encrypt);
+           error(_("error: couldn't exec server encryption%s.\n"), srv_encrypt);
            /*NOTREACHED*/
        }
     }
@@ -1688,8 +1625,8 @@ sendbackup_response(
     assert(sech != NULL);
 
     if (pkt == NULL) {
-       errstr = newvstralloc(errstr, "[request failed: ",
-           security_geterror(sech), "]", NULL);
+       errstr = newvstrallocf(errstr, _("[request failed: %s]"),
+           security_geterror(sech));
        *response_error = 1;
        return;
     }
@@ -1700,7 +1637,7 @@ sendbackup_response(
     memset(ports, 0, SIZEOF(ports));
     if (pkt->type == P_NAK) {
 #if defined(PACKET_DEBUG)
-       fprintf(stderr, "got nak response:\n----\n%s\n----\n\n", pkt->body);
+       g_fprintf(stderr, _("got nak response:\n----\n%s\n----\n\n"), pkt->body);
 #endif
 
        tok = strtok(pkt->body, " ");
@@ -1709,26 +1646,24 @@ sendbackup_response(
 
        tok = strtok(NULL, "\n");
        if (tok != NULL) {
-           errstr = newvstralloc(errstr, "NAK: ", tok, NULL);
+           errstr = newvstrallocf(errstr, "NAK: %s", tok);
            *response_error = 1;
        } else {
 bad_nak:
-           errstr = newstralloc(errstr, "request NAK");
+           errstr = newvstrallocf(errstr, "request NAK");
            *response_error = 2;
        }
        return;
     }
 
     if (pkt->type != P_REP) {
-       errstr = newvstralloc(errstr, "received strange packet type ",
-           pkt_type2str(pkt->type), ": ", pkt->body, NULL);
+       errstr = newvstrallocf(errstr, _("received strange packet type %s: %s"),
+           pkt_type2str(pkt->type), pkt->body);
        *response_error = 1;
        return;
     }
 
-#if 1
-    fprintf(stderr, "got response:\n----\n%s\n----\n\n", pkt->body);
-#endif
+    dbprintf(_("got response:\n----\n%s\n----\n\n"), pkt->body);
 
     for(i = 0; i < NSTREAMS; i++) {
        ports[i] = -1;
@@ -1746,8 +1681,8 @@ bad_nak:
        if (strcmp(tok, "ERROR") == 0) {
            tok = strtok(NULL, "\n");
            if (tok == NULL)
-               tok = "[bogus error packet]";
-           errstr = newstralloc(errstr, tok);
+               tok = _("[bogus error packet]");
+           errstr = newvstrallocf(errstr, "%s", tok);
            *response_error = 2;
            return;
        }
@@ -1763,22 +1698,17 @@ bad_nak:
            for (i = 0; i < NSTREAMS; i++) {
                tok = strtok(NULL, " ");
                if (tok == NULL || strcmp(tok, streams[i].name) != 0) {
-                   extra = vstralloc("CONNECT token is \"",
-                                     tok ? tok : "(null)",
-                                     "\": expected \"",
-                                     streams[i].name,
-                                     "\"",
-                                     NULL);
+                   extra = vstrallocf(
+                               _("CONNECT token is \"%s\": expected \"%s\""),
+                               tok ? tok : "(null)",
+                               streams[i].name);
                    goto parse_error;
                }
                tok = strtok(NULL, " \n");
                if (tok == NULL || sscanf(tok, "%d", &ports[i]) != 1) {
-                   extra = vstralloc("CONNECT ",
-                                     streams[i].name,
-                                     " token is \"",
-                                     tok ? tok : "(null)",
-                                     "\": expected a port number",
-                                     NULL);
+                   extra = vstrallocf(
+                       _("CONNECT %s token is \"%s\": expected a port number"),
+                       streams[i].name, tok ? tok : "(null)");
                    goto parse_error;
                }
            }
@@ -1791,7 +1721,7 @@ bad_nak:
        if (strcmp(tok, "OPTIONS") == 0) {
            tok = strtok(NULL, "\n");
            if (tok == NULL) {
-               extra = stralloc("OPTIONS token is missing");
+               extra = vstrallocf(_("OPTIONS token is missing"));
                goto parse_error;
            }
 
@@ -1801,10 +1731,9 @@ bad_nak:
                if(strncmp_const_skip(tok, "features=", tok, ch) == 0) {
                    am_release_feature_set(their_features);
                    if((their_features = am_string_to_feature(tok)) == NULL) {
-                       errstr = newvstralloc(errstr,
-                                             "OPTIONS: bad features value: ",
-                                             tok,
-                                             NULL);
+                       errstr = newvstrallocf(errstr,
+                                             _("OPTIONS: bad features value: %s"),
+                                             tok);
                        goto parse_error;
                    }
                }
@@ -1813,13 +1742,14 @@ bad_nak:
            continue;
        }
 
-       extra = vstralloc("next token is \"",
-                         tok ? tok : "(null)",
-                         "\": expected \"CONNECT\", \"ERROR\" or \"OPTIONS\"",
-                         NULL);
+       extra = vstrallocf(_("next token is \"%s\": expected \"CONNECT\", \"ERROR\" or \"OPTIONS\""),
+                         tok ? tok : "(null)");
        goto parse_error;
     }
 
+    if (dumper_kencrypt == KENCRYPT_WILL_DO)
+       dumper_kencrypt = KENCRYPT_YES;
+
     /*
      * Connect the streams to their remote ports
      */
@@ -1828,9 +1758,10 @@ bad_nak:
            continue;
        streams[i].fd = security_stream_client(sech, ports[i]);
        if (streams[i].fd == NULL) {
-           errstr = newvstralloc(errstr,
-               "[could not connect ", streams[i].name, " stream: ",
-               security_geterror(sech), "]", NULL);
+           errstr = newvstrallocf(errstr,
+               _("[could not connect %s stream: %s]"),
+               streams[i].name,
+               security_geterror(sech));
            goto connect_error;
        }
     }
@@ -1852,9 +1783,10 @@ bad_nak:
            continue;
 #endif
        if (security_stream_auth(streams[i].fd) < 0) {
-           errstr = newvstralloc(errstr,
-               "[could not authenticate ", streams[i].name, " stream: ",
-               security_stream_geterror(streams[i].fd), "]", NULL);
+           errstr = newvstrallocf(errstr,
+               _("[could not authenticate %s stream: %s]"),
+               streams[i].name, 
+               security_stream_geterror(streams[i].fd));
            goto connect_error;
        }
     }
@@ -1864,7 +1796,7 @@ bad_nak:
      * them, complain.
      */
     if (streams[MESGFD].fd == NULL || streams[DATAFD].fd == NULL) {
-       errstr = newstralloc(errstr, "[couldn't open MESG or INDEX streams]");
+       errstr = newvstrallocf(errstr, _("[couldn't open MESG or INDEX streams]"));
        goto connect_error;
     }
 
@@ -1873,11 +1805,9 @@ bad_nak:
     return;
 
 parse_error:
-    errstr = newvstralloc(errstr,
-                         "[parse of reply message failed: ",
-                         extra ? extra : "(no additional information)",
-                         "]",
-                         NULL);
+    errstr = newvstrallocf(errstr,
+                         _("[parse of reply message failed: %s]"),
+                         extra ? extra : _("(no additional information)"));
     amfree(extra);
     *response_error = 2;
     return;
@@ -1907,6 +1837,11 @@ dumper_get_security_conf(
                 return (client_username);
         } else if(strcmp(string, "ssh_keys")==0) {
                 return (ssh_keys);
+        } else if(strcmp(string, "kencrypt")==0) {
+               if (dumper_kencrypt == KENCRYPT_YES)
+                    return ("yes");
+               else
+                   return (NULL);
         }
         return(NULL);
 }
@@ -1967,7 +1902,7 @@ startup_dump(
        }
     }
 
-    snprintf(level_string, SIZEOF(level_string), "%d", level);
+    g_snprintf(level_string, SIZEOF(level_string), "%d", level);
     if(strcmp(progname, "DUMP") == 0
        || strcmp(progname, "GNUTAR") == 0) {
        backup_api = "";
@@ -1997,12 +1932,13 @@ startup_dump(
                    "\n",
                    NULL);
 
-fprintf(stderr, "send request:\n----\n%s\n----\n\n", req);
+    dbprintf(_("send request:\n----\n%s\n----\n\n"), req);
     secdrv = security_getdriver(authopt);
     if (secdrv == NULL) {
-       error("no '%s' security driver available for host '%s'",
-           authopt, hostname);
-       /*NOTREACHED*/
+       errstr = newvstrallocf(errstr,
+               _("[could not find security driver '%s']"), authopt);
+       amfree(req);
+       return 2;
     }
 
     protocol_sendreq(hostname, secdrv, dumper_get_security_conf, req,