Imported Upstream version 2.5.1
[debian/amanda] / server-src / amcheck.c
index 36ab3d957e10cfdfdb009495ae6c001b477c5fab..9e83962ea1ba19cdf84a5241a592870213b6a933 100644 (file)
@@ -24,7 +24,7 @@
  * file named AUTHORS, in the root directory of this distribution.
  */
 /*
- * $Id: amcheck.c,v 1.121 2006/02/06 22:17:09 ktill Exp $
+ * $Id: amcheck.c,v 1.149 2006/08/24 01:57:16 paddy_s Exp $
  *
  * checks for common problems in server and clients
  */
@@ -50,7 +50,7 @@
 
 #define BUFFER_SIZE    32768
 
-static int conf_ctimeout;
+static time_t conf_ctimeout;
 static int overwrite;
 
 static disklist_t origq;
@@ -59,16 +59,17 @@ static uid_t uid_dumpuser;
 
 /* local functions */
 
-void usage P((void));
-int start_client_checks P((int fd));
-int start_server_check P((int fd, int do_localchk, int do_tapechk));
-int main P((int argc, char **argv));
-int test_server_pgm P((FILE *outf, char *dir, char *pgm,
-                      int suid, uid_t dumpuid));
+void usage(void);
+pid_t start_client_checks(int fd);
+pid_t start_server_check(int fd, int do_localchk, int do_tapechk);
+int main(int argc, char **argv);
+int test_server_pgm(FILE *outf, char *dir, char *pgm, int suid, uid_t dumpuid);
 
-void usage()
+void
+usage(void)
 {
-    error("Usage: amcheck%s [-M <username>] [-mawsclt] <conf> [host [disk]* ]*", versionsuffix());
+    error("Usage: amcheck%s [-am] [-w] [-sclt] [-M <address>] <conf> [host [disk]* ]* [-o configoption]*", versionsuffix());
+    /*NOTREACHED*/
 }
 
 static unsigned long malloc_hist_1, malloc_size_1;
@@ -79,18 +80,20 @@ static char *our_feature_string = NULL;
 static char *displayunit;
 static long int unitdivisor;
 
-int main(argc, argv)
-int argc;
-char **argv;
+int
+main(
+    int                argc,
+    char **    argv)
 {
     char buffer[BUFFER_SIZE];
     char *version_string;
     char *mainfname = NULL;
     char pid_str[NUM_STR_SIZE];
-    int do_clientchk, clientchk_pid, client_probs;
-    int do_localchk, do_tapechk, serverchk_pid, server_probs;
-    int chk_flag;
-    int opt, size, tempfd, mainfd;
+    int do_clientchk, client_probs;
+    int do_localchk, do_tapechk, server_probs;
+    pid_t clientchk_pid, serverchk_pid;
+    int opt, tempfd, mainfd;
+    ssize_t size;
     amwait_t retstat;
     pid_t pid;
     extern int optind;
@@ -104,6 +107,9 @@ char **argv;
     char *dumpuser;
     struct passwd *pw;
     uid_t uid_me;
+    int    new_argc,   my_argc;
+    char **new_argv, **my_argv;
+    char *errstr;
 
     safe_fd(-1, 0);
     safe_cd();
@@ -113,11 +119,12 @@ char **argv;
     /* Don't die when child closes pipe */
     signal(SIGPIPE, SIG_IGN);
 
-    dbopen();
+    dbopen(DBG_SUBDIR_SERVER);
 
+    memset(buffer, 0, sizeof(buffer));
     malloc_size_1 = malloc_inuse(&malloc_hist_1);
 
-    snprintf(pid_str, sizeof(pid_str), "%ld", (long)getpid());
+    snprintf(pid_str, SIZEOF(pid_str), "%ld", (long)getpid());
 
     erroutput_type = ERR_INTERACTIVE;
 
@@ -131,15 +138,23 @@ char **argv;
 
     alwaysmail = mailout = overwrite = 0;
     do_localchk = do_tapechk = do_clientchk = 0;
-    chk_flag = 0;
     server_probs = client_probs = 0;
     tempfd = mainfd = -1;
 
+    parse_server_conf(argc, argv, &new_argc, &new_argv);
+    my_argc = new_argc;
+    my_argv = new_argv;
+
     /* process arguments */
 
-    while((opt = getopt(argc, argv, "M:mawsclt")) != EOF) {
+    while((opt = getopt(my_argc, my_argv, "M:mawsclt")) != EOF) {
        switch(opt) {
        case 'M':       mailto=stralloc(optarg);
+                       if(!validate_mailto(mailto)){
+                          printf("Invalid characters in mail address\n");
+                          exit(1);
+                       }
+                       /*FALLTHROUGH*/
        case 'm':       
 #ifdef MAILER
                        mailout = 1;
@@ -159,43 +174,77 @@ char **argv;
                        exit(1);
 #endif
                        break;
-       case 's':       do_localchk = 1; do_tapechk = 1;
-                       chk_flag = 1;
+       case 's':       do_localchk = do_clientchk = do_tapechk = 1;
                        break;
        case 'c':       do_clientchk = 1;
-                       chk_flag = 1;
                        break;
        case 'l':       do_localchk = 1;
-                       chk_flag = 1;
                        break;
-       case 'w':       do_tapechk = 1; overwrite = 1;
-                       chk_flag = 1;
+       case 'w':       overwrite = 1;
                        break;
        case 't':       do_tapechk = 1;
-                       chk_flag = 1;
                        break;
        case '?':
        default:
            usage();
        }
     }
-    argc -= optind, argv += optind;
-    if(! chk_flag) {
+    my_argc -= optind, my_argv += optind;
+    if(my_argc < 1) usage();
+
+
+    if ((do_localchk | do_clientchk | do_tapechk) == 0) {
+       /* Check everything if individual checks were not asked for */
        do_localchk = do_clientchk = do_tapechk = 1;
     }
 
-    if(argc < 1) usage();
+    if(overwrite)
+       do_tapechk = 1;
 
-    config_name = stralloc(*argv);
+    config_name = stralloc(*my_argv);
 
     config_dir = vstralloc(CONFIG_DIR, "/", config_name, "/", NULL);
     conffile = stralloc2(config_dir, CONFFILE_NAME);
     if(read_conffile(conffile)) {
        error("errors processing config file \"%s\"", conffile);
+       /*NOTREACHED*/
     }
+
+    dbrename(config_name, DBG_SUBDIR_SERVER);
+
+    report_bad_conf_arg();
+
     amfree(conffile);
+    if(mailout && !mailto && 
+       (getconf_seen(CNF_MAILTO)==0 || strlen(getconf_str(CNF_MAILTO)) == 0)) {
+       printf("\nNo mail address configured in  amanda.conf\n");
+        if(alwaysmail)        
+               printf("When using -a option please specify -Maddress also\n\n"); 
+       else
+               printf("Use -Maddress instead of -m\n\n"); 
+       exit(1);
+    }
+    if(mailout && !mailto)
+    { 
+       if(getconf_seen(CNF_MAILTO) && 
+          strlen(getconf_str(CNF_MAILTO)) > 0) {
+          if(!validate_mailto(getconf_str(CNF_MAILTO))){
+               printf("\nMail address in amanda.conf has invalid characters"); 
+               printf("\nNo email will be sent\n"); 
+                mailout = 0;
+          }
+       }
+       else {
+         printf("\nNo mail address configured in  amanda.conf\n");
+          if(alwaysmail)        
+               printf("When using -a option please specify -Maddress also\n\n"); 
+         else
+               printf("Use -Maddress instead of -m\n\n"); 
+         exit(1);
+      }
+    }
 
-    conf_ctimeout = getconf_int(CNF_CTIMEOUT);
+    conf_ctimeout = getconf_time(CNF_CTIMEOUT);
 
     conf_diskfile = getconf_str(CNF_DISKFILE);
     if (*conf_diskfile == '/') {
@@ -205,8 +254,13 @@ char **argv;
     }
     if(read_diskfile(conf_diskfile, &origq) < 0) {
        error("could not load disklist %s", conf_diskfile);
+       /*NOTREACHED*/
+    }
+    errstr = match_disklist(&origq, my_argc-1, my_argv+1);
+    if (errstr) {
+       printf("%s",errstr);
+       amfree(errstr);
     }
-    match_disklist(&origq, argc-1, argv+1);
     amfree(conf_diskfile);
 
     /*
@@ -215,15 +269,17 @@ char **argv;
     dumpuser = getconf_str(CNF_DUMPUSER);
     if ((pw = getpwnam(dumpuser)) == NULL) {
        error("cannot look up dump user \"%s\"", dumpuser);
+       /*NOTREACHED*/
     }
     uid_dumpuser = pw->pw_uid;
     if ((pw = getpwuid(uid_me)) == NULL) {
        error("cannot look up my own uid (%ld)", (long)uid_me);
+       /*NOTREACHED*/
     }
     if (uid_me != uid_dumpuser) {
        error("running as user \"%s\" instead of \"%s\"",
-             pw->pw_name,
-             dumpuser);
+             pw->pw_name, dumpuser);
+        /*NOTREACHED*/
     }
 
     displayunit = getconf_str(CNF_DISPLAYUNIT);
@@ -240,8 +296,10 @@ char **argv;
     if(do_clientchk && (do_localchk || do_tapechk)) {
        /* we need the temp file */
        tempfname = vstralloc(AMANDA_TMPDIR, "/amcheck.temp.", pid_str, NULL);
-       if((tempfd = open(tempfname, O_RDWR|O_CREAT|O_TRUNC, 0600)) == -1)
+       if((tempfd = open(tempfname, O_RDWR|O_CREAT|O_TRUNC, 0600)) == -1) {
            error("could not open %s: %s", tempfname, strerror(errno));
+           /*NOTREACHED*/
+       }
        unlink(tempfname);                      /* so it goes away on close */
        amfree(tempfname);
     }
@@ -249,8 +307,10 @@ char **argv;
     if(mailout) {
        /* the main fd is a file too */
        mainfname = vstralloc(AMANDA_TMPDIR, "/amcheck.main.", pid_str, NULL);
-       if((mainfd = open(mainfname, O_RDWR|O_CREAT|O_TRUNC, 0600)) == -1)
+       if((mainfd = open(mainfname, O_RDWR|O_CREAT|O_TRUNC, 0600)) == -1) {
            error("could not open %s: %s", mainfname, strerror(errno));
+           /*NOTREACHED*/
+       }
        unlink(mainfname);                      /* so it goes away on close */
        amfree(mainfname);
     }
@@ -289,11 +349,13 @@ char **argv;
            char number[NUM_STR_SIZE];
            char *wait_msg = NULL;
 
-           snprintf(number, sizeof(number), "%ld", (long)pid);
+           snprintf(number, SIZEOF(number), "%ld", (long)pid);
            wait_msg = vstralloc("parent: reaped bogus pid ", number, "\n",
                                 NULL);
-           if (fullwrite(mainfd, wait_msg, strlen(wait_msg)) < 0)
+           if (fullwrite(mainfd, wait_msg, strlen(wait_msg)) < 0) {
                error("write main file: %s", strerror(errno));
+               /*NOTREACHED*/
+           }
            amfree(wait_msg);
        }
     }
