]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/stored/acquire.c
Fix #1695 about bacula-sd crash in detach_dcr_from_dev()
[bacula/bacula] / bacula / src / stored / acquire.c
index 47a2a75eb8cc270fd0c4f2d437fb527610faa7ed..146aa4530c7ebdee36f4558d05668ffc41cfc1e6 100644 (file)
@@ -1,12 +1,12 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2002-2008 Free Software Foundation Europe e.V.
+   Copyright (C) 2002-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
+   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.
 
@@ -15,7 +15,7 @@
    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
+   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.
@@ -30,7 +30,6 @@
  *
  *   Kern Sibbald, August MMII
  *
- *   Version $Id$
  */
 
 #include "bacula.h"                   /* pull in global headers */
@@ -38,6 +37,8 @@
 
 /* Forward referenced functions */
 static void attach_dcr_to_dev(DCR *dcr);
+static void detach_dcr_from_dev(DCR *dcr);
+static void set_dcr_from_vol(DCR *dcr, VOL_LIST *vol);
 
 
 /*********************************************************************
@@ -62,7 +63,8 @@ bool acquire_device_for_read(DCR *dcr)
    int vol_label_status;
    int retry = 0;
    
-   Dmsg1(950, "jcr->dcr=%p\n", jcr->dcr);
+   Dmsg2(950, "dcr=%p dev=%p\n", dcr, dcr->dev);
+   Dmsg2(950, "MediaType dcr=%s dev=%s\n", dcr->media_type, dev->device->media_type);
    dev->dblock(BST_DOING_ACQUIRE);
 
    if (dev->num_writers > 0) {
@@ -88,15 +90,9 @@ bool acquire_device_for_read(DCR *dcr)
          jcr->NumReadVolumes, jcr->CurReadVolume);
       goto get_out;                   /* should not happen */   
    }
-   /*    
-    * Note, if we want to be able to work from a .bsr file only          
-    *  for disaster recovery, we must "simulate" reading the catalog
-    */
-   bstrncpy(dcr->VolumeName, vol->VolumeName, sizeof(dcr->VolumeName));
-   bstrncpy(dcr->VolCatInfo.VolCatName, vol->VolumeName, sizeof(dcr->VolCatInfo.VolCatName));
-   bstrncpy(dcr->media_type, vol->MediaType, sizeof(dcr->media_type));
-   dcr->VolCatInfo.Slot = vol->Slot;
-   dcr->VolCatInfo.InChanger = vol->Slot > 0; 
+   set_dcr_from_vol(dcr, vol);
+
+   Dmsg2(100, "Want Vol=%s Slot=%d\n", vol->VolumeName, vol->Slot);
     
    /*
     * If the MediaType requested for this volume is not the
@@ -116,10 +112,10 @@ bool acquire_device_for_read(DCR *dcr)
       DIRSTORE *store;
       int stat;
 
-      Jmsg3(jcr, M_INFO, 0, _("Changing device. Want Media Type=\"%s\" have=\"%s\"\n"
+      Jmsg3(jcr, M_INFO, 0, _("Changing read device. Want Media Type=\"%s\" have=\"%s\"\n"
                               "  device=%s\n"), 
             dcr->media_type, dev->device->media_type, dev->print_name());
-      Dmsg3(50, "Changing device. Want Media Type=\"%s\" have=\"%s\"\n"
+      Dmsg3(50, "Changing read device. Want Media Type=\"%s\" have=\"%s\"\n"
                               "  device=%s\n", 
             dcr->media_type, dev->device->media_type, dev->print_name());
 
@@ -128,6 +124,7 @@ bool acquire_device_for_read(DCR *dcr)
       lock_reservations();
       memset(&rctx, 0, sizeof(RCTX));
       rctx.jcr = jcr;
+      jcr->read_dcr = dcr;
       jcr->reserve_msgs = New(alist(10, not_owned_by_alist));
       rctx.any_drive = true;
       rctx.device_name = vol->device;
@@ -152,12 +149,12 @@ bool acquire_device_for_read(DCR *dcr)
          dev = dcr->dev;                     /* get new device pointer */
          dev->dblock(BST_DOING_ACQUIRE); 
          dcr->VolumeName[0] = 0;
