]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/dird/verify.c
Adapt new prune code with old db_accurate_get_jobids()
[bacula/bacula] / bacula / src / dird / verify.c
index 8f6b84a776a9f6a87d8f4b4ed68908d831920ce6..d288aa237701670fa963631046a72237bc3d8fee 100644 (file)
@@ -1,14 +1,14 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
+   Copyright (C) 2000-2010 Free Software Foundation Europe e.V.
 
    The main author of Bacula is Kern Sibbald, with contributions from
    many others, a complete list can be found in the file AUTHORS.
    This program is Free Software; you can redistribute it and/or
    modify it under the terms of version two of the GNU General Public
-   License as published by the Free Software Foundation plus additions
-   that are listed in the file LICENSE.
+   License as published by the Free Software Foundation and included
+   in the file LICENSE.
 
    This program is distributed in the hope that it will be useful, but
    WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -20,7 +20,7 @@
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
 
-   Bacula® is a registered trademark of John Walker.
+   Bacula® is a registered trademark of Kern Sibbald.
    The licensor of Bacula is the Free Software Foundation Europe
    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
    Switzerland, email:ftf@fsfeurope.org.
@@ -38,7 +38,6 @@
  *     When the File daemon sends the attributes, compare them to
  *       what is in the DB.
  *
- *   Version $Id$
  */
 
 
 #include "findlib/find.h"
 
 /* Commands sent to File daemon */
-static char verifycmd[]    = "verify level=%s\n";
-static char storaddr[]     = "storage address=%s port=%d ssl=0\n";
+static char verifycmd[] = "verify level=%s\n";
+static char storaddr[]  = "storage address=%s port=%d ssl=0 Authorization=%s\n";
 
 /* Responses received from File daemon */
-static char OKverify[]    = "2000 OK verify\n";
-static char OKstore[]     = "2000 OK storage\n";
-static char OKbootstrap[] = "2000 OK bootstrap\n";
+static char OKverify[]  = "2000 OK verify\n";
+static char OKstore[]   = "2000 OK storage\n";
+
+/* Responses received from the Storage daemon */
+static char OKbootstrap[] = "3000 OK bootstrap\n";
 
 /* Forward referenced functions */
 static void prt_fname(JCR *jcr);
@@ -66,6 +67,26 @@ static int missing_handler(void *ctx, int num_fields, char **row);
  */
 bool do_verify_init(JCR *jcr) 
 {
+   if (!allow_duplicate_job(jcr)) {
+      return false;
+   }
+   switch (jcr->getJobLevel()) {
+   case L_VERIFY_INIT:
+   case L_VERIFY_CATALOG:
+   case L_VERIFY_DISK_TO_CATALOG:
+      free_rstorage(jcr);
+      free_wstorage(jcr);
+      break;
+   case L_VERIFY_VOLUME_TO_CATALOG:
+      free_wstorage(jcr);
+      break;
+   case L_VERIFY_DATA:
+      break;
+   default:
+      Jmsg2(jcr, M_FATAL, 0, _("Unimplemented Verify level %d(%c)\n"), jcr->getJobLevel(),
+         jcr->getJobLevel());
+      return false;
+   }
    return true;
 }
 
@@ -102,20 +123,20 @@ bool do_verify(JCR *jcr)
     *   For VERIFY_VOLUME_TO_CATALOG, we want the JobId of the
     *       last backup Job.
     */
