]> git.sur5r.net Git - bacula/bacula/commitdiff
kes Fix existing switch drive SD code to call autochanger to release
authorKern Sibbald <kern@sibbald.com>
Thu, 3 Jan 2008 14:08:43 +0000 (14:08 +0000)
committerKern Sibbald <kern@sibbald.com>
Thu, 3 Jan 2008 14:08:43 +0000 (14:08 +0000)
     any old volume. This must be done to keep the autochanger from
     releasing subsequently newly reserved volumes in doing a close().
     This should fix bug #1018.
kes  Apply big backport of current SVN SD code that corrects a number
     of race conditions. This is a first step in fixing bug #1018.

git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/branches/Branch-2.2@6185 91ce42f0-d328-0410-95d8-f526ca767f89

23 files changed:
bacula/ReleaseNotes
bacula/src/lib/message.c
bacula/src/lib/message.h
bacula/src/stored/acquire.c
bacula/src/stored/askdir.c
bacula/src/stored/bcopy.c
bacula/src/stored/bextract.c
bacula/src/stored/block.c
bacula/src/stored/bls.c
bacula/src/stored/bscan.c
bacula/src/stored/btape.c
bacula/src/stored/dev.c
bacula/src/stored/dev.h
bacula/src/stored/device.c
bacula/src/stored/dvd.c
bacula/src/stored/job.c
bacula/src/stored/label.c
bacula/src/stored/mount.c
bacula/src/stored/protos.h
bacula/src/stored/record.c
bacula/src/stored/reserve.c
bacula/src/version.h
bacula/technotes-2.1

index 315e9ab38954add193220e43ee82114c4627b72e..908c6f5bfc8bf50e230f6748f97587bdbc270b78 100644 (file)
@@ -10,7 +10,7 @@ use some of the new features that affect the FD.  In other words, you should
 not have to upgrade all your File daemons when you upgrade. There is
 no database upgrade needed from version 2.0.x to 2.2.0.
 
-Version 2.2.7 has several new features and several importatn bug fixes
+Version 2.2.7 has several new features and several important bug fixes
   since version 2.2.6:
 - It fixes bugs: 1009, 1022, 1024, 1019, 1012, 1021, 1020
   1007, 1008.  For more details, please see the technotes-2.1 file.
index 7075d1b9a886edfc33555b25d5d5ae24a6877626..f4bcc5cc0d19a12865fbf63232f746dbf720368d 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
+   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.
@@ -54,6 +54,7 @@ const char *working_directory = NULL;       /* working directory path stored her
 int verbose = 0;                      /* increase User messages */
 /* Keep debug level set to zero by default */
 int debug_level = 0;                  /* debug level */
+bool dbg_timestamp = false;           /* print timestamp in debug output */
 time_t daemon_start_time = 0;         /* Daemon start time */
 const char *version = VERSION " (" BDATE ")";
 char my_name[30];                     /* daemon name is stored here */
index 476d3611a9b9e6b506978e195b630cfd8f6aa015..785954222ee3eff1e070a21b4d045a6e08b3fb30 100644 (file)
@@ -1,13 +1,7 @@
-/*
- * Define Message Types for Bacula
- *    Kern Sibbald, 2000
- *
- *   Version $Id$
- */
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
+   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.
    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
    Switzerland, email:ftf@fsfeurope.org.
 */
+/*
+ * Define Message Types for Bacula
+ *    Kern Sibbald, 2000
+ *
+ *   Version $Id$
+ */
 
 #include "bits.h"
 
@@ -154,6 +154,7 @@ extern DLL_IMP_EXP sql_query     p_sql_query;
 extern DLL_IMP_EXP sql_escape    p_sql_escape;
 
 extern DLL_IMP_EXP int           debug_level;
+extern DLL_IMP_EXP bool          dbg_timestamp;            /* print timestamp in debug output */
 extern DLL_IMP_EXP int           verbose;
 extern DLL_IMP_EXP char          my_name[];
 extern DLL_IMP_EXP const char *  working_directory;
index 9bb22a78092f30eef3c796810a8f0a715d872f6d..f9a8be1e695996fc67da86a9b9041b7410e09e04 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2002-2007 Free Software Foundation Europe e.V.
+   Copyright (C) 2002-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.
@@ -38,6 +38,7 @@
 
 /* Forward referenced functions */
 static void attach_dcr_to_dev(DCR *dcr);
+static bool is_suitable_volume_mounted(DCR *dcr);
 
 
 /*********************************************************************
@@ -316,9 +317,9 @@ get_out:
  */
 DCR *acquire_device_for_append(DCR *dcr)
 {
-   bool release = false;
-   bool recycle = false;
    bool do_mount = false;
+   bool release = false;
+   bool have_vol;
    DEVICE *dev = dcr->dev;
    JCR *jcr = dcr->jcr;
 
@@ -337,6 +338,11 @@ DCR *acquire_device_for_append(DCR *dcr)
       goto get_out;
    }
 
+   /*
+    * have_vol defines whether or not mount_next_write_volume should
+    *   ask the Director again about what Volume to use.
+    */
+   have_vol = is_suitable_volume_mounted(dcr);
    if (dev->can_append()) {
       Dmsg0(190, "device already in append.\n");
       /*
@@ -351,25 +357,11 @@ DCR *acquire_device_for_append(DCR *dcr)
        *  dcr->VolumeName is what we pass into the routines, or
        *    get back from the subroutines.
        */
-      bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName));
-      if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_WRITE) &&
+      if (!have_vol &&
           !(dir_find_next_appendable_volume(dcr) &&
             strcmp(dev->VolHdr.VolumeName, dcr->VolumeName) == 0)) { /* wrong tape mounted */
-         Dmsg2(190, "Wrong tape mounted: %s. wants:%s\n", dev->VolHdr.VolumeName,
-            dcr->VolumeName);
-         /* Release volume reserved by dir_find_next_appendable_volume() */
-         if (dcr->VolumeName[0]) {
-            volume_unused(dcr);
-         }
-         if (dev->num_writers != 0) {
-            Jmsg3(jcr, M_FATAL, 0, _("Wanted to append to Volume \"%s\", but device %s is busy writing on \"%s\" .\n"), 
-                 dcr->VolumeName, dev->print_name(), dev->VolHdr.VolumeName);
-            Dmsg3(200, "Wanted to append to Volume \"%s\", but device %s is busy writing on \"%s\" .\n",  
-                 dcr->VolumeName, dev->print_name(), dev->VolHdr.VolumeName);
-            goto get_out;
-         }
          /* Wrong tape mounted, release it, then fall through to get correct one */
-         Dmsg0(190, "Wrong tape mounted, release and try mount.\n");
+         Dmsg0(50, "Wrong tape mounted, release and try mount.\n");
          release = true;
          do_mount = true;
       } else {
@@ -378,14 +370,17 @@ DCR *acquire_device_for_append(DCR *dcr)
           *   we do not need to do mount_next_write_volume(), unless
           *   we need to recycle the tape.
           */
-          recycle = strcmp(dcr->VolCatInfo.VolCatStatus, "Recycle") == 0;
-          Dmsg1(190, "Correct tape mounted. recycle=%d\n", recycle);
-          if (recycle && dev->num_writers != 0) {
+          do_mount = strcmp(dcr->VolCatInfo.VolCatStatus, "Recycle") == 0;
+          Dmsg2(190, "jid=%u Correct tape mounted. recycle=%d\n", 
+                (uint32_t)jcr->JobId, do_mount);
+#ifdef xxx
+          if (do_mount && dev->num_writers != 0) {
              Jmsg(jcr, M_FATAL, 0, _("Cannot recycle volume \"%s\""
                   " on device %s because it is in use by another job.\n"),
                   dev->VolHdr.VolumeName, dev->print_name());
              goto get_out;
           }
+#endif
           if (dev->num_writers == 0) {
              memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
           }
@@ -415,21 +410,23 @@ DCR *acquire_device_for_append(DCR *dcr)
       }
    } else {
       /* Not already in append mode, so mount the device */
-      Dmsg0(190, "Not in append mode, try mount.\n");
+      Dmsg2(190, "jid=%u Not in append mode, try mount have_vol=%d\n", 
+            (uint32_t)jcr->JobId, have_vol);
+
       ASSERT(dev->num_writers == 0);
       do_mount = true;
    }
 