@@ -301,23 +363,31 @@ char **argv;
     /* copy temp output to main output and write tagline */
 
     if(do_clientchk && (do_localchk || do_tapechk)) {
-       if(lseek(tempfd, 0, 0) == -1)
+       if(lseek(tempfd, (off_t)0, 0) == (off_t)-1) {
            error("seek temp file: %s", strerror(errno));
+           /*NOTREACHED*/
+       }
 
-       while((size=fullread(tempfd, buffer, sizeof(buffer))) > 0) {
-           if (fullwrite(mainfd, buffer, size) < 0)
+       while((size = fullread(tempfd, buffer, SIZEOF(buffer))) > 0) {
+           if (fullwrite(mainfd, buffer, (size_t)size) < 0) {
                error("write main file: %s", strerror(errno));
+               /*NOTREACHED*/
+           }
        }
-       if(size < 0)
+       if(size < 0) {
            error("read temp file: %s", strerror(errno));
+           /*NOTREACHED*/
+       }
        aclose(tempfd);
     }
 
     version_string = vstralloc("\n",
                               "(brought to you by Amanda ", version(), ")\n",
                               NULL);
-    if (fullwrite(mainfd, version_string, strlen(version_string)) < 0)
+    if (fullwrite(mainfd, version_string, strlen(version_string)) < 0) {
        error("write main file: %s", strerror(errno));
+       /*NOTREACHED*/
+    }
     amfree(version_string);
     amfree(config_dir);
     amfree(config_name);
@@ -344,10 +414,8 @@ char **argv;
        char *subject;
        char **a;
        amwait_t retstat;
-       pid_t mailpid;
-       pid_t wpid;
-       int r;
-       int w;
+       ssize_t r;
+       ssize_t w;
        char *err = NULL;
        char *extra_info = NULL;
        char *line = NULL;
@@ -357,8 +425,9 @@ char **argv;
        char number[NUM_STR_SIZE];
 
        fflush(stdout);
-       if(lseek(mainfd, (off_t)0, SEEK_SET) == -1) {
+       if(lseek(mainfd, (off_t)0, SEEK_SET) == (off_t)-1) {
            error("lseek main file: %s", strerror(errno));
+           /*NOTREACHED*/
        }
        if(alwaysmail && !(server_probs || client_probs)) {
            subject = stralloc2(getconf_str(CNF_ORG),
@@ -375,19 +444,20 @@ char **argv;
         * Remember that split() returns the original input string in
         * argv[0], so we have to skip over that.
         */
-       a = (char **) alloc((MAILTO_LIMIT + 1) * sizeof(char *));
-       memset(a, 0, (MAILTO_LIMIT + 1) * sizeof(char *));
+       a = (char **) alloc((MAILTO_LIMIT + 1) * SIZEOF(char *));
+       memset(a, 0, (MAILTO_LIMIT + 1) * SIZEOF(char *));
        if(mailto) {
            a[1] = mailto;
            a[2] = NULL;
        } else {
-           r = split(getconf_str(CNF_MAILTO), a, MAILTO_LIMIT, " ");
+           r = (ssize_t)split(getconf_str(CNF_MAILTO), a, MAILTO_LIMIT, " ");
            a[r + 1] = NULL;
        }
        if((nullfd = open("/dev/null", O_RDWR)) < 0) {
            error("nullfd: /dev/null: %s", strerror(errno));
+           /*NOTREACHED*/
        }
-       mailpid = pipespawn(MAILER, STDIN_PIPE | STDERR_PIPE,
+       pipespawn(MAILER, STDIN_PIPE | STDERR_PIPE,
                            &mailfd, &nullfd, &errfd,
                            MAILER,
                            "-s", subject,
@@ -402,28 +472,36 @@ char **argv;
         * cases, the pipe will break and we will exit out of the loop.
         */
        signal(SIGPIPE, SIG_IGN);
-       while((r = fullread(mainfd, buffer, sizeof(buffer))) > 0) {
-           if((w = fullwrite(mailfd, buffer, r)) != r) {
+       while((r = fullread(mainfd, buffer, SIZEOF(buffer))) > 0) {
+           if((w = fullwrite(mailfd, buffer, (size_t)r)) != (ssize_t)r) {
                if(w < 0 && errno == EPIPE) {
                    strappend(extra_info, "EPIPE writing to mail process\n");
                    break;
                } else if(w < 0) {
                    error("mailfd write: %s", strerror(errno));
+                   /*NOTREACHED*/
                } else {
                    error("mailfd write: wrote %d instead of %d", w, r);
+                   /*NOTREACHED*/
                }
            }
        }
        aclose(mailfd);
        ferr = fdopen(errfd, "r");
+       if (!ferr) {
+           error("Can't fdopen: %s", strerror(errno));
+           /*NOTREACHED*/
+       }
        for(; (line = agets(ferr)) != NULL; free(line)) {
+           if (line[0] == '\0')
+               continue;
            strappend(extra_info, line);
            strappend(extra_info, "\n");
        }
        afclose(ferr);
        errfd = -1;
        rc = 0;
-       while ((wpid = wait(&retstat)) != -1) {
+       while (wait(&retstat) != -1) {
            if (WIFSIGNALED(retstat)) {
                    ret = 0;
                    rc = sig = WTERMSIG(retstat);
@@ -438,7 +516,7 @@ char **argv;
                    } else {
                        strappend(err, "returned ");
                    }
-                   snprintf(number, sizeof(number), "%d", ret);
+                   snprintf(number, SIZEOF(number), "%d", ret);
                    strappend(err, number);
            }
        }
@@ -448,9 +526,13 @@ char **argv;
                amfree(extra_info);
            }
            error("error running mailer %s: %s", MAILER, err);
+           /*NOTREACHED*/
        }
     }
 #endif
+    free_new_argv(new_argc, new_argv);
+    free_server_config();
+
     dbclose();
     return (server_probs || client_probs);
 }
@@ -463,58 +545,71 @@ char *first_match_label = NULL, *first_match = NULL, *found_device = NULL;
 char *label;
 char *searchlabel, *labelstr;
 tape_t *tp;
-FILE *errf;
-
-int test_server_pgm(outf, dir, pgm, suid, dumpuid)
-FILE *outf;
-char *dir;
-char *pgm;
-int suid;
-uid_t dumpuid;
+FILE *errf = NULL;
+
+int
+test_server_pgm(
+    FILE *     outf,
+    char *     dir,
+    char *     pgm,
+    int                suid,
+    uid_t      dumpuid)
 {
     struct stat statbuf;
     int pgmbad = 0;
+    char *quoted;
 
     pgm = vstralloc(dir, "/", pgm, versionsuffix(), NULL);
+    quoted = quote_string(pgm);
     if(stat(pgm, &statbuf) == -1) {
        fprintf(outf, "ERROR: program %s: does not exist\n",
-               pgm);
+               quoted);
        pgmbad = 1;
     } else if (!S_ISREG(statbuf.st_mode)) {
        fprintf(outf, "ERROR: program %s: not a file\n",
-               pgm);
+               quoted);
        pgmbad = 1;
     } else if (access(pgm, X_OK) == -1) {
        fprintf(outf, "ERROR: program %s: not executable\n",
-               pgm);
+               quoted);
        pgmbad = 1;
     } else if (suid \
               && dumpuid != 0
               && (statbuf.st_uid != 0 || (statbuf.st_mode & 04000) == 0)) {
-       fprintf(outf, "WARNING: program %s: not setuid-root\n",
-               pgm);
+       fprintf(outf, "ERROR: program %s: not setuid-root\n",
+               quoted);
+       pgmbad = 1;
     }
+    amfree(quoted);
     amfree(pgm);
     return pgmbad;
 }
 
-int start_server_check(fd, do_localchk, do_tapechk)
-    int fd;
-    int do_localchk, do_tapechk;
+pid_t
+start_server_check(
+    int                fd,
+    int                do_localchk,
+    int                do_tapechk)
 {
     char *tapename;
     generic_fs_stats_t fs;
-    FILE *outf;
+    FILE *outf = NULL;
     holdingdisk_t *hdp;
-    int pid;
+    pid_t pid;
     int confbad = 0, tapebad = 0, disklow = 0, logbad = 0;
     int userbad = 0, infobad = 0, indexbad = 0, pgmbad = 0;
     int testtape = do_tapechk;
     tapetype_t *tp = NULL;
+    char *quoted;
 
     switch(pid = fork()) {
-    case -1: error("could not fork server check: %s", strerror(errno));
-    case 0: break;
+    case -1:
+       error("could not fork server check: %s", strerror(errno));
+       /*NOTREACHED*/
+
+    case 0:
+       break;
+
     default:
        return pid;
     }
@@ -526,8 +621,10 @@ int start_server_check(fd, do_localchk, do_tapechk)
 
     startclock();
 
-    if((outf = fdopen(fd, "w")) == NULL)
+    if((outf = fdopen(fd, "w")) == NULL) {
        error("fdopen %d: %s", fd, strerror(errno));
+       /*NOTREACHED*/
+    }
     errf = outf;
 
     fprintf(outf, "Amanda Tape Server Host Check\n");
@@ -551,7 +648,7 @@ int start_server_check(fd, do_localchk, do_tapechk)
            amfree(errstr);
            confbad = 1;
        }
-       lbl_templ = tp->lbl_templ;
+       lbl_templ = tapetype_get_lbl_templ(tp);
        if(strcmp(lbl_templ, "") != 0) {
            if(strchr(lbl_templ, '/') == NULL) {
                lbl_templ = stralloc2(config_dir, lbl_templ);
@@ -570,61 +667,61 @@ int start_server_check(fd, do_localchk, do_tapechk)
            confbad = 1;
 #endif
        }
+
+       /* check that localhost is resolvable */
+       if ((gethostbyname("localhost")) == NULL) {
+           fprintf(outf, "ERROR: Cannot resolve `localhost'.\n");
+       }
     }
 
     /*
      * Look up the programs used on the server side.
      */
     if(do_localchk) {
-       int suid_check=1;
-#ifdef SSH_SECURITY
-       suid_check=0;
-#endif 
+       /* 
+        * entreprise version will do planner/dumper suid check
+        */
        if(access(libexecdir, X_OK) == -1) {
+           quoted = quote_string(libexecdir);
            fprintf(outf, "ERROR: program dir %s: not accessible\n",
-                   libexecdir);
+                   quoted);
            pgmbad = 1;
+           amfree(quoted);
        } else {
-           pgmbad = pgmbad \
-                    || test_server_pgm(outf, libexecdir, "planner",
-                                       suid_check, uid_dumpuser);
-           pgmbad = pgmbad \
-                    || test_server_pgm(outf, libexecdir, "dumper",
-                                       suid_check, uid_dumpuser);
-           pgmbad = pgmbad \
-                    || test_server_pgm(outf, libexecdir, "driver",
-                                       0, uid_dumpuser);
-           pgmbad = pgmbad \
-                    || test_server_pgm(outf, libexecdir, "taper",
-                                       0, uid_dumpuser);
-           pgmbad = pgmbad \
-                    || test_server_pgm(outf, libexecdir, "amtrmidx",
-                                       0, uid_dumpuser);
-           pgmbad = pgmbad \
-                    || test_server_pgm(outf, libexecdir, "amlogroll",
-                                       0, uid_dumpuser);
+           if(test_server_pgm(outf, libexecdir, "planner", 1, uid_dumpuser))
+               pgmbad = 1;
+           if(test_server_pgm(outf, libexecdir, "dumper", 1, uid_dumpuser))
+               pgmbad = 1;
+           if(test_server_pgm(outf, libexecdir, "driver", 0, uid_dumpuser))
+               pgmbad = 1;
+           if(test_server_pgm(outf, libexecdir, "taper", 0, uid_dumpuser))
+               pgmbad = 1;
+           if(test_server_pgm(outf, libexecdir, "amtrmidx", 0, uid_dumpuser))
+               pgmbad = 1;
+           if(test_server_pgm(outf, libexecdir, "amlogroll", 0, uid_dumpuser))
+               pgmbad = 1;
        }
        if(access(sbindir, X_OK) == -1) {
+           quoted = quote_string(sbindir);
            fprintf(outf, "ERROR: program dir %s: not accessible\n",
                    sbindir);
            pgmbad = 1;
+           amfree(quoted);
        } else {
-           pgmbad = pgmbad \
-                    || test_server_pgm(outf, sbindir, "amgetconf",
-                                       0, uid_dumpuser);
-           pgmbad = pgmbad \
-                    || test_server_pgm(outf, sbindir, "amcheck",
-                                       1, uid_dumpuser);
-           pgmbad = pgmbad \
-                    || test_server_pgm(outf, sbindir, "amdump",
-                                       0, uid_dumpuser);
-           pgmbad = pgmbad \
-                    || test_server_pgm(outf, sbindir, "amreport",
-                                       0, uid_dumpuser);
+           if(test_server_pgm(outf, sbindir, "amgetconf", 0, uid_dumpuser))
+               pgmbad = 1;
+           if(test_server_pgm(outf, sbindir, "amcheck", 1, uid_dumpuser))
+               pgmbad = 1;
+           if(test_server_pgm(outf, sbindir, "amdump", 0, uid_dumpuser))
+               pgmbad = 1;
+           if(test_server_pgm(outf, sbindir, "amreport", 0, uid_dumpuser))
+               pgmbad = 1;
        }
        if(access(COMPRESS_PATH, X_OK) == -1) {
+           quoted = quote_string(COMPRESS_PATH);
            fprintf(outf, "WARNING: %s is not executable, server-compression and indexing will not work\n",
-                   COMPRESS_PATH);
+                   quoted);
+           amfree(quoted);
        }
     }
 