-         Jmsg(jcr, M_INFO, 0, _("Media Type change.  New device %s chosen.\n"),
+         Jmsg(jcr, M_INFO, 0, _("Media Type change.  New read device %s chosen.\n"),
             dev->print_name());
-         Dmsg1(50, "Media Type change.  New device %s chosen.\n", dev->print_name());
+         Dmsg1(50, "Media Type change.  New read device %s chosen.\n", dev->print_name());
 
          bstrncpy(dcr->VolumeName, vol->VolumeName, sizeof(dcr->VolumeName));
-         bstrncpy(dcr->VolCatInfo.VolCatName, vol->VolumeName, sizeof(dcr->VolCatInfo.VolCatName));
+         dcr->setVolCatName(vol->VolumeName);
          bstrncpy(dcr->media_type, vol->MediaType, sizeof(dcr->media_type));
          dcr->VolCatInfo.Slot = vol->Slot;
          dcr->VolCatInfo.InChanger = vol->Slot > 0; 
@@ -171,23 +168,16 @@ bool acquire_device_for_read(DCR *dcr)
          goto get_out;
       }
    }
+   Dmsg2(400, "MediaType dcr=%s dev=%s\n", dcr->media_type, dev->device->media_type);
 
    dev->clear_unload();
 
-   if (reserve_volume(dcr, dcr->VolumeName) == NULL) {
-      Dmsg2(100, "Could not reserve volume %s on %s\n", dcr->VolumeName,
-            dcr->dev->print_name());
-      Jmsg2(jcr, M_FATAL, 0, _("Could not reserve volume %s on %s\n"), dcr->VolumeName,
-            dcr->dev->print_name());
-      goto get_out;
-   }
    if (dev->vol && dev->vol->is_swapping()) {
       dev->vol->set_slot(vol->Slot);
       Dmsg3(100, "swapping: slot=%d Vol=%s dev=%s\n", dev->vol->get_slot(),
          dev->vol->vol_name, dev->print_name());
    }
 
-
    init_device_wait_timers(dcr);
 
    tape_previously_mounted = dev->can_read() || dev->can_append() ||
@@ -200,7 +190,7 @@ bool acquire_device_for_read(DCR *dcr)
    if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_READ)) {
       Dmsg2(150, "dir_get_vol_info failed for vol=%s: %s\n", 
          dcr->VolumeName, jcr->errmsg);
-      Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg);
+      Jmsg1(jcr, M_WARNING, 0, "Read acquire: %s", jcr->errmsg);
    }
    dev->set_load();                /* set to load volume */
    
@@ -217,7 +207,10 @@ bool acquire_device_for_read(DCR *dcr)
          goto get_out;                /* error return */
       }
 
-      dcr->do_swapping(false/*is_writing*/);
+      dcr->do_unload();
+      dcr->do_swapping(false/*!is_writing*/);
+      dcr->do_load(false /*!is_writing*/);
+      set_dcr_from_vol(dcr, vol);          /* refresh dcr with desired volume info */
 
       /*
        * This code ensures that the device is ready for
@@ -239,38 +232,39 @@ bool acquire_device_for_read(DCR *dcr)
       vol_label_status = read_dev_volume_label(dcr);
       switch (vol_label_status) {
       case VOL_OK:
+         Dmsg0(50, "Got correct volume.\n");
          ok = true;
          dev->VolCatInfo = dcr->VolCatInfo;     /* structure assignment */
          break;                    /* got it */
       case VOL_IO_ERROR:
+         Dmsg0(50, "IO Error\n");
          /*
           * Send error message generated by read_dev_volume_label()
           *  only we really had a tape mounted. This supresses superfluous
           *  error messages when nothing is mounted.
           */
          if (tape_previously_mounted) {
-            Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
+            Jmsg(jcr, M_WARNING, 0, "Read acquire: %s", jcr->errmsg);
          }
          goto default_path;
       case VOL_NAME_ERROR:
+         Dmsg3(50, "Vol name=%s want=%s drv=%s.\n", dev->VolHdr.VolumeName, 
+               dcr->VolumeName, dev->print_name());
          if (dev->is_volume_to_unload()) {
             goto default_path;
          }
-//       if (tape_initially_mounted) {
-            tape_initially_mounted = false;
-//          goto default_path;
-//       }
          dev->set_unload();              /* force unload of unwanted tape */
          if (!unload_autochanger(dcr, -1)) {
             /* at least free the device so we can re-open with correct volume */
             dev->close();                                                          
+            free_volume(dev);
          }
          dev->set_load();
-         ASSERT(0);
          /* Fall through */
       default:
-         Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg);
+         Jmsg1(jcr, M_WARNING, 0, "Read acquire: %s", jcr->errmsg);
 default_path:
+         Dmsg0(50, "default path\n");
          tape_previously_mounted = true;
          
          /*
@@ -278,6 +272,7 @@ default_path:
           */
          if (dev->requires_mount()) {
             dev->close();
+            free_volume(dev);
          }
          
          /* Call autochanger only once unless ask_sysop called */
@@ -290,15 +285,6 @@ default_path:
                try_autochanger = false;
                continue;              /* try reading volume mounted */
             }
-            /* Try closing and re-opening */
-            dev->close();
-            if (dev->open(dcr, OPEN_READ_ONLY) >= 0) {
-               continue;
-            }
-            if (!dev->poll) {
-               Jmsg3(jcr, M_WARNING, 0, _("Read open device %s Volume \"%s\" failed: ERR=%s\n"),
-                     dev->print_name(), dcr->VolumeName, dev->bstrerror());
-            }
          }
          
          /* Mount a specific volume and no other */
@@ -306,7 +292,18 @@ default_path:
          if (!dir_ask_sysop_to_mount_volume(dcr, ST_READ)) {
             goto get_out;             /* error return */
          }
-         try_autochanger = true;      /* permit using autochanger again */
+
+         /* Volume info is always needed because of VolParts */
+         Dmsg1(150, "dir_get_volume_info vol=%s\n", dcr->VolumeName);
+         if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_READ)) {
+            Dmsg2(150, "dir_get_vol_info failed for vol=%s: %s\n", 
+                  dcr->VolumeName, jcr->errmsg);
+            Jmsg1(jcr, M_WARNING, 0, "Read acquire: %s", jcr->errmsg);
+         }
+         dev->set_load();                /* set to load volume */
+
+         try_autochanger = true;      /* permit trying the autochanger again */
+
          continue;                    /* try reading again */
       } /* end switch */
       break;
@@ -338,11 +335,11 @@ get_out:
    } else {
       dev->dunlock();               /* dunblock() unlock the device too */
    }
-   Dmsg1(950, "jcr->dcr=%p\n", jcr->dcr);
+   Dmsg2(950, "dcr=%p dev=%p\n", dcr, dcr->dev);
+   Dmsg2(950, "MediaType dcr=%s dev=%s\n", dcr->media_type, dev->device->media_type);
    return ok;
 }
 
-
 /*
  * Acquire device for writing. We permit multiple writers.
  *  If this is the first one, we read the label.
@@ -361,7 +358,8 @@ DCR *acquire_device_for_append(DCR *dcr)
 
    init_device_wait_timers(dcr);
 
-   dev->dblock(BST_DOING_ACQUIRE);
+   P(dev->acquire_mutex);           /* only one job at a time */
+   dev->dlock();
    Dmsg1(100, "acquire_append device is %s\n", dev->is_tape()?"tape":
         (dev->is_dvd()?"DVD":"disk"));
 