-   if (do_mount || recycle) {
-      Dmsg0(190, "Do mount_next_write_vol\n");
-      bool mounted = mount_next_write_volume(dcr, release);
+   if (do_mount || !have_vol) {
+      Dmsg1(190, "jid=%u Do mount_next_write_vol\n", (uint32_t)jcr->JobId);
+      bool mounted = mount_next_write_volume(dcr, have_vol, release);
       if (!mounted) {
          if (!job_canceled(jcr)) {
             /* Reduce "noise" -- don't print if job canceled */
             Jmsg(jcr, M_FATAL, 0, _("Could not ready device %s for append.\n"),
                dev->print_name());
-            Dmsg1(200, "Could not ready device %s for append.\n", 
-               dev->print_name());
+            Dmsg2(200, "jid=%u Could not ready device %s for append.\n", 
+               (uint32_t)jcr->JobId, dev->print_name());
          }
          goto get_out;
       }
@@ -441,11 +438,12 @@ DCR *acquire_device_for_append(DCR *dcr)
       jcr->NumWriteVolumes = 1;
    }
    dev->VolCatInfo.VolCatJobs++;              /* increment number of jobs on vol */
-   dir_update_volume_info(dcr, false);        /* send Volume info to Director */
+   dir_update_volume_info(dcr, false, false); /* send Volume info to Director */
    dev->dlock();
    if (dcr->reserved_device) {
       dev->reserved_device--;
-      Dmsg2(100, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name());
+      Dmsg3(100, "jid=%u Dec reserve=%d dev=%s\n", (uint32_t)jcr->JobId,
+            dev->reserved_device, dev->print_name());
       dcr->reserved_device = false;
    }
    dev->dunblock(DEV_LOCKED);
@@ -458,7 +456,8 @@ get_out:
    dev->dlock();
    if (dcr->reserved_device) {
       dev->reserved_device--;
-      Dmsg2(100, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name());
+      Dmsg3(100, "jid=%u Dec reserve=%d dev=%s\n", (uint32_t)jcr->JobId, 
+            dev->reserved_device, dev->print_name());
       dcr->reserved_device = false;
    }
    dev->dunblock(DEV_LOCKED);
@@ -466,6 +465,18 @@ get_out:
 }
 
 
+static bool is_suitable_volume_mounted(DCR *dcr)
+{
+   DEVICE *dev = dcr->dev;
+
+   /* Volume mounted? */
+   if (dev->VolHdr.VolumeName[0] == 0) {
+      return false;                      /* no */
+   }
+   bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName));
+   return dir_get_volume_info(dcr, GET_VOL_INFO_FOR_WRITE);
+}
+
 /*
  * This job is done, so release the device. From a Unix standpoint,
  *  the device remains open.
@@ -496,7 +507,7 @@ bool release_device(DCR *dcr)
    if (dev->can_read()) {
       dev->clear_read();              /* clear read bit */
       Dmsg0(100, "dir_update_vol_info. Release0\n");
-      dir_update_volume_info(dcr, false); /* send Volume info to Director */
+      dir_update_volume_info(dcr, false, false); /* send Volume info to Director */
 
    } else if (dev->num_writers > 0) {
       /* 
@@ -522,7 +533,7 @@ bool release_device(DCR *dcr)
             dev->VolCatInfo.VolCatFiles = dev->file;   /* set number of files */
             /* Note! do volume update before close, which zaps VolCatInfo */
             Dmsg0(100, "dir_update_vol_info. Release0\n");
-            dir_update_volume_info(dcr, false); /* send Volume info to Director */
+            dir_update_volume_info(dcr, false, false); /* send Volume info to Director */
          }
       }
 
@@ -621,7 +632,12 @@ DCR *new_dcr(JCR *jcr, DCR *dcr, DEVICE *dev)
       if (dcr->attached_to_dev) {
          detach_dcr_from_dev(dcr);
       }
-      dcr->max_job_spool_size = dev->device->max_job_spool_size;
+      /* Use job spoolsize prior to device spoolsize */
+      if (jcr->spool_size) {
+         dcr->max_job_spool_size = jcr->spool_size;
+      } else {
+         dcr->max_job_spool_size = dev->device->max_job_spool_size;
+      }
       dcr->device = dev->device;
       dcr->dev = dev;
       attach_dcr_to_dev(dcr);
index e533d76f83118a472c23b5033fcf1720395d0b55..785a25b33c292df2dca1841d5be2e107cab2a28d 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
+   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.
@@ -42,7 +42,7 @@ static char Find_media[]   = "CatReq Job=%s FindMedia=%d pool_name=%s media_type
 static char Get_Vol_Info[] = "CatReq Job=%s GetVolInfo VolName=%s write=%d\n";
 static char Update_media[] = "CatReq Job=%s UpdateMedia VolName=%s"
    " VolJobs=%u VolFiles=%u VolBlocks=%u VolBytes=%s VolMounts=%u"
-   " VolErrors=%u VolWrites=%u MaxVolBytes=%s EndTime=%d VolStatus=%s"
+   " VolErrors=%u VolWrites=%u MaxVolBytes=%s EndTime=%s VolStatus=%s"
    " Slot=%d relabel=%d InChanger=%d VolReadTime=%s VolWriteTime=%s"
    " VolFirstWritten=%s VolParts=%u\n";
 static char Create_job_media[] = "CatReq Job=%s CreateJobMedia"
@@ -98,7 +98,7 @@ bool dir_update_device(JCR *jcr, DEVICE *dev)
    } else {
       pm_strcpy(ChangerName, "*");
    }