@@ -660,31 +757,47 @@ int start_server_check(fd, do_localchk, do_tapechk)
         */
        }
        if(access(tape_dir, W_OK) == -1) {
-           fprintf(outf, "ERROR: tapelist dir %s: not writable.\n", tape_dir);
+           quoted = quote_string(tape_dir);
+           fprintf(outf, "ERROR: tapelist dir %s: not writable.\n", quoted);
            tapebad = 1;
+           amfree(quoted);
        }
        else if(stat(tapefile, &statbuf) == -1) {
-           fprintf(outf, "ERROR: tapefile %s: %s, you must create an empty file.\n",
-                   tapefile, strerror(errno));
+           quoted = quote_string(tape_dir);
+           fprintf(outf, "ERROR: tapefile %s (%s), "
+                   "you must create an empty file.\n",
+                   quoted, strerror(errno));
            tapebad = 1;
+           amfree(quoted);
        }
        else if(!S_ISREG(statbuf.st_mode)) {
-           fprintf(outf, "ERROR: tapefile %s: should be a regular file.\n", tapefile);
+           quoted = quote_string(tapefile);
+           fprintf(outf, "ERROR: tapefile %s: should be a regular file.\n",
+                   quoted);
            tapebad = 1;
+           amfree(quoted);
        }
        else if(access(tapefile, F_OK) != 0) {
-           fprintf(outf, "ERROR: can't access tape list %s\n", tapefile);
+           quoted = quote_string(tapefile);
+           fprintf(outf, "ERROR: can't access tape list %s\n", quoted);
            tapebad = 1;
+           amfree(quoted);
        } else if(access(tapefile, F_OK) == 0 && access(tapefile, W_OK) != 0) {
-           fprintf(outf, "ERROR: tape list %s: not writable\n", tapefile);
+           quoted = quote_string(tapefile);
+           fprintf(outf, "ERROR: tape list %s: not writable\n", quoted);
            tapebad = 1;
+           amfree(quoted);
        } else if(read_tapelist(tapefile)) {
-           fprintf(outf, "ERROR: tape list %s: parse error\n", tapefile);
+           quoted = quote_string(tapefile);
+           fprintf(outf, "ERROR: tape list %s: parse error\n", quoted);
            tapebad = 1;
+           amfree(quoted);
        }
        holdfile = vstralloc(config_dir, "/", "hold", NULL);
        if(access(holdfile, F_OK) != -1) {
+           quoted = quote_string(holdfile);
            fprintf(outf, "WARNING: hold file %s exists\n", holdfile);
+           amfree(quoted);
        }
        amfree(tapefile);
        amfree(tape_dir);
