]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/stored/mac.c
Make bad Storage check in is_on_same_storage non-fatal
[bacula/bacula] / bacula / src / stored / mac.c
index 6eaec57f961ad2e5366835a566969be9978349f5..d4de7c124176d863e4d587f9cfee0d1dc3765cab 100644 (file)
@@ -1,24 +1,36 @@
+/*
+   Bacula® - The Network Backup Solution
+
+   Copyright (C) 2006-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 three of the GNU Affero 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 Affero 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 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.
+*/
 /*
  * SD -- mac.c --  responsible for doing
- *     migration, archive, and copy jobs.
+ *     migration, archive, copy, and virtual backup jobs.
  *
  *     Kern Sibbald, January MMVI
  *
- *   Version $Id$
- */
-/*
-   Copyright (C) 2006 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"
@@ -44,7 +56,7 @@ bool do_mac(JCR *jcr)
    char ec1[50];
    DEVICE *dev;
 
-   switch(jcr->JobType) {
+   switch(jcr->getJobType()) {
    case JT_MIGRATE:
       Type = "Migration";
       break;
@@ -54,6 +66,9 @@ bool do_mac(JCR *jcr)
    case JT_COPY:
       Type = "Copy";
       break;
+   case JT_BACKUP:
+      Type = "Virtual Backup";
+      break;
    default:
       Type = "Unknown";
       break;
@@ -66,28 +81,36 @@ bool do_mac(JCR *jcr)
       Jmsg(jcr, M_FATAL, 0, _("Read and write devices not properly initialized.\n"));
       goto bail_out;
    }
-   Dmsg2(000, "read_dcr=%p write_dcr=%p\n", jcr->read_dcr, jcr->dcr);
+   Dmsg2(100, "read_dcr=%p write_dcr=%p\n", jcr->read_dcr, jcr->dcr);
 
-
-   create_restore_volume_list(jcr);
-   if (jcr->NumVolumes == 0) {
+   if (jcr->NumReadVolumes == 0) {
       Jmsg(jcr, M_FATAL, 0, _("No Volume names found for %s.\n"), Type);
       goto bail_out;
    }
 
-   Dmsg3(200, "Found %d volumes names for %s. First=%s\n", jcr->NumVolumes,
+   Dmsg3(200, "Found %d volumes names for %s. First=%s\n", jcr->NumReadVolumes,
       jcr->VolList->VolumeName, Type);
 
    /* Ready devices for reading and writing */
    if (!acquire_device_for_read(jcr->read_dcr) ||
        !acquire_device_for_append(jcr->dcr)) {
-      set_jcr_job_status(jcr, JS_ErrorTerminated);
+      jcr->setJobStatus(JS_ErrorTerminated);
       goto bail_out;
    }
 
+   Dmsg2(200, "===== After acquire pos %u:%u\n", jcr->dcr->dev->file, jcr->dcr->dev->block_num);
+     
+   jcr->setJobStatus(JS_Running);
+   dir_send_job_status(jcr);
+
+   begin_data_spool(jcr->dcr);
+   begin_attribute_spool(jcr);
+
    jcr->dcr->VolFirstIndex = jcr->dcr->VolLastIndex = 0;
    jcr->run_time = time(NULL);
+   set_start_vol_position(jcr->dcr);
 
+   jcr->JobFiles = 0;
    ok = read_records(jcr->read_dcr, record_cb, mount_next_read_volume);
    goto ok_out;
 