-   ok =bnet_fsend(dir, Device_update, 
+   ok = dir->fsend(Device_update, 
       jcr->Job,
       dev_name.c_str(),
       dev->can_append()!=0,
@@ -125,7 +125,7 @@ bool dir_update_changer(JCR *jcr, AUTOCHANGER *changer)
    pm_strcpy(MediaType, device->media_type);
    bash_spaces(MediaType);
    /* This is mostly to indicate that we are here */
-   ok = bnet_fsend(dir, Device_update,
+   ok = dir->fsend(Device_update,
       jcr->Job,
       dev_name.c_str(),         /* Changer name */
       0, 0, 0,                  /* append, read, num_writers */
@@ -148,7 +148,7 @@ bool dir_update_changer(JCR *jcr, AUTOCHANGER *changer)
  */
 bool dir_send_job_status(JCR *jcr)
 {
-   return bnet_fsend(jcr->dir_bsock, Job_status, jcr->Job, jcr->JobStatus);
+   return jcr->dir_bsock->fsend(Job_status, jcr->Job, jcr->JobStatus);
 }
 
 /*
@@ -179,7 +179,7 @@ static bool do_get_volume_info(DCR *dcr)
        return false;
     }
     memset(&vol, 0, sizeof(vol));
-    Dmsg1(100, "<dird %s\n", dir->msg);
+    Dmsg1(100, "<dird %s", dir->msg);
     n = sscanf(dir->msg, OK_media, vol.VolCatName,
                &vol.VolCatJobs, &vol.VolCatFiles,
                &vol.VolCatBlocks, &vol.VolCatBytes,
@@ -191,7 +191,8 @@ static bool do_get_volume_info(DCR *dcr)
                &vol.EndFile, &vol.EndBlock, &vol.VolCatParts,
                &vol.LabelType, &vol.VolMediaId);
     if (n != 22) {
-       Dmsg3(100, "Bad response from Dir fields=%d, len=%d: %s", n, dir->msglen, dir->msg);
+       Dmsg3(100, "Bad response from Dir fields=%d, len=%d: %s", 
+             n, dir->msglen, dir->msg);
        Mmsg(jcr->errmsg, _("Error getting Volume info: %s"), dir->msg);
        return false;
     }
@@ -226,7 +227,7 @@ bool dir_get_volume_info(DCR *dcr, enum get_vol_info_rw writing)
     bash_spaces(dcr->VolCatInfo.VolCatName);
     dir->fsend(Get_Vol_Info, jcr->Job, dcr->VolCatInfo.VolCatName,
        writing==GET_VOL_INFO_FOR_WRITE?1:0);
-    Dmsg1(100, ">dird: %s\n", dir->msg);
+    Dmsg1(100, ">dird %s", dir->msg);
     unbash_spaces(dcr->VolCatInfo.VolCatName);
     bool ok = do_get_volume_info(dcr);
     V(vol_info_mutex);
@@ -253,7 +254,9 @@ bool dir_find_next_appendable_volume(DCR *dcr)
     BSOCK *dir = jcr->dir_bsock;
     bool found = false;
 
-    Dmsg0(200, "dir_find_next_appendable_volume\n");
+    Dmsg2(200, "dir_find_next_appendable_volume: reserved=%d Vol=%s\n", 
+       dcr->reserved_device, dcr->VolumeName);
+
     /*
      * Try the twenty oldest or most available volumes.  Note,
      *   the most available could already be mounted on another
@@ -268,7 +271,7 @@ bool dir_find_next_appendable_volume(DCR *dcr)
        dir->fsend(Find_media, jcr->Job, vol_index, dcr->pool_name, dcr->media_type);
        unbash_spaces(dcr->media_type);
        unbash_spaces(dcr->pool_name);
-       Dmsg1(100, ">dird: %s", dir->msg);
+       Dmsg1(100, ">dird %s", dir->msg);
        bool ok = do_get_volume_info(dcr);
        if (ok) {
           if (!is_volume_in_use(dcr)) {
@@ -311,14 +314,13 @@ bail_out:
  * back to the director. The information comes from the
  * dev record.
  */
-bool dir_update_volume_info(DCR *dcr, bool label)
+bool dir_update_volume_info(DCR *dcr, bool label, bool update_LastWritten)
 {
    JCR *jcr = dcr->jcr;
    BSOCK *dir = jcr->dir_bsock;
    DEVICE *dev = dcr->dev;
-   time_t LastWritten = time(NULL);
    VOLUME_CAT_INFO *vol = &dev->VolCatInfo;
-   char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50];
+   char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50], ed6[50];
    int InChanger;
    bool ok = false;
    POOL_MEM VolumeName;
@@ -341,21 +343,25 @@ bool dir_update_volume_info(DCR *dcr, bool label)
    if (label) {
       bstrncpy(vol->VolCatStatus, "Append", sizeof(vol->VolCatStatus));
    }
+// if (update_LastWritten) {
+      vol->VolLastWritten = time(NULL);
+// }
    pm_strcpy(VolumeName, vol->VolCatName);
    bash_spaces(VolumeName);
    InChanger = vol->InChanger;
-   bnet_fsend(dir, Update_media, jcr->Job,
+   dir->fsend(Update_media, jcr->Job,
       VolumeName.c_str(), vol->VolCatJobs, vol->VolCatFiles,
       vol->VolCatBlocks, edit_uint64(vol->VolCatBytes, ed1),
       vol->VolCatMounts, vol->VolCatErrors,
       vol->VolCatWrites, edit_uint64(vol->VolCatMaxBytes, ed2),
-      LastWritten, vol->VolCatStatus, vol->Slot, label,
+      edit_uint64(vol->VolLastWritten, ed6), 
+      vol->VolCatStatus, vol->Slot, label,
       InChanger,                      /* bool in structure */
       edit_int64(vol->VolReadTime, ed3),
       edit_int64(vol->VolWriteTime, ed4),
       edit_uint64(vol->VolFirstWritten, ed5),
       vol->VolCatParts);
-    Dmsg1(100, ">dird: %s", dir->msg);
+    Dmsg1(100, ">dird %s", dir->msg);
 
    /* Do not lock device here because it may be locked from label */
    if (!do_get_volume_info(dcr)) {
@@ -364,7 +370,7 @@ bool dir_update_volume_info(DCR *dcr, bool label)
          vol->VolCatName, jcr->errmsg);
       goto bail_out;
    }
-   Dmsg1(420, "get_volume_info(): %s", dir->msg);
+   Dmsg1(420, "get_volume_info() %s", dir->msg);
    /* Update dev Volume info in case something changed (e.g. expired) */
    dev->VolCatInfo = dcr->VolCatInfo;
    ok = true;
@@ -393,20 +399,20 @@ bool dir_create_jobmedia_record(DCR *dcr)
    }
 
    dcr->WroteVol = false;
-   bnet_fsend(dir, Create_job_media, jcr->Job,
+   dir->fsend(Create_job_media, jcr->Job,
       dcr->VolFirstIndex, dcr->VolLastIndex,
       dcr->StartFile, dcr->EndFile,
       dcr->StartBlock, dcr->EndBlock, 
       dcr->Copy, dcr->Stripe, 
       edit_uint64(dcr->VolMediaId, ed1));
-    Dmsg1(100, ">dird: %s", dir->msg);
+    Dmsg1(100, ">dird %s", dir->msg);
    if (bnet_recv(dir) <= 0) {
       Dmsg0(190, "create_jobmedia error bnet_recv\n");
       Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia record: ERR=%s\n"),
-           bnet_strerror(dir));
+           dir->bstrerror());
       return false;
    }
-   Dmsg1(100, "<dir: %s", dir->msg);
+   Dmsg1(100, "<dird %s", dir->msg);
    if (strcmp(dir->msg, OK_create) != 0) {
       Dmsg1(130, "Bad response from Dir: %s\n", dir->msg);
       Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia record: %s\n"), dir->msg);
@@ -429,9 +435,10 @@ bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec)
    return true;
 #endif
 
-   dir->msglen = sprintf(dir->msg, FileAttributes, jcr->Job);
-   dir->msg = check_pool_memory_size(dir->msg, dir->msglen +
-                sizeof(DEV_RECORD) + rec->data_len);
+   dir->msg = check_pool_memory_size(dir->msg, sizeof(FileAttributes) +
+                MAX_NAME_LENGTH + sizeof(DEV_RECORD) + rec->data_len + 1);
+   dir->msglen = bsnprintf(dir->msg, sizeof(FileAttributes) +
+                MAX_NAME_LENGTH + 1, FileAttributes, jcr->Job);
    ser_begin(dir->msg + dir->msglen, 0);
    ser_uint32(rec->VolSessionId);
    ser_uint32(rec->VolSessionTime);
@@ -440,8 +447,8 @@ bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec)
    ser_uint32(rec->data_len);
    ser_bytes(rec->data, rec->data_len);
    dir->msglen = ser_length(dir->msg);
-   Dmsg1(1800, ">dird: %s\n", dir->msg);    /* Attributes */
-   return bnet_send(dir);
+   Dmsg1(1800, ">dird %s\n", dir->msg);    /* Attributes */
+   return dir->send();
 }
 
 
index edec449576a27cd9fab4781fc2df0d1afa5ca832..5d0e00eebac07565b30d3f84af7f2a97c759a47a 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2002-2007 Free Software Foundation Europe e.V.
+   Copyright (C) 2002-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.
@@ -42,6 +42,7 @@
 int generate_daemon_event(JCR *jcr, const char *event) { return 1; }
 
 /* Forward referenced functions */
+static void get_session_record(DEVICE *dev, DEV_RECORD *rec, SESSION_LABEL *sessrec);
 static bool record_cb(DCR *dcr, DEV_RECORD *rec);
 
 
@@ -52,10 +53,11 @@ static JCR *in_jcr;                    /* input jcr */
 static JCR *out_jcr;                   /* output jcr */
 static BSR *bsr = NULL;
 static const char *wd = "/tmp";
-static int list_records = 0;
+static bool list_records = false;
 static uint32_t records = 0;
 static uint32_t jobs = 0;
 static DEV_BLOCK *out_block;
+static SESSION_LABEL sessrec;
 
 #define CONFIG_FILE "bacula-sd.conf"
 char *configfile = NULL;
@@ -73,7 +75,7 @@ PROG_COPYRIGHT
 "Usage: bcopy [-d debug_level] <input-archive> <output-archive>\n"
 "       -b bootstrap      specify a bootstrap file\n"
 "       -c <file>         specify configuration file\n"
-"       -d <nn>           set debug level to nn\n"
+"       -d <nn>           set debug level to <nn>\n"
 "       -i                specify input Volume names (separated by |)\n"
 "       -o                specify output Volume names (separated by |)\n"
 "       -p                proceed inspite of errors\n"
@@ -113,9 +115,14 @@ int main (int argc, char *argv[])
          break;
 
       case 'd':                    /* debug level */
-         debug_level = atoi(optarg);
-         if (debug_level <= 0)
-            debug_level = 1;
+         if (*optarg == 't') {
+            dbg_timestamp = true;
+         } else {
+            debug_level = atoi(optarg);
+            if (debug_level <= 0) {
+               debug_level = 1;
+            }
+         }
          break;
 
       case 'i':                    /* input Volume name */