@@ -703,48 +816,73 @@ int start_server_check(fd, do_localchk, do_tapechk)
 
     if(do_localchk) {
        for(hdp = holdingdisks; hdp != NULL; hdp = hdp->next) {
-           if(get_fs_stats(hdp->diskdir, &fs) == -1) {
-               fprintf(outf, "ERROR: holding dir %s: %s, you must create a directory.\n",
-                       hdp->diskdir, strerror(errno));
+           quoted = quote_string(holdingdisk_get_diskdir(hdp));
+           if(get_fs_stats(holdingdisk_get_diskdir(hdp), &fs) == -1) {
+               fprintf(outf, "ERROR: holding dir %s (%s), "
+                       "you must create a directory.\n",
+                       quoted, strerror(errno));
                disklow = 1;
            }
-           else if(access(hdp->diskdir, W_OK) == -1) {
+           else if(access(holdingdisk_get_diskdir(hdp), W_OK) == -1) {
                fprintf(outf, "ERROR: holding disk %s: not writable: %s.\n",
-                       hdp->diskdir, strerror(errno));
+                       quoted, strerror(errno));
+               disklow = 1;
+           }
+           else if(access(holdingdisk_get_diskdir(hdp), X_OK) == -1) {
+               fprintf(outf, "ERROR: holding disk %s: not searcheable: %s.\n",
+                       quoted, strerror(errno));
                disklow = 1;
            }
-           else if(fs.avail == -1) {
+           else if(fs.avail == (off_t)-1) {
                fprintf(outf,
-                       "WARNING: holding disk %s: available space unknown (%ld KB requested)\n",
-                       hdp->diskdir, (long)hdp->disksize);
+                       "WARNING: holding disk %s: "
+                       "available space unknown (" OFF_T_FMT" KB requested)\n",
+                       quoted, (OFF_T_FMT_TYPE)holdingdisk_get_disksize(hdp));
                disklow = 1;
            }
-           else if(hdp->disksize > 0) {
-               if(fs.avail < hdp->disksize) {
+           else if(holdingdisk_get_disksize(hdp) > (off_t)0) {
+               if(fs.avail < holdingdisk_get_disksize(hdp)) {
                    fprintf(outf,
-                           "WARNING: holding disk %s: only %ld %sB free (%ld %sB requested)\n",
-                           hdp->diskdir, (long)fs.avail/unitdivisor, displayunit,
-                           (long)hdp->disksize/unitdivisor, displayunit);
+                           "WARNING: holding disk %s: "
+                           "only " OFF_T_FMT " %sB free ("
+                           OFF_T_FMT " %sB requested)\n", quoted,
+                           (OFF_T_FMT_TYPE)(fs.avail / (off_t)unitdivisor),
+                           displayunit,
+                           (OFF_T_FMT_TYPE)(holdingdisk_get_disksize(hdp)/(off_t)unitdivisor),
+                           displayunit);
                    disklow = 1;
                }
-               else
+               else {
                    fprintf(outf,
-                           "Holding disk %s: %ld %sB disk space available, that's plenty\n",
-                           hdp->diskdir, fs.avail/unitdivisor, displayunit);
+                           "Holding disk %s: " OFF_T_FMT
+                           " %sB disk space available, that's plenty\n",
+                           quoted, (OFF_T_FMT_TYPE)(fs.avail/(off_t)unitdivisor),
+                           displayunit);
+               }
            }
            else {
-               if(fs.avail < -hdp->disksize) {
+               assert(holdingdisk_get_disksize(hdp) < (off_t)0);
+               if((fs.avail + holdingdisk_get_disksize(hdp)) <= (off_t)0) {
                    fprintf(outf,
-                           "WARNING: holding disk %s: only %ld %sB free, using nothing\n",
-                           hdp->diskdir, fs.avail/unitdivisor, displayunit);
+                           "WARNING: holding disk %s: "
+                           "only " OFF_T_FMT " %sB free, using nothing\n",
+                           quoted, (OFF_T_FMT_TYPE)(fs.avail/(off_t)unitdivisor),
+                           displayunit);
                    disklow = 1;
                }
-               else
+               else {
                    fprintf(outf,
-                           "Holding disk %s: %ld %sB disk space available, using %ld %sB\n",
-                           hdp->diskdir, fs.avail/unitdivisor, displayunit,
-                           (fs.avail + hdp->disksize)/unitdivisor, displayunit);
+                           "Holding disk %s: "
+                           OFF_T_FMT " %sB disk space available, using "
+                           OFF_T_FMT " %sB\n",
+                           quoted,
+                           (OFF_T_FMT_TYPE)(fs.avail/(off_t)unitdivisor),
+                           displayunit,
+                           (OFF_T_FMT_TYPE)(fs.avail + holdingdisk_get_disksize(hdp) / (off_t)unitdivisor),
+                           displayunit);
+               }
            }
+           amfree(quoted);
        }
     }
 