@@ -389,12 +387,15 @@ DCR *acquire_device_for_append(DCR *dcr)
        *   we need to recycle the tape.
        */
        if (dev->num_writers == 0) {
-          memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
+          dev->VolCatInfo = dcr->VolCatInfo;   /* structure assignment */
        }
        have_vol = dcr->is_tape_position_ok();
    }
 
    if (!have_vol) {
+      dev->r_dlock(true);
+      block_device(dev, BST_DOING_ACQUIRE);
+      dev->dunlock();
       Dmsg1(190, "jid=%u Do mount_next_write_vol\n", (uint32_t)jcr->JobId);
       if (!dcr->mount_next_write_volume()) {
          if (!job_canceled(jcr)) {
@@ -404,9 +405,13 @@ DCR *acquire_device_for_append(DCR *dcr)
             Dmsg1(200, "Could not ready device %s for append.\n", 
                dev->print_name());
          }
+         dev->dlock();
+         unblock_device(dev);
          goto get_out;
       }
       Dmsg2(190, "Output pos=%u:%u\n", dcr->dev->file, dcr->dev->block_num);
+      dev->dlock();
+      unblock_device(dev);
    }
 
    dev->num_writers++;                /* we are now a writer */
@@ -414,13 +419,16 @@ DCR *acquire_device_for_append(DCR *dcr)
       jcr->NumWriteVolumes = 1;
    }
    dev->VolCatInfo.VolCatJobs++;              /* increment number of jobs on vol */
+   Dmsg4(100, "=== nwriters=%d nres=%d vcatjob=%d dev=%s\n", 
+      dev->num_writers, dev->num_reserved(), dev->VolCatInfo.VolCatJobs, 
+      dev->print_name());
    dir_update_volume_info(dcr, false, false); /* send Volume info to Director */
    ok = true;
 
 get_out:
-   dev->dlock();
    dcr->clear_reserved();
-   dev->dunblock(DEV_LOCKED);
+   dev->dunlock();
+   V(dev->acquire_mutex);
    return ok ? dcr : NULL;
 }
 
@@ -428,8 +436,9 @@ get_out:
  * This job is done, so release the device. From a Unix standpoint,
  *  the device remains open.
  *
- * Note, if we are spooling, we may enter with the device locked.
- * However, in all cases, unlock the device when leaving.
+ * Note, if we were spooling, we may enter with the device blocked.
+ *   We unblock at the end, only if it was us who blocked the
+ *   device.
  *
  */
 bool release_device(DCR *dcr)
@@ -438,10 +447,14 @@ bool release_device(DCR *dcr)
    DEVICE *dev = dcr->dev;
    bool ok = true;
    char tbuf[100];
+   int was_blocked = BST_NOT_BLOCKED;
 