@@ -97,6 +120,7 @@ bail_out:
 ok_out:
    if (jcr->dcr) {
       dev = jcr->dcr->dev;
+      Dmsg1(100, "ok=%d\n", ok);
       if (ok || dev->can_write()) {
          /* Flush out final partial block of this session */
          if (!write_block_to_device(jcr->dcr)) {
@@ -105,14 +129,27 @@ ok_out:
             Dmsg0(100, _("Set ok=FALSE after write_block_to_device.\n"));
             ok = false;
          }
+         Dmsg2(200, "Flush block to device pos %u:%u\n", dev->file, dev->block_num);
       }  
 
+      if (!ok) {
+         discard_data_spool(jcr->dcr);
+      } else {
+         /* Note: if commit is OK, the device will remain blocked */
+         commit_data_spool(jcr->dcr);
+      }
 
       if (ok && dev->is_dvd()) {
          ok = dvd_close_job(jcr->dcr);   /* do DVD cleanup if any */
       }
       /* Release the device -- and send final Vol info to DIR */
       release_device(jcr->dcr);
+
+      if (!ok || job_canceled(jcr)) {
+         discard_attribute_spool(jcr);
+      } else {
+         commit_attribute_spool(jcr);
+      }
    }
 
    if (jcr->read_dcr) {
@@ -121,30 +158,20 @@ ok_out:
       }
    }
 
-   free_restore_volume_list(jcr);
-
-
-   if (!ok || job_canceled(jcr)) {
-      discard_attribute_spool(jcr);
-   } else {
-      commit_attribute_spool(jcr);
-   }
-
    dir_send_job_status(jcr);          /* update director */
 
-
    Dmsg0(30, "Done reading.\n");
    jcr->end_time = time(NULL);
    dequeue_messages(jcr);             /* send any queued messages */
    if (ok) {
-      set_jcr_job_status(jcr, JS_Terminated);
+      jcr->setJobStatus(JS_Terminated);
    }
    generate_daemon_event(jcr, "JobEnd");
-   bnet_fsend(dir, Job_end, jcr->Job, jcr->JobStatus, jcr->JobFiles,
-      edit_uint64(jcr->JobBytes, ec1));
-   Dmsg4(400, Job_end, jcr->Job, jcr->JobStatus, jcr->JobFiles, ec1); 
+   dir->fsend(Job_end, jcr->Job, jcr->JobStatus, jcr->JobFiles,
+      edit_uint64(jcr->JobBytes, ec1), jcr->JobErrors);
+   Dmsg4(100, Job_end, jcr->Job, jcr->JobStatus, jcr->JobFiles, ec1); 
        
-   bnet_sig(dir, BNET_EOD);           /* send EOD to Director daemon */
+   dir->signal(BNET_EOD);             /* send EOD to Director daemon */
 
    return ok;
 }