@@ -765,36 +903,44 @@ int start_server_check(fd, do_localchk, do_tapechk)
        }
        logfile = vstralloc(conf_logdir, "/log", NULL);
 
+       quoted = quote_string(conf_logdir);
        if(stat(conf_logdir, &statbuf) == -1) {
-           fprintf(outf, "ERROR: logdir %s: %s, you must create a directory.\n",
-                   conf_logdir, strerror(errno));
+           fprintf(outf, "ERROR: logdir %s (%s), you must create directory.\n",
+                   quoted, strerror(errno));
            disklow = 1;
        }
        else if(access(conf_logdir, W_OK) == -1) {
-           fprintf(outf, "ERROR: log dir %s: not writable\n", conf_logdir);
+           fprintf(outf, "ERROR: log dir %s: not writable\n", quoted);
            logbad = 1;
        }
+       amfree(quoted);
 
        if(access(logfile, F_OK) == 0) {
            testtape = 0;
            logbad = 1;
-           if(access(logfile, W_OK) != 0)
-               fprintf(outf, "ERROR: log file %s: not writable\n",
-                       logfile);
+           if(access(logfile, W_OK) != 0) {
+               quoted = quote_string(logfile);
+               fprintf(outf, "ERROR: log file %s: not writable\n", quoted);
+               amfree(quoted);
+           }
        }
 
        olddir = vstralloc(conf_logdir, "/oldlog", NULL);
+       quoted = quote_string(olddir);
        if (stat(olddir,&stat_old) == 0) { /* oldlog exist */
            if(!(S_ISDIR(stat_old.st_mode))) {
-               fprintf(outf, "ERROR: oldlog directory \"%s\" is not a directory\n", olddir);
+               fprintf(outf, "ERROR: oldlog directory %s is not a directory\n",
+                       quoted);
            }
            if(access(olddir, W_OK) == -1) {
-               fprintf(outf, "ERROR: oldlog dir %s: not writable\n", olddir);
+               fprintf(outf, "ERROR: oldlog dir %s: not writable\n", quoted);
            }
        }
        else if(lstat(olddir,&stat_old) == 0) {
-           fprintf(outf, "ERROR: oldlog directory \"%s\" is not a directory\n", olddir);
+           fprintf(outf, "ERROR: oldlog directory %s is not a directory\n",
+                   quoted);
        }
+       amfree(quoted);
 
        if (testtape) {
            logfile = newvstralloc(logfile, conf_logdir, "/amdump", NULL);
@@ -804,13 +950,13 @@ int start_server_check(fd, do_localchk, do_tapechk)
            }
        }
 
+       amfree(olddir);
        amfree(logfile);
        amfree(conf_logdir);
     }
 
     if (testtape) {
        /* check that the tape is a valid amanda tape */
-        char *error_msg;
         int tape_status;
 
        tapedays = getconf_int(CNF_TAPECYCLE);
@@ -822,20 +968,19 @@ int start_server_check(fd, do_localchk, do_tapechk)
                    "WARNING: if a tape changer is not available, runtapes must be set to 1\n");
        }
 
-        tape_status = taper_scan(NULL, &label, &datestamp, &error_msg,
-                                 &tapename);
-        fprintf(outf, "%s\n", error_msg);
-        amfree(error_msg);
+        tape_status = taper_scan(NULL, &label, &datestamp, &tapename,
+                                FILE_taperscan_output_callback, outf);
         if (tape_status < 0) {
            tape_t *exptape = lookup_last_reusable_tape(0);
            fprintf(outf, "       (expecting ");
            if(exptape != NULL) fprintf(outf, "tape %s or ", exptape->label);
            fprintf(outf, "a new tape)\n");
+            tapebad = 1;
        } else {
             if (overwrite) {
                 char *wrlabel_status;
                 wrlabel_status = tape_wrlabel(tapename, "X", label,
-                                              tp->blocksize * 1024);
+                               (unsigned)(tapetype_get_blocksize(tp) * 1024));
                 if (wrlabel_status != NULL) {
                     if (tape_status == 3) {
                         fprintf(outf,
@@ -865,6 +1010,7 @@ int start_server_check(fd, do_localchk, do_tapechk)
                 }                    
             }
         }
+       amfree(tapename);
     } else if (do_tapechk) {
        fprintf(outf, "WARNING: skipping tape test because amdump or amflush seem to be running\n");
        fprintf(outf, "WARNING: if they are not, you must run amcleanup\n");
@@ -916,21 +1062,29 @@ int start_server_check(fd, do_localchk, do_tapechk)
        }
 
 #if TEXTDB
+       quoted = quote_string(conf_infofile);
        if(stat(conf_infofile, &statbuf) == -1) {
-           fprintf(outf, "NOTE: info dir %s: does not exist\n", conf_infofile);
-           fprintf(outf, "NOTE: it will be created on the next run.\n");
+           if (errno == ENOENT) {
+               fprintf(outf, "NOTE: conf info dir %s does not exist\n",
+                       quoted);
+               fprintf(outf, "NOTE: it will be created on the next run.\n");
+           } else {
+               fprintf(outf, "ERROR: conf info dir %s (%s)\n",
+                       quoted, strerror(errno));
+           }   
            amfree(conf_infofile);
        } else if (!S_ISDIR(statbuf.st_mode)) {
-           fprintf(outf, "ERROR: info dir %s: not a directory\n", conf_infofile);
+           fprintf(outf, "ERROR: info dir %s: not a directory\n", quoted);
            amfree(conf_infofile);
            infobad = 1;
        } else if (access(conf_infofile, W_OK) == -1) {
-           fprintf(outf, "ERROR: info dir %s: not writable\n", conf_infofile);
+           fprintf(outf, "ERROR: info dir %s: not writable\n", quoted);
            amfree(conf_infofile);
            infobad = 1;
        } else {
            strappend(conf_infofile, "/");
        }