@@ -201,6 +208,7 @@ int main (int argc, char *argv[])
    out_block = out_jcr->dcr->block;
 
    ok = read_records(in_jcr->dcr, record_cb, mount_next_read_volume);
+
    if (ok || out_dev->can_write()) {
       if (!write_block_to_device(out_jcr->dcr)) {
          Pmsg0(000, _("Write of last block failed.\n"));
@@ -233,6 +241,7 @@ static bool record_cb(DCR *in_dcr, DEV_RECORD *rec)
     *
     */
    if (rec->FileIndex < 0) {
+      get_session_record(in_dcr->dev, rec, &sessrec);
 
       if (verbose > 1) {
          dump_label_record(in_dcr->dev, rec, 1);
@@ -294,10 +303,46 @@ static bool record_cb(DCR *in_dcr, DEV_RECORD *rec)
    return true;
 }
 
+static void get_session_record(DEVICE *dev, DEV_RECORD *rec, SESSION_LABEL *sessrec)
+{
+   const char *rtype;
+   memset(sessrec, 0, sizeof(sessrec));
+   switch (rec->FileIndex) {
+   case PRE_LABEL:
+      rtype = _("Fresh Volume Label");
+      break;
+   case VOL_LABEL:
+      rtype = _("Volume Label");
+      unser_volume_label(dev, rec);
+      break;
+   case SOS_LABEL:
+      rtype = _("Begin Job Session");
+      unser_session_label(sessrec, rec);
+      break;
+   case EOS_LABEL:
+      rtype = _("End Job Session");
+      unser_session_label(sessrec, rec);
+      break;
+   case 0:
+   case EOM_LABEL:
+      rtype = _("End of Medium");
+      break;
+   default:
+      rtype = _("Unknown");
+      break;
+   }
+   Dmsg5(10, "%s Record: VolSessionId=%d VolSessionTime=%d JobId=%d DataLen=%d\n",
+         rtype, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
+   if (verbose) {
+      Pmsg5(-1, _("%s Record: VolSessionId=%d VolSessionTime=%d JobId=%d DataLen=%d\n"),
+            rtype, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
+   }
+}
+
 
 /* Dummies to replace askdir.c */
 bool    dir_find_next_appendable_volume(DCR *dcr) { return 1;}
-bool    dir_update_volume_info(DCR *dcr, bool relabel) { return 1; }
+bool    dir_update_volume_info(DCR *dcr, bool relabel, bool update_LastWritten) { return 1; }
 bool    dir_create_jobmedia_record(DCR *dcr) { return 1; }
 bool    dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; }
 bool    dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;}
index 53f40d9738efcc6516fd7ad59c244c72425a6989..7c5cfada4634971e05c076ec3afc0a381e586823 100644 (file)
@@ -1,16 +1,7 @@
-/*
- *
- *  Dumb program to extract files from a Bacula backup.
- *
- *   Kern E. Sibbald, MM
- *
- *   Version $Id$
- *
- */
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
+   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.
    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
    Switzerland, email:ftf@fsfeurope.org.
 */
+/*
+ *
+ *  Dumb program to extract files from a Bacula backup.
+ *
+ *   Kern E. Sibbald, MM
+ *
+ *   Version $Id$
+ *
+ */
 
 #include "bacula.h"
 #include "stored.h"
@@ -79,7 +79,7 @@ PROG_COPYRIGHT
 "Usage: bextract <options> <bacula-archive-device-name> <directory-to-store-files>\n"
 "       -b <file>       specify a bootstrap file\n"
 "       -c <file>       specify a configuration file\n"
-"       -d <nn>         set debug level to nn\n"
+"       -d <nn>         set debug level to <nn>\n"
 "       -e <file>       exclude list\n"
 "       -i <file>       include list\n"
 "       -p              proceed inspite of I/O errors\n"
@@ -126,9 +126,14 @@ int main (int argc, char *argv[])
          break;
 
       case 'd':                    /* debug level */
-         debug_level = atoi(optarg);
-         if (debug_level <= 0)
-            debug_level = 1;
+         if (*optarg == 't') {
+            dbg_timestamp = true;
+         } else {
+            debug_level = atoi(optarg);
+            if (debug_level <= 0) {
+               debug_level = 1;
+            }
+         }
          break;
 
       case 'e':                    /* exclude list */
@@ -476,7 +481,7 @@ static bool record_cb(DCR *dcr, DEV_RECORD *rec)
 
 /* Dummies to replace askdir.c */
 bool    dir_find_next_appendable_volume(DCR *dcr) { return 1;}
-bool    dir_update_volume_info(DCR *dcr, bool relabel) { return 1; }
+bool    dir_update_volume_info(DCR *dcr, bool relabel, bool update_LastWritten) { return 1; }
 bool    dir_create_jobmedia_record(DCR *dcr) { return 1; }
 bool    dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; }
 bool    dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;}
index e5b95b624db4a98acd1838415a184553ddbcde48..b9cbbfa36acaf72ae8c5c831ac24953ed4d438b8 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2001-2007 Free Software Foundation Europe e.V.
+   Copyright (C) 2001-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.
@@ -746,7 +746,7 @@ static bool terminate_writing_volume(DCR *dcr)
       dev->VolCatInfo.VolCatParts = dev->num_dvd_parts;
    }
    
-   if (!dir_update_volume_info(dcr, false)) {
+   if (!dir_update_volume_info(dcr, false, true)) {
       ok = false;
    }
    Dmsg1(100, "dir_update_volume_info terminate writing -- %s\n", ok?"OK":"ERROR");
@@ -798,7 +798,7 @@ static bool do_new_file_bookkeeping(DCR *dcr)
       return false;
    }
    dev->VolCatInfo.VolCatFiles = dev->file;