@@ -156,62 +183,85 @@ ok_out:
  */
 static bool record_cb(DCR *dcr, DEV_RECORD *rec)
 {
-   bool ok = true;
    JCR *jcr = dcr->jcr;
+   DEVICE *dev = jcr->dcr->dev;
    char buf1[100], buf2[100];
-   int32_t stream;   
    
+#ifdef xxx
+   Dmsg5(000, "on entry     JobId=%d FI=%s SessId=%d Strm=%s len=%d\n",
+      jcr->JobId,
+      FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
+      stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len);
+#endif
+   /* If label and not for us, discard it */
+   if (rec->FileIndex < 0 && rec->match_stat <= 0) {
+      return true;
+   }
+   /* We want to write SOS_LABEL and EOS_LABEL discard all others */
    switch (rec->FileIndex) {                        
    case PRE_LABEL:
    case VOL_LABEL:
    case EOT_LABEL:
+   case EOM_LABEL:
       return true;                    /* don't write vol labels */
    }
+//   if (jcr->getJobType() == JT_BACKUP) {
+      /*
+       * For normal migration jobs, FileIndex values are sequential because
+       *  we are dealing with one job.  However, for Vbackup (consolidation),
+       *  we will be getting records from multiple jobs and writing them back
+       *  out, so we need to ensure that the output FileIndex is sequential.
+       *  We do so by detecting a FileIndex change and incrementing the
+       *  JobFiles, which we then use as the output FileIndex.
+       */
+      if (rec->FileIndex >= 0) { 
+         /* If something changed, increment FileIndex */
+         if (rec->VolSessionId != rec->last_VolSessionId || 
+             rec->VolSessionTime != rec->last_VolSessionTime ||
+             rec->FileIndex != rec->last_FileIndex) {
+            jcr->JobFiles++;
+            rec->last_VolSessionId = rec->VolSessionId;
+            rec->last_VolSessionTime = rec->VolSessionTime;
+            rec->last_FileIndex = rec->FileIndex;
+         }
+         rec->FileIndex = jcr->JobFiles;     /* set sequential output FileIndex */
+      }
+//   }
+   /*
+    * Modify record SessionId and SessionTime to correspond to
+    * output.
+    */
    rec->VolSessionId = jcr->VolSessionId;
    rec->VolSessionTime = jcr->VolSessionTime;
-   Dmsg4(850, "before writ_rec FI=%d SessId=%d Strm=%s len=%d\n",
-      rec->FileIndex, rec->VolSessionId, 
-      stream_to_ascii(buf1, rec->Stream,rec->FileIndex),
-      rec->data_len);
-
+   Dmsg5(200, "before write JobId=%d FI=%s SessId=%d Strm=%s len=%d\n",
+      jcr->JobId,
+      FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
+      stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len);
    while (!write_record_to_block(jcr->dcr->block, rec)) {
-      Dmsg2(850, "!write_record_to_block data_len=%d rem=%d\n", rec->data_len,
-                 rec->remainder);
+      Dmsg4(200, "!write_record_to_block blkpos=%u:%u len=%d rem=%d\n", 
+            dev->file, dev->block_num, rec->data_len, rec->remainder);
       if (!write_block_to_device(jcr->dcr)) {
-         DEVICE *dev = jcr->dcr->dev;
          Dmsg2(90, "Got write_block_to_dev error on device %s. %s\n",
             dev->print_name(), dev->bstrerror());
          Jmsg2(jcr, M_FATAL, 0, _("Fatal append error on device %s: ERR=%s\n"),
                dev->print_name(), dev->bstrerror());
          return false;
       }
+      Dmsg2(200, "===== Wrote block new pos %u:%u\n", dev->file, dev->block_num);
    }
-   jcr->JobBytes += rec->data_len;   /* increment bytes this job */
-   if (rec->FileIndex > 0) {
-      jcr->JobFiles = rec->FileIndex;
+   /* Restore packet */
+   rec->VolSessionId = rec->last_VolSessionId;
+   rec->VolSessionTime = rec->last_VolSessionTime;
+   if (rec->FileIndex < 0) {
+      return true;                    /* don't send LABELs to Dir */
    }
-   Dmsg4(850, "write_record FI=%s SessId=%d Strm=%s len=%d\n",
+   jcr->JobBytes += rec->data_len;   /* increment bytes this job */
+   Dmsg5(500, "wrote_record JobId=%d FI=%s SessId=%d Strm=%s len=%d\n",
+      jcr->JobId,
       FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
       stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len);
 
-   /* Send attributes and digest to Director for Catalog */
-   stream = rec->Stream;
-   if (stream == STREAM_UNIX_ATTRIBUTES || stream == STREAM_UNIX_ATTRIBUTES_EX ||
-       crypto_digest_stream_type(stream) != CRYPTO_DIGEST_NONE) {
-      if (!jcr->no_attributes) {
-         if (are_attributes_spooled(jcr)) {
-            jcr->dir_bsock->spool = true;
-         }
-         Dmsg0(850, "Send attributes to dir.\n");
-         if (!dir_update_file_attributes(jcr->dcr, rec)) {
-            jcr->dir_bsock->spool = false;
-            Jmsg(jcr, M_FATAL, 0, _("Error updating file attributes. ERR=%s\n"),
-               bnet_strerror(jcr->dir_bsock));
-            return false;
-         }
-         jcr->dir_bsock->spool = false;
-      }
-   }
+   send_attrs_to_dir(jcr, rec);
 
-   return ok;
+   return true;
 }