+       amfree(quoted);
 #endif
 
        while(!empty(origq)) {
@@ -939,135 +1093,191 @@ int start_server_check(fd, do_localchk, do_tapechk)
 #if TEXTDB
            if(conf_infofile) {
                hostinfodir = newstralloc2(hostinfodir, conf_infofile, host);
+               quoted = quote_string(hostinfodir);
                if(stat(hostinfodir, &statbuf) == -1) {
-                   fprintf(outf, "NOTE: info dir %s: does not exist\n",
-                           hostinfodir);
-                   fprintf(outf, "NOTE: it will be created on the next run.\n");
+                   if (errno == ENOENT) {
+                       fprintf(outf, "NOTE: host info dir %s does not exist\n",
+                               quoted);
+                       fprintf(outf,
+                               "NOTE: it will be created on the next run.\n");
+                   } else {
+                       fprintf(outf, "ERROR: host info dir %s (%s)\n",
+                               quoted, strerror(errno));
+                   }   
                    amfree(hostinfodir);
                } else if (!S_ISDIR(statbuf.st_mode)) {
                    fprintf(outf, "ERROR: info dir %s: not a directory\n",
-                           hostinfodir);
+                           quoted);
                    amfree(hostinfodir);
                    infobad = 1;
                } else if (access(hostinfodir, W_OK) == -1) {
-                   fprintf(outf, "ERROR: info dir %s: not writable\n",
-                           hostinfodir);
+                   fprintf(outf, "ERROR: info dir %s: not writable\n", quoted);
                    amfree(hostinfodir);
                    infobad = 1;
                } else {
                    strappend(hostinfodir, "/");
                }
+               amfree(quoted);
            }
 #endif
            for(dp = hostp->disks; dp != NULL; dp = dp->hostnext) {
                disk = sanitise_filename(dp->name);
 #if TEXTDB
                if(hostinfodir) {
+                   char *quotedif;
+
                    diskdir = newstralloc2(diskdir, hostinfodir, disk);
                    infofile = vstralloc(diskdir, "/", "info", NULL);
+                   quoted = quote_string(diskdir);
+                   quotedif = quote_string(infofile);
                    if(stat(diskdir, &statbuf) == -1) {
-                       fprintf(outf, "NOTE: info dir %s: does not exist\n",
-                               diskdir);
-                       fprintf(outf, "NOTE: it will be created on the next run.\n");
+                       if (errno == ENOENT) {
+                           fprintf(outf, "NOTE: info dir %s does not exist\n",
+                               quoted);
+                           fprintf(outf,
+                               "NOTE: it will be created on the next run.\n");
+                       } else {
+                           fprintf(outf, "ERROR: info dir %s (%s)\n",
+                                   quoted, strerror(errno));
+                       }       
                    } else if (!S_ISDIR(statbuf.st_mode)) {
                        fprintf(outf, "ERROR: info dir %s: not a directory\n",
-                               diskdir);
+                               quoted);
                        infobad = 1;
                    } else if (access(diskdir, W_OK) == -1) {
                        fprintf(outf, "ERROR: info dir %s: not writable\n",
-                               diskdir);
+                               quoted);
                        infobad = 1;
                    } else if(stat(infofile, &statbuf) == -1) {
-                       fprintf(outf, "WARNING: info file %s: does not exist\n",
-                               infofile);
-                       fprintf(outf, "NOTE: it will be created on the next run.\n");
+                       if (errno == ENOENT) {
+                           fprintf(outf, "NOTE: info file %s does not exist\n",
+                                   quotedif);
+                           fprintf(outf, "NOTE: it will be created on the next run.\n");
+                       } else {
+                           fprintf(outf, "ERROR: info dir %s (%s)\n",
+                               quoted, strerror(errno));
+                       }       
                    } else if (!S_ISREG(statbuf.st_mode)) {
                        fprintf(outf, "ERROR: info file %s: not a file\n",
-                               infofile);
+                               quotedif);
                        infobad = 1;
                    } else if (access(infofile, R_OK) == -1) {
                        fprintf(outf, "ERROR: info file %s: not readable\n",
-                               infofile);
+                               quotedif);
                        infobad = 1;
                    }
+                   amfree(quotedif);
+                   amfree(quoted);
                    amfree(infofile);
                }
 #endif
                if(dp->index) {
                    if(! indexdir_checked) {
+                       quoted = quote_string(conf_indexdir);
                        if(stat(conf_indexdir, &statbuf) == -1) {
-                           fprintf(outf, "NOTE: index dir %s: does not exist\n",
-                                   conf_indexdir);
-                           fprintf(outf, "NOTE: it will be created on the next run.\n");
+                           if (errno == ENOENT) {
+                               fprintf(outf, "NOTE: index dir %s does not exist\n",
+                                   quoted);
+                               fprintf(outf, "NOTE: it will be created on the next run.\n");
+                           } else {
+                               fprintf(outf, "ERROR: index dir %s (%s)\n",
+                                       quoted, strerror(errno));
+                           }   
                            amfree(conf_indexdir);
                        } else if (!S_ISDIR(statbuf.st_mode)) {
                            fprintf(outf, "ERROR: index dir %s: not a directory\n",
-                                   conf_indexdir);
+                                   quoted);
                            amfree(conf_indexdir);
                            indexbad = 1;
                        } else if (access(conf_indexdir, W_OK) == -1) {
                            fprintf(outf, "ERROR: index dir %s: not writable\n",
-                                   conf_indexdir);
+                                   quoted);
                            amfree(conf_indexdir);
                            indexbad = 1;
                        } else {
                            strappend(conf_indexdir, "/");
                        }
                        indexdir_checked = 1;
+                       amfree(quoted);
                    }
                    if(conf_indexdir) {
                        if(! hostindexdir_checked) {
                            hostindexdir = stralloc2(conf_indexdir, host);
+                           quoted = quote_string(hostindexdir);
                            if(stat(hostindexdir, &statbuf) == -1) {
-                               fprintf(outf, "NOTE: index dir %s: does not exist\n",
-                                       hostindexdir);
-                               fprintf(outf, "NOTE: it will be created on the next run.\n");
+                               if (errno == ENOENT) {
+                                   fprintf(outf, "NOTE: index dir %s does not exist\n",
+                                       quoted);
+                                   fprintf(outf, "NOTE: it will be created on the next run.\n");
+                               } else {
+                                   fprintf(outf, "ERROR: index dir %s (%s)\n",
+                                           quoted, strerror(errno));
+                               }
                                amfree(hostindexdir);
                            } else if (!S_ISDIR(statbuf.st_mode)) {
                                fprintf(outf, "ERROR: index dir %s: not a directory\n",
-                                       hostindexdir);
+                                       quoted);
                                amfree(hostindexdir);
                                indexbad = 1;
                            } else if (access(hostindexdir, W_OK) == -1) {
                                fprintf(outf, "ERROR: index dir %s: not writable\n",
-                                       hostindexdir);
+                                       quoted);
                                amfree(hostindexdir);
                                indexbad = 1;
                            } else {
                                strappend(hostindexdir, "/");
                            }
                            hostindexdir_checked = 1;