-   if (jcr->JobLevel == L_VERIFY_CATALOG ||
-       jcr->JobLevel == L_VERIFY_VOLUME_TO_CATALOG ||
-       jcr->JobLevel == L_VERIFY_DISK_TO_CATALOG) {
+   if (jcr->getJobLevel() == L_VERIFY_CATALOG ||
+       jcr->getJobLevel() == L_VERIFY_VOLUME_TO_CATALOG ||
+       jcr->getJobLevel() == L_VERIFY_DISK_TO_CATALOG) {
       memcpy(&jr, &jcr->jr, sizeof(jr));
       if (jcr->verify_job &&
-          (jcr->JobLevel == L_VERIFY_VOLUME_TO_CATALOG ||
-           jcr->JobLevel == L_VERIFY_DISK_TO_CATALOG)) {
+          (jcr->getJobLevel() == L_VERIFY_VOLUME_TO_CATALOG ||
+           jcr->getJobLevel() == L_VERIFY_DISK_TO_CATALOG)) {
          Name = jcr->verify_job->name();  
       } else {
          Name = NULL;
       }
       Dmsg1(100, "find last jobid for: %s\n", NPRT(Name));
       if (!db_find_last_jobid(jcr, jcr->db, Name, &jr)) {
-         if (jcr->JobLevel == L_VERIFY_CATALOG) {
+         if (jcr->getJobLevel() == L_VERIFY_CATALOG) {
             Jmsg(jcr, M_FATAL, 0, _(
                  "Unable to find JobId of previous InitCatalog Job.\n"
                  "Please run a Verify with Level=InitCatalog before\n"
@@ -133,16 +154,17 @@ bool do_verify(JCR *jcr)
     * Now get the job record for the previous backup that interests
     *   us. We use the verify_jobid that we found above.
     */
-   if (jcr->JobLevel == L_VERIFY_CATALOG ||
-       jcr->JobLevel == L_VERIFY_VOLUME_TO_CATALOG ||
-       jcr->JobLevel == L_VERIFY_DISK_TO_CATALOG) {
+   if (jcr->getJobLevel() == L_VERIFY_CATALOG ||
+       jcr->getJobLevel() == L_VERIFY_VOLUME_TO_CATALOG ||
+       jcr->getJobLevel() == L_VERIFY_DISK_TO_CATALOG) {
       jcr->previous_jr.JobId = verify_jobid;
       if (!db_get_job_record(jcr, jcr->db, &jcr->previous_jr)) {
          Jmsg(jcr, M_FATAL, 0, _("Could not get job record for previous Job. ERR=%s"),
               db_strerror(jcr->db));
          return false;
       }
-      if (jcr->previous_jr.JobStatus != 'T') {
+      if (!(jcr->previous_jr.JobStatus == JS_Terminated ||
+            jcr->previous_jr.JobStatus == JS_Warnings)) {
          Jmsg(jcr, M_FATAL, 0, _("Last Job %d did not terminate normally. JobStatus=%c\n"),
             verify_jobid, jcr->previous_jr.JobStatus);
          return false;
@@ -157,18 +179,28 @@ bool do_verify(JCR *jcr)
     *   create a dummy authorization key (passed to
     *   File daemon but not used).
     */
-   if (jcr->JobLevel == L_VERIFY_VOLUME_TO_CATALOG) {
-      if (!create_restore_bootstrap_file(jcr)) {
+   if (jcr->getJobLevel() == L_VERIFY_VOLUME_TO_CATALOG) {
+      int stat;
+      /*
+       * Note: negative status is an error, zero status, means
+       *  no files were backed up, so skip calling SD and
+       *  client.
+       */
+      stat = create_restore_bootstrap_file(jcr);
+      if (stat < 0) {                      /* error */
          return false;
+      } else if (stat == 0) {              /* No files, nothing to do */
+         verify_cleanup(jcr, JS_Terminated); /* clean up */
+         return true;                      /* get out */
       }
    } else {
       jcr->sd_auth_key = bstrdup("dummy");    /* dummy Storage daemon key */
    }
 
-   if (jcr->JobLevel == L_VERIFY_DISK_TO_CATALOG && jcr->verify_job) {
+   if (jcr->getJobLevel() == L_VERIFY_DISK_TO_CATALOG && jcr->verify_job) {
       jcr->fileset = jcr->verify_job->fileset;
    }
-   Dmsg2(100, "ClientId=%u JobLevel=%c\n", jcr->previous_jr.ClientId, jcr->JobLevel);
+   Dmsg2(100, "ClientId=%u JobLevel=%c\n", jcr->previous_jr.ClientId, jcr->getJobLevel());
 
    if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
       Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
@@ -177,9 +209,10 @@ bool do_verify(JCR *jcr)
 
    /* Print Job Start message */
    Jmsg(jcr, M_INFO, 0, _("Start Verify JobId=%s Level=%s Job=%s\n"),
-      edit_uint64(jcr->JobId, ed1), level_to_str(jcr->JobLevel), jcr->Job);
+      edit_uint64(jcr->JobId, ed1), level_to_str(jcr->getJobLevel()), jcr->Job);
 
-   if (jcr->JobLevel == L_VERIFY_VOLUME_TO_CATALOG) {
+   if (jcr->getJobLevel() == L_VERIFY_VOLUME_TO_CATALOG) {
+      BSOCK *sd;
       /*
        * Start conversation with Storage daemon
        */
@@ -193,7 +226,15 @@ bool do_verify(JCR *jcr)
       if (!start_storage_daemon_job(jcr, jcr->rstorage, NULL)) {
          return false;
       }
-      if (!bnet_fsend(jcr->store_bsock, "run")) {
+      sd = jcr->store_bsock;
+      /*
+       * Send the bootstrap file -- what Volumes/files to restore
+       */
+      if (!send_bootstrap_file(jcr, sd) ||
+          !response(jcr, sd, OKbootstrap, "Bootstrap", DISPLAY_ERROR)) {
+         goto bail_out;
+      }
+      if (!sd->fsend("run")) {
          return false;
       }
       /*
@@ -211,7 +252,7 @@ bool do_verify(JCR *jcr)
     */
    set_jcr_job_status(jcr, JS_Blocked);
    if (!connect_to_file_daemon(jcr, 10, FDConnectTimeout, 1)) {
-      return false;
+      goto bail_out;
    }
 
    set_jcr_job_status(jcr, JS_Running);
@@ -220,19 +261,19 @@ bool do_verify(JCR *jcr)
 
    Dmsg0(30, ">filed: Send include list\n");
    if (!send_include_list(jcr)) {
-      return false;
+      goto bail_out;
    }
 
    Dmsg0(30, ">filed: Send exclude list\n");
    if (!send_exclude_list(jcr)) {
-      return false;
+      goto bail_out;
    }
 
    /*
     * Send Level command to File daemon, as well
     *   as the Storage address if appropriate.
     */
-   switch (jcr->JobLevel) {
+   switch (jcr->getJobLevel()) {
    case L_VERIFY_INIT:
       level = "init";
       break;
@@ -246,22 +287,15 @@ bool do_verify(JCR *jcr)
       if (jcr->rstore->SDDport == 0) {
          jcr->rstore->SDDport = jcr->rstore->SDport;
       }
-      bnet_fsend(fd, storaddr, jcr->rstore->address, jcr->rstore->SDDport);
+      bnet_fsend(fd, storaddr, jcr->rstore->address, 
+                 jcr->rstore->SDDport, jcr->sd_auth_key);
       if (!response(jcr, fd, OKstore, "Storage", DISPLAY_ERROR)) {
-         return false;
-      }
-
-      /*
-       * Send the bootstrap file -- what Volumes/files to restore
-       */
-      if (!send_bootstrap_file(jcr, fd) ||
-          !response(jcr, fd, OKbootstrap, "Bootstrap", DISPLAY_ERROR)) {
-         return false;
+         goto bail_out;
       }
 
       if (!jcr->RestoreBootstrap) {
          Jmsg0(jcr, M_FATAL, 0, _("Deprecated feature ... use bootstrap.\n"));
-         return false;
+         goto bail_out;
       }
 
       level = "volume";
@@ -273,21 +307,21 @@ bool do_verify(JCR *jcr)
       level="disk_to_catalog";
       break;
    default:
-      Jmsg2(jcr, M_FATAL, 0, _("Unimplemented Verify level %d(%c)\n"), jcr->JobLevel,
-         jcr->JobLevel);
-      return false;
+      Jmsg2(jcr, M_FATAL, 0, _("Unimplemented Verify level %d(%c)\n"), jcr->getJobLevel(),
+         jcr->getJobLevel());
+      goto bail_out;
    }
 
    if (!send_runscripts_commands(jcr)) {
-      return false;
+      goto bail_out;
    }
 
    /*
     * Send verify command/level to File daemon
     */
-   bnet_fsend(fd, verifycmd, level);
+   fd->fsend(verifycmd, level);
    if (!response(jcr, fd, OKverify, "Verify", DISPLAY_ERROR)) {
-      return false;
+      goto bail_out;
    }
 
    /*
@@ -296,7 +330,7 @@ bool do_verify(JCR *jcr)
     *  catalog depending on the run type.
     */
    /* Compare to catalog */
-   switch (jcr->JobLevel) {
+   switch (jcr->getJobLevel()) {
    case L_VERIFY_CATALOG:
       Dmsg0(10, "Verify level=catalog\n");
       jcr->sd_msg_thread_done = true;   /* no SD msg thread, so it is done */
@@ -322,18 +356,20 @@ bool do_verify(JCR *jcr)
       jcr->sd_msg_thread_done = true;   /* no SD msg thread, so it is done */
       jcr->SDJobStatus = JS_Terminated;
       get_attributes_and_put_in_catalog(jcr);
+      db_end_transaction(jcr, jcr->db);   /* terminate any open transaction */
+      db_write_batch_file_records(jcr);
       break;
 
    default:
-      Jmsg1(jcr, M_FATAL, 0, _("Unimplemented verify level %d\n"), jcr->JobLevel);
-      return false;
+      Jmsg1(jcr, M_FATAL, 0, _("Unimplemented verify level %d\n"), jcr->getJobLevel());
+      goto bail_out;
    }
 
    stat = wait_for_job_termination(jcr);
-   if (stat == JS_Terminated) {
-      verify_cleanup(jcr, stat);
-      return true;
-   }
+   verify_cleanup(jcr, stat);
+   return true;
+
+bail_out:
    return false;
 }
 
@@ -354,23 +390,21 @@ void verify_cleanup(JCR *jcr, int TermCode)
 
 // Dmsg1(100, "Enter verify_cleanup() TermCod=%d\n", TermCode);
 
-   Dmsg3(900, "JobLevel=%c Expected=%u JobFiles=%u\n", jcr->JobLevel,
+   Dmsg3(900, "JobLevel=%c Expected=%u JobFiles=%u\n", jcr->getJobLevel(),
       jcr->ExpectedFiles, jcr->JobFiles);
-   if (jcr->JobLevel == L_VERIFY_VOLUME_TO_CATALOG &&
+   if (jcr->getJobLevel() == L_VERIFY_VOLUME_TO_CATALOG &&
        jcr->ExpectedFiles != jcr->JobFiles) {
       TermCode = JS_ErrorTerminated;
    }
 
-   /* If no files were expected, there can be no error */
-   if (jcr->JobLevel == L_VERIFY_VOLUME_TO_CATALOG &&
-       jcr->ExpectedFiles == 0) {
-      TermCode = JS_Terminated;
-   }
-
    JobId = jcr->jr.JobId;
 
    update_job_end(jcr, TermCode);
 
+   if (job_canceled(jcr)) {
+      cancel_storage_daemon_job(jcr);
+   }
+
    if (jcr->unlink_bsr && jcr->RestoreBootstrap) {
       unlink(jcr->RestoreBootstrap);
       jcr->unlink_bsr = false;
@@ -410,9 +444,9 @@ void verify_cleanup(JCR *jcr, int TermCode)
    }
 
    jobstatus_to_ascii(jcr->FDJobStatus, fd_term_msg, sizeof(fd_term_msg));
-   if (jcr->JobLevel == L_VERIFY_VOLUME_TO_CATALOG) {
+   if (jcr->getJobLevel() == L_VERIFY_VOLUME_TO_CATALOG) {
       jobstatus_to_ascii(jcr->SDJobStatus, sd_term_msg, sizeof(sd_term_msg));
-   Jmsg(jcr, msg_type, 0, _("Bacula %s %s (%s): %s\n"
+      Jmsg(jcr, msg_type, 0, _("%s %s %s (%s): %s\n"
 "  Build OS:               %s %s %s\n"
 "  JobId:                  %d\n"
 "  Job:                    %s\n"
@@ -429,25 +463,25 @@ void verify_cleanup(JCR *jcr, int TermCode)
 "  FD termination status:  %s\n"
 "  SD termination status:  %s\n"
 "  Termination:            %s\n\n"),
-        my_name, VERSION, LSMDATE, edt,
-        HOST_OS, DISTNAME, DISTVER,
-         jcr->jr.JobId,
-         jcr->jr.Job,
-         jcr->fileset->hdr.name,
-         level_to_str(jcr->JobLevel),
-         jcr->client->hdr.name,
-         jcr->previous_jr.JobId,
-         Name,
-         sdt,
-         edt,
-         edit_uint64_with_commas(jcr->ExpectedFiles, ec1),
-         edit_uint64_with_commas(jcr->JobFiles, ec2),
-         jcr->Errors,
-         fd_term_msg,
-         sd_term_msg,
-         term_msg);
+           BACULA, my_name, VERSION, LSMDATE, edt,
+           HOST_OS, DISTNAME, DISTVER,
+           jcr->jr.JobId,
+           jcr->jr.Job,
+           jcr->fileset->hdr.name,
+           level_to_str(jcr->getJobLevel()),
+           jcr->client->hdr.name,
+           jcr->previous_jr.JobId,
+           Name,
+           sdt,
+           edt,
+           edit_uint64_with_commas(jcr->ExpectedFiles, ec1),
+           edit_uint64_with_commas(jcr->JobFiles, ec2),
+           jcr->JobErrors,
+           fd_term_msg,
+           sd_term_msg,
+           term_msg);
    } else {
-   Jmsg(jcr, msg_type, 0, _("Bacula %s %s (%s): %s\n"
+      Jmsg(jcr, msg_type, 0, _("%s %s %s (%s): %s\n"
 "  Build:                  %s %s %s\n"
 "  JobId:                  %d\n"
 "  Job:                    %s\n"
@@ -462,21 +496,21 @@ void verify_cleanup(JCR *jcr, int TermCode)
 "  Non-fatal FD errors:    %d\n"
 "  FD termination status:  %s\n"
 "  Termination:            %s\n\n"),
-        my_name, VERSION, LSMDATE, edt,
-        HOST_OS, DISTNAME, DISTVER,
-         jcr->jr.JobId,
-         jcr->jr.Job,
-         jcr->fileset->hdr.name,
-         level_to_str(jcr->JobLevel),
-         jcr->client->hdr.name,
-         jcr->previous_jr.JobId,
-         Name,
-         sdt,
-         edt,
-         edit_uint64_with_commas(jcr->JobFiles, ec1),
-         jcr->Errors,
-         fd_term_msg,
-         term_msg);
+           BACULA, my_name, VERSION, LSMDATE, edt,
+           HOST_OS, DISTNAME, DISTVER,
+           jcr->jr.JobId,
+           jcr->jr.Job,
+           jcr->fileset->hdr.name,
+           level_to_str(jcr->getJobLevel()),
+           jcr->client->name(),
+           jcr->previous_jr.JobId,
+           Name,
+           sdt,
+           edt,
+           edit_uint64_with_commas(jcr->JobFiles, ec1),
+           jcr->JobErrors,
+           fd_term_msg,
+           term_msg);
    }
    Dmsg0(100, "Leave verify_cleanup()\n");
 }
@@ -484,14 +518,13 @@ void verify_cleanup(JCR *jcr, int TermCode)
 /*
  * This routine is called only during a Verify
  */
-int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId)
+void get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId)
 {
    BSOCK   *fd;
    int n, len;
    FILE_DBR fdbr;
    struct stat statf;                 /* file stat */
    struct stat statc;                 /* catalog stat */
-   int stat = JS_Terminated;
    char buf[MAXSTRING];
    POOLMEM *fname = get_pool_memory(PM_MESSAGE);
    int do_Digest = CRYPTO_DIGEST_NONE;
@@ -519,7 +552,7 @@ int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId)
       char Opts_Digest[MAXSTRING];        /* Verify Opts or MD5/SHA1 digest */
 
       if (job_canceled(jcr)) {
-         return false;
+         return;
       }
       fname = check_pool_memory_size(fname, fd->msglen);
       jcr->fname = check_pool_memory_size(jcr->fname, fd->msglen);
@@ -528,7 +561,7 @@ int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId)
             fname)) != 3) {
          Jmsg3(jcr, M_FATAL, 0, _("bird<filed: bad attributes, expected 3 fields got %d\n"
 " mslen=%d msg=%s\n"), len, fd->msglen, fd->msg);
-         return false;
+         return;
       }
       /*
        * We read the Options or Signature into fname
@@ -556,6 +589,7 @@ int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId)
          Dmsg2(400, "file_index=%d attr=%s\n", file_index, attr);
          jcr->JobFiles++;
          jcr->FileIndex = file_index;    /* remember attribute file_index */
+         jcr->previous_jr.FileIndex = file_index;
          decode_stat(attr, &statf, &LinkFIf);  /* decode file stat packet */
          do_Digest = CRYPTO_DIGEST_NONE;
          jcr->fn_printed = false;
@@ -572,7 +606,7 @@ int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId)
               &jcr->previous_jr, &fdbr)) {
             Jmsg(jcr, M_INFO, 0, _("New file: %s\n"), jcr->fname);
             Dmsg1(020, _("File not in catalog: %s\n"), jcr->fname);
-            stat = JS_Differences;
+            set_jcr_job_status(jcr, JS_Differences);
             continue;
          } else {
             /*
@@ -598,7 +632,7 @@ int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId)
                   Jmsg(jcr, M_INFO, 0, _("      st_ino   differ. Cat: %s File: %s\n"),
                      edit_uint64((uint64_t)statc.st_ino, ed1),
                      edit_uint64((uint64_t)statf.st_ino, ed2));
-                  stat = JS_Differences;
+                  set_jcr_job_status(jcr, JS_Differences);
                }
                break;
             case 'p':                /* permissions bits */
@@ -606,7 +640,7 @@ int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId)
                   prt_fname(jcr);
                   Jmsg(jcr, M_INFO, 0, _("      st_mode  differ. Cat: %x File: %x\n"),
                      (uint32_t)statc.st_mode, (uint32_t)statf.st_mode);
-                  stat = JS_Differences;
+                  set_jcr_job_status(jcr, JS_Differences);
                }
                break;
             case 'n':                /* number of links */
@@ -614,7 +648,7 @@ int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId)
                   prt_fname(jcr);
                   Jmsg(jcr, M_INFO, 0, _("      st_nlink differ. Cat: %d File: %d\n"),
                      (uint32_t)statc.st_nlink, (uint32_t)statf.st_nlink);
-                  stat = JS_Differences;
+                  set_jcr_job_status(jcr, JS_Differences);
                }
                break;
             case 'u':                /* user id */
@@ -622,7 +656,7 @@ int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId)
                   prt_fname(jcr);
                   Jmsg(jcr, M_INFO, 0, _("      st_uid   differ. Cat: %u File: %u\n"),
                      (uint32_t)statc.st_uid, (uint32_t)statf.st_uid);
-                  stat = JS_Differences;
+                  set_jcr_job_status(jcr, JS_Differences);
                }
                break;
             case 'g':                /* group id */
@@ -630,7 +664,7 @@ int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId)
                   prt_fname(jcr);
                   Jmsg(jcr, M_INFO, 0, _("      st_gid   differ. Cat: %u File: %u\n"),
                      (uint32_t)statc.st_gid, (uint32_t)statf.st_gid);
-                  stat = JS_Differences;
+                  set_jcr_job_status(jcr, JS_Differences);
                }
                break;
             case 's':                /* size */
@@ -639,28 +673,28 @@ int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId)
                   Jmsg(jcr, M_INFO, 0, _("      st_size  differ. Cat: %s File: %s\n"),
                      edit_uint64((uint64_t)statc.st_size, ed1),
                      edit_uint64((uint64_t)statf.st_size, ed2));
-                  stat = JS_Differences;
+                  set_jcr_job_status(jcr, JS_Differences);
                }
                break;
             case 'a':                /* access time */
                if (statc.st_atime != statf.st_atime) {
                   prt_fname(jcr);
                   Jmsg(jcr, M_INFO, 0, _("      st_atime differs\n"));
-                  stat = JS_Differences;
+                  set_jcr_job_status(jcr, JS_Differences);
                }
                break;
             case 'm':
                if (statc.st_mtime != statf.st_mtime) {
                   prt_fname(jcr);
                   Jmsg(jcr, M_INFO, 0, _("      st_mtime differs\n"));
-                  stat = JS_Differences;
+                  set_jcr_job_status(jcr, JS_Differences);
                }
                break;
             case 'c':                /* ctime */
                if (statc.st_ctime != statf.st_ctime) {
                   prt_fname(jcr);
                   Jmsg(jcr, M_INFO, 0, _("      st_ctime differs\n"));
-                  stat = JS_Differences;
+                  set_jcr_job_status(jcr, JS_Differences);
                }
                break;
             case 'd':                /* file size decrease */
@@ -669,7 +703,7 @@ int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId)
                   Jmsg(jcr, M_INFO, 0, _("      st_size  decrease. Cat: %s File: %s\n"),
                      edit_uint64((uint64_t)statc.st_size, ed1),
                      edit_uint64((uint64_t)statf.st_size, ed2));
-                  stat = JS_Differences;
+                  set_jcr_job_status(jcr, JS_Differences);
                }
                break;
             case '5':                /* compare MD5 */
@@ -692,26 +726,21 @@ int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId)
       } else if (crypto_digest_stream_type(stream) != CRYPTO_DIGEST_NONE) {
          Dmsg2(400, "stream=Digest inx=%d Digest=%s\n", file_index, Opts_Digest);
          /*
-          * When ever we get a digest is MUST have been
+          * When ever we get a digest it MUST have been
           * preceded by an attributes record, which sets attr_file_index
           */
          if (jcr->FileIndex != (uint32_t)file_index) {
             Jmsg2(jcr, M_FATAL, 0, _("MD5/SHA1 index %d not same as attributes %d\n"),
                file_index, jcr->FileIndex);
-            return false;
+            return;
          }
          if (do_Digest != CRYPTO_DIGEST_NONE) {
-            db_escape_string(buf, Opts_Digest, strlen(Opts_Digest));
+            db_escape_string(jcr, jcr->db, buf, Opts_Digest, strlen(Opts_Digest));
             if (strcmp(buf, fdbr.Digest) != 0) {
                prt_fname(jcr);
-               if (debug_level >= 10) {
-                  Jmsg(jcr, M_INFO, 0, _("      %s not same. File=%s Cat=%s\n"),
-                       stream_to_ascii(stream), buf, fdbr.Digest);
-               } else {
-                  Jmsg(jcr, M_INFO, 0, _("      %s differs.\n"),
-                       stream_to_ascii(stream));
-               }
-               stat = JS_Differences;
+               Jmsg(jcr, M_INFO, 0, _("      %s differs. File=%s Cat=%s\n"),
+                    stream_to_ascii(stream), buf, fdbr.Digest);
+               set_jcr_job_status(jcr, JS_Differences);
             }
             do_Digest = CRYPTO_DIGEST_NONE;
          }
@@ -721,8 +750,8 @@ int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId)
    if (is_bnet_error(fd)) {
       berrno be;
       Jmsg2(jcr, M_FATAL, 0, _("bdird<filed: bad attributes from filed n=%d : %s\n"),
-                        n, be.strerror());
-      return false;
+                        n, be.bstrerror());
+      return;
    }
 
    /* Now find all the files that are missing -- i.e. all files in
@@ -731,18 +760,16 @@ int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId)
    jcr->fn_printed = false;
    bsnprintf(buf, sizeof(buf),
       "SELECT Path.Path,Filename.Name FROM File,Path,Filename "
-      "WHERE File.JobId=%d "
+      "WHERE File.JobId=%d AND File.FileIndex > 0 "
       "AND File.MarkId!=%d AND File.PathId=Path.PathId "
       "AND File.FilenameId=Filename.FilenameId",
          JobId, jcr->JobId);
    /* missing_handler is called for each file found */
    db_sql_query(jcr->db, buf, missing_handler, (void *)jcr);
    if (jcr->fn_printed) {
-      stat = JS_Differences;
+      set_jcr_job_status(jcr, JS_Differences);
    }
    free_pool_memory(fname);
