*/
if (ok && lmr.PoolId == mr->PoolId) {
Dmsg2(050, "Vol=%s MediaId=%d purged.\n", lmr.VolumeName, (int)lmr.MediaId);
- mr = &lmr; /* struct copy */
+ memcpy(mr, &lmr, sizeof(lmr));
break; /* got a volume */
}
/*
struct s_vars {
const char *name;
- char *fmt;
+ const char *fmt;
};
/* Read-only variables */
}
while (bnet_recv(dir) >= 0) {
- Dmsg1(200, "filed<dird: bootstrap file %s\n", dir->msg);
+ Dmsg1(200, "filed<dird: bootstrap: %s", dir->msg);
fputs(dir->msg, bs);
}
fclose(bs);
struct s_vars {
const char *name;
- char *fmt;
+ const char *fmt;
};
/* Read-only variables */
* For a set of errors, ... keep the current status
* so it isn't lost. For all others, set it.
*/
- Dmsg2(100, "OnEntry JobStatus=%c set=%c\n", jcr->JobStatus, JobStatus);
+ Dmsg2(200, "OnEntry JobStatus=%c set=%c\n", jcr->JobStatus, JobStatus);
switch (jcr->JobStatus) {
case JS_ErrorTerminated:
case JS_FatalError:
default:
jcr->JobStatus = JobStatus;
}
- Dmsg2(100, "OnExit JobStatus=%c set=%c\n", jcr->JobStatus, JobStatus);
+ Dmsg2(200, "OnExit JobStatus=%c set=%c\n", jcr->JobStatus, JobStatus);
}
#ifdef TRACE_JCR_CHAIN
dev->num_writers, jcr->JobId);
goto get_out;
}
+ dev->clear_unload();
/* Find next Volume, if any */
vol = jcr->VolList;
/* Volume info is always needed because of VolParts */
- Dmsg0(200, "dir_get_volume_info\n");
+ Dmsg1(150, "dir_get_volume_info vol=%s\n", dcr->VolumeName);
if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_READ)) {
+ Dmsg2(150, "dir_get_vol_info failed for vol=%s: %s\n",
+ dcr->VolumeName, jcr->errmsg);
Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg);
}
dev->set_load(); /* set to load volume */
switch (vol_label_status) {
case VOL_OK:
ok = true;
- memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
+ dev->VolCatInfo = dcr->VolCatInfo; /* structure assignment */
break; /* got it */
case VOL_IO_ERROR:
/*
}
goto default_path;
case VOL_NAME_ERROR:
- if (tape_initially_mounted) {
- tape_initially_mounted = false;
- goto default_path;
- }
- /* If polling and got a previous bad name, ignore it */
- if (dev->poll && strcmp(dev->BadVolName, dev->VolHdr.VolumeName) == 0) {
+ if (dev->is_volume_to_unload()) {
goto default_path;
- } else {
- bstrncpy(dev->BadVolName, dev->VolHdr.VolumeName, sizeof(dev->BadVolName));
}
+// if (tape_initially_mounted) {
+ tape_initially_mounted = false;
+// goto default_path;
+// }
+ dev->set_unload(); /* force unload of unwanted tape */
if (!unload_autochanger(dcr, -1)) {
/* at least free the device so we can re-open with correct volume */
dev->close();
}
+ dev->set_load();
+ ASSERT(0);
/* Fall through */
default:
Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg);
}
/* Try closing and re-opening */
dev->close();
- dev->clear_unload();
if (dev->open(dcr, OPEN_READ_ONLY) >= 0) {
continue;
}
} /* end switch */
break;
} /* end for loop */
+
if (!ok) {
Jmsg1(jcr, M_FATAL, 0, _("Too many errors trying to mount device %s for reading.\n"),
dev->print_name());
goto get_out;
}
+ dev->clear_unload();
+
/*
* have_vol defines whether or not mount_next_write_volume should
* ask the Director again about what Volume to use.
if (rcode != R_DIRECTOR) {
Dmsg1(dbglvl, "I only authenticate Directors, not %d\n", rcode);
- Emsg1(M_FATAL, 0, _("I only authenticate Directors, not %d\n"), rcode);
+ Jmsg1(jcr, M_FATAL, 0, _("I only authenticate Directors, not %d\n"), rcode);
return 0;
}
if (bs->msglen < 25 || bs->msglen > 500) {
Dmsg2(dbglvl, "Bad Hello command from Director at %s. Len=%d.\n",
bs->who(), bs->msglen);
- Emsg2(M_FATAL, 0, _("Bad Hello command from Director at %s. Len=%d.\n"),
+ Jmsg2(jcr, M_FATAL, 0, _("Bad Hello command from Director at %s. Len=%d.\n"),
bs->who(), bs->msglen);
return 0;
}
bs->msg[100] = 0;
Dmsg2(dbglvl, "Bad Hello command from Director at %s: %s\n",
bs->who(), bs->msg);
- Emsg2(M_FATAL, 0, _("Bad Hello command from Director at %s: %s\n"),
+ Jmsg2(jcr, M_FATAL, 0, _("Bad Hello command from Director at %s: %s\n"),
bs->who(), bs->msg);
return 0;
}
if (!director) {
Dmsg2(dbglvl, "Connection from unknown Director %s at %s rejected.\n",
dirname, bs->who());
- Emsg2(M_FATAL, 0, _("Connection from unknown Director %s at %s rejected.\n"
+ Jmsg2(jcr, M_FATAL, 0, _("Connection from unknown Director %s at %s rejected.\n"
"Please see http://www.bacula.org/rel-manual/faq.html#AuthorizationErrors for help.\n"),
dirname, bs->who());
free_pool_memory(dirname);
}
if (!auth_success) {
- Emsg0(M_FATAL, 0, _("Incorrect password given by Director.\n"
+ Jmsg0(jcr, M_FATAL, 0, _("Incorrect password given by Director.\n"
"Please see http://www.bacula.org/rel-manual/faq.html#AuthorizationErrors for help.\n"));
auth_success = false;
goto auth_fatal;
/* Verify that the remote host is willing to meet our TLS requirements */
if (tls_remote_need < tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) {
- Emsg0(M_FATAL, 0, _("Authorization problem: Remote server did not"
+ Jmsg0(jcr, M_FATAL, 0, _("Authorization problem: Remote server did not"
" advertise required TLS support.\n"));
auth_success = false;
goto auth_fatal;
/* Verify that we are willing to meet the remote host's requirements */
if (tls_remote_need > tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) {
- Emsg0(M_FATAL, 0, _("Authorization problem: Remote server requires TLS.\n"));
+ Jmsg0(jcr, M_FATAL, 0, _("Authorization problem: Remote server requires TLS.\n"));
auth_success = false;
goto auth_fatal;
}
if (tls_local_need >= BNET_TLS_OK && tls_remote_need >= BNET_TLS_OK) {
/* Engage TLS! Full Speed Ahead! */
if (!bnet_tls_server(director->tls_ctx, bs, verify_list)) {
- Emsg0(M_FATAL, 0, _("TLS negotiation failed.\n"));
+ Jmsg0(jcr, M_FATAL, 0, _("TLS negotiation failed.\n"));
auth_success = false;
goto auth_fatal;
}
if (!authenticate(R_DIRECTOR, dir, jcr)) {
dir->fsend("%s", Dir_sorry);
Dmsg1(dbglvl, "Unable to authenticate Director at %s.\n", dir->who());
- Emsg1(M_ERROR, 0, _("Unable to authenticate Director at %s.\n"), dir->who());
+ Jmsg1(jcr, M_ERROR, 0, _("Unable to authenticate Director at %s.\n"), dir->who());
bmicrosleep(5, 0);
return 0;
}
free_volume(dev); /* Free any volume associated with this drive */
free_pool_memory(changer);
}
- dev->clear_unload();
+ if (ok) {
+ dev->clear_unload();
+ }
return ok;
}
Dmsg2(100, "Slot %d unloaded %s\n", dev->get_slot(), dev->print_name());
dev->set_slot(0); /* nothing loaded */
}
- dev->clear_unload();
+ if (ok) {
+ dev->clear_unload();
+ }
unlock_changer(dcr);
dev->dunlock();
#endif
}
+/*
+ * Set to unload the current volume in the drive
+ */
+void DEVICE::set_unload()
+{
+ if (!m_unload && VolHdr.VolumeName[0] != 0) {
+ m_unload = true;
+ memcpy(UnloadVolName, VolHdr.VolumeName, sizeof(UnloadVolName));
+ }
+}
/*
* Clear volume header
dev->rem_wait_sec = dev->wait_sec;
dev->num_wait = 0;
dev->poll = false;
- dev->BadVolName[0] = 0;
jcr->min_wait = 60 * 60;
jcr->max_wait = 24 * 60 * 60;
char pool_name[MAX_NAME_LENGTH]; /* pool name */
char pool_type[MAX_NAME_LENGTH]; /* pool type */
- /* Device wait times ***FIXME*** look at durations */
- char BadVolName[MAX_NAME_LENGTH]; /* Last wrong Volume mounted */
+ char UnloadVolName[MAX_NAME_LENGTH]; /* Last wrong Volume mounted */
bool poll; /* set to poll Volume */
+
+ /* Device wait times ***FIXME*** look at durations */
int min_wait;
int max_wait;
int max_num_wait;
void set_part_spooled(int val) { if (val) state |= ST_PART_SPOOLED; \
else state &= ~ST_PART_SPOOLED;
};
- void set_unload() { m_unload = true; };
+ bool is_volume_to_unload() const { \
+ return m_unload && strcmp(VolHdr.VolumeName, UnloadVolName) == 0; };
void set_load() { m_load = true; };
void inc_reserved() { m_num_reserved++; }
void set_mounted(int val) { if (val) state |= ST_MOUNTED; \
void clear_media() { state &= ~ST_MEDIA; };
void clear_short_block() { state &= ~ST_SHORT; };
void clear_freespace_ok() { state &= ~ST_FREESPACE_OK; };
- void clear_unload() { m_unload = false; };
+ void clear_unload() { m_unload = false; UnloadVolName[0] = 0; };
void clear_load() { m_load = false; };
char *bstrerror(void) { return errmsg; };
char *print_errmsg() { return errmsg; };
int32_t get_slot() const { return m_slot; };
+ void set_unload(); /* in dev.c */
void clear_volhdr(); /* in dev.c */
void close(); /* in dev.c */
void close_part(DCR *dcr); /* in dev.c */
void mark_volume_in_error();
void mark_volume_not_inchanger();
int try_autolabel(bool opened);
+ bool find_a_volume();
bool is_suitable_volume_mounted();
bool is_eod_valid();
int check_volume_label(bool &ask, bool &autochanger);
}
free_record(record); /* finished reading Volume record */
+ if (!dev->is_volume_to_unload()) {
+ dev->clear_unload();
+ }
+
if (!ok) {
if (forge_on || jcr->ignore_label_errors) {
dev->set_labeled(); /* set has Bacula label */
}
dev->set_labeled(); /* set has Bacula label */
- Dmsg1(100, "Call reserve_volume=%s\n", dev->VolHdr.VolumeName);
- Dmsg2(100, "=== dcr->dev=%p dev=%p\n", dcr->dev, dev);
- if (reserve_volume(dcr, dev->VolHdr.VolumeName) == NULL) {
- Mmsg2(jcr->errmsg, _("Could not reserve volume %s on %s\n"),
- dev->VolHdr.VolumeName, dev->print_name());
- stat = VOL_NAME_ERROR;
- goto bail_out;
- }
- Dmsg2(100, "=== dcr->dev=%p dev=%p\n", dcr->dev, dev);
/* Compare Volume Names */
Dmsg2(130, "Compare Vol names: VolName=%s hdr=%s\n", VolName?VolName:"*", dev->VolHdr.VolumeName);
}
Dmsg0(150, "return VOL_NAME_ERROR\n");
stat = VOL_NAME_ERROR;
- volume_unused(dcr); /* mark volume "released" */
goto bail_out;
}
- Dmsg1(130, "Copy vol_name=%s\n", dev->VolHdr.VolumeName);
+
if (debug_level >= 10) {
dump_volume_label(dev);
stat = read_ansi_ibm_label(dcr);
/* If we want a label and didn't find it, return error */
if (stat != VOL_OK) {
- volume_unused(dcr); /* mark volume "released" */
goto bail_out;
}
}
}
+
+ Dmsg1(100, "Call reserve_volume=%s\n", dev->VolHdr.VolumeName);
+ if (reserve_volume(dcr, dev->VolHdr.VolumeName) == NULL) {
+ Mmsg2(jcr->errmsg, _("Could not reserve volume %s on %s\n"),
+ dev->VolHdr.VolumeName, dev->print_name());
+ stat = VOL_NAME_ERROR;
+ goto bail_out;
+ }
+
empty_block(block);
return VOL_OK;
goto no_lock_bail_out;
}
lock_volumes();
+ Dmsg1(150, "Continue after dir_ask_sysop_to_mount. must_load=%d\n", dev->must_load());
}
if (job_canceled(jcr)) {
Jmsg(jcr, M_FATAL, 0, _("Job %d canceled.\n"), jcr->JobId);
}
do_swapping(true /*writing*/);
- if (!is_suitable_volume_mounted()) {
- bool have_vol = false;
- /* Do we have a candidate volume? */
- if (dev->vol) {
- bstrncpy(VolumeName, dev->vol->vol_name, sizeof(VolumeName));
- have_vol = dir_get_volume_info(this, GET_VOL_INFO_FOR_WRITE);
- }
- /*
- * Get Director's idea of what tape we should have mounted.
- * in dcr->VolCatInfo
- */
- if (!have_vol) {
- Dmsg0(200, "Before dir_find_next_appendable_volume.\n");
- while (!dir_find_next_appendable_volume(dcr)) {
- Dmsg0(200, "not dir_find_next\n");
- if (job_canceled(jcr)) {
- goto bail_out;
- }
- unlock_volumes();
- if (!dir_ask_sysop_to_create_appendable_volume(dcr)) {
- goto no_lock_bail_out;
- }
- lock_volumes();
- Dmsg0(200, "Again dir_find_next_append...\n");
- }
- goto mount_next_vol;
- }
+ if (retry < 2 && !find_a_volume()) {
+ goto no_lock_bail_out;
}
+
if (job_canceled(jcr)) {
goto bail_out;
}
* we will fail, recurse and ask the operator the next time.
*/
if (!dev->must_unload() && dev->is_tape() && dev->has_cap(CAP_AUTOMOUNT)) {
- Dmsg0(150, "(1)Ask=0\n");
+ Dmsg0(250, "(1)Ask=0\n");
ask = false; /* don't ask SYSOP this time */
}
/* Don't ask if not removable */
if (!dev->is_removable()) {
- Dmsg0(150, "(2)Ask=0\n");
+ Dmsg0(250, "(2)Ask=0\n");
ask = false;
}
- Dmsg2(150, "Ask=%d autochanger=%d\n", ask, autochanger);
+ Dmsg2(250, "Ask=%d autochanger=%d\n", ask, autochanger);
if (ask) {
unlock_volumes();
if (!dir_ask_sysop_to_mount_volume(dcr, ST_APPEND)) {
Dmsg0(150, "Error return ask_sysop ...\n");
- goto no_lock_bail_out; /* error return */
+ goto no_lock_bail_out;
}
lock_volumes();
}
if (try_autolabel(false) == try_read_vol) {
break; /* created a new volume label */
}
+ Dmsg0(50, "set_unload\n");
dev->set_unload(); /* force ask sysop */
ask = true;
+ Dmsg0(150, "goto mount_next_vol\n");
goto mount_next_vol;
-#ifdef xxx
- /* If DVD, ignore the error, very often you cannot open the device
- * (when there is no DVD, or when the one inserted is a wrong one) */
- if (dev->poll || dev->is_dvd()) {
- goto mount_next_vol;
- } else {
- Jmsg2(jcr, M_ERROR, 0, _("Could not open device %s: ERR=%s\n"),
- dev->print_name(), dev->print_errmsg());
- goto bail_out;
- }
-#endif
}
/*
* Now check the volume label to make sure we have the right tape mounted
*/
read_volume:
-
switch (check_volume_label(ask, autochanger)) {
case check_next_vol:
+ Dmsg0(50, "set_unload\n");
dev->set_unload(); /* want a different Volume */
+ Dmsg0(150, "goto mount_next_vol\n");
goto mount_next_vol;
case check_read_vol:
goto read_volume;
goto mount_next_vol;
}
if (!is_eod_valid()) {
+ Dmsg0(150, "goto mount_next_vol\n");
goto mount_next_vol;
}
return false;
}
+/*
+ * This routine is meant to be called once the first pass
+ * to ensure that we have a candidate volume to mount.
+ * Otherwise, we ask the sysop to created one.
+ */
+bool DCR::find_a_volume()
+{
+ DCR *dcr = this;
+ if (!is_suitable_volume_mounted()) {
+ bool have_vol = false;
+ /* Do we have a candidate volume? */
+ if (dev->vol) {
+ bstrncpy(VolumeName, dev->vol->vol_name, sizeof(VolumeName));
+ have_vol = dir_get_volume_info(this, GET_VOL_INFO_FOR_WRITE);
+ }
+ /*
+ * Get Director's idea of what tape we should have mounted.
+ * in dcr->VolCatInfo
+ */
+ if (!have_vol) {
+ Dmsg0(200, "Before dir_find_next_appendable_volume.\n");
+ while (!dir_find_next_appendable_volume(dcr)) {
+ Dmsg0(200, "not dir_find_next\n");
+ if (job_canceled(jcr)) {
+ unlock_volumes();
+ return false;
+ }
+ unlock_volumes();
+ if (!dir_ask_sysop_to_create_appendable_volume(dcr)) {
+ return false;
+ }
+ lock_volumes();
+ Dmsg0(150, "Again dir_find_next_append...\n");
+ }
+ }
+ }
+ return true;
+}
+
int DCR::check_volume_label(bool &ask, bool &autochanger)
{
int vol_label_status;
VOLUME_CAT_INFO dcrVolCatInfo, devVolCatInfo;
char saveVolumeName[MAX_NAME_LENGTH];
+ Dmsg1(150, "Vol NAME Error Name=%s\n", VolumeName);
+ if (dev->is_volume_to_unload()) {
+ ask = true;
+ goto check_next_volume;
+ }
+
/* If not removable, Volume is broken */
if (!dev->is_removable()) {
Jmsg(jcr, M_WARNING, 0, _("Volume \"%s\" not on device %s.\n"),
goto check_next_volume;
}
- Dmsg1(150, "Vol NAME Error Name=%s\n", VolumeName);
- /* If polling and got a previous bad name, ignore it */
- if (dev->poll && strcmp(dev->BadVolName, dev->VolHdr.VolumeName) == 0) {
- ask = true;
- Dmsg1(200, "Vol Name error supress due to poll. Name=%s\n", VolumeName);
- goto check_next_volume;
- }
/*
* OK, we got a different volume mounted. First save the
* requested Volume info (dcr) structure, then query if
mark_volume_not_inchanger();
}
dev->VolCatInfo = devVolCatInfo; /* structure assignment */
- bstrncpy(dev->BadVolName, dev->VolHdr.VolumeName, sizeof(dev->BadVolName));
+ dev->set_unload(); /* unload this volume */
Jmsg(jcr, M_WARNING, 0, _("Director wanted Volume \"%s\".\n"
" Current Volume \"%s\" not acceptable because:\n"
" %s"),
*/
Dmsg1(150, "Got new Volume name=%s\n", VolumeName);
dev->VolCatInfo = VolCatInfo; /* structure assignment */
+ Dmsg1(100, "Call reserve_volume=%s\n", dev->VolHdr.VolumeName);
+ if (reserve_volume(this, dev->VolHdr.VolumeName) == NULL) {
+ Jmsg2(jcr, M_WARNING, 0, _("Could not reserve volume %s on %s\n"),
+ dev->VolHdr.VolumeName, dev->print_name());
+ ask = true;
+ goto check_next_volume;
+ }
break; /* got a Volume */
/*
* At this point, we assume we have a blank tape mounted.
void DCR::do_swapping(bool is_writing)
{
if (dev->must_unload()) {
- Dmsg1(100, "swapping: unloading %s\n", dev->print_name());
+ Dmsg1(100, "must_unload release %s\n", dev->print_name());
release_volume();
- dev->clear_unload();
}
/*
* See if we are asked to swap the Volume from another device
dev->swap_dev = NULL;
}
if (dev->must_load()) {
- Dmsg1(100, "swapping: must load %s\n", dev->print_name());
+ Dmsg1(100, "Must load %s\n", dev->print_name());
if (autoload_device(this, is_writing, NULL) > 0) {
dev->clear_load();
}
Dmsg0(150, "dir_update_vol_info. Set Error.\n");
dir_update_volume_info(this, false, false);
volume_unused(this);
+ Dmsg0(50, "set_unload\n");
dev->set_unload(); /* must get a new volume */
}
dev->block_num = dev->file = 0;
dev->EndBlock = dev->EndFile = 0;
memset(&dev->VolCatInfo, 0, sizeof(dev->VolCatInfo));
-// memset(&VolCatInfo, 0, sizeof(VolCatInfo));
dev->clear_volhdr();
/* Force re-read of label */
dev->clear_labeled();
if (dev->is_open()) {
dev->offline_or_rewind();
}
- dev->set_unload();
+// Dmsg0(50, "set_unload\n");
+// dev->set_unload();
Dmsg0(190, "release_volume\n");
}
struct s_vars {
const char *name;
- char *fmt;
+ const char *fmt;
};
static struct s_vars getvars[] = {
}
Dmsg3(dbglvl, "jid=%u reserve_vol free vol=%s at %p\n", jid(), vol->vol_name, vol->vol_name);
free_volume(dev);
-// volume_unused(dcr);
dev->set_unload(); /* have to unload current volume */
debug_list_volumes("reserve_vol free");
}
Dmsg4(dbglvl, "==== jid=%u Swap vol=%s from dev=%s to %s\n", jid(),
VolumeName, vol->dev->print_name(), dev->print_name());
free_volume(dev); /* free any volume attached to our drive */
-// volume_unused(dcr);
dev->set_unload(); /* Unload any volume that is on our drive */
dcr->dev = vol->dev; /* temp point to other dev */
slot = get_autochanger_loaded_slot(dcr); /* get slot on other drive */
/*
Bacula® - The Network Backup Solution
- Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
+ Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
The main author of Bacula is Kern Sibbald, with contributions from
many others, a complete list can be found in the file AUTHORS.
#undef VERSION
#define VERSION "2.4.1"
-#define BDATE "26 June 2008"
-#define LSMDATE "26Jun08"
+#define BDATE "30 June 2008"
+#define LSMDATE "30Jun08"
#define PROG_COPYRIGHT "Copyright (C) %d-2008 Free Software Foundation Europe e.V.\n"
#define BYEAR "2008" /* year for copyright messages in progs */
Technical notes on version 2.2
General:
+27Jun08
+kes Generally clean up the manual tape loading code. The main
+ conceptial change is that when a volume is marked to be unloaded,
+ its volume name is retained, and it is only marked as unloaded
+ when either the autoloader says it is unloaded or another tape
+ is read on that drive.
26Jun08
kes Fix a recycling problem with two autochangers reported in bug
#1106. This may also (unlikely) fix a second recycling bug as