-   /* lock only if not already locked by this thread */
-   if (!dcr->is_dev_locked()) {
-      dev->r_dlock();
+   dev->dlock();
+   if (!dev->is_blocked()) {
+      block_device(dev, BST_RELEASING);
+   } else {
+      was_blocked = dev->blocked();
+      dev->set_blocked(BST_RELEASING);
    }
    lock_volumes();
    Dmsg2(100, "release_device device %s is %s\n", dev->print_name(), dev->is_tape()?"tape":"disk");
@@ -450,11 +463,15 @@ bool release_device(DCR *dcr)
    dcr->clear_reserved();
 
    if (dev->can_read()) {
+      VOLUME_CAT_INFO *vol = &dev->VolCatInfo;
       dev->clear_read();              /* clear read bit */
-      Dmsg0(100, "dir_update_vol_info. Release0\n");
-      dir_update_volume_info(dcr, false, false); /* send Volume info to Director */
-      volume_unused(dcr);
-
+      Dmsg2(150, "dir_update_vol_info. label=%d Vol=%s\n",
+         dev->is_labeled(), vol->VolCatName);
+      if (dev->is_labeled() && vol->VolCatName[0] != 0) {
+         dir_update_volume_info(dcr, false, false); /* send Volume info to Director */
+         remove_read_volume(jcr, dcr->VolumeName);
+         volume_unused(dcr);
+      }
    } else if (dev->num_writers > 0) {
       /* 
        * Note if WEOT is set, we are at the end of the tape
@@ -466,10 +483,10 @@ bool release_device(DCR *dcr)
       Dmsg1(100, "There are %d writers in release_device\n", dev->num_writers);
       if (dev->is_labeled()) {
          Dmsg2(200, "dir_create_jobmedia. Release vol=%s dev=%s\n", 
-               dev->VolCatInfo.VolCatName, dev->print_name());
+               dev->getVolCatName(), dev->print_name());
          if (!dev->at_weot() && !dir_create_jobmedia_record(dcr)) {
-            Jmsg(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
-               dcr->VolCatInfo.VolCatName, jcr->Job);
+            Jmsg2(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
+               dcr->getVolCatName(), jcr->Job);
          }
          /* If no more writers, and no errors, and wrote something, write an EOF */
          if (!dev->num_writers && dev->can_write() && dev->block_num > 0) {
@@ -481,7 +498,7 @@ bool release_device(DCR *dcr)
             /* Note! do volume update before close, which zaps VolCatInfo */
             dir_update_volume_info(dcr, false, false); /* send Volume info to Director */
             Dmsg2(200, "dir_update_vol_info. Release vol=%s dev=%s\n", 
-                  dev->VolCatInfo.VolCatName, dev->print_name());
+                  dev->getVolCatName(), dev->print_name());
          }
          if (dev->num_writers == 0) {         /* if not being used */
             volume_unused(dcr);               /*  we obviously are not using the volume */
@@ -496,16 +513,14 @@ bool release_device(DCR *dcr)
        */
       volume_unused(dcr);
    }
-   unlock_volumes();
    Dmsg3(100, "%d writers, %d reserve, dev=%s\n", dev->num_writers, dev->num_reserved(),
          dev->print_name());
-   debug_list_volumes("acquire:release_device()");
-
 
    /* If no writers, close if file or !CAP_ALWAYS_OPEN */
    if (dev->num_writers == 0 && (!dev->is_tape() || !dev->has_cap(CAP_ALWAYSOPEN))) {
       dvd_remove_empty_part(dcr);        /* get rid of any empty spool part */
       dev->close();
+      free_volume(dev);
    }
 
    /* Fire off Alert command and include any output */
@@ -516,7 +531,8 @@ bool release_device(DCR *dcr)
       char line[MAXSTRING];
       alert = get_pool_memory(PM_FNAME);
       alert = edit_device_codes(dcr, alert, dcr->device->alert_command, "");
-      bpipe = open_bpipe(alert, 0, "r");
+      /* Wait maximum 5 minutes */
+      bpipe = open_bpipe(alert, 60 * 5, "r");
       if (bpipe) {
          while (fgets(line, sizeof(line), bpipe->rfd)) {
             Jmsg(jcr, M_ALERT, 0, _("Alert: %s"), line);
@@ -538,16 +554,22 @@ bool release_device(DCR *dcr)
    Dmsg2(100, "JobId=%u broadcast wait_device_release at %s\n", 
          (uint32_t)jcr->JobId, bstrftimes(tbuf, sizeof(tbuf), (utime_t)time(NULL)));
    pthread_cond_broadcast(&wait_device_release);
-   dev->dunlock();
+   unlock_volumes();
+
+   /*
+    * If we are the thread that blocked the device, then unblock it
+    */
+   if (pthread_equal(dev->no_wait_id, pthread_self())) {
+      dev->dunblock(true);
+   } else {
+      /* Otherwise, reset the prior block status and unlock */
+      dev->set_blocked(was_blocked);
+      dev->dunlock();
+   }
+
    if (dcr->keep_dcr) {
       detach_dcr_from_dev(dcr);
    } else {
-      if (jcr->read_dcr == dcr) {
-         jcr->read_dcr = NULL;
-      }
-      if (jcr->dcr == dcr) {
-         jcr->dcr = NULL;
-      }
       free_dcr(dcr);
    }
    Dmsg2(100, "===== Device %s released by JobId=%u\n", dev->print_name(),
@@ -583,10 +605,17 @@ bool clean_device(DCR *dcr)
 DCR *new_dcr(JCR *jcr, DCR *dcr, DEVICE *dev)
 {
    if (!dcr) {
+      int errstat;
       dcr = (DCR *)malloc(sizeof(DCR));
       memset(dcr, 0, sizeof(DCR));
       dcr->tid = pthread_self();
       dcr->spool_fd = -1;
+      if ((errstat = pthread_mutex_init(&dcr->m_mutex, NULL)) != 0) {
+         berrno be;
+         dev->dev_errno = errstat;
+         Mmsg1(dev->errmsg, _("Unable to init mutex: ERR=%s\n"), be.bstrerror(errstat));
+         Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg);
+      }
    }
    dcr->jcr = jcr;                 /* point back to jcr */
    /* Set device information, possibly change device */
@@ -646,31 +675,49 @@ static void remove_dcr_from_dcrs(DCR *dcr)
 
 static void attach_dcr_to_dev(DCR *dcr)
 {
-   DEVICE *dev = dcr->dev;
-   JCR *jcr = dcr->jcr;
+   DEVICE *dev;
+   JCR *jcr;
 
+   P(dcr->m_mutex);
+   dev = dcr->dev;
+   jcr = dcr->jcr;
    if (jcr) Dmsg1(500, "JobId=%u enter attach_dcr_to_dev\n", (uint32_t)jcr->JobId);
-   if (!dcr->attached_to_dev && dev->initiated && jcr && jcr->JobType != JT_SYSTEM) {
+   /* ***FIXME*** return error if dev not initiated */
+   if (!dcr->attached_to_dev && dev->initiated && jcr && jcr->getJobType() != JT_SYSTEM) {
+      dev->dlock();
       dev->attached_dcrs->append(dcr);  /* attach dcr to device */
+      dev->dunlock();
       dcr->attached_to_dev = true;
       Dmsg1(500, "JobId=%u attach_dcr_to_dev\n", (uint32_t)jcr->JobId);
    }
+   V(dcr->m_mutex);
 }
 
-void detach_dcr_from_dev(DCR *dcr)
+/* 
+ * DCR is locked before calling this routine
+ */
+static void locked_detach_dcr_from_dev(DCR *dcr)
 {
    DEVICE *dev = dcr->dev;
    Dmsg0(500, "Enter detach_dcr_from_dev\n"); /* jcr is NULL in some cases */
 
    /* Detach this dcr only if attached */
    if (dcr->attached_to_dev && dev) {
-      dev->dlock();
       dcr->unreserve_device();
+      dev->dlock();
       dcr->dev->attached_dcrs->remove(dcr);  /* detach dcr from device */
-      dcr->attached_to_dev = false;
 //    remove_dcr_from_dcrs(dcr);      /* remove dcr from jcr list */
       dev->dunlock();
    }
+   dcr->attached_to_dev = false;
+}
+
+
+static void detach_dcr_from_dev(DCR *dcr)
+{
+   P(dcr->m_mutex);
+   locked_detach_dcr_from_dev(dcr);
+   V(dcr->m_mutex);
 }
 
 /*
@@ -679,9 +726,11 @@ void detach_dcr_from_dev(DCR *dcr)
  */
 void free_dcr(DCR *dcr)
 {
-   JCR *jcr = dcr->jcr;
+   JCR *jcr;
 
-   detach_dcr_from_dev(dcr);
+   P(dcr->m_mutex);
+   jcr = dcr->jcr;
+   locked_detach_dcr_from_dev(dcr);
 
    if (dcr->block) {
       free_block(dcr->block);
@@ -692,5 +741,23 @@ void free_dcr(DCR *dcr)
    if (jcr && jcr->dcr == dcr) {
       jcr->dcr = NULL;
    }
+   if (jcr && jcr->read_dcr == dcr) {
+      jcr->read_dcr = NULL;
+   }
+   V(dcr->m_mutex);
+   pthread_mutex_destroy(&dcr->m_mutex);
    free(dcr);
 }
+
+static void set_dcr_from_vol(DCR *dcr, VOL_LIST *vol)
+{
+   /*    
+    * Note, if we want to be able to work from a .bsr file only          
+    *  for disaster recovery, we must "simulate" reading the catalog
+    */
+   bstrncpy(dcr->VolumeName, vol->VolumeName, sizeof(dcr->VolumeName));
+   dcr->setVolCatName(vol->VolumeName);
+   bstrncpy(dcr->media_type, vol->MediaType, sizeof(dcr->media_type));
+   dcr->VolCatInfo.Slot = vol->Slot;
+   dcr->VolCatInfo.InChanger = vol->Slot > 0; 
+}