-   if (!dir_update_volume_info(dcr, false)) {
+   if (!dir_update_volume_info(dcr, false, false)) {
       Dmsg0(190, "Error from update_vol_info.\n");
       terminate_writing_volume(dcr);
       dev->dev_errno = EIO;
@@ -856,7 +856,7 @@ static bool do_dvd_size_checks(DCR *dcr)
       
       dev->VolCatInfo.VolCatParts = dev->num_dvd_parts;
             
-      if (!dir_update_volume_info(dcr, false)) {
+      if (!dir_update_volume_info(dcr, false, false)) {
          Dmsg0(190, "Error from update_vol_info.\n");
          dev->dev_errno = EIO;
          return false;
index 92d6fbcc95682d55a8735a5bab602deda575da35..0ce876deaba60502dc4547c4825cfccbcdb2d09e 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
+   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.
@@ -79,7 +79,7 @@ PROG_COPYRIGHT
 "Usage: bls [options] <device-name>\n"
 "       -b <file>       specify a bootstrap file\n"
 "       -c <file>       specify a config file\n"
-"       -d <level>      specify debug level\n"
+"       -d <nn>         set debug level to <nn>\n"
 "       -e <file>       exclude list\n"
 "       -i <file>       include list\n"
 "       -j              list jobs\n"
@@ -130,9 +130,14 @@ int main (int argc, char *argv[])
          break;
 
       case 'd':                    /* debug level */
-         debug_level = atoi(optarg);
-         if (debug_level <= 0)
-            debug_level = 1;
+         if (*optarg == 't') {
+            dbg_timestamp = true;
+         } else {
+            debug_level = atoi(optarg);
+            if (debug_level <= 0) {
+               debug_level = 1;
+            }
+         }
          break;
 
       case 'e':                    /* exclude list */
@@ -440,7 +445,7 @@ static void get_session_record(DEVICE *dev, DEV_RECORD *rec, SESSION_LABEL *sess
 
 /* Dummies to replace askdir.c */
 bool    dir_find_next_appendable_volume(DCR *dcr) { return 1;}
-bool    dir_update_volume_info(DCR *dcr, bool relabel) { return 1; }
+bool    dir_update_volume_info(DCR *dcr, bool relabel, bool update_LastWritten) { return 1; }
 bool    dir_create_jobmedia_record(DCR *dcr) { return 1; }
 bool    dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; }
 bool    dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;}
index 71254e5bbf8035d618740a511a4b5bacb1d440c3..85ddc1d399efc97c2d87e18c1bd293c125053d17 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2001-2007 Free Software Foundation Europe e.V.
+   Copyright (C) 2001-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.
@@ -116,7 +116,7 @@ PROG_COPYRIGHT
 "Usage: bscan [ options ] <bacula-archive>\n"
 "       -b bootstrap      specify a bootstrap file\n"
 "       -c <file>         specify configuration file\n"
-"       -d <nn>           set debug level to nn\n"
+"       -d <nn>           set debug level to <nn>\n"
 "       -m                update media info in database\n"
 "       -n <name>         specify the database name (default bacula)\n"
 "       -u <user>         specify database user name (default bacula)\n"
@@ -166,9 +166,14 @@ int main (int argc, char *argv[])
          break;
 
       case 'd':                    /* debug level */
-         debug_level = atoi(optarg);
-         if (debug_level <= 0)
-            debug_level = 1;
+         if (*optarg == 't') {
+            dbg_timestamp = true;
+         } else {
+            debug_level = atoi(optarg);
+            if (debug_level <= 0) {
+               debug_level = 1;
+            }
+         }
          break;
 
       case 'h':
@@ -1271,7 +1276,7 @@ static JCR *create_jcr(JOB_DBR *jr, DEV_RECORD *rec, uint32_t JobId)
 
 /* Dummies to replace askdir.c */
 bool    dir_find_next_appendable_volume(DCR *dcr) { return 1;}
-bool    dir_update_volume_info(DCR *dcr, bool relabel) { return 1; }
+bool    dir_update_volume_info(DCR *dcr, bool relabel, bool update_LastWritten) { return 1; }
 bool    dir_create_jobmedia_record(DCR *dcr) { return 1; }
 bool    dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; }
 bool    dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;}
index a951ba804be84f0bcd2adf19aead04b15c58b231..1a276916d5604a09f0994a4ed65d6c63e5c031fc 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
+   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.
@@ -220,9 +220,13 @@ int main(int margc, char *margv[])
          break;
 
       case 'd':                    /* set debug level */
-         debug_level = atoi(optarg);
-         if (debug_level <= 0) {
-            debug_level = 1;
+         if (*optarg == 't') {
+            dbg_timestamp = true;
+         } else {
+            debug_level = atoi(optarg);
+            if (debug_level <= 0) {
+               debug_level = 1;
+            }
          }
          break;
 
@@ -2598,7 +2602,7 @@ PROG_COPYRIGHT
 "Usage: btape <options> <device_name>\n"
 "       -b <file>   specify bootstrap file\n"
 "       -c <file>   set configuration file to file\n"
-"       -d <nn>     set debug level to nn\n"
+"       -d <nn>     set debug level to <nn>\n"
 "       -p          proceed inspite of I/O errors\n"
 "       -s          turn off signals\n"
 "       -v          be verbose\n"
@@ -2644,7 +2648,7 @@ get_cmd(const char *prompt)
 bool    dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;}
 bool    dir_send_job_status(JCR *jcr) {return 1;}
 
-bool dir_update_volume_info(DCR *dcr, bool relabel)
+bool dir_update_volume_info(DCR *dcr, bool relabel, bool update_LastWritten)
 {
    return 1;
 }
index eebac478c573b977083d1373450a53992c3cc0f2..28bcc4e8032a58d3f04701ff3a85630135977fe5 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
+   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.
@@ -89,7 +89,7 @@
 /* Forward referenced functions */
 void set_os_device_parameters(DCR *dcr);   
 static bool dev_get_os_pos(DEVICE *dev, struct mtget *mt_stat);
-static char *mode_to_str(int mode);
+static const char *mode_to_str(int mode);
 
 /*
  * Allocate and initialize the DEVICE structure
@@ -490,7 +490,7 @@ void DEVICE::open_file_device(DCR *dcr, int omode)
       Mmsg2(errmsg, _("Could not open: %s, ERR=%s\n"), archive_name.c_str(), 
             be.bstrerror());
       Dmsg1(100, "open failed: %s", errmsg);
-      Emsg0(M_FATAL, 0, errmsg);
+      Jmsg1(NULL, M_WARNING, 0, "%s", errmsg);
    } else {
       dev_errno = 0;
       file = 0;
@@ -2468,7 +2468,7 @@ static bool dev_get_os_pos(DEVICE *dev, struct mtget *mt_stat)
           mt_stat->mt_fileno >= 0;
 }
 
-static char *modes[] = {
+static const char *modes[] = {
    "CREATE_READ_WRITE",
    "OPEN_READ_WRITE",
    "OPEN_READ_ONLY",
@@ -2476,7 +2476,7 @@ static char *modes[] = {
 };
 
 
-static char *mode_to_str(int mode)  
+static const char *mode_to_str(int mode)  
 {
    static char buf[100];
    if (mode < 1 || mode > 4) {
index f51f3ce1602fca6cb0b1b51b641069e2b10c166e..45068b282664de196df8c60839e93de6d5c18546 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
+   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.
@@ -158,6 +158,7 @@ struct VOLUME_CAT_INFO {
    btime_t  VolWriteTime;             /* time spent writing this Volume */
    int64_t  VolMediaId;               /* MediaId */
    utime_t  VolFirstWritten;          /* Time of first write */
+   utime_t  VolLastWritten;           /* Time of last write */
    bool     InChanger;                /* Set if vol in current magazine */
    char VolCatStatus[20];             /* Volume status */
    char VolCatName[MAX_NAME_LENGTH];  /* Desired volume to mount */
@@ -473,8 +474,9 @@ public:
 class VOLRES { 
 public:
    dlink link;
-   char *vol_name;
-   DEVICE *dev;
+   char *vol_name;                    /* Volume name */
+   DEVICE *dev;                       /* Pointer to device to which we are attached */
+   bool released;                     /* set when the Volume can be released */
 };
 
 
index 34fbc0cec7f03570b23573992eb098067286edc0..7e8656974f9342f259cb42be8082c06a869ea3b2 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
+   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.
@@ -122,7 +122,8 @@ bool fixup_device_block_write_error(DCR *dcr)
         edit_uint64_with_commas(dev->VolCatInfo.VolCatBlocks, b2),
         bstrftime(dt, sizeof(dt), time(NULL)));
 