+                           amfree(quoted);
                        }
                        if(hostindexdir) {
                            diskdir = newstralloc2(diskdir, hostindexdir, disk);
+                           quoted = quote_string(diskdir);
                            if(stat(diskdir, &statbuf) == -1) {
-                               fprintf(outf, "NOTE: index dir %s: does not exist\n",
-                                       diskdir);
-                               fprintf(outf, "NOTE: it will be created on the next run.\n");
+                               if (errno == ENOENT) {
+                                   fprintf(outf, "NOTE: index dir %s does not exist\n",
+                                       quoted);
+                                   fprintf(outf, "NOTE: it will be created on the next run.\n");
+                               } else {
+                                   fprintf(outf, "ERROR: index dir %s (%s)\n",
+                                       quoted, strerror(errno));
+                               }       
                            } else if (!S_ISDIR(statbuf.st_mode)) {
                                fprintf(outf, "ERROR: index dir %s: not a directory\n",
-                                       diskdir);
+                                       quoted);
                                indexbad = 1;
                            } else if (access(diskdir, W_OK) == -1) {
                                fprintf(outf, "ERROR: index dir %s: is not writable\n",
-                                       diskdir);
+                                       quoted);
                                indexbad = 1;
                            }
+                           amfree(quoted);
                        }
                    }
                }
 
-               if ( dp->encrypt == ENCRYPT_SERV_CUST && dp->srv_encrypt ) {
-                 if(access(dp->srv_encrypt, X_OK) == -1) {
+               if ( dp->encrypt == ENCRYPT_SERV_CUST ) {
+                 if ( dp->srv_encrypt[0] == '\0' ) {
+                   fprintf(outf, "ERROR: server encryption program not specified\n");
+                   pgmbad = 1;
+                 }
+                 else if(access(dp->srv_encrypt, X_OK) == -1) {
                    fprintf(outf, "ERROR: %s is not executable, server encryption will not work\n",
                            dp->srv_encrypt );
                    pgmbad = 1;
                  }
                }
-               if ( dp->compress == COMP_SERV_CUST && dp->srvcompprog ) {
-                 if(access(dp->srvcompprog, X_OK) == -1) {
+               if ( dp->compress == COMP_SERV_CUST ) {
+                 if ( dp->srvcompprog[0] == '\0' ) {
+                   fprintf(outf, "ERROR: server custom compression program not specified\n");
+                   pgmbad = 1;
+                 }
+                 else if(access(dp->srvcompprog, X_OK) == -1) {
+                   quoted = quote_string(dp->srvcompprog);
+
                    fprintf(outf, "ERROR: %s is not executable, server custom compression will not work\n",
-                           dp->srvcompprog );
+                           quoted);
+                   amfree(quoted);
                    pgmbad = 1;
                  }
                }
@@ -1108,7 +1318,7 @@ int start_server_check(fd, do_localchk, do_tapechk)
         || infobad \
         || indexbad \
         || pgmbad);
-    /* NOTREACHED */
+    /*NOTREACHED*/
     return 0;
 }
 
@@ -1117,7 +1327,8 @@ int start_server_check(fd, do_localchk, do_tapechk)
 int remote_errors;
 FILE *outf;
 
-static void handle_result P((void *, pkt_t *, security_handle_t *));
+static void handle_result(void *, pkt_t *, security_handle_t *);
+void start_host(am_host_t *hostp);
 
 #define HOST_READY                             ((void *)0)     /* must be 0 */
 #define HOST_ACTIVE                            ((void *)1)
@@ -1127,12 +1338,13 @@ static void handle_result P((void *, pkt_t *, security_handle_t *));
 #define DISK_ACTIVE                            ((void *)1)
 #define DISK_DONE                              ((void *)2)
 
-void start_host(hostp)
-    am_host_t *hostp;
+void
+start_host(
+    am_host_t *hostp)
 {
     disk_t *dp;
     char *req = NULL;
-    int req_len = 0;
+    size_t req_len = 0;
     int disk_count;
     const security_driver_t *secdrv;
     char number[NUM_STR_SIZE];
@@ -1162,6 +1374,8 @@ void start_host(hostp)
                                          fe_req_options_hostname);
        int has_maxdumps = am_has_feature(hostp->features,
                                          fe_req_options_maxdumps);
+       int has_config   = am_has_feature(hostp->features,
+                                         fe_req_options_config);
 
        if(!am_has_feature(hostp->features, fe_selfcheck_req) &&
           !am_has_feature(hostp->features, fe_selfcheck_req_device)) {
@@ -1198,7 +1412,7 @@ void start_host(hostp)
                   hostp->hostname);
        }
 
-       snprintf(number, sizeof(number), "%d", hostp->maxdumps);
+       snprintf(number, SIZEOF(number), "%d", hostp->maxdumps);
        req = vstralloc("SERVICE ", "selfcheck", "\n",
                        "OPTIONS ",
                        has_features ? "features=" : "",
@@ -1210,6 +1424,9 @@ void start_host(hostp)
                        has_hostname ? "hostname=" : "",
                        has_hostname ? hostp->hostname : "",
                        has_hostname ? ";" : "",
+                       has_config   ? "config=" : "",
+                       has_config   ? config_name : "",
+                       has_config   ? ";" : "",
                        "\n",
                        NULL);
 
