]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/dird/verify.c
ebl Modify disk-changer to check if slot contains something before
[bacula/bacula] / bacula / src / dird / verify.c
index bf4ef9cd6915a776e7fbb72b6e10bf9a11194457..57663a26e29c9f0ac2629e9863a14782bc235070 100644 (file)
@@ -1,3 +1,30 @@
+/*
+   Bacula® - The Network Backup Solution
+
+   Copyright (C) 2000-2008 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 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
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+   Bacula® is a registered trademark of John Walker.
+   The licensor of Bacula is the Free Software Foundation Europe
+   (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
+   Switzerland, email:ftf@fsfeurope.org.
+*/
 /*
  *
  *   Bacula Director -- verify.c -- responsible for running file verification
  *
  *   Version $Id$
  */
-/*
-   Copyright (C) 2000-2005 Kern Sibbald
-
-   This program is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public License
-   version 2 as amended with additional clauses defined in the
-   file LICENSE in the main source directory.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
-   the file LICENSE for additional details.
-
- */
 
 
 #include "bacula.h"
 #include "dird.h"
 #include "findlib/find.h"
 
-/* Imported Global Variables */
-extern int debug_level;
-
 /* Commands sent to File daemon */
 static char verifycmd[]    = "verify level=%s\n";
 static char storaddr[]     = "storage address=%s port=%d ssl=0\n";
@@ -43,6 +53,7 @@ static char storaddr[]     = "storage address=%s port=%d ssl=0\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";
 
 /* Forward referenced functions */
 static void prt_fname(JCR *jcr);