-   if (!mount_next_write_volume(dcr, 1)) {
+   /* Called with have_vol=false, release=true */
+   if (!mount_next_write_volume(dcr, false, true)) {
       free_block(label_blk);
       dcr->block = block;
       dev->dlock();  
@@ -131,7 +132,7 @@ bool fixup_device_block_write_error(DCR *dcr)
    dev->dlock();                    /* lock again */
 
    dev->VolCatInfo.VolCatJobs++;              /* increment number of jobs on vol */
-   dir_update_volume_info(dcr, false);        /* send Volume info to Director */
+   dir_update_volume_info(dcr, false, false); /* send Volume info to Director */
 
    Jmsg(jcr, M_INFO, 0, _("New volume \"%s\" mounted on device %s at %s.\n"),
       dcr->VolumeName, dev->print_name(), bstrftime(dt, sizeof(dt), time(NULL)));
index 367e6a8a019cdb41dbd359b492d309ee4795ed76..3a8241a80b678d029b30397b26e73a23f874eec7 100644 (file)
@@ -1,16 +1,7 @@
-/*
- *
- *   dvd.c  -- Routines specific to DVD devices (and
- *             possibly other removable hard media). 
- *
- *    Nicolas Boichat, MMV
- *
- *   Version $Id$
- */
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2005-2006 Free Software Foundation Europe e.V.
+   Copyright (C) 2005-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.
    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
    Switzerland, email:ftf@fsfeurope.org.
 */
+/*
+ *
+ *   dvd.c  -- Routines specific to DVD devices (and
+ *             possibly other removable hard media). 
+ *
+ *    Nicolas Boichat, MMV
+ *
+ *   Version $Id$
+ */
 
 #include "bacula.h"
 #include "stored.h"
@@ -686,7 +686,7 @@ bool truncate_dvd(DCR *dcr)
    dcr->VolCatInfo.VolCatBytes = 0;
 
    /* Update catalog */
-   if (!dir_update_volume_info(dcr, false)) {
+   if (!dir_update_volume_info(dcr, false, true)) {
       return false;
    }
    
index 79b7aa58a56bdff968099050e794fd23479e9a06..e18d41c7eedbedab55f8c950d1ce8e3f687ace51 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
+   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.
@@ -48,10 +48,14 @@ extern bool do_mac(JCR *jcr);
 
 /* Requests from the Director daemon */
 static char jobcmd[] = "JobId=%d job=%127s job_name=%127s client_name=%127s "
+      "type=%d level=%d FileSet=%127s NoAttr=%d SpoolAttr=%d FileSetMD5=%127s "
+      "SpoolData=%d WritePartAfterJob=%d PreferMountedVols=%d SpoolSize=%s\n";
+static char oldjobcmd[] = "JobId=%d job=%127s job_name=%127s client_name=%127s "
       "type=%d level=%d FileSet=%127s NoAttr=%d SpoolAttr=%d FileSetMD5=%127s "
       "SpoolData=%d WritePartAfterJob=%d PreferMountedVols=%d\n";
 
 
+
 /* Responses sent to Director daemon */
 static char OKjob[]     = "3000 OK Job SDid=%u SDtime=%u Authorization=%s\n";
 static char BAD_job[]   = "3915 Bad Job command. stat=%d CMD: %s\n";
@@ -73,6 +77,7 @@ bool job_cmd(JCR *jcr)
 {
    int JobId;
    char auth_key[100];
+   char spool_size[30];
    char seed[100];
    BSOCK *dir = jcr->dir_bsock;
    POOL_MEM job_name, client_name, job, fileset_name, fileset_md5;
@@ -85,17 +90,26 @@ bool job_cmd(JCR *jcr)
     * Get JobId and permissions from Director
     */
    Dmsg1(100, "<dird: %s", dir->msg);
+   bstrncpy(spool_size, "0", sizeof(spool_size));
    stat = sscanf(dir->msg, jobcmd, &JobId, job.c_str(), job_name.c_str(),
               client_name.c_str(),
               &JobType, &level, fileset_name.c_str(), &no_attributes,
-              &spool_attributes, fileset_md5.c_str(), &spool_data, 
+              &spool_attributes, fileset_md5.c_str(), &spool_data,
+              &write_part_after_job, &PreferMountedVols, spool_size);
+   if (stat != 14) {
+      /* Try old version */
+      stat = sscanf(dir->msg, oldjobcmd, &JobId, job.c_str(), job_name.c_str(),
+              client_name.c_str(),
+              &JobType, &level, fileset_name.c_str(), &no_attributes,
+              &spool_attributes, fileset_md5.c_str(), &spool_data,
               &write_part_after_job, &PreferMountedVols);
-   if (stat != 13) {
-      pm_strcpy(jcr->errmsg, dir->msg);
-      dir->fsend(BAD_job, stat, jcr->errmsg);
-      Dmsg1(100, ">dird: %s", dir->msg);
-      set_jcr_job_status(jcr, JS_ErrorTerminated);
-      return false;
+      if (stat != 13) {
+         pm_strcpy(jcr->errmsg, dir->msg);
+         dir->fsend(BAD_job, stat, jcr->errmsg);
+         Dmsg1(100, ">dird: %s", dir->msg);
+         set_jcr_job_status(jcr, JS_ErrorTerminated);
+         return false;
+      }
    }
    /*
     * Since this job could be rescheduled, we
@@ -125,6 +139,7 @@ bool job_cmd(JCR *jcr)
    jcr->no_attributes = no_attributes;
    jcr->spool_attributes = spool_attributes;
    jcr->spool_data = spool_data;
+   jcr->spool_size = str_to_int64(spool_size);
    jcr->write_part_after_job = write_part_after_job;
    jcr->fileset_md5 = get_pool_memory(PM_NAME);
    pm_strcpy(jcr->fileset_md5, fileset_md5);
index e56e32c39be11f77e852d77a5c677d6ac8fbd988..5e6c75bfca368026510c2f8622ffa368bb3d7e0a 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
+   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.
@@ -505,7 +505,7 @@ bool rewrite_volume_label(DCR *dcr, bool recycle)
    }
    Dmsg0(150, "dir_update_vol_info. Set Append\n");
    bstrncpy(dev->VolCatInfo.VolCatStatus, "Append", sizeof(dev->VolCatInfo.VolCatStatus));
-   if (!dir_update_volume_info(dcr, true)) {  /* indicate doing relabel */
+   if (!dir_update_volume_info(dcr, true, true)) {  /* indicate doing relabel */
       return false;
    }
    if (recycle) {
@@ -716,7 +716,7 @@ bool write_session_label(DCR *dcr, int label)
       }
       break;
    default:
-      Jmsg1(jcr, M_ABORT, 0, _("Bad session label = %d\n"), label);
+      Jmsg1(jcr, M_ABORT, 0, _("Bad Volume session label = %d\n"), label);
       break;
    }
    create_session_label(dcr, rec, label);
index 0b91ce6b7432d6a35c81dc52b320851d9c213f8d..c8beb34a999b84292f398d80a7d7f1950bce3b7c 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2002-2007 Free Software Foundation Europe e.V.
+   Copyright (C) 2002-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.
@@ -60,7 +60,7 @@ enum {
  *  impossible to get the requested Volume.
  *
  */
-bool mount_next_write_volume(DCR *dcr, bool release)
+bool mount_next_write_volume(DCR *dcr, bool have_vol, bool release)
 {
    int retry = 0;
    bool ask = false, recycle, autochanger;
@@ -108,12 +108,16 @@ mount_next_vol:
     *    in dcr->VolCatInfo
     */
    Dmsg0(200, "Before dir_find_next_appendable_volume.\n");
-   while (!dir_find_next_appendable_volume(dcr)) {
-       Dmsg0(200, "not dir_find_next\n");
-       if (!dir_ask_sysop_to_create_appendable_volume(dcr)) {
-         return false;
+   if (!have_vol) {
+      while (!dir_find_next_appendable_volume(dcr)) {
+         Dmsg0(200, "not dir_find_next\n");
+         if (!dir_ask_sysop_to_create_appendable_volume(dcr)) {
+            return false;
+          }
+          Dmsg0(200, "Again dir_find_next_append...\n");
        }
-       Dmsg0(200, "Again dir_find_next_append...\n");
+   } else {
+      have_vol = false;               /* set false for next pass if any */
    }
    if (job_canceled(jcr)) {
       return false;
@@ -144,7 +148,7 @@ mount_next_vol:
     * If we autochanged to correct Volume or (we have not just
     *   released the Volume AND we can automount) we go ahead
     *   and read the label. If there is no tape in the drive,
-    *   we will err, recurse and ask the operator the next time.
+    *   we will fail, recurse and ask the operator the next time.
     */
    if (!release && dev->is_tape() && dev->has_cap(CAP_AUTOMOUNT)) {
       Dmsg0(150, "(1)Ask=0\n");
@@ -432,7 +436,7 @@ read_volume:
       }
       dev->VolCatInfo.VolCatMounts++;      /* Update mounts */
       Dmsg1(150, "update volinfo mounts=%d\n", dev->VolCatInfo.VolCatMounts);
-      if (!dir_update_volume_info(dcr, false)) {
+      if (!dir_update_volume_info(dcr, false, false)) {
          return false;
       }
       
@@ -519,7 +523,7 @@ static int try_autolabel(DCR *dcr, bool opened)
       Dmsg0(150, "dir_update_vol_info. Set Append\n");
       /* Copy Director's info into the device info */
       dev->VolCatInfo = dcr->VolCatInfo;    /* structure assignment */
-      if (!dir_update_volume_info(dcr, true)) {  /* indicate tape labeled */
+      if (!dir_update_volume_info(dcr, true, true)) {  /* indicate tape labeled */
          return try_error;
       }
       Jmsg(dcr->jcr, M_INFO, 0, _("Labeled new Volume \"%s\" on device %s.\n"),
@@ -552,7 +556,7 @@ void mark_volume_in_error(DCR *dcr)
    dev->VolCatInfo = dcr->VolCatInfo;     /* structure assignment */
    bstrncpy(dev->VolCatInfo.VolCatStatus, "Error", sizeof(dev->VolCatInfo.VolCatStatus));
    Dmsg0(150, "dir_update_vol_info. Set Error.\n");
-   dir_update_volume_info(dcr, false);
+   dir_update_volume_info(dcr, false, false);
 }
 
 /*
@@ -570,7 +574,7 @@ static void mark_volume_not_inchanger(DCR *dcr)
    dcr->VolCatInfo.InChanger = false;
    dev->VolCatInfo.InChanger = false;
    Dmsg0(400, "update vol info in mount\n");
-   dir_update_volume_info(dcr, true);  /* set new status */
+   dir_update_volume_info(dcr, true, false);  /* set new status */
 }
 
 /*
@@ -588,6 +592,7 @@ void release_volume(DCR *dcr)
    /*
     * First erase all memory of the current volume
     */
+   free_volume(dev);
    dev->block_num = dev->file = 0;
    dev->EndBlock = dev->EndFile = 0;
    memset(&dev->VolCatInfo, 0, sizeof(dev->VolCatInfo));
index 783241d30ba6ab3e5286390b550bdb32f1cf8d8e..0a673d0141ddc704a510a78af914d8dedfd61517 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
+   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.
@@ -49,7 +49,7 @@ enum get_vol_info_rw {
 };
 bool    dir_get_volume_info(DCR *dcr, enum get_vol_info_rw);
 bool    dir_find_next_appendable_volume(DCR *dcr);
-bool    dir_update_volume_info(DCR *dcr, bool label);
+bool    dir_update_volume_info(DCR *dcr, bool label, bool update_LastWritten);
 bool    dir_ask_sysop_to_create_appendable_volume(DCR *dcr);
 bool    dir_ask_sysop_to_mount_volume(DCR *dcr);
 bool    dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec);
@@ -182,7 +182,7 @@ BSR     *find_next_bsr(BSR *root_bsr, DEVICE *dev);
 bool     is_this_bsr_done(BSR *bsr, DEV_RECORD *rec);
 
 /* From mount.c */
-bool     mount_next_write_volume(DCR *dcr, bool release);
+bool     mount_next_write_volume(DCR *dcr, bool have_vol, bool release);
 bool     mount_next_read_volume(DCR *dcr);
 void     mark_volume_in_error(DCR *dcr);
 
index a2eff5ecdddadc07206072296a02adf69d0c200b..d47d74ccd838b330b75ee5a2b0cefd4b6f2460e5 100644 (file)
@@ -1,17 +1,7 @@
-/*
- *
- *   record.c -- tape record handling functions
- *
- *              Kern Sibbald, April MMI
- *                added BB02 format October MMII
- *
- *   Version $Id$
- *
- */
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2001-2006 Free Software Foundation Europe e.V.
+   Copyright (C) 2001-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.
    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
    Switzerland, email:ftf@fsfeurope.org.
 */
+/*
+ *
+ *   record.c -- tape record handling functions
+ *
+ *              Kern Sibbald, April MMI
+ *                added BB02 format October MMII
+ *
+ *   Version $Id$
+ *
+ */
 
 
 #include "bacula.h"
@@ -254,7 +254,7 @@ bool write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec)
    ASSERT(block->buf_len >= block->binbuf);
 
    Dmsg6(890, "write_record_to_block() FI=%s SessId=%d Strm=%s len=%d\n"
-"rem=%d remainder=%d\n",
+      "rem=%d remainder=%d\n",
       FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
       stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
       remlen, rec->remainder);
@@ -365,7 +365,7 @@ bool write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec)
          if (!sm_check_rtn(__FILE__, __LINE__, False)) {
             /* We damaged a buffer */
             Dmsg6(0, "Damaged block FI=%s SessId=%d Strm=%s len=%d\n"
-"rem=%d remainder=%d\n",
+               "rem=%d remainder=%d\n",
                FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
                stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
                remlen, rec->remainder);
index 349aa29592073efa3bdb95628292ea98a362008f..6cd269eeae833ff49bc1376d12a67b7c3b70124d 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
+   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.
@@ -212,11 +212,11 @@ void list_volumes(void sendit(const char *msg, int len, void *sarg), void *arg)
       if (dev) {
          len = Mmsg(msg, "%s on device %s\n", vol->vol_name, dev->print_name());
          sendit(msg.c_str(), len, arg);
-         len = Mmsg(msg, "    Reader=%d writers=%d reserved=%d\n", dev->can_read()?1:0,
-            dev->num_writers, dev->reserved_device);
+         len = Mmsg(msg, "    Reader=%d writers=%d reserved=%d released=%d\n", 
+            dev->can_read()?1:0, dev->num_writers, dev->reserved_device, vol->released);
          sendit(msg.c_str(), len, arg);
       } else {
-         len = Mmsg(msg, "%s no dev\n", vol->vol_name);
+         len = Mmsg(msg, "%s no device. released=%d\n", vol->vol_name, vol->released);
          sendit(msg.c_str(), len, arg);
       }
    }
@@ -292,11 +292,11 @@ static void free_vol_item(VOLRES *vol)
  *  already exist and are correctly programmed and will need no changes -- use 
  *  counts are always very tricky.
  *
- *  The old code had a concept of "reserving" a Volume, but it needs to be changed 
+ *  The old code had a concept of "reserving" a Volume, but was changed 
  *  to reserving and using a drive.  A volume is must be attached to (owned by) a 
  *  drive and can move from drive to drive or be unused given certain specific 
  *  conditions of the drive.  The key is that the drive must "own" the Volume.  
- *  The old code has the job (dcr) owning the volume (more or less).  The job is 
+ *  The old code had the job (dcr) owning the volume (more or less).  The job was
  *  to change the insertion and removal of the volumes from the list to be based 
  *  on the drive rather than the job.  
  *
@@ -329,13 +329,14 @@ VOLRES *reserve_volume(DCR *dcr, const char *VolumeName)
        *  because it was probably inserted by another job.
        */
       if (strcmp(vol->vol_name, VolumeName) == 0) {
+         Dmsg1(dbglvl, "OK, vol=%s on device.\n", VolumeName);
          goto get_out;                  /* Volume already on this device */
       } else {
-         Dmsg3(dbglvl, "jid=%u reserve_vol free vol=%s at %p\n", 
+         Dmsg3(dbglvl, "jid=%u reserve_vol free vol=%s at %p\n",
                (int)dcr->jcr->JobId, vol->vol_name, vol->vol_name);
+         unload_autochanger(dcr, -1);    /* unload the volume */       
+         free_volume(dev);
          debug_list_volumes("reserve_vol free");
-         vol_list->remove(vol);
-         free_vol_item(vol);
       }
    }
 
@@ -378,12 +379,16 @@ VOLRES *reserve_volume(DCR *dcr, const char *VolumeName)
             Dmsg4(dbglvl, "jid=%u Volume busy could not swap vol=%s from dev=%s to %s\n", 
                jid(), VolumeName, vol->dev->print_name(), dev->print_name());
             vol = NULL;                /* device busy */
+            goto get_out;
          }
       }
    }
    dev->vol = vol;
 
 get_out:
+   if (vol) {
+      vol->released = false;
+   }
    debug_list_volumes("end new volume");
    unlock_volumes();
    return vol;
@@ -462,6 +467,7 @@ bool volume_unused(DCR *dcr)
     *  explicitly read in this drive. This allows the SD to remember
     *  where the tapes are or last were.
     */
+   dev->vol->released = true;
    if (dev->is_tape() || dev->is_autochanger()) {
       return true;
    } else {
@@ -837,6 +843,7 @@ bool find_suitable_device_for_job(JCR *jcr, RCTX &rctx)
       dlist *temp_vol_list, *save_vol_list;
       VOLRES *vol = NULL;
       lock_volumes();
+      Dmsg0(dbglvl, "lock volumes\n");                           
 
       /*  
        * Create a temporary copy of the volume list.  We do this,
@@ -1122,6 +1129,26 @@ static int reserve_device(RCTX &rctx)
              */
             if (dcr->volume_in_use && !rctx.PreferMountedVols) {
                rctx.PreferMountedVols = true;
+               if (dcr->VolumeName[0]) {
+                  volume_unused(dcr);
+               }
+               goto bail_out;
+            }
+            /*
+             * Note. Under some circumstances, the Director can hand us
+             *  a Volume name that is no the same as the one on the current
+             *  drive, and in that case, the call above to find the next
+             *  volume will fail because in attempting to reserve the Volume
+             *  the code will realize that we already have a tape mounted,
+             *  and it will fail.  This *should* only happen if there are 
+             *  writers, thus the following test.  In that case, we simply
+             *  bail out, and continue waiting, rather than plunging on
+             *  and hoping that the operator can resolve the problem. 
+             */
+            if (dcr->dev->num_writers != 0) {
+               if (dcr->VolumeName[0]) {
+                  volume_unused(dcr);
+               }
                goto bail_out;
             }
          }
@@ -1270,6 +1297,51 @@ bail_out:
    return ok;
 }
 
+static int is_pool_ok(DCR *dcr)
+{
+   DEVICE *dev = dcr->dev;
+   JCR *jcr = dcr->jcr;
+
+   /* Now check if we want the same Pool and pool type */
+   if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
+       strcmp(dev->pool_type, dcr->pool_type) == 0) {
+      /* OK, compatible device */
+      Dmsg1(dbglvl, "OK dev: %s num_writers=0, reserved, pool matches\n", dev->print_name());
+      return 1;
+   } else {
+      /* Drive Pool not suitable for us */
+      Mmsg(jcr->errmsg, _(
+"3608 JobId=%u wants Pool=\"%s\" but have Pool=\"%s\" nreserve=%d on drive %s.\n"), 
+            (uint32_t)jcr->JobId, dcr->pool_name, dev->pool_name,
+            dev->reserved_device, dev->print_name());
+      queue_reserve_message(jcr);
+      Dmsg2(dbglvl, "failed: busy num_writers=0, reserved, pool=%s wanted=%s\n",
+         dev->pool_name, dcr->pool_name);
+   }
+   return 0;
+}
+
+static bool is_max_jobs_ok(DCR *dcr) 
+{
+   DEVICE *dev = dcr->dev;
+   JCR *jcr = dcr->jcr;
+
+   Dmsg4(dbglvl, "MaxJobs=%d Jobs=%d reserves=%d Vol=%s\n",
+         dcr->VolCatInfo.VolCatMaxJobs,
+         dcr->VolCatInfo.VolCatJobs, dev->reserved_device,
+         dcr->VolumeName);
+   if (dcr->VolCatInfo.VolCatMaxJobs > 0 && dcr->VolCatInfo.VolCatMaxJobs <=
+        (dcr->VolCatInfo.VolCatJobs + dev->reserved_device)) {
+      /* Max Job Vols depassed or already reserved */
+      Mmsg(jcr->errmsg, _("3610 JobId=%u Volume max jobs exceeded on drive %s.\n"), 
+            (uint32_t)jcr->JobId, dev->print_name());
+      queue_reserve_message(jcr);
+      Dmsg1(dbglvl, "reserve dev failed: %s", jcr->errmsg);
+      return false;                /* wait */
+   }
+   return true;
+}
+
 /*
  * Returns: 1 if drive can be reserved
  *          0 if we should wait
@@ -1285,6 +1357,11 @@ static int can_reserve_drive(DCR *dcr, RCTX &rctx)
          rctx.PreferMountedVols, rctx.exact_match, rctx.suitable_device,
          rctx.autochanger_only, rctx.any_drive);
 
+   /* Check for max jobs on this Volume */
+   if (!is_max_jobs_ok(dcr)) {
+      return 0;
+   }
+
    /* setting any_drive overrides PreferMountedVols flag */
    if (!rctx.any_drive) {
       /*
@@ -1374,32 +1451,10 @@ static int can_reserve_drive(DCR *dcr, RCTX &rctx)
    if (dev->num_writers == 0) {
       /* Now check if there are any reservations on the drive */
       if (dev->reserved_device) {           
-         /* Now check if we want the same Pool and pool type */
-         if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
-             strcmp(dev->pool_type, dcr->pool_type) == 0) {
-            /* OK, compatible device */
-            Dmsg2(dbglvl, "jid=%u OK dev: %s num_writers=0, reserved, pool matches\n",
-               jcr->JobId, dev->print_name());
-            return 1;
-         } else {
-            /* Drive Pool not suitable for us */
-            Mmsg(jcr->errmsg, _(
-"3608 JobId=%u wants Pool=\"%s\" but have Pool=\"%s\" nreserve=%d on drive %s.\n"), 
-                  jcr->JobId, dcr->pool_name, dev->pool_name,
-                  dev->reserved_device, dev->print_name());
-            queue_reserve_message(jcr);
-            Dmsg3(dbglvl, "jid=%u failed: busy num_writers=0, reserved, pool=%s wanted=%s\n",
-               (int)jcr->JobId, dev->pool_name, dcr->pool_name);
-            return 0;                 /* wait */
-         }
+         return is_pool_ok(dcr);
       } else if (dev->can_append()) {
-         /* Device in append mode, check if changing pool */
-         if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
-             strcmp(dev->pool_type, dcr->pool_type) == 0) {
-            Dmsg2(dbglvl, "jid=%u OK dev: %s num_writers=0, can_append, pool matches.\n",
-               jcr->JobId, dev->print_name());
-            /* OK, compatible device */
-            return 1;
+         if (is_pool_ok(dcr)) {
+            return 1; 
          } else {
             /* Changing pool, unload old tape if any in drive */
             Dmsg1(dbglvl, "jid=%u OK dev: num_writers=0, not reserved, pool change, unload changer\n",
@@ -1419,22 +1474,7 @@ static int can_reserve_drive(DCR *dcr, RCTX &rctx)
     *  available if pool is the same).
     */
    if (dev->can_append() || dev->num_writers > 0) {
-      /* Yes, now check if we want the same Pool and pool type */
-      if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
-          strcmp(dev->pool_type, dcr->pool_type) == 0) {
-         Dmsg2(dbglvl, "jid=%u OK dev: %s num_writers>=0, can_append, pool matches.\n",
-            jcr->JobId, dev->print_name());
-         /* OK, compatible device */
-         return 1;
-      } else {
-         /* Drive Pool not suitable for us */
-         Mmsg(jcr->errmsg, _("3609 JobId=%u wants Pool=\"%s\" but has Pool=\"%s\" on drive %s.\n"), 
-               jcr->JobId, dcr->pool_name, dev->pool_name, dev->print_name());
-         queue_reserve_message(jcr);
-         Dmsg3(dbglvl, "jid=%u failed: busy num_writers>0, can_append, pool=%s wanted=%s\n",
-            (int)jcr->JobId, dev->pool_name, dcr->pool_name);
-         return 0;                    /* wait */
-      }
+      return is_pool_ok(dcr);
    } else {
       Pmsg1(000, _("Logic error!!!! JobId=%u Should not get here.\n"), (int)jcr->JobId);
       Mmsg(jcr->errmsg, _("3910 JobId=%u Logic error!!!! drive %s Should not get here.\n"),
index eb38344e0751b0f765c13499660a84a78bc32467..9d3a642b4e7933e0f91c928cc0c62353df2a31f7 100644 (file)
@@ -3,17 +3,17 @@
  */
 
 #undef  VERSION
-#define VERSION "2.2.7"
-#define BDATE   "24 December 2007"
-#define LSMDATE "24Dec07"
+#define VERSION "2.2.8"
+#define BDATE   "01 January 2008"
+#define LSMDATE "01Jan08"
 
-#define PROG_COPYRIGHT "Copyright (C) %d-2007 Free Software Foundation Europe e.V.\n"
-#define BYEAR "2007"       /* year for copyright messages in progs */
+#define PROG_COPYRIGHT "Copyright (C) %d-2008 Free Software Foundation Europe e.V.\n"
+#define BYEAR "2008"       /* year for copyright messages in progs */
 
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
+   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.
index 5c270425b5be2de3680056ef492c770660c5f60b..828f06c42dbb2e56b978bad262f3f74b1d26881e 100644 (file)
@@ -1,6 +1,22 @@
               Technical notes on version 2.2
 
 General:
+03Jan08
+kes  Move Heartbeat documentation from Job to Director resource.
+     This fixes bug #1033.
+02Jan08
+kes  Fix existing switch drive SD code to call autochanger to release
+     any old volume. This must be done to keep the autochanger from
+     releasing subsequently newly reserved volumes in doing a close().
+     This should fix bug #1018.
+kes  Apply big backport of current SVN SD code that corrects a number
+     of race conditions. This is a first step in fixing bug #1018.
+29Dec07
+ebl  Fixes bug #1028 where "Selection Type" option was not usable 
+     with JobDefs.
+
+
+Release Version 2.2.7
 24Dec07
 kes  Partial back out (disabled) %f job code editing because it
      does not build on Win32.