@@ -1218,30 +1435,46 @@ void start_host(hostp)
        req_len += 256;                         /* room for non-disk answers */
        for(dp = hostp->disks; dp != NULL; dp = dp->hostnext) {
            char *l;
-           int l_len;
+           size_t l_len;
            char *o;
-           char* calcsize;
+           char *calcsize;
+           char *qname;
+           char *qdevice;
 
            if(dp->up != DISK_READY || dp->todo != 1) {
                continue;
            }
            o = optionstr(dp, hostp->features, outf);
+           if (o == NULL) {
+               remote_errors++;
+               continue;
+           }
+           qname = quote_string(dp->name); 
+           qdevice = quote_string(dp->device); 
+           if ((dp->name && qname[0] == '"') || 
+               (dp->device && qdevice[0] == '"')) {
+               if(!am_has_feature(hostp->features, fe_interface_quoted_text)) {
+                   fprintf(outf,
+                           "WARNING: %s:%s:%s host does not support quoted text\n",
+                           hostp->hostname, qname, qdevice);
+               }
+           }
 
            if(dp->device) {
                if(!am_has_feature(hostp->features, fe_selfcheck_req_device)) {
                    fprintf(outf,
                     "ERROR: %s:%s (%s): selfcheck does not support device.\n",
-                    hostp->hostname, dp->name, dp->device);
+                    hostp->hostname, qname, dp->device);
                }
                if(!am_has_feature(hostp->features, fe_sendsize_req_device)) {
                    fprintf(outf,
                     "ERROR: %s:%s (%s): sendsize does not support device.\n",
-                    hostp->hostname, dp->name, dp->device);
+                    hostp->hostname, qname, dp->device);
                }
                if(!am_has_feature(hostp->features, fe_sendbackup_req_device)) {
                    fprintf(outf,
                     "ERROR: %s:%s (%s): sendbackup does not support device.\n",
-                    hostp->hostname, dp->name, dp->device);
+                    hostp->hostname, qname, dp->device);
                }
            }
            if(strncmp(dp->program,"DUMP",4) == 0 || 
@@ -1249,17 +1482,17 @@ void start_host(hostp)
                if(strcmp(dp->program, "DUMP") == 0 &&
                   !am_has_feature(hostp->features, fe_program_dump)) {
                    fprintf(outf, "ERROR: %s:%s does not support DUMP.\n",
-                           hostp->hostname, dp->name);
+                           hostp->hostname, qname);
                }
                if(strcmp(dp->program, "GNUTAR") == 0 &&
                   !am_has_feature(hostp->features, fe_program_gnutar)) {
                    fprintf(outf, "ERROR: %s:%s does not support GNUTAR.\n",
-                           hostp->hostname, dp->name);
+                           hostp->hostname, qname);
                }
                if(dp->estimate == ES_CALCSIZE &&
                   !am_has_feature(hostp->features, fe_calcsize_estimate)) {
                    fprintf(outf, "ERROR: %s:%s does not support CALCSIZE for estimate, using CLIENT.\n",
-                           hostp->hostname, dp->name);
+                           hostp->hostname, qname);
                    dp->estimate = ES_CLIENT;
                }
                if(dp->estimate == ES_CALCSIZE &&
@@ -1291,7 +1524,7 @@ void start_host(hostp)
                if(dp->device) {
                    l = vstralloc(calcsize,
                                  dp->program, " ",
-                                 dp->name, " ",
+                                 qname, " ",
                                  dp->device,
                                  " 0 OPTIONS |",
                                  o,
@@ -1301,7 +1534,7 @@ void start_host(hostp)
                else {
                    l = vstralloc(calcsize,
                                  dp->program, " ",
-                                 dp->name,
+                                 qname,
                                  " 0 OPTIONS |",
                                  o,
                                  "\n",
@@ -1310,12 +1543,12 @@ void start_host(hostp)
            } else {
                if(!am_has_feature(hostp->features, fe_program_dumper_api)) {
                    fprintf(outf, "ERROR: %s:%s does not support DUMPER-API.\n",
-                           hostp->hostname, dp->name);
+                           hostp->hostname, qname);
                }
                l = vstralloc("DUMPER ",
                              dp->program, 
                              " ",
-                             dp->name,
+                             qname,
                              " ",
                              dp->device,
                              " 0 OPTIONS |",
@@ -1323,15 +1556,11 @@ void start_host(hostp)
                              "\n",
                              NULL);
            }
+           amfree(qname);
+           amfree(qdevice);
            l_len = strlen(l);
            amfree(o);
-           /*
-            * Allow 2X for err response.
-            */
-           if(req_len + l_len > MAX_PACKET / 2) {
-               amfree(l);
-               break;
-           }
+
            strappend(req, l);
            req_len += l_len;
            amfree(l);
@@ -1363,8 +1592,9 @@ void start_host(hostp)
     if (secdrv == NULL) {
        error("could not find security driver '%s' for host '%s'",
              hostp->disks->security_driver, hostp->hostname);
+        /*NOTREACHED*/
     }
-    protocol_sendreq(hostp->hostname, secdrv, generic_get_security_conf, 
+    protocol_sendreq(hostp->hostname, secdrv, amhost_get_security_conf, 
                     req, conf_ctimeout, handle_result, hostp);
 
     amfree(req);
@@ -1372,17 +1602,24 @@ void start_host(hostp)
     hostp->up = HOST_ACTIVE;
 }
 
-int start_client_checks(fd)
-int fd;
+pid_t
+start_client_checks(
+    int                fd)
 {
     am_host_t *hostp;
     disk_t *dp;
-    int hostcount, pid;
+    int hostcount;
+    pid_t pid;
     int userbad = 0;
 
     switch(pid = fork()) {
-    case -1: error("could not fork client check: %s", strerror(errno));
-    case 0: break;
+    case -1:
+       error("could not fork client check: %s", strerror(errno));
+       /*NOTREACHED*/
+
+    case 0:
+       break;
+
     default:
        return pid;
     }
@@ -1394,8 +1631,10 @@ int fd;
 
     startclock();
 
-    if((outf = fdopen(fd, "w")) == NULL)
+    if((outf = fdopen(fd, "w")) == NULL) {
        error("fdopen %d: %s", fd, strerror(errno));
+       /*NOTREACHED*/
+    }
     errf = outf;
 
     fprintf(outf, "\nAmanda Backup Client Hosts Check\n");
@@ -1407,7 +1646,7 @@ int fd;
 
     for(dp = origq.head; dp != NULL; dp = dp->next) {
        hostp = dp->host;
-       if(hostp->up == HOST_READY) {
+       if(hostp->up == HOST_READY && dp->todo == 1) {
            start_host(hostp);
            hostcount++;
            protocol_check();
@@ -1433,14 +1672,15 @@ int fd;
     }
 
     exit(userbad || remote_errors > 0);
-    /* NOTREACHED */
+    /*NOTREACHED*/
     return 0;
 }
 
-static void handle_result(datap, pkt, sech)
-void *datap;
-pkt_t *pkt;
-security_handle_t *sech;
+static void
+handle_result(
+    void *             datap,
+    pkt_t *            pkt,
+    security_handle_t *        sech)
 {
     am_host_t *hostp;
     disk_t *dp;
@@ -1471,19 +1711,19 @@ security_handle_t *sech;
     ch = *s++;
     while(ch) {
        line = s - 1;
-       skip_line(s, ch);
+       skip_quoted_line(s, ch);
        if (s[-2] == '\n') {
            s[-2] = '\0';
        }
 
 #define sc "OPTIONS "
-       if(strncmp(line, sc, sizeof(sc)-1) == 0) {
+       if(strncmp(line, sc, SIZEOF(sc)-1) == 0) {
 #undef sc
 
 #define sc "features="
            t = strstr(line, sc);
            if(t != NULL && (isspace((int)t[-1]) || t[-1] == ';')) {
-               t += sizeof(sc)-1;
+               t += SIZEOF(sc)-1;
 #undef sc
                am_release_feature_set(hostp->features);
                if((hostp->features = am_string_to_feature(t)) == NULL) {
@@ -1496,14 +1736,14 @@ security_handle_t *sech;
        }
 
 #define sc "OK "
-       if(strncmp(line, sc, sizeof(sc)-1) == 0) {
+       if(strncmp(line, sc, SIZEOF(sc)-1) == 0) {
            continue;
 #undef sc
        }
 
 #define sc "ERROR "
-       if(strncmp(line, sc, sizeof(sc)-1) == 0) {
-           t = line + sizeof(sc) - 1;
+       if(strncmp(line, sc, SIZEOF(sc)-1) == 0) {
+           t = line + SIZEOF(sc) - 1;
            tch = t[-1];
 #undef sc
 
@@ -1513,11 +1753,9 @@ security_handle_t *sech;
             * just means the client is "old" (does not support the service).
             * We can ignore this.
             */
-           if(hostp->features == NULL
-              && pkt->type == P_NAK
-              && (strcmp(t - 1, "unknown service: noop") == 0
-                  || strcmp(t - 1, "noop: invalid service") == 0)) {
-           } else {
+           if(!((hostp->features == NULL) && (pkt->type == P_NAK)
+              && ((strcmp(t - 1, "unknown service: noop") == 0)
+                  || (strcmp(t - 1, "noop: invalid service") == 0)))) {
                fprintf(outf, "ERROR: %s%s: %s\n",
                        (pkt->type == P_NAK) ? "NAK " : "",
                        hostp->hostname,
@@ -1548,4 +1786,6 @@ security_handle_t *sech;
        }
     }
     start_host(hostp);
+    if(hostp->up == HOST_DONE)
+       security_close_connection(sech, hostp->hostname);
 }