void my_mysql_free_result(B_DB *mdb)
{
+ db_lock(mdb);
if (mdb->result) {
mysql_free_result(mdb->result);
mdb->result = NULL;
}
+ db_unlock(mdb);
}
char *my_mysql_batch_lock_path_query = "LOCK TABLES Path write, "
void my_postgresql_free_result(B_DB *mdb)
{
+
+ db_lock(mdb);
if (mdb->result) {
PQclear(mdb->result);
mdb->result = NULL;
free(mdb->fields);
mdb->fields = NULL;
}
+ db_unlock(mdb);
}
int my_postgresql_currval(B_DB *mdb, char *table_name)
*/
bool my_batch_start(JCR *jcr, B_DB *mdb)
{
- return db_sql_query(mdb,
+ bool ok;
+
+ db_lock(mdb);
+ ok = db_sql_query(mdb,
" CREATE TEMPORARY TABLE batch "
" (fileindex integer, "
" jobid integer, "
" name blob, "
" lstat tinyblob, "
" md5 tinyblob) ",NULL, NULL);
+ db_unlock(mdb);
+ return ok;
}
/*
if (!complete_jcr_for_job(jcr, job, run->pool)) {
return false;
}
+ if (!jcr->jr.PoolId) {
+ ua->error_msg(_("Could not Pool Job %s\n"), job->name());
+ continue;
+ }
memset(&pr, 0, sizeof(pr));
pr.PoolId = jcr->jr.PoolId;
if (!db_get_pool_record(ua->jcr, ua->db, &pr)) {
get_job_storage(&store, job, run);
mr.StorageId = store.store->StorageId;
if (!find_next_volume_for_append(jcr, &mr, 1, fnv_no_create_vol, fnv_prune)) {
- ua->error_msg(_("Could not find next Volume for Job %s (%s, %s).\n"),
- job->hdr.name, pr.Name, level_to_str(run->level));
+ ua->error_msg(_("Could not find next Volume for Job %s (Pool=%s, Level=%s).\n"),
+ job->name(), pr.Name, level_to_str(run->level));
} else {
ua->send_msg(
- _("The next Volume to be used by Job \"%s\" (%s, %s) will be %s\n"),
- job->hdr.name, pr.Name, level_to_str(run->level), mr.VolumeName);
+ _("The next Volume to be used by Job \"%s\" (Pool=%s, Level=%s) will be %s\n"),
+ job->name(), pr.Name, level_to_str(run->level), mr.VolumeName);
found = true;
}
if (jcr->db && jcr->db != ua->db) {
rctx.store = store;
/*
- * Note, if search_for_device() succeeds, we get a new_dcr,
+ * Note, if search_for_device() succeeds, we get a new dcr,
* which we do not use except for the dev info.
*/
stat = search_res_for_device(rctx);
release_msgs(jcr); /* release queued messages */
unlock_reservations();
if (stat == 1) {
- DCR *new_dcr = jcr->read_dcr;
+ DCR *ndcr = jcr->read_dcr;
dev->unblock(dev_unlocked);
detach_dcr_from_dev(dcr); /* release old device */
/* Copy important info from the new dcr */
- dev = dcr->dev = new_dcr->dev;
+ dev = dcr->dev = ndcr->dev;
jcr->read_dcr = dcr;
- dcr->device = new_dcr->device;
+ dcr->device = ndcr->device;
dcr->max_job_spool_size = dcr->device->max_job_spool_size;
attach_dcr_to_dev(dcr);
- new_dcr->VolumeName[0] = 0;
- free_dcr(new_dcr);
+ ndcr->VolumeName[0] = 0;
+ free_dcr(ndcr);
dev->block(BST_DOING_ACQUIRE);
Jmsg(jcr, M_INFO, 0, _("Media Type change. New device %s chosen.\n"),
dev->print_name());
/*
* Create a new Device Control Record and attach
* it to the device (if this is a real job).
+ * Note, this has been updated so that it can be called first
+ * without a DEVICE, then a second or third time with a DEVICE,
+ * and each time, it should cleanup and point to the new device.
+ * This should facilitate switching devices.
+ * Note, each dcr must point to the controlling job (jcr). However,
+ * a job can have multiple dcrs, so we must not store in the jcr's
+ * structure as previously. The higher level routine must store
+ * this dcr in the right place
+ *
*/
-DCR *new_dcr(JCR *jcr, DEVICE *dev)
+DCR *new_dcr(JCR *jcr, DCR *dcr, DEVICE *dev)
{
- if (jcr) Dmsg2(100, "enter new_dcr JobId=%u dev=%p\n", (uint32_t)jcr->JobId, dev);
- DCR *dcr = (DCR *)malloc(sizeof(DCR));
- memset(dcr, 0, sizeof(DCR));
- dcr->jcr = jcr;
- if (dev) {
+ if (!dcr) {
+ dcr = (DCR *)malloc(sizeof(DCR));
+ memset(dcr, 0, sizeof(DCR));
dcr->tid = pthread_self();
- dcr->dev = dev;
- dcr->device = dev->device;
+ dcr->spool_fd = -1;
+ }
+ dcr->jcr = jcr; /* point back to jcr */
+ /* Set device information, possibly change device */
+ if (dev) {
+ if (dcr->block) {
+ free_block(dcr->block);
+ }
dcr->block = new_block(dev);
+ if (dcr->rec) {
+ free_record(dcr->rec);
+ }
dcr->rec = new_record();
+ if (dcr->attached_to_dev) {
+ detach_dcr_from_dev(dcr);
+ }
dcr->max_job_spool_size = dev->device->max_job_spool_size;
+ dcr->device = dev->device;
+ dcr->dev = dev;
attach_dcr_to_dev(dcr);
}
- dcr->spool_fd = -1;
return dcr;
}
void detach_dcr_from_dev(DCR *dcr)
{
Dmsg1(500, "JobId=%u enter detach_dcr_from_dev\n", (uint32_t)dcr->jcr->JobId);
- unreserve_device(dcr);
/* Detach this dcr only if attached */
- if (dcr->attached_to_dev) {
+ if (dcr->attached_to_dev && dcr->dev) {
+ unreserve_device(dcr);
dcr->dev->attached_dcrs->remove(dcr); /* detach dcr from device */
dcr->attached_to_dev = false;
// remove_dcr_from_dcrs(dcr); /* remove dcr from jcr list */
{
JCR *jcr = dcr->jcr;
- if (dcr->dev) {
- detach_dcr_from_dev(dcr);
- }
+ detach_dcr_from_dev(dcr);
if (dcr->block) {
free_block(dcr->block);
return dev->Slot;
}
/* Virtual disk autochanger */
- if (dcr->device->changer_command[0] ==0) {
+ if (dcr->device->changer_command[0] == 0) {
return 1;
}
-/*
- *
- * Program to scan a Bacula Volume and compare it with
- * the catalog and optionally synchronize the catalog
- * with the tape.
- *
- * Kern E. Sibbald, December 2001
- *
- *
- * Version $Id$
- */
/*
Bacula® - The Network Backup Solution
- Copyright (C) 2001-2006 Free Software Foundation Europe e.V.
+ Copyright (C) 2001-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.
(FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
Switzerland, email:ftf@fsfeurope.org.
*/
+/*
+ *
+ * Program to scan a Bacula Volume and compare it with
+ * the catalog and optionally synchronize the catalog
+ * with the tape.
+ *
+ * Kern E. Sibbald, December 2001
+ *
+ *
+ * Version $Id$
+ */
#include "bacula.h"
#include "stored.h"
Dmsg1(100, "Walk attached jcrs. Volume=%s\n", dev->VolCatInfo.VolCatName);
foreach_dlist(mdcr, dev->attached_dcrs) {
JCR *mjcr = mdcr->jcr;
+ Dmsg1(000, "========== JobId=%u ========\n", mjcr->JobId);
if (mjcr->JobId == 0) {
continue;
}
if (verbose) {
Pmsg1(000, _("Create JobMedia for Job %s\n"), mjcr->Job);
}
- if (dev->is_tape()) {
- mdcr->EndBlock = dcr->EndBlock;
- mdcr->EndFile = dcr->EndFile;
-// } else {
-// mdcr->EndBlock = (uint32_t)dcr->file_addr;
-// mdcr->EndFile = (uint32_t)(dcr->file_addr >> 32);
- }
+ mdcr->StartBlock = dcr->StartBlock;
+ mdcr->StartFile = dcr->StartFile;
+ mdcr->EndBlock = dcr->EndBlock;
+ mdcr->EndFile = dcr->EndFile;
mjcr->read_dcr->VolLastIndex = dcr->VolLastIndex;
if (!create_jobmedia_record(db, mjcr)) {
Pmsg2(000, _("Could not create JobMedia record for Volume=%s Job=%s\n"),
dev->VolCatInfo.VolCatName, mjcr->Job);
}
}
+
+ update_media_record(db, &mr);
+
/* Now let common read routine get up next tape. Note,
* we call mount_next... with bscan's jcr because that is where we
* have the Volume list, but we get attached.
mr->LabelDate = mktime(&tm);
}
lasttime = mr->LabelDate;
+ if (mr->VolJobs == 0) {
+ mr->VolJobs = 1;
+ }
+ if (mr->VolMounts == 0) {
+ mr->VolMounts = 1;
+ }
if (!update_db) {
return 1;
JOBMEDIA_DBR jmr;
DCR *dcr = mjcr->read_dcr;
- if (dev->is_tape()) {
- dcr->EndBlock = dev->EndBlock;
- dcr->EndFile = dev->EndFile;
-#ifdef needed
- } else {
- dcr->EndBlock = (uint32_t)dev->file_addr;
- dcr->EndFile = (uint32_t)(dev->file_addr >> 32);
-#endif
- }
+ dcr->EndBlock = dev->EndBlock;
+ dcr->EndFile = dev->EndFile;
memset(&jmr, 0, sizeof(jmr));
jmr.JobId = mjcr->JobId;
jobjcr->VolSessionId = rec->VolSessionId;
jobjcr->VolSessionTime = rec->VolSessionTime;
jobjcr->ClientId = jr->ClientId;
- jobjcr->read_dcr = new_dcr(jobjcr, dev);
+ jobjcr->dcr = jobjcr->read_dcr = new_dcr(jobjcr, NULL, dev);
return jobjcr;
}
-/*
- *
- * Utility routines for "tool" programs such as bscan, bls,
- * bextract, ... Some routines also used by Bacula.
- *
- * Kern Sibbald, MM
- *
- * Normally nothing in this file is called by the Storage
- * daemon because we interact more directly with the user
- * i.e. printf, ...
- *
- * Version $Id$
- */
/*
Bacula® - The Network Backup Solution
- Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
+ Copyright (C) 2000-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.
(FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
Switzerland, email:ftf@fsfeurope.org.
*/
+/*
+ *
+ * Utility routines for "tool" programs such as bscan, bls,
+ * bextract, ... Some routines also used by Bacula.
+ *
+ * Kern Sibbald, MM
+ *
+ * Normally nothing in this file is called by the Storage
+ * daemon because we interact more directly with the user
+ * i.e. printf, ...
+ *
+ * Version $Id$
+ */
#include "bacula.h"
#include "stored.h"
return NULL;
}
device->dev = dev;
- dcr = new_dcr(jcr, dev);
- jcr->dcr = dcr;
+ jcr->dcr = dcr = new_dcr(jcr, NULL, dev);
if (VolName[0]) {
bstrncpy(dcr->VolumeName, VolName, sizeof(dcr->VolumeName));
}
static bool changer_cmd(JCR *sjcr);
static bool do_label(JCR *jcr, int relabel);
static DCR *find_device(JCR *jcr, POOL_MEM &dev_name, int drive);
-static void read_volume_label(JCR *jcr, DEVICE *dev, int Slot);
+static void read_volume_label(JCR *jcr, DCR *dcr, DEVICE *dev, int Slot);
static void label_volume_if_ok(DCR *dcr, char *oldname,
char *newname, char *poolname,
int Slot, int relabel);
-static bool try_autoload_device(JCR *jcr, int slot, const char *VolName);
+static bool try_autoload_device(JCR *jcr, DCR *dcr, int slot, const char *VolName);
static void send_dir_busy_message(BSOCK *dir, DEVICE *dev);
struct s_cmds {
}
dev->dunlock();
free_dcr(dcr);
- jcr->dcr = NULL;
} else {
bnet_fsend(dir, _("3999 Device \"%s\" not found or could not be opened.\n"), dev_name.c_str());
}
Dmsg0(90, "try_autoload_device - looking for volume_info\n");
- if (!try_autoload_device(dcr->jcr, slot, volname)) {
+ if (!try_autoload_device(dcr->jcr, dcr, slot, volname)) {
goto bail_out; /* error */
}
if (found) {
Dmsg1(100, "Found device %s\n", device->hdr.name);
- dcr = new_dcr(jcr, device->dev);
+ dcr = new_dcr(jcr, NULL, device->dev);
dcr->device = device;
- jcr->dcr = dcr;
}
return dcr;
}
case BST_UNMOUNTED_WAITING_FOR_SYSOP:
case BST_UNMOUNTED:
if (dev->is_autochanger() && slot > 0) {
- try_autoload_device(jcr, slot, "");
+ try_autoload_device(jcr, dcr, slot, "");
}
/* We freed the device, so reopen it and wake any waiting threads */
if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
case BST_NOT_BLOCKED:
if (dev->is_autochanger() && slot > 0) {
- try_autoload_device(jcr, slot, "");
+ try_autoload_device(jcr, dcr, slot, "");
}
if (dev->is_open()) {
if (dev->is_labeled()) {
}
dev->dunlock();
free_dcr(dcr);
- jcr->dcr = NULL;
} else {
bnet_fsend(dir, _("3999 Device \"%s\" not found or could not be opened.\n"), devname.c_str());
}
}
dev->dunlock();
free_dcr(dcr);
- jcr->dcr = NULL;
} else {
bnet_fsend(dir, _("3999 Device \"%s\" not found or could not be opened.\n"), devname.c_str());
}
}
dev->dunlock();
free_dcr(dcr);
- jcr->dcr = NULL;
} else {
bnet_fsend(dir, _("3999 Device \"%s\" not found or could not be opened.\n"), devname.c_str());
}
}
dev->dunlock();
free_dcr(dcr);
- jcr->dcr = NULL;
} else {
bnet_fsend(dir, _("3999 Device \"%s\" not found or could not be opened.\n"), devname.c_str());
}
dev = dcr->dev;
dev->dlock(); /* Use P to avoid indefinite block */
if (!dev->is_open()) {
- read_volume_label(jcr, dev, Slot);
+ read_volume_label(jcr, dcr, dev, Slot);
dev->close();
/* Under certain "safe" conditions, we can steal the lock */
} else if (dev->can_steal_lock()) {
- read_volume_label(jcr, dev, Slot);
+ read_volume_label(jcr, dcr, dev, Slot);
} else if (dev->is_busy() || dev->is_blocked()) {
send_dir_busy_message(dir, dev);
} else { /* device not being used */
- read_volume_label(jcr, dev, Slot);
+ read_volume_label(jcr, dcr, dev, Slot);
}
dev->dunlock();
free_dcr(dcr);
- jcr->dcr = NULL;
} else {
bnet_fsend(dir, _("3999 Device \"%s\" not found or could not be opened.\n"), devname.c_str());
}
*
* Enter with the mutex set
*/
-static void read_volume_label(JCR *jcr, DEVICE *dev, int Slot)
+static void read_volume_label(JCR *jcr, DCR *dcr, DEVICE *dev, int Slot)
{
BSOCK *dir = jcr->dir_bsock;
bsteal_lock_t hold;
- DCR *dcr = jcr->dcr;
dcr->dev = dev;
steal_device_lock(dev, &hold, BST_WRITING_LABEL);
- if (!try_autoload_device(jcr, Slot, "")) {
+ if (!try_autoload_device(jcr, dcr, Slot, "")) {
goto bail_out; /* error */
}
return;
}
-static bool try_autoload_device(JCR *jcr, int slot, const char *VolName)
+static bool try_autoload_device(JCR *jcr, DCR *dcr, int slot, const char *VolName)
{
- DCR *dcr = jcr->dcr;
BSOCK *dir = jcr->dir_bsock;
bstrncpy(dcr->VolumeName, VolName, sizeof(dcr->VolumeName));
}
jcr->dcrs = NULL;
+ /* Avoid a double free */
+ if (jcr->dcr == jcr->read_dcr) {
+ jcr->read_dcr = NULL;
+ }
if (jcr->dcr) {
free_dcr(jcr->dcr);
jcr->dcr = NULL;
DCR *acquire_device_for_append(DCR *dcr);
bool acquire_device_for_read(DCR *dcr);
bool release_device(DCR *dcr);
-DCR *new_dcr(JCR *jcr, DEVICE *dev);
+DCR *new_dcr(JCR *jcr, DCR *dcr, DEVICE *dev);
void free_dcr(DCR *dcr);
void detach_dcr_from_dev(DCR *dcr);
* explicitly read in this drive. This allows the SD to remember
* where the tapes are or last were.
*/
- if (dev->is_tape()) {
+ if (dev->is_tape() || dev->is_autochanger()) {
return true;
} else {
return free_volume(dev);
}
lock_volumes();
foreach_dlist(vol, vol_list) {
- Dmsg3(dbglvl, "jid=%u Unreleased Volume=%s dev=%p\n", jid(), vol->vol_name, vol->dev);
+ if (vol->dev) {
+ Dmsg3(dbglvl, "jid=%u free vol_list Volume=%s dev=%s\n", jid(),
+ vol->vol_name, vol->dev->print_name());
+ } else {
+ Dmsg3(dbglvl, "jid=%u free vol_list Volume=%s dev=%p\n", jid(),
+ vol->vol_name, vol->dev);
+ }
free(vol->vol_name);
vol->vol_name = NULL;
}
}
init_jcr_device_wait_timers(jcr);
+ jcr->dcr = new_dcr(jcr, NULL, NULL); /* get a dcr */
+ if (!jcr->dcr) {
+ BSOCK *dir = jcr->dir_bsock;
+ dir->fsend(_("3939 Could not get dcr\n"));
+ Dmsg1(dbglvl, ">dird: %s", dir->msg);
+ ok = false;
+ }
/*
* At this point, we have a list of all the Director's Storage
* resources indicated for this Job, which include Pool, PoolType,
int repeat = 0;
bool fail = false;
rctx.notify_dir = true;
+
lock_reservations();
for ( ; !fail && !job_canceled(jcr); ) {
while ((msg = (char *)msgs->pop())) {
rctx.VolumeName[0] = 0;
rctx.any_drive = false;
if (!jcr->PreferMountedVols) {
- /* Look for unused drives in autochangers */
+ /*
+ * Here we try to find a drive that is not used.
+ * This will maximize the use of available drives.
+ *
+ */
rctx.num_writers = 20000000; /* start with impossible number */
rctx.low_use_drive = NULL;
rctx.PreferMountedVols = false;
break;
}
}
- /* Look for an exact match all drives */
+ /*
+ * Now we look for a drive that may or may not be in
+ * use.
+ */
+ /* Look for an exact Volume match all drives */
rctx.PreferMountedVols = true;
rctx.exact_match = true;
rctx.autochanger_only = false;
unlock_reservations();
}
+/*
+ * Walk through the autochanger resources and check if
+ * the volume is in one of them.
+ *
+ * Returns: true if volume is in device
+ * false otherwise
+ */
+static bool is_vol_in_autochanger(RCTX &rctx, VOLRES *vol)
+{
+ AUTOCHANGER *changer;
+ Dmsg2(dbglvl, "jid=%u search changers for %s\n", (int)rctx.jcr->JobId,
+ rctx.device_name);
+ foreach_res(changer, R_AUTOCHANGER) {
+ Dmsg2(dbglvl, "jid=%u Try match changer res=%s\n",
+ (int)rctx.jcr->JobId, changer->hdr.name);
+ /* Find resource, and make sure we were able to open it */
+ if (fnmatch(rctx.device_name, changer->hdr.name, 0) == 0) {
+ DEVRES *device;
+ /* Try each device in this AutoChanger */
+ foreach_alist(device, changer->device) {
+ Dmsg2(dbglvl, "jid=%u Try changer device %s\n",
+ (int)rctx.jcr->JobId, device->hdr.name);
+ if (device->dev == vol->dev) {
+ Dmsg2(dbglvl, "jid=%u Found changer device %s\n",
+ (int)rctx.jcr->JobId, device->hdr.name);
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
/*
* Search for a device suitable for this job.
*/
DIRSTORE *store;
char *device_name;
alist *dirstore;
+ DCR *dcr = jcr->dcr;
if (rctx.append) {
dirstore = jcr->write_store;
rctx.PreferMountedVols, rctx.exact_match, rctx.suitable_device,
rctx.autochanger_only);
+ /*
+ * If the appropriate conditions of this if are met, namely that
+ * we are appending and the user wants mounted drive (or we
+ * force try a mounted drive because they are all busy), we
+ * start by looking at all the Volumes in the volume list.
+ */
if (!vol_list->empty() && rctx.append && rctx.PreferMountedVols) {
dlist *temp_vol_list, *save_vol_list;
VOLRES *vol = NULL;
unlock_volumes();
/* Look through reserved volumes for one we can use */
+ Dmsg1(dbglvl, "jid=%u look for vol in vol list\n", (int)rctx.jcr->JobId);
foreach_dlist(vol, temp_vol_list) {
if (!vol->dev) {
+ Dmsg2(dbglvl, "jid=%u vol=%s no dev\n", (int)rctx.jcr->JobId, vol->vol_name);
+ continue;
+ }
+ /* Check with Director if this Volume is OK */
+ bstrncpy(dcr->VolumeName, vol->vol_name, sizeof(dcr->VolumeName));
+ if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_WRITE)) {
continue;
}
+
+ Dmsg2(dbglvl, "jid=%u vol=%s\n", (int)rctx.jcr->JobId, vol->vol_name);
foreach_alist(store, dirstore) {
+ int stat;
rctx.store = store;
foreach_alist(device_name, store->device) {
- int stat;
- if (strcmp(device_name, vol->dev->device->hdr.name) != 0) {
- continue;
- }
+ /* Found a device, try to use it */
rctx.device_name = device_name;
rctx.device = vol->dev->device;
+
+ if (!vol->dev->is_autochanger()) {
+ if (!is_vol_in_autochanger(rctx, vol)) {
+ continue;
+ }
+ } else if (strcmp(device_name, vol->dev->device->hdr.name) != 0) {
+ Dmsg3(dbglvl, "jid=%u device=%s not suitable want %s\n", (int)rctx.jcr->JobId,
+ vol->dev->device->hdr.name, device_name);
+ continue;
+ }
+
bstrncpy(rctx.VolumeName, vol->vol_name, sizeof(rctx.VolumeName));
rctx.have_volume = true;
/* Try reserving this device and volume */
}
}
} /* end for loop over reserved volumes */
+
lock_volumes();
save_vol_list = vol_list;
vol_list = temp_vol_list;
rctx.suitable_device = true;
Dmsg2(dbglvl, "jid=%u try reserve %s\n", rctx.jcr->JobId, rctx.device->hdr.name);
- dcr = new_dcr(rctx.jcr, rctx.device->dev);
+ rctx.jcr->dcr = dcr = new_dcr(rctx.jcr, rctx.jcr->dcr, rctx.device->dev);
if (!dcr) {
BSOCK *dir = rctx.jcr->dir_bsock;
dir->fsend(_("3926 Could not get dcr for device: %s\n"), rctx.device_name);
bail_out:
rctx.have_volume = false;
- free_dcr(dcr);
+// free_dcr(dcr);
Dmsg1(dbglvl, "jid=%u Not OK.\n", (int)rctx.jcr->JobId);
return 0;
}
rdev->max_block_size = dcr->dev->max_block_size;
rdev->min_block_size = dcr->dev->min_block_size;
rdev->device = dcr->dev->device;
- rdcr = new_dcr(jcr, rdev);
+ rdcr = new_dcr(jcr, NULL, rdev);
rdcr->spool_fd = dcr->spool_fd;
- rdcr->jcr = jcr; /* set a valid jcr */
block = dcr->block; /* save block */
dcr->block = rdcr->block; /* make read and write block the same */
continue;
}
- jcr->dcr = dcr = new_dcr(jcr, dev);
+ jcr->dcr = dcr = new_dcr(jcr, NULL, dev);
if (dev->is_autochanger()) {
/* If autochanger set slot in dev sturcture */
get_autochanger_loaded_slot(dcr);
*/
#undef VERSION
-#define VERSION "2.1.18"
-#define BDATE "16 June 2007"
-#define LSMDATE "16Jun07"
+#define VERSION "2.1.19"
+#define BDATE "18 June 2007"
+#define LSMDATE "18Jun07"
#define PROG_COPYRIGHT "Copyright (C) %d-2007 Free Software Foundation Europe e.V.\n"
#define BYEAR "2007" /* year for copyright messages in progs */
Technical notes on version 2.1
General:
+18Jun08
+kes Add some additional locking in the cats directory in subroutines
+ that modify packet variables called from batch insert.
+kes Rework how dcrs are allocated. new_dcr() can now be called
+ with an existing pointer, and it will simply clean it up.
+ This allows the reservation system to test various different
+ devices, and will permit easy device changes.
+kes A bunch of changes all over to handle new new_dcr() calling
+ sequence.
+kes Work more on the Volume management in the SD. Remember Volumes
+ for tape drives and for autochangers (even virtual disk changers).
+kes When looking at the Volume list to reserve a drive, handle
+ autochanger names correctly by interating through the changer
+ devices. Also call the Director to see if a Volume is suitable
+ for the current job.
+kes Fix some bugs in bscan. Make sure all media records are written.
+ Make sure that valid JobMedia records are written for disk files.
+ Previously they were completely wrong.
+kes Move source tar files for depkgs-mingw32 to www.bacula.org so
+ that the URLs don't change and so that the developers will all
+ work off the same copy. Rebuild from scrach.
+kes Upgrade Win32 SQLite3 from 3.3.8 to 3.3.17.
Release: 2.1.18 beta
16Jun07
kes Fix seg fault in FD from incorrect digest size.