@@ -55,18 +66,43 @@ static int missing_handler(void *ctx, int num_fields, char **row);
  */
 bool do_verify_init(JCR *jcr) 
 {
+   if (!allow_duplicate_job(jcr)) {
+      return false;
+   }
+   return true;
+}
+
+
+/*
+ * Do a verification of the specified files against the Catlaog
+ *
+ *  Returns:  false on failure
+ *            true  on success
+ */
+bool do_verify(JCR *jcr)
+{
+   const char *level;
+   BSOCK   *fd;
+   int stat;
+   char ed1[100];
    JOB_DBR jr;
    JobId_t verify_jobid = 0;
    const char *Name;
 
-   memset(&jcr->target_jr, 0, sizeof(jcr->target_jr));
+   free_wstorage(jcr);                   /* we don't write */
 
-   Dmsg1(9, "bdird: created client %s record\n", jcr->client->hdr.name);
+   memset(&jcr->previous_jr, 0, sizeof(jcr->previous_jr));
 
    /*
-    * Find JobId of last job that ran.  E.g.
-    *   for VERIFY_CATALOG we want the JobId of the last INIT.
-    *   for VERIFY_VOLUME_TO_CATALOG, we want the JobId of the
+    * Find JobId of last job that ran. Note, we do this when
+    *   the job actually starts running, not at schedule time,
+    *   so that we find the last job that terminated before
+    *   this job runs rather than before it is scheduled. This
+    *   permits scheduling a Backup and Verify at the same time,
+    *   but with the Verify at a lower priority.
+    *
+    *   For VERIFY_CATALOG we want the JobId of the last INIT.
+    *   For VERIFY_VOLUME_TO_CATALOG, we want the JobId of the
     *       last backup Job.
     */
    if (jcr->JobLevel == L_VERIFY_CATALOG ||
@@ -76,7 +112,7 @@ bool do_verify_init(JCR *jcr)
       if (jcr->verify_job &&
           (jcr->JobLevel == L_VERIFY_VOLUME_TO_CATALOG ||
            jcr->JobLevel == L_VERIFY_DISK_TO_CATALOG)) {
-         Name = jcr->verify_job->hdr.name;
+         Name = jcr->verify_job->name();  
       } else {
          Name = NULL;
       }
@@ -103,19 +139,19 @@ bool do_verify_init(JCR *jcr)
    if (jcr->JobLevel == L_VERIFY_CATALOG ||
        jcr->JobLevel == L_VERIFY_VOLUME_TO_CATALOG ||
        jcr->JobLevel == L_VERIFY_DISK_TO_CATALOG) {
-      jcr->target_jr.JobId = verify_jobid;
-      if (!db_get_job_record(jcr, jcr->db, &jcr->target_jr)) {
+      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->target_jr.JobStatus != 'T') {
+      if (jcr->previous_jr.JobStatus != 'T') {
          Jmsg(jcr, M_FATAL, 0, _("Last Job %d did not terminate normally. JobStatus=%c\n"),
-            verify_jobid, jcr->target_jr.JobStatus);
+            verify_jobid, jcr->previous_jr.JobStatus);
          return false;
       }
       Jmsg(jcr, M_INFO, 0, _("Verifying against JobId=%d Job=%s\n"),
-         jcr->target_jr.JobId, jcr->target_jr.Job);
+         jcr->previous_jr.JobId, jcr->previous_jr.Job);
    }
 
    /*
@@ -125,31 +161,9 @@ bool do_verify_init(JCR *jcr)
     *   File daemon but not used).
     */
    if (jcr->JobLevel == L_VERIFY_VOLUME_TO_CATALOG) {
-      RBSR *bsr = new_bsr();
-      UAContext *ua;
-      bsr->JobId = jcr->target_jr.JobId;
-      ua = new_ua_context(jcr);
-      complete_bsr(ua, bsr);
-      bsr->fi = new_findex();
-      bsr->fi->findex = 1;
-      bsr->fi->findex2 = jcr->target_jr.JobFiles;
-      jcr->ExpectedFiles = write_bsr_file(ua, bsr);
-      if (jcr->ExpectedFiles == 0) {
-         free_ua_context(ua);
-         free_bsr(bsr);
+      if (!create_restore_bootstrap_file(jcr)) {
          return false;
       }
-      if (jcr->RestoreBootstrap) {
-         free(jcr->RestoreBootstrap);
-      }
-      POOLMEM *fname = get_pool_memory(PM_MESSAGE);
-      make_unique_restore_filename(ua, &fname);
-      jcr->RestoreBootstrap = bstrdup(fname);
-      free_ua_context(ua);
-      free_bsr(bsr);
-      free_pool_memory(fname);
-      jcr->needs_sd = true;
-
    } else {
       jcr->sd_auth_key = bstrdup("dummy");    /* dummy Storage daemon key */
    }
@@ -157,22 +171,7 @@ bool do_verify_init(JCR *jcr)
    if (jcr->JobLevel == L_VERIFY_DISK_TO_CATALOG && jcr->verify_job) {
       jcr->fileset = jcr->verify_job->fileset;
    }
-   Dmsg2(100, "ClientId=%u JobLevel=%c\n", jcr->target_jr.ClientId, jcr->JobLevel);
-   return true;
-}
-
-
-/*
- * Do a verification of the specified files against the Catlaog
- *
- *  Returns:  false on failure
- *            true  on success
- */
-bool do_verify(JCR *jcr)
-{
-   const char *level;
-   BSOCK   *fd;
-   int stat;
+   Dmsg2(100, "ClientId=%u JobLevel=%c\n", jcr->previous_jr.ClientId, jcr->JobLevel);
 
    if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
       Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
@@ -180,8 +179,8 @@ bool do_verify(JCR *jcr)
    }
 
    /* Print Job Start message */
-   Jmsg(jcr, M_INFO, 0, _("Start Verify JobId=%d Level=%s Job=%s\n"),
-      jcr->JobId, level_to_str(jcr->JobLevel), jcr->Job);
+   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);
 
    if (jcr->JobLevel == L_VERIFY_VOLUME_TO_CATALOG) {
       /*
@@ -194,7 +193,10 @@ bool do_verify(JCR *jcr)
       /*
        * Now start a job with the Storage daemon
        */
-      if (!start_storage_daemon_job(jcr, jcr->storage, SD_READ)) {
+      if (!start_storage_daemon_job(jcr, jcr->rstorage, NULL)) {
+         return false;
+      }
+      if (!jcr->store_bsock->fsend("run")) {
          return false;
       }
       /*
@@ -204,6 +206,7 @@ bool do_verify(JCR *jcr)
          return false;
       }
       Dmsg0(50, "Storage daemon connection OK\n");
+
    }
    /*
     * OK, now connect to the File daemon
@@ -211,7 +214,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,12 +223,12 @@ 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;
    }
 
    /*
@@ -243,24 +246,25 @@ bool do_verify(JCR *jcr)
       /*
        * send Storage daemon address to the File daemon
        */
-      if (jcr->store->SDDport == 0) {
-         jcr->store->SDDport = jcr->store->SDport;
+      if (jcr->rstore->SDDport == 0) {
+         jcr->rstore->SDDport = jcr->rstore->SDport;
       }
-      bnet_fsend(fd, storaddr, jcr->store->address, jcr->store->SDDport);
+      bnet_fsend(fd, storaddr, jcr->rstore->address, jcr->rstore->SDDport);
       if (!response(jcr, fd, OKstore, "Storage", DISPLAY_ERROR)) {
-         return false;
+         goto bail_out;
       }
 
       /*
        * Send the bootstrap file -- what Volumes/files to restore
        */
-      if (!send_bootstrap_file(jcr)) {
-         return false;
+      if (!send_bootstrap_file(jcr, fd) ||
+          !response(jcr, fd, OKbootstrap, "Bootstrap", DISPLAY_ERROR)) {
+         goto bail_out;
       }
 
       if (!jcr->RestoreBootstrap) {
          Jmsg0(jcr, M_FATAL, 0, _("Deprecated feature ... use bootstrap.\n"));
-         return false;
+         goto bail_out;
       }
 
       level = "volume";
@@ -274,19 +278,19 @@ bool do_verify(JCR *jcr)
    default:
       Jmsg2(jcr, M_FATAL, 0, _("Unimplemented Verify level %d(%c)\n"), jcr->JobLevel,
          jcr->JobLevel);
-      return false;
+      goto bail_out;
    }
 
-   if (!send_run_before_and_after_commands(jcr)) {
-      return false;
+   if (!send_runscripts_commands(jcr)) {
+      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;
    }
 
    /*
@@ -300,19 +304,19 @@ bool do_verify(JCR *jcr)
       Dmsg0(10, "Verify level=catalog\n");
       jcr->sd_msg_thread_done = true;   /* no SD msg thread, so it is done */
       jcr->SDJobStatus = JS_Terminated;
-      get_attributes_and_compare_to_catalog(jcr, jcr->target_jr.JobId);
+      get_attributes_and_compare_to_catalog(jcr, jcr->previous_jr.JobId);
       break;
 
    case L_VERIFY_VOLUME_TO_CATALOG:
       Dmsg0(10, "Verify level=volume\n");
-      get_attributes_and_compare_to_catalog(jcr, jcr->target_jr.JobId);
+      get_attributes_and_compare_to_catalog(jcr, jcr->previous_jr.JobId);
       break;
 
    case L_VERIFY_DISK_TO_CATALOG:
       Dmsg0(10, "Verify level=disk_to_catalog\n");
       jcr->sd_msg_thread_done = true;   /* no SD msg thread, so it is done */
       jcr->SDJobStatus = JS_Terminated;
-      get_attributes_and_compare_to_catalog(jcr, jcr->target_jr.JobId);
+      get_attributes_and_compare_to_catalog(jcr, jcr->previous_jr.JobId);
       break;
 
    case L_VERIFY_INIT:
@@ -321,18 +325,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;
+      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;
 }
 
@@ -352,7 +358,6 @@ void verify_cleanup(JCR *jcr, int TermCode)
    const char *Name;
 
 // Dmsg1(100, "Enter verify_cleanup() TermCod=%d\n", TermCode);
-   dequeue_messages(jcr);             /* display any queued messages */
 
    Dmsg3(900, "JobLevel=%c Expected=%u JobFiles=%u\n", jcr->JobLevel,
       jcr->ExpectedFiles, jcr->JobFiles);
@@ -368,9 +373,13 @@ void verify_cleanup(JCR *jcr, int TermCode)
    }
 
    JobId = jcr->jr.JobId;
-   set_jcr_job_status(jcr, TermCode);
 
-   update_job_end_record(jcr);
+   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;
@@ -412,7 +421,8 @@ 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) {
       jobstatus_to_ascii(jcr->SDJobStatus, sd_term_msg, sizeof(sd_term_msg));
-      Jmsg(jcr, msg_type, 0, _("Bacula " VERSION " (" LSMDATE "): %s\n"
+      Jmsg(jcr, msg_type, 0, _("Bacula %s %s (%s): %s\n"
+"  Build OS:               %s %s %s\n"
 "  JobId:                  %d\n"
 "  Job:                    %s\n"
 "  FileSet:                %s\n"
@@ -428,13 +438,14 @@ void verify_cleanup(JCR *jcr, int TermCode)
 "  FD termination status:  %s\n"
 "  SD termination status:  %s\n"
 "  Termination:            %s\n\n"),
-         edt,
+        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->target_jr.JobId,
+         jcr->previous_jr.JobId,
          Name,
          sdt,
          edt,
@@ -445,7 +456,8 @@ void verify_cleanup(JCR *jcr, int TermCode)
          sd_term_msg,
          term_msg);
    } else {
-      Jmsg(jcr, msg_type, 0, _("Bacula " VERSION " (" LSMDATE "): %s\n"
+      Jmsg(jcr, msg_type, 0, _("Bacula %s %s (%s): %s\n"
+"  Build:                  %s %s %s\n"
 "  JobId:                  %d\n"
 "  Job:                    %s\n"
 "  FileSet:                %s\n"
@@ -459,13 +471,14 @@ void verify_cleanup(JCR *jcr, int TermCode)
 "  Non-fatal FD errors:    %d\n"
 "  FD termination status:  %s\n"
 "  Termination:            %s\n\n"),
-         edt,
+        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->target_jr.JobId,
+         jcr->client->name(),
+         jcr->previous_jr.JobId,
          Name,
          sdt,
          edt,
@@ -490,7 +503,7 @@ int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId)
    int stat = JS_Terminated;
    char buf[MAXSTRING];
    POOLMEM *fname = get_pool_memory(PM_MESSAGE);
-   int do_SIG = NO_SIG;
+   int do_Digest = CRYPTO_DIGEST_NONE;
    int32_t file_index = 0;
 
    memset(&fdbr, 0, sizeof(FILE_DBR));
@@ -504,7 +517,7 @@ int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId)
     * We expect:
     *   FileIndex
     *   Stream
-    *   Options or SIG (MD5/SHA1)
+    *   Options or Digest (MD5/SHA1)
     *   Filename
     *   Attributes
     *   Link name  ???
@@ -512,11 +525,14 @@ int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId)
    while ((n=bget_dirmsg(fd)) >= 0 && !job_canceled(jcr)) {
       int stream;
       char *attr, *p, *fn;
-      char Opts_SIG[MAXSTRING];        /* Verify Opts or MD5/SHA1 signature */
+      char Opts_Digest[MAXSTRING];        /* Verify Opts or MD5/SHA1 digest */
 
+      if (job_canceled(jcr)) {
+         return false;
+      }
       fname = check_pool_memory_size(fname, fd->msglen);
       jcr->fname = check_pool_memory_size(jcr->fname, fd->msglen);
-      Dmsg1(200, "Atts+SIG=%s\n", fd->msg);
+      Dmsg1(200, "Atts+Digest=%s\n", fd->msg);
       if ((len = sscanf(fd->msg, "%ld %d %100s", &file_index, &stream,
             fname)) != 3) {
          Jmsg3(jcr, M_FATAL, 0, _("bird<filed: bad attributes, expected 3 fields got %d\n"
@@ -527,13 +543,13 @@ int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId)
        * We read the Options or Signature into fname
        *  to prevent overrun, now copy it to proper location.
        */
-      bstrncpy(Opts_SIG, fname, sizeof(Opts_SIG));
+      bstrncpy(Opts_Digest, fname, sizeof(Opts_Digest));
       p = fd->msg;
       skip_nonspaces(&p);             /* skip FileIndex */
       skip_spaces(&p);
       skip_nonspaces(&p);             /* skip Stream */
       skip_spaces(&p);
-      skip_nonspaces(&p);             /* skip Opts_SIG */
+      skip_nonspaces(&p);             /* skip Opts_Digest */
       p++;                            /* skip space */
       fn = fname;
       while (*p != 0) {
@@ -550,7 +566,7 @@ int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId)
          jcr->JobFiles++;
          jcr->FileIndex = file_index;    /* remember attribute file_index */
          decode_stat(attr, &statf, &LinkFIf);  /* decode file stat packet */
-         do_SIG = NO_SIG;
+         do_Digest = CRYPTO_DIGEST_NONE;
          jcr->fn_printed = false;
          pm_strcpy(jcr->fname, fname);  /* move filename into JCR */
 
@@ -562,7 +578,7 @@ int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId)
           */
          fdbr.FileId = 0;
          if (!db_get_file_attributes_record(jcr, jcr->db, jcr->fname,
-              &jcr->target_jr, &fdbr)) {
+              &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;
@@ -576,13 +592,13 @@ int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId)
          }
 
          Dmsg3(400, "Found %s in catalog. inx=%d Opts=%s\n", jcr->fname,
-            file_index, Opts_SIG);
+            file_index, Opts_Digest);
          decode_stat(fdbr.LStat, &statc, &LinkFIc); /* decode catalog stat */
          /*
           * Loop over options supplied by user and verify the
           * fields he requests.
           */
-         for (p=Opts_SIG; *p; p++) {
+         for (p=Opts_Digest; *p; p++) {
             char ed1[30], ed2[30];
             switch (*p) {
             case 'i':                /* compare INODEs */
@@ -667,10 +683,10 @@ int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId)
                break;
             case '5':                /* compare MD5 */
                Dmsg1(500, "set Do_MD5 for %s\n", jcr->fname);
-               do_SIG = MD5_SIG;
+               do_Digest = CRYPTO_DIGEST_MD5;
                break;
             case '1':                 /* compare SHA1 */
-               do_SIG = SHA1_SIG;
+               do_Digest = CRYPTO_DIGEST_SHA1;
                break;
             case ':':
             case 'V':
@@ -679,13 +695,13 @@ int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId)
             }
          }
       /*
-       * Got SIG Signature from Storage daemon
-       *  It came across in the Opts_SIG field.
+       * Got Digest Signature from Storage daemon
+       *  It came across in the Opts_Digest field.
        */
-      } else if (stream == STREAM_MD5_SIGNATURE || stream == STREAM_SHA1_SIGNATURE) {
-         Dmsg2(400, "stream=SIG inx=%d SIG=%s\n", file_index, Opts_SIG);
+      } 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 signature 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) {
@@ -693,20 +709,20 @@ int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId)
                file_index, jcr->FileIndex);
             return false;
          }
