+++ /dev/null
-
- This patch fixes a float point editing bug introduced in 2.2.7 (I think)
- causing the rate fields to be formated incorrectly (actually trunctated).
- This fixes bug #1036.
-
- Apply it to version 2.2.7 with:
-
- cd <bacula-source>
- patch -p0 <2.2.7-fpformat.patch
- ./configure <your-options>
- make
- ...
- make install
-
-
-Index: src/lib/bsnprintf.c
-===================================================================
---- src/lib/bsnprintf.c (revision 6183)
-+++ src/lib/bsnprintf.c (working copy)
-@@ -16,7 +16,7 @@
- /*
- Bacula® - The Network Backup Solution
-
-- Copyright (C) 2005-2007 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.
-@@ -566,11 +566,11 @@
- return result;
- }
-
--static long round(LDOUBLE value)
-+static int64_t round(LDOUBLE value)
- {
-- long intpart;
-+ int64_t intpart;
-
-- intpart = (long)value;
-+ intpart = (int64_t)value;
- value = value - intpart;
- if (value >= 0.5)
- intpart++;
-@@ -584,8 +584,8 @@
- int signvalue = 0;
- LDOUBLE ufvalue;
- #ifndef HAVE_FCVT
-- char iconvert[25];
-- char fconvert[25];
-+ char iconvert[311];
-+ char fconvert[311];
- #else
- char iconvert[311];
- char fconvert[311];
-@@ -602,6 +602,7 @@
- int caps = 0;
- int64_t intpart;
- int64_t fracpart;
-+ const char *cvt_str;
-
- /*
- * AIX manpage says the default is 0, but Solaris says the default
-@@ -625,7 +626,7 @@
- #endif
-
- #ifndef HAVE_FCVT
-- intpart = (long)ufvalue;
-+ intpart = (int64_t)ufvalue;
-
- /*
- * Sorry, we only support 9 digits past the decimal because of our
-@@ -645,28 +646,30 @@
- }
-
- #ifdef DEBUG_SNPRINTF
-- printf("fmtfp: %g %d.%d min=%d max=%d\n",
-+ printf("fmtfp: %g %lld.%lld min=%d max=%d\n",
- (double)fvalue, intpart, fracpart, min, max);
- #endif
-
- /* Convert integer part */
-+ cvt_str = caps ? "0123456789ABCDEF" : "0123456789abcdef";
- do {
-- iconvert[iplace++] =
-- (caps ? "0123456789ABCDEF" : "0123456789abcdef")[intpart % 10];
-+ iconvert[iplace++] = cvt_str[(int)(intpart % 10)];
- intpart = (intpart / 10);
-- } while (intpart && (iplace < (int)sizeof(iplace)));
-- if (iplace == (int)sizeof(iplace)) {
-+ } while (intpart && (iplace < (int)sizeof(iconvert)));
-+
-+ if (iplace == (int)sizeof(fconvert)) {
- iplace--;
- }
- iconvert[iplace] = 0;
-
- /* Convert fractional part */
-+ cvt_str = caps ? "0123456789ABCDEF" : "0123456789abcdef";
- do {
-- fconvert[fplace++] =
-- (caps ? "0123456789ABCDEF" : "0123456789abcdef")[fracpart % 10];
-+ fconvert[fplace++] = cvt_str[fracpart % 10];
- fracpart = (fracpart / 10);
-- } while (fracpart && (fplace < (int)sizeof(fplace)));
-- if (fplace == (int)sizeof(fplace)) {
-+ } while (fracpart && (fplace < (int)sizeof(fconvert)));
-+
-+ if (fplace == (int)sizeof(fconvert)) {
- fplace--;
- }
- fconvert[fplace] = 0;
-@@ -825,7 +828,7 @@
- NULL
- };
- double fp_nums[] = { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
-- 0.9996, 1.996, 4.136, 6442452944.1234, 0
-+ 0.9996, 1.996, 4.136, 6442452944.1234, 0, 23365.5
- };
- #endif
- char *int_fmt[] = {
+++ /dev/null
-
- This patch permits to use migration options with JobDefs.
- This patch fixes bug #1028.
-
- Apply the patch to 2.2.7 (and possibly any 2.2.x version with):
-
- cd <bacula-source>
- patch -p0 <2.2.7-jobdefs-migtype.patch
- ./configure <your-options>
- make
- ...
- make install
-
-Index: src/dird/dird.c
-===================================================================
---- src/dird/dird.c (revision 6183)
-+++ src/dird/dird.c (working copy)
-@@ -58,6 +58,7 @@
- void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass);
- void store_level(LEX *lc, RES_ITEM *item, int index, int pass);
- void store_replace(LEX *lc, RES_ITEM *item, int index, int pass);
-+void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass);
- void init_device_resources();
-
- static char *runjob = NULL;
-@@ -698,6 +699,7 @@
- job_items[i].handler == store_jobtype ||
- job_items[i].handler == store_level ||
- job_items[i].handler == store_pint ||
-+ job_items[i].handler == store_migtype ||
- job_items[i].handler == store_replace) {
- def_ivalue = (int *)((char *)(job->jobdefs) + offset);
- Dmsg5(400, "Job \"%s\", field \"%s\" def_ivalue=%d item %d offset=%u\n",
-Index: src/dird/dird_conf.c
-===================================================================
---- src/dird/dird_conf.c (revision 6183)
-+++ src/dird/dird_conf.c (working copy)
-@@ -74,8 +74,8 @@
- void store_level(LEX *lc, RES_ITEM *item, int index, int pass);
- void store_replace(LEX *lc, RES_ITEM *item, int index, int pass);
- void store_acl(LEX *lc, RES_ITEM *item, int index, int pass);
-+void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass);
- static void store_device(LEX *lc, RES_ITEM *item, int index, int pass);
--static void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass);
- static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass);
- static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass);
- static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass);
-@@ -1548,7 +1548,7 @@
- * Store JobType (backup, verify, restore)
- *
- */
--static void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
-+void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
- {
- int token, i;
-
+++ /dev/null
-
- This patch fixes bug #1034 about Temporary MySQL table 'batch'
- disappears if MySQL connection times out.
-
- Apply the patch to 2.2.7 (and possibly any 2.2.x version with):
-
- cd <bacula-source>
- patch -p0 <2.2.7-mysql-batch-timeout.patch
- ./configure <your-options>
- make
- ...
- make install
-
-
-
-Index: src/cats/mysql.c
-===================================================================
---- src/cats/mysql.c (révision 6192)
-+++ src/cats/mysql.c (copie de travail)
-@@ -205,6 +205,10 @@
- Dmsg3(100, "opendb ref=%d connected=%d db=%p\n", mdb->ref_count,
- mdb->connected, mdb->db);
-
-+ /* Set connection timeout to 8 days specialy for batch mode */
-+ sql_query(mdb, "SET wait_timeout=691200");
-+ sql_query(mdb, "SET interactive_timeout=691200");
-+
- V(mutex);
- return 1;
- }
+++ /dev/null
-
- If you have an old version of PostgreSQL, for example,
- version 7.3 or older, it may not properly build with the current
- Bacula release due to incompatible changes in the PostgreSQL
- header files between version. Only in the case that build fails,
- you might try applying this patch with:
-
- cd <bacula-2.2.7-source>
- patch -p1 <2.2.7-old-postgresql.patch
- ./configure <your-options>
- make
- ...
- make install
-
-
-diff -uNr bacula-2.2.7/src/cats/postgresql.c bacula-2.2.7-fixed/src/cats/postgresql.c
---- bacula-2.2.7/src/cats/postgresql.c 2007-12-08 04:54:55.000000000 -0500
-+++ bacula-2.2.7-fixed/src/cats/postgresql.c 2007-12-29 08:34:10.000000000 -0500
-@@ -47,7 +47,6 @@
- #ifdef HAVE_POSTGRESQL
-
- #include "postgres_ext.h" /* needed for NAMEDATALEN */
--#include "pg_config_manual.h" /* get NAMEDATALEN on version 8.3 or later */
-
- /* -----------------------------------------------------------------------
- *
+++ /dev/null
-
- This patch has a number of cleanups and improvements to the SD
- reservations system. It should fix a number of problems with
- dual drive autochangers as well ensure that volume use durations
- and max volume jobs are better respected.
-
- Apply it to version 2.2.7 (possibly some earlier versions) with:
-
- cd <bacula-source>
- patch -p1 <2.2.7-reserve.patch
- ./configure <your options>
- make
- ...
- make install
-
-
-diff -ur k1/src/lib/message.c k3/src/lib/message.c
---- k1/src/lib/message.c 2007-10-19 13:47:58.000000000 +0200
-+++ k3/src/lib/message.c 2007-12-22 19:13:00.000000000 +0100
-@@ -54,6 +54,7 @@
- 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 */
-diff -ur k1/src/lib/message.h k3/src/lib/message.h
---- k1/src/lib/message.h 2007-10-03 13:36:47.000000000 +0200
-+++ k3/src/lib/message.h 2007-12-22 19:13:06.000000000 +0100
-@@ -154,6 +154,7 @@
- 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;
-diff -ur k1/src/stored/acquire.c k3/src/stored/acquire.c
---- k1/src/stored/acquire.c 2007-09-14 11:49:06.000000000 +0200
-+++ k3/src/stored/acquire.c 2007-12-22 19:12:23.000000000 +0100
-@@ -30,7 +30,7 @@
- *
- * Kern Sibbald, August MMII
- *
-- * Version $Id: acquire.c 5552 2007-09-14 09:49:06Z kerns $
-+ * Version $Id: acquire.c 6081 2007-12-21 14:11:40Z kerns $
- */
-
- #include "bacula.h" /* pull in global headers */
-@@ -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 @@
- */
- 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 @@
- 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->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 @@
- * 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 @@
- }
- } 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 @@
- 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 @@
- 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 @@
- }
-
-
-+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 @@
- 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 @@
- 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 @@
- 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);
-diff -ur k1/src/stored/askdir.c k3/src/stored/askdir.c
---- k1/src/stored/askdir.c 2007-09-09 12:03:23.000000000 +0200
-+++ k3/src/stored/askdir.c 2007-12-22 19:11:50.000000000 +0100
-@@ -31,7 +31,7 @@
- *
- * Kern Sibbald, December 2000
- *
-- * Version $Id: askdir.c 5503 2007-09-09 10:03:23Z kerns $
-+ * Version $Id: askdir.c 5852 2007-11-04 19:57:42Z kerns $
- */
-
- #include "bacula.h" /* pull in global headers */
-@@ -42,7 +42,7 @@
- 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 @@
- } 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 @@
- 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_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 @@
- 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 @@
- &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 @@
- 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 @@
- 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 @@
- 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 @@
- * 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 @@
- 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 @@
- 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 @@
- }
-
- 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 @@
- 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 @@
- 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();
- }
-
-
-diff -ur k1/src/stored/bcopy.c k3/src/stored/bcopy.c
---- k1/src/stored/bcopy.c 2007-12-03 20:27:38.000000000 +0100
-+++ k3/src/stored/bcopy.c 2007-12-22 19:10:29.000000000 +0100
-@@ -32,7 +32,7 @@
- * Kern E. Sibbald, October 2002
- *
- *
-- * Version $Id: bcopy.c 6017 2007-12-03 19:27:38Z kerns $
-+ * Version $Id: bcopy.c 6016 2007-12-03 19:27:21Z kerns $
- */
-
- #include "bacula.h"
-@@ -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 *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 @@
- "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 @@
- 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 @@
- 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 @@
- *
- */
- 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 @@
- 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;}
-diff -ur k1/src/stored/bextract.c k3/src/stored/bextract.c
---- k1/src/stored/bextract.c 2007-10-03 13:36:47.000000000 +0200
-+++ k3/src/stored/bextract.c 2007-12-22 19:10:20.000000000 +0100
-@@ -4,7 +4,7 @@
- *
- * Kern E. Sibbald, MM
- *
-- * Version $Id: bextract.c 5713 2007-10-03 11:36:47Z kerns $
-+ * Version $Id: bextract.c 5852 2007-11-04 19:57:42Z kerns $
- *
- */
- /*
-@@ -79,7 +79,7 @@
- "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 @@
- 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 @@
-
- /* 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;}
-diff -ur k1/src/stored/block.c k3/src/stored/block.c
---- k1/src/stored/block.c 2007-10-03 13:36:47.000000000 +0200
-+++ k3/src/stored/block.c 2007-12-22 19:12:33.000000000 +0100
-@@ -32,7 +32,7 @@
- * Kern Sibbald, March MMI
- * added BB02 format October MMII
- *
-- * Version $Id: block.c 5713 2007-10-03 11:36:47Z kerns $
-+ * Version $Id: block.c 5852 2007-11-04 19:57:42Z kerns $
- *
- */
-
-@@ -746,7 +746,7 @@
- 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 @@
- 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 @@
-
- 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;
-diff -ur k1/src/stored/bls.c k3/src/stored/bls.c
---- k1/src/stored/bls.c 2007-10-03 13:36:47.000000000 +0200
-+++ k3/src/stored/bls.c 2007-12-22 19:10:57.000000000 +0100
-@@ -31,7 +31,7 @@
- *
- * Kern Sibbald, MM
- *
-- * Version $Id: bls.c 5713 2007-10-03 11:36:47Z kerns $
-+ * Version $Id: bls.c 5852 2007-11-04 19:57:42Z kerns $
- */
-
- #include "bacula.h"
-@@ -79,7 +79,7 @@
- "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 @@
- 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 @@
-
- /* 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;}
-diff -ur k1/src/stored/bscan.c k3/src/stored/bscan.c
---- k1/src/stored/bscan.c 2007-10-03 13:36:47.000000000 +0200
-+++ k3/src/stored/bscan.c 2007-12-22 19:11:05.000000000 +0100
-@@ -34,7 +34,7 @@
- * Kern E. Sibbald, December 2001
- *
- *
-- * Version $Id: bscan.c 5713 2007-10-03 11:36:47Z kerns $
-+ * Version $Id: bscan.c 5852 2007-11-04 19:57:42Z kerns $
- */
-
- #include "bacula.h"
-@@ -116,7 +116,7 @@
- "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 @@
- 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 @@
-
- /* 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;}
-diff -ur k1/src/stored/btape.c k3/src/stored/btape.c
---- k1/src/stored/btape.c 2007-06-07 16:46:43.000000000 +0200
-+++ k3/src/stored/btape.c 2007-12-22 19:11:14.000000000 +0100
-@@ -37,7 +37,7 @@
- * Note, this program reads stored.conf, and will only
- * talk to devices that are configured.
- *
-- * Version $Id: btape.c 4992 2007-06-07 14:46:43Z kerns $
-+ * Version $Id: btape.c 5852 2007-11-04 19:57:42Z kerns $
- *
- */
-
-@@ -220,9 +220,13 @@
- 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 @@
- "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 @@
- 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;
- }
-diff -ur k1/src/stored/dev.c k3/src/stored/dev.c
---- k1/src/stored/dev.c 2007-12-02 19:03:17.000000000 +0100
-+++ k3/src/stored/dev.c 2007-12-22 19:11:57.000000000 +0100
-@@ -47,7 +47,7 @@
- * daemon. More complicated coding (double buffering, writer
- * thread, ...) is left for a later version.
- *
-- * Version $Id: dev.c 6011 2007-12-02 18:03:17Z kerns $
-+ * Version $Id: dev.c 5999 2007-11-29 21:36:36Z ricozz $
- */
-
- /*
-@@ -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 @@
- 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 @@
- 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 *mode_to_str(int mode)
-+static const char *mode_to_str(int mode)
- {
- static char buf[100];
- if (mode < 1 || mode > 4) {
-diff -ur k1/src/stored/dev.h k3/src/stored/dev.h
---- k1/src/stored/dev.h 2007-09-09 12:03:23.000000000 +0200
-+++ k3/src/stored/dev.h 2007-12-22 19:12:14.000000000 +0100
-@@ -31,7 +31,7 @@
- *
- * Kern Sibbald, MM
- *
-- * Version $Id: dev.h 5503 2007-09-09 10:03:23Z kerns $
-+ * Version $Id: dev.h 5852 2007-11-04 19:57:42Z kerns $
- *
- */
-
-@@ -158,6 +158,7 @@
- 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 @@
- 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 */
- };
-
-
-diff -ur k1/src/stored/device.c k3/src/stored/device.c
---- k1/src/stored/device.c 2007-06-29 14:12:26.000000000 +0200
-+++ k3/src/stored/device.c 2007-12-22 19:11:23.000000000 +0100
-@@ -53,7 +53,7 @@
- *
- * Kern Sibbald, MM, MMI
- *
-- * Version $Id: device.c 5114 2007-06-29 12:12:26Z kerns $
-+ * Version $Id: device.c 5852 2007-11-04 19:57:42Z kerns $
- */
-
- #include "bacula.h" /* pull in global headers */
-@@ -122,7 +122,8 @@
- 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 @@
- 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)));
-diff -ur k1/src/stored/dvd.c k3/src/stored/dvd.c
---- k1/src/stored/dvd.c 2007-06-07 16:46:43.000000000 +0200
-+++ k3/src/stored/dvd.c 2007-12-22 19:26:23.000000000 +0100
-@@ -1,16 +1,7 @@
- /*
-- *
-- * dvd.c -- Routines specific to DVD devices (and
-- * possibly other removable hard media).
-- *
-- * Nicolas Boichat, MMV
-- *
-- * Version $Id: dvd.c 4992 2007-06-07 14:46:43Z kerns $
-- */
--/*
- Bacula® - The Network Backup Solution
-
-- Copyright (C) 2005-2006 Free Software Foundation Europe e.V.
-+ Copyright (C) 2005-2007 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.
-@@ -34,6 +25,15 @@
- (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: dvd.c 5852 2007-11-04 19:57:42Z kerns $
-+ */
-
- #include "bacula.h"
- #include "stored.h"
-@@ -686,7 +686,7 @@
- dcr->VolCatInfo.VolCatBytes = 0;
-
- /* Update catalog */
-- if (!dir_update_volume_info(dcr, false)) {
-+ if (!dir_update_volume_info(dcr, false, true)) {
- return false;
- }
-
-diff -ur k1/src/stored/job.c k3/src/stored/job.c
---- k1/src/stored/job.c 2007-09-29 00:01:16.000000000 +0200
-+++ k3/src/stored/job.c 2007-12-22 19:11:41.000000000 +0100
-@@ -30,7 +30,7 @@
- *
- * Kern Sibbald, MM
- *
-- * Version $Id: job.c 5686 2007-09-28 22:01:16Z kerns $
-+ * Version $Id: job.c 5697 2007-09-30 17:40:08Z ricozz $
- *
- */
-
-@@ -49,9 +49,13 @@
- /* 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 @@
- {
- 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 @@
- * 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 @@
- 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);
-diff -ur k1/src/stored/label.c k3/src/stored/label.c
---- k1/src/stored/label.c 2007-10-03 13:36:47.000000000 +0200
-+++ k3/src/stored/label.c 2007-12-22 19:10:49.000000000 +0100
-@@ -32,7 +32,7 @@
- * Kern Sibbald, MM
- *
- *
-- * Version $Id: label.c 5713 2007-10-03 11:36:47Z kerns $
-+ * Version $Id: label.c 5852 2007-11-04 19:57:42Z kerns $
- */
-
- #include "bacula.h" /* pull in global headers */
-@@ -505,7 +505,7 @@
- }
- 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 @@
- }
- 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);
-diff -ur k1/src/stored/mount.c k3/src/stored/mount.c
---- k1/src/stored/mount.c 2007-09-14 11:49:06.000000000 +0200
-+++ k3/src/stored/mount.c 2007-12-22 19:11:30.000000000 +0100
-@@ -32,7 +32,7 @@
- *
- * Kern Sibbald, August MMII
- *
-- * Version $Id: mount.c 5552 2007-09-14 09:49:06Z kerns $
-+ * Version $Id: mount.c 5852 2007-11-04 19:57:42Z kerns $
- */
-
- #include "bacula.h" /* pull in global headers */
-@@ -60,7 +60,7 @@
- * 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 @@
- * 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 @@
- * 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 @@
- }
- 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 @@
- 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 @@
- 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 @@
- 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 @@
- /*
- * 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));
-diff -ur k1/src/stored/protos.h k3/src/stored/protos.h
---- k1/src/stored/protos.h 2007-06-28 13:57:03.000000000 +0200
-+++ k3/src/stored/protos.h 2007-12-22 19:12:43.000000000 +0100
-@@ -28,7 +28,7 @@
- /*
- * Protypes for stored -- Kern Sibbald MM
- *
-- * Version $Id: protos.h 5112 2007-06-28 11:57:03Z kerns $
-+ * Version $Id: protos.h 5852 2007-11-04 19:57:42Z kerns $
- */
-
- /* From stored.c */
-@@ -49,7 +49,7 @@
- };
- 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 @@
- 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);
-
-diff -ur k1/src/stored/record.c k3/src/stored/record.c
---- k1/src/stored/record.c 2007-06-07 16:46:43.000000000 +0200
-+++ k3/src/stored/record.c 2007-12-22 19:12:06.000000000 +0100
-@@ -1,14 +1,4 @@
- /*
-- *
-- * record.c -- tape record handling functions
-- *
-- * Kern Sibbald, April MMI
-- * added BB02 format October MMII
-- *
-- * Version $Id: record.c 4992 2007-06-07 14:46:43Z kerns $
-- *
-- */
--/*
- Bacula® - The Network Backup Solution
-
- Copyright (C) 2001-2006 Free Software Foundation Europe e.V.
-@@ -35,6 +25,16 @@
- (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: record.c 6014 2007-12-03 18:14:27Z kerns $
-+ *
-+ */
-
-
- #include "bacula.h"
-@@ -254,7 +254,7 @@
- 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 @@
- 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);
-diff -ur k1/src/stored/reserve.c k3/src/stored/reserve.c
---- k1/src/stored/reserve.c 2007-08-04 18:46:32.000000000 +0200
-+++ k3/src/stored/reserve.c 2007-12-22 19:09:56.000000000 +0100
-@@ -212,11 +212,11 @@
- 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 @@
- * 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 @@
- * 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);
-- debug_list_volumes("reserve_vol free");
- vol_list->remove(vol);
- free_vol_item(vol);
-+ debug_list_volumes("reserve_vol free");
- }
- }
-
-@@ -378,12 +379,16 @@
- 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 @@
- * 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 @@
- 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 @@
- */
- 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 @@
- 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 @@
- 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 @@
- 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 @@
- * 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"),
--- /dev/null
+
+ This patch fixes a float point editing bug introduced in 2.2.7 (I think)
+ causing the rate fields to be formated incorrectly (actually trunctated).
+ This fixes bug #1036.
+
+ Apply it to version 2.2.7 with:
+
+ cd <bacula-source>
+ patch -p0 <2.2.7-fpformat.patch
+ ./configure <your-options>
+ make
+ ...
+ make install
+
+
+Index: src/lib/bsnprintf.c
+===================================================================
+--- src/lib/bsnprintf.c (revision 6183)
++++ src/lib/bsnprintf.c (working copy)
+@@ -16,7 +16,7 @@
+ /*
+ Bacula® - The Network Backup Solution
+
+- Copyright (C) 2005-2007 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.
+@@ -566,11 +566,11 @@
+ return result;
+ }
+
+-static long round(LDOUBLE value)
++static int64_t round(LDOUBLE value)
+ {
+- long intpart;
++ int64_t intpart;
+
+- intpart = (long)value;
++ intpart = (int64_t)value;
+ value = value - intpart;
+ if (value >= 0.5)
+ intpart++;
+@@ -584,8 +584,8 @@
+ int signvalue = 0;
+ LDOUBLE ufvalue;
+ #ifndef HAVE_FCVT
+- char iconvert[25];
+- char fconvert[25];
++ char iconvert[311];
++ char fconvert[311];
+ #else
+ char iconvert[311];
+ char fconvert[311];
+@@ -602,6 +602,7 @@
+ int caps = 0;
+ int64_t intpart;
+ int64_t fracpart;
++ const char *cvt_str;
+
+ /*
+ * AIX manpage says the default is 0, but Solaris says the default
+@@ -625,7 +626,7 @@
+ #endif
+
+ #ifndef HAVE_FCVT
+- intpart = (long)ufvalue;
++ intpart = (int64_t)ufvalue;
+
+ /*
+ * Sorry, we only support 9 digits past the decimal because of our
+@@ -645,28 +646,30 @@
+ }
+
+ #ifdef DEBUG_SNPRINTF
+- printf("fmtfp: %g %d.%d min=%d max=%d\n",
++ printf("fmtfp: %g %lld.%lld min=%d max=%d\n",
+ (double)fvalue, intpart, fracpart, min, max);
+ #endif
+
+ /* Convert integer part */
++ cvt_str = caps ? "0123456789ABCDEF" : "0123456789abcdef";
+ do {
+- iconvert[iplace++] =
+- (caps ? "0123456789ABCDEF" : "0123456789abcdef")[intpart % 10];
++ iconvert[iplace++] = cvt_str[(int)(intpart % 10)];
+ intpart = (intpart / 10);
+- } while (intpart && (iplace < (int)sizeof(iplace)));
+- if (iplace == (int)sizeof(iplace)) {
++ } while (intpart && (iplace < (int)sizeof(iconvert)));
++
++ if (iplace == (int)sizeof(fconvert)) {
+ iplace--;
+ }
+ iconvert[iplace] = 0;
+
+ /* Convert fractional part */
++ cvt_str = caps ? "0123456789ABCDEF" : "0123456789abcdef";
+ do {
+- fconvert[fplace++] =
+- (caps ? "0123456789ABCDEF" : "0123456789abcdef")[fracpart % 10];
++ fconvert[fplace++] = cvt_str[fracpart % 10];
+ fracpart = (fracpart / 10);
+- } while (fracpart && (fplace < (int)sizeof(fplace)));
+- if (fplace == (int)sizeof(fplace)) {
++ } while (fracpart && (fplace < (int)sizeof(fconvert)));
++
++ if (fplace == (int)sizeof(fconvert)) {
+ fplace--;
+ }
+ fconvert[fplace] = 0;
+@@ -825,7 +828,7 @@
+ NULL
+ };
+ double fp_nums[] = { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
+- 0.9996, 1.996, 4.136, 6442452944.1234, 0
++ 0.9996, 1.996, 4.136, 6442452944.1234, 0, 23365.5
+ };
+ #endif
+ char *int_fmt[] = {
--- /dev/null
+
+ This patch permits to use migration options with JobDefs.
+ This patch fixes bug #1028.
+
+ Apply the patch to 2.2.7 (and possibly any 2.2.x version with):
+
+ cd <bacula-source>
+ patch -p0 <2.2.7-jobdefs-migtype.patch
+ ./configure <your-options>
+ make
+ ...
+ make install
+
+Index: src/dird/dird.c
+===================================================================
+--- src/dird/dird.c (revision 6183)
++++ src/dird/dird.c (working copy)
+@@ -58,6 +58,7 @@
+ void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass);
+ void store_level(LEX *lc, RES_ITEM *item, int index, int pass);
+ void store_replace(LEX *lc, RES_ITEM *item, int index, int pass);
++void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass);
+ void init_device_resources();
+
+ static char *runjob = NULL;
+@@ -698,6 +699,7 @@
+ job_items[i].handler == store_jobtype ||
+ job_items[i].handler == store_level ||
+ job_items[i].handler == store_pint ||
++ job_items[i].handler == store_migtype ||
+ job_items[i].handler == store_replace) {
+ def_ivalue = (int *)((char *)(job->jobdefs) + offset);
+ Dmsg5(400, "Job \"%s\", field \"%s\" def_ivalue=%d item %d offset=%u\n",
+Index: src/dird/dird_conf.c
+===================================================================
+--- src/dird/dird_conf.c (revision 6183)
++++ src/dird/dird_conf.c (working copy)
+@@ -74,8 +74,8 @@
+ void store_level(LEX *lc, RES_ITEM *item, int index, int pass);
+ void store_replace(LEX *lc, RES_ITEM *item, int index, int pass);
+ void store_acl(LEX *lc, RES_ITEM *item, int index, int pass);
++void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass);
+ static void store_device(LEX *lc, RES_ITEM *item, int index, int pass);
+-static void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass);
+ static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass);
+ static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass);
+ static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass);
+@@ -1548,7 +1548,7 @@
+ * Store JobType (backup, verify, restore)
+ *
+ */
+-static void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
++void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
+ {
+ int token, i;
+
--- /dev/null
+
+ This patch fixes bug #1034 about Temporary MySQL table 'batch'
+ disappears if MySQL connection times out.
+
+ Apply the patch to 2.2.7 (and possibly any 2.2.x version with):
+
+ cd <bacula-source>
+ patch -p0 <2.2.7-mysql-batch-timeout.patch
+ ./configure <your-options>
+ make
+ ...
+ make install
+
+
+
+Index: src/cats/mysql.c
+===================================================================
+--- src/cats/mysql.c (révision 6192)
++++ src/cats/mysql.c (copie de travail)
+@@ -205,6 +205,10 @@
+ Dmsg3(100, "opendb ref=%d connected=%d db=%p\n", mdb->ref_count,
+ mdb->connected, mdb->db);
+
++ /* Set connection timeout to 8 days specialy for batch mode */
++ sql_query(mdb, "SET wait_timeout=691200");
++ sql_query(mdb, "SET interactive_timeout=691200");
++
+ V(mutex);
+ return 1;
+ }
--- /dev/null
+
+ If you have an old version of PostgreSQL, for example,
+ version 7.3 or older, it may not properly build with the current
+ Bacula release due to incompatible changes in the PostgreSQL
+ header files between version. Only in the case that build fails,
+ you might try applying this patch with:
+
+ cd <bacula-2.2.7-source>
+ patch -p1 <2.2.7-old-postgresql.patch
+ ./configure <your-options>
+ make
+ ...
+ make install
+
+
+diff -uNr bacula-2.2.7/src/cats/postgresql.c bacula-2.2.7-fixed/src/cats/postgresql.c
+--- bacula-2.2.7/src/cats/postgresql.c 2007-12-08 04:54:55.000000000 -0500
++++ bacula-2.2.7-fixed/src/cats/postgresql.c 2007-12-29 08:34:10.000000000 -0500
+@@ -47,7 +47,6 @@
+ #ifdef HAVE_POSTGRESQL
+
+ #include "postgres_ext.h" /* needed for NAMEDATALEN */
+-#include "pg_config_manual.h" /* get NAMEDATALEN on version 8.3 or later */
+
+ /* -----------------------------------------------------------------------
+ *
--- /dev/null
+
+ This patch has a number of cleanups and improvements to the SD
+ reservations system. It should fix a number of problems with
+ dual drive autochangers as well ensure that volume use durations
+ and max volume jobs are better respected.
+
+ Apply it to version 2.2.7 (possibly some earlier versions) with:
+
+ cd <bacula-source>
+ patch -p1 <2.2.7-reserve.patch
+ ./configure <your options>
+ make
+ ...
+ make install
+
+
+diff -ur k1/src/lib/message.c k3/src/lib/message.c
+--- k1/src/lib/message.c 2007-10-19 13:47:58.000000000 +0200
++++ k3/src/lib/message.c 2007-12-22 19:13:00.000000000 +0100
+@@ -54,6 +54,7 @@
+ 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 */
+diff -ur k1/src/lib/message.h k3/src/lib/message.h
+--- k1/src/lib/message.h 2007-10-03 13:36:47.000000000 +0200
++++ k3/src/lib/message.h 2007-12-22 19:13:06.000000000 +0100
+@@ -154,6 +154,7 @@
+ 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;
+diff -ur k1/src/stored/acquire.c k3/src/stored/acquire.c
+--- k1/src/stored/acquire.c 2007-09-14 11:49:06.000000000 +0200
++++ k3/src/stored/acquire.c 2007-12-22 19:12:23.000000000 +0100
+@@ -30,7 +30,7 @@
+ *
+ * Kern Sibbald, August MMII
+ *
+- * Version $Id: acquire.c 5552 2007-09-14 09:49:06Z kerns $
++ * Version $Id: acquire.c 6081 2007-12-21 14:11:40Z kerns $
+ */
+
+ #include "bacula.h" /* pull in global headers */
+@@ -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 @@
+ */
+ 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 @@
+ 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->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 @@
+ * 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 @@
+ }
+ } 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 @@
+ 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 @@
+ 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 @@
+ }
+
+
++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 @@
+ 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 @@
+ 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 @@
+ 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);
+diff -ur k1/src/stored/askdir.c k3/src/stored/askdir.c
+--- k1/src/stored/askdir.c 2007-09-09 12:03:23.000000000 +0200
++++ k3/src/stored/askdir.c 2007-12-22 19:11:50.000000000 +0100
+@@ -31,7 +31,7 @@
+ *
+ * Kern Sibbald, December 2000
+ *
+- * Version $Id: askdir.c 5503 2007-09-09 10:03:23Z kerns $
++ * Version $Id: askdir.c 5852 2007-11-04 19:57:42Z kerns $
+ */
+
+ #include "bacula.h" /* pull in global headers */
+@@ -42,7 +42,7 @@
+ 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 @@
+ } 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 @@
+ 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_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 @@
+ 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 @@
+ &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 @@
+ 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 @@
+ 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 @@
+ 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 @@
+ * 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 @@
+ 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 @@
+ 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 @@
+ }
+
+ 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 @@
+ 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 @@
+ 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();
+ }
+
+
+diff -ur k1/src/stored/bcopy.c k3/src/stored/bcopy.c
+--- k1/src/stored/bcopy.c 2007-12-03 20:27:38.000000000 +0100
++++ k3/src/stored/bcopy.c 2007-12-22 19:10:29.000000000 +0100
+@@ -32,7 +32,7 @@
+ * Kern E. Sibbald, October 2002
+ *
+ *
+- * Version $Id: bcopy.c 6017 2007-12-03 19:27:38Z kerns $
++ * Version $Id: bcopy.c 6016 2007-12-03 19:27:21Z kerns $
+ */
+
+ #include "bacula.h"
+@@ -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 *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 @@
+ "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 @@
+ 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 @@
+ 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 @@
+ *
+ */
+ 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 @@
+ 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;}
+diff -ur k1/src/stored/bextract.c k3/src/stored/bextract.c
+--- k1/src/stored/bextract.c 2007-10-03 13:36:47.000000000 +0200
++++ k3/src/stored/bextract.c 2007-12-22 19:10:20.000000000 +0100
+@@ -4,7 +4,7 @@
+ *
+ * Kern E. Sibbald, MM
+ *
+- * Version $Id: bextract.c 5713 2007-10-03 11:36:47Z kerns $
++ * Version $Id: bextract.c 5852 2007-11-04 19:57:42Z kerns $
+ *
+ */
+ /*
+@@ -79,7 +79,7 @@
+ "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 @@
+ 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 @@
+
+ /* 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;}
+diff -ur k1/src/stored/block.c k3/src/stored/block.c
+--- k1/src/stored/block.c 2007-10-03 13:36:47.000000000 +0200
++++ k3/src/stored/block.c 2007-12-22 19:12:33.000000000 +0100
+@@ -32,7 +32,7 @@
+ * Kern Sibbald, March MMI
+ * added BB02 format October MMII
+ *
+- * Version $Id: block.c 5713 2007-10-03 11:36:47Z kerns $
++ * Version $Id: block.c 5852 2007-11-04 19:57:42Z kerns $
+ *
+ */
+
+@@ -746,7 +746,7 @@
+ 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 @@
+ 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 @@
+
+ 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;
+diff -ur k1/src/stored/bls.c k3/src/stored/bls.c
+--- k1/src/stored/bls.c 2007-10-03 13:36:47.000000000 +0200
++++ k3/src/stored/bls.c 2007-12-22 19:10:57.000000000 +0100
+@@ -31,7 +31,7 @@
+ *
+ * Kern Sibbald, MM
+ *
+- * Version $Id: bls.c 5713 2007-10-03 11:36:47Z kerns $
++ * Version $Id: bls.c 5852 2007-11-04 19:57:42Z kerns $
+ */
+
+ #include "bacula.h"
+@@ -79,7 +79,7 @@
+ "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 @@
+ 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 @@
+
+ /* 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;}
+diff -ur k1/src/stored/bscan.c k3/src/stored/bscan.c
+--- k1/src/stored/bscan.c 2007-10-03 13:36:47.000000000 +0200
++++ k3/src/stored/bscan.c 2007-12-22 19:11:05.000000000 +0100
+@@ -34,7 +34,7 @@
+ * Kern E. Sibbald, December 2001
+ *
+ *
+- * Version $Id: bscan.c 5713 2007-10-03 11:36:47Z kerns $
++ * Version $Id: bscan.c 5852 2007-11-04 19:57:42Z kerns $
+ */
+
+ #include "bacula.h"
+@@ -116,7 +116,7 @@
+ "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 @@
+ 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 @@
+
+ /* 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;}
+diff -ur k1/src/stored/btape.c k3/src/stored/btape.c
+--- k1/src/stored/btape.c 2007-06-07 16:46:43.000000000 +0200
++++ k3/src/stored/btape.c 2007-12-22 19:11:14.000000000 +0100
+@@ -37,7 +37,7 @@
+ * Note, this program reads stored.conf, and will only
+ * talk to devices that are configured.
+ *
+- * Version $Id: btape.c 4992 2007-06-07 14:46:43Z kerns $
++ * Version $Id: btape.c 5852 2007-11-04 19:57:42Z kerns $
+ *
+ */
+
+@@ -220,9 +220,13 @@
+ 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 @@
+ "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 @@
+ 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;
+ }
+diff -ur k1/src/stored/dev.c k3/src/stored/dev.c
+--- k1/src/stored/dev.c 2007-12-02 19:03:17.000000000 +0100
++++ k3/src/stored/dev.c 2007-12-22 19:11:57.000000000 +0100
+@@ -47,7 +47,7 @@
+ * daemon. More complicated coding (double buffering, writer
+ * thread, ...) is left for a later version.
+ *
+- * Version $Id: dev.c 6011 2007-12-02 18:03:17Z kerns $
++ * Version $Id: dev.c 5999 2007-11-29 21:36:36Z ricozz $
+ */
+
+ /*
+@@ -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 @@
+ 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 @@
+ 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 *mode_to_str(int mode)
++static const char *mode_to_str(int mode)
+ {
+ static char buf[100];
+ if (mode < 1 || mode > 4) {
+diff -ur k1/src/stored/dev.h k3/src/stored/dev.h
+--- k1/src/stored/dev.h 2007-09-09 12:03:23.000000000 +0200
++++ k3/src/stored/dev.h 2007-12-22 19:12:14.000000000 +0100
+@@ -31,7 +31,7 @@
+ *
+ * Kern Sibbald, MM
+ *
+- * Version $Id: dev.h 5503 2007-09-09 10:03:23Z kerns $
++ * Version $Id: dev.h 5852 2007-11-04 19:57:42Z kerns $
+ *
+ */
+
+@@ -158,6 +158,7 @@
+ 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 @@
+ 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 */
+ };
+
+
+diff -ur k1/src/stored/device.c k3/src/stored/device.c
+--- k1/src/stored/device.c 2007-06-29 14:12:26.000000000 +0200
++++ k3/src/stored/device.c 2007-12-22 19:11:23.000000000 +0100
+@@ -53,7 +53,7 @@
+ *
+ * Kern Sibbald, MM, MMI
+ *
+- * Version $Id: device.c 5114 2007-06-29 12:12:26Z kerns $
++ * Version $Id: device.c 5852 2007-11-04 19:57:42Z kerns $
+ */
+
+ #include "bacula.h" /* pull in global headers */
+@@ -122,7 +122,8 @@
+ 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 @@
+ 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)));
+diff -ur k1/src/stored/dvd.c k3/src/stored/dvd.c
+--- k1/src/stored/dvd.c 2007-06-07 16:46:43.000000000 +0200
++++ k3/src/stored/dvd.c 2007-12-22 19:26:23.000000000 +0100
+@@ -1,16 +1,7 @@
+ /*
+- *
+- * dvd.c -- Routines specific to DVD devices (and
+- * possibly other removable hard media).
+- *
+- * Nicolas Boichat, MMV
+- *
+- * Version $Id: dvd.c 4992 2007-06-07 14:46:43Z kerns $
+- */
+-/*
+ Bacula® - The Network Backup Solution
+
+- Copyright (C) 2005-2006 Free Software Foundation Europe e.V.
++ Copyright (C) 2005-2007 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.
+@@ -34,6 +25,15 @@
+ (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: dvd.c 5852 2007-11-04 19:57:42Z kerns $
++ */
+
+ #include "bacula.h"
+ #include "stored.h"
+@@ -686,7 +686,7 @@
+ dcr->VolCatInfo.VolCatBytes = 0;
+
+ /* Update catalog */
+- if (!dir_update_volume_info(dcr, false)) {
++ if (!dir_update_volume_info(dcr, false, true)) {
+ return false;
+ }
+
+diff -ur k1/src/stored/job.c k3/src/stored/job.c
+--- k1/src/stored/job.c 2007-09-29 00:01:16.000000000 +0200
++++ k3/src/stored/job.c 2007-12-22 19:11:41.000000000 +0100
+@@ -30,7 +30,7 @@
+ *
+ * Kern Sibbald, MM
+ *
+- * Version $Id: job.c 5686 2007-09-28 22:01:16Z kerns $
++ * Version $Id: job.c 5697 2007-09-30 17:40:08Z ricozz $
+ *
+ */
+
+@@ -49,9 +49,13 @@
+ /* 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 @@
+ {
+ 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 @@
+ * 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 @@
+ 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);
+diff -ur k1/src/stored/label.c k3/src/stored/label.c
+--- k1/src/stored/label.c 2007-10-03 13:36:47.000000000 +0200
++++ k3/src/stored/label.c 2007-12-22 19:10:49.000000000 +0100
+@@ -32,7 +32,7 @@
+ * Kern Sibbald, MM
+ *
+ *
+- * Version $Id: label.c 5713 2007-10-03 11:36:47Z kerns $
++ * Version $Id: label.c 5852 2007-11-04 19:57:42Z kerns $
+ */
+
+ #include "bacula.h" /* pull in global headers */
+@@ -505,7 +505,7 @@
+ }
+ 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 @@
+ }
+ 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);
+diff -ur k1/src/stored/mount.c k3/src/stored/mount.c
+--- k1/src/stored/mount.c 2007-09-14 11:49:06.000000000 +0200
++++ k3/src/stored/mount.c 2007-12-22 19:11:30.000000000 +0100
+@@ -32,7 +32,7 @@
+ *
+ * Kern Sibbald, August MMII
+ *
+- * Version $Id: mount.c 5552 2007-09-14 09:49:06Z kerns $
++ * Version $Id: mount.c 5852 2007-11-04 19:57:42Z kerns $
+ */
+
+ #include "bacula.h" /* pull in global headers */
+@@ -60,7 +60,7 @@
+ * 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 @@
+ * 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 @@
+ * 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 @@
+ }
+ 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 @@
+ 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 @@
+ 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 @@
+ 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 @@
+ /*
+ * 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));
+diff -ur k1/src/stored/protos.h k3/src/stored/protos.h
+--- k1/src/stored/protos.h 2007-06-28 13:57:03.000000000 +0200
++++ k3/src/stored/protos.h 2007-12-22 19:12:43.000000000 +0100
+@@ -28,7 +28,7 @@
+ /*
+ * Protypes for stored -- Kern Sibbald MM
+ *
+- * Version $Id: protos.h 5112 2007-06-28 11:57:03Z kerns $
++ * Version $Id: protos.h 5852 2007-11-04 19:57:42Z kerns $
+ */
+
+ /* From stored.c */
+@@ -49,7 +49,7 @@
+ };
+ 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 @@
+ 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);
+
+diff -ur k1/src/stored/record.c k3/src/stored/record.c
+--- k1/src/stored/record.c 2007-06-07 16:46:43.000000000 +0200
++++ k3/src/stored/record.c 2007-12-22 19:12:06.000000000 +0100
+@@ -1,14 +1,4 @@
+ /*
+- *
+- * record.c -- tape record handling functions
+- *
+- * Kern Sibbald, April MMI
+- * added BB02 format October MMII
+- *
+- * Version $Id: record.c 4992 2007-06-07 14:46:43Z kerns $
+- *
+- */
+-/*
+ Bacula® - The Network Backup Solution
+
+ Copyright (C) 2001-2006 Free Software Foundation Europe e.V.
+@@ -35,6 +25,16 @@
+ (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: record.c 6014 2007-12-03 18:14:27Z kerns $
++ *
++ */
+
+
+ #include "bacula.h"
+@@ -254,7 +254,7 @@
+ 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 @@
+ 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);
+diff -ur k1/src/stored/reserve.c k3/src/stored/reserve.c
+--- k1/src/stored/reserve.c 2007-08-04 18:46:32.000000000 +0200
++++ k3/src/stored/reserve.c 2007-12-22 19:09:56.000000000 +0100
+@@ -212,11 +212,11 @@
+ 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 @@
+ * 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 @@
+ * 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);
+- debug_list_volumes("reserve_vol free");
+ vol_list->remove(vol);
+ free_vol_item(vol);
++ debug_list_volumes("reserve_vol free");
+ }
+ }
+
+@@ -378,12 +379,16 @@
+ 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 @@
+ * 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 @@
+ 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 @@
+ */
+ 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 @@
+ 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 @@
+ 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 @@
+ 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 @@
+ * 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"),