-   set_jcr_job_status(jcr, stat);
-   return stat == JS_Terminated;
 }
 
 /*
@@ -759,11 +786,11 @@ static int missing_handler(void *ctx, int num_fields, char **row)
       return 1;
    }
    if (!jcr->fn_printed) {
-      Jmsg(jcr, M_INFO, 0, "\n");
-      Jmsg(jcr, M_INFO, 0, _("The following files are in the Catalog but not on disk:\n"));
+      Qmsg(jcr, M_WARNING, 0, _("The following files are in the Catalog but not on %s:\n"),
+          jcr->getJobLevel() == L_VERIFY_VOLUME_TO_CATALOG ? "the Volume(s)" : "disk");
       jcr->fn_printed = true;
    }
-   Jmsg(jcr, M_INFO, 0, "      %s%s\n", row[0]?row[0]:"", row[1]?row[1]:"");
+   Qmsg(jcr, M_INFO, 0, "      %s%s\n", row[0]?row[0]:"", row[1]?row[1]:"");
    return 0;
 }
 
@@ -775,6 +802,6 @@ static void prt_fname(JCR *jcr)
 {
    if (!jcr->fn_printed) {
       Jmsg(jcr, M_INFO, 0, _("File: %s\n"), jcr->fname);
-      jcr->fn_printed = TRUE;
+      jcr->fn_printed = true;
    }
 }