-         if (do_SIG) {
-            db_escape_string(buf, Opts_SIG, strlen(Opts_SIG));
-            if (strcmp(buf, fdbr.SIG) != 0) {
+         if (do_Digest != CRYPTO_DIGEST_NONE) {
+            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==STREAM_MD5_SIGNATURE?"MD5":"SHA1", buf, fdbr.SIG);
+                       stream_to_ascii(stream), buf, fdbr.Digest);
                } else {
                   Jmsg(jcr, M_INFO, 0, _("      %s differs.\n"),
-                       stream==STREAM_MD5_SIGNATURE?"MD5":"SHA1");
+                       stream_to_ascii(stream));
                }
                stat = JS_Differences;
             }
-            do_SIG = FALSE;
+            do_Digest = CRYPTO_DIGEST_NONE;
          }
       }
       jcr->JobFiles = file_index;
@@ -714,27 +730,29 @@ 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());
+                        n, be.bstrerror());
       return false;
    }
 
    /* Now find all the files that are missing -- i.e. all files in
-    *  the database where the MarkedId != current JobId
+    *  the database where the MarkId != current JobId
     */
    jcr->fn_printed = false;
    bsnprintf(buf, sizeof(buf),
-"SELECT Path.Path,Filename.Name FROM File,Path,Filename "
-"WHERE File.JobId=%d "
-"AND File.MarkedId!=%d AND File.PathId=Path.PathId "
-"AND File.FilenameId=Filename.FilenameId",
-      JobId, jcr->JobId);
+      "SELECT Path.Path,Filename.Name FROM File,Path,Filename "
+      "WHERE File.JobId=%d "
+      "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;
    }
    free_pool_memory(fname);
-   set_jcr_job_status(jcr, stat);
+   if (!job_canceled(jcr)) {
+      jcr->JobStatus = stat;
+   }
    return stat == JS_Terminated;
 }
 
@@ -748,12 +766,15 @@ static int missing_handler(void *ctx, int num_fields, char **row)
 {
    JCR *jcr = (JCR *)ctx;
 
+   if (job_canceled(jcr)) {
+      return 1;
+   }
    if (!jcr->fn_printed) {
-      Jmsg(jcr, M_INFO, 0, "\n");
-      Jmsg(jcr, M_INFO, 0, _("The following files are missing:\n"));
+      Qmsg(jcr, M_INFO, 0, _("\nThe following files are in the Catalog but not on %s:\n"),
+       jcr->JobLevel == 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;
 }
 
@@ -765,6 +786,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;
    }
 }