- The wait command can now be made to wait for jobids.
- New command line keywords are permitted in update volume. They
are Inchanger=yes/no, slot=nn.
+- Add two new console commands: enable job=<job-name> and
+ disable job=<job-name>. When a job is disabled, it will not
+ be started by the scheduler. If you disable a job and restart
+ Bacula or reload the .conf file, the job will be re-enabled.
+- Add a new Job resource directive "enable = yes|no".
Major bug fixes:
- Fix race condition in multiple-drive autochangers where
Priority:
For 1.39:
+- Fix re-read of last block to check if job has actually written
+ a block, and check if block was written by a different job
+ (i.e. multiple simultaneous jobs writing).
+- JobStatus and Termination codes.
- Some users claim that they must do two prune commands to get a
Volume marked as purged.
- Print warning message if LANG environment variable does not specify
Kern Sibbald
General:
+24Mar06
+- Create datestyle fix for PostgreSQL. Fixes bug #574.
+- Correct editing of JobId from int to int64 in fd_cmds.c
+- Eliminate FileSet name race with bash_spaces() and multiple
+ threads by bashing in a local.
+- Fix error return from 'use storage' to print a correct error
+ message rather than nothing.
+- Correct false re-read last block error message when two jobs
+ are simultaneously writing at the end of a tape.
+- Simplify exit conditions in the reserve.c code to avoid
+ possible non-release of reservation_lock().
+- Suffle lock order in reserve to avoid deadlock between
+ reservation lock and device mutex.
+- Add Thorsten's VSS timeout code to 1.38 branch.
+21Mar06
+- Initialize jcr mutex before first use. Thanks to Thorsten for
+ tracking this down for me !!!! as it broke the Win32 build.
+20Mar06
+- Integrate addition of line count limitation to bsmtp -l from
+ Sebastian Stark <stark at tuebingen.mpg.de>
+17Mar06
+- Implement regex test program in tools directory.
+- Attempt to fix time problem with bsmtp with foreign langs.
+- Add strip_trailing_newline() submitted by user.
+
16Mar06
- Fix bug #537 to allow arbitrary time to mount a volume for
restore, if polling is turned on.
Kern Sibbald
General:
+24Mar06
+- Create datestyle fix for PostgreSQL. Fixes bug #574.
+- Correct editing of JobId from int to int64 in fd_cmds.c
+- Eliminate FileSet name race with bash_spaces() and multiple
+ threads by bashing in a local.
+- Fix error return from 'use storage' to print a correct error
+ message rather than nothing.
+- Correct false re-read last block error message when two jobs
+ are simultaneously writing at the end of a tape.
+- Simplify exit conditions in the reserve.c code to avoid
+ possible non-release of reservation_lock().
+- Suffle lock order in reserve to avoid deadlock between
+ reservation lock and device mutex.
+21Mar06
+- Initialize jcr mutex before first use. Thanks to Thorsten for
+ tracking this down for me !!!! as it broke the Win32 build.
20Mar06
- Integrate addition of line count limitation to bsmtp -l from
Sebastian Stark <stark at tuebingen.mpg.de>
if $bindir/psql -f - -d template1 $* <<END-OF-DATA
CREATE DATABASE bacula $ENCODING;
+ALTER DATABASE bacula SET datestyle TO 'ISO, YMD';
END-OF-DATA
then
echo "Creation of bacula database succeeded."
* Version $Id$
*/
/*
- Copyright (C) 2003-2005 Kern Sibbald
+ Copyright (C) 2003-2006 Kern Sibbald
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
return 0;
}
+ sql_query(mdb, "SET datestyle TO 'ISO, YMD'");
+
mdb->connected = true;
V(mutex);
return 1;
/* Commands sent to File daemon */
static char filesetcmd[] = "fileset%s\n"; /* set full fileset */
-static char jobcmd[] = "JobId=%d Job=%s SDid=%u SDtime=%u Authorization=%s\n";
+static char jobcmd[] = "JobId=%s Job=%s SDid=%u SDtime=%u Authorization=%s\n";
/* Note, mtime_only is not used here -- implemented as file option */
static char levelcmd[] = "level = %s%s mtime_only=%d\n";
static char runbefore[] = "RunBeforeJob %s\n";
int verbose)
{
BSOCK *fd;
+ char ed1[30];
if (!jcr->file_bsock) {
fd = bnet_connect(jcr, retry_interval, max_retry_time,
/*
* Now send JobId and authorization key
*/
- bnet_fsend(fd, jobcmd, jcr->JobId, jcr->Job, jcr->VolSessionId,
+ bnet_fsend(fd, jobcmd, edit_int64(jcr->JobId, ed1), jcr->Job, jcr->VolSessionId,
jcr->VolSessionTime, jcr->sd_auth_key);
if (strcmp(jcr->sd_auth_key, "dummy") != 0) {
memset(jcr->sd_auth_key, 0, strlen(jcr->sd_auth_key));
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
/* Commands sent to Storage daemon */
-static char jobcmd[] = "JobId=%d job=%s job_name=%s client_name=%s "
+static char jobcmd[] = "JobId=%s job=%s job_name=%s client_name=%s "
"type=%d level=%d FileSet=%s NoAttr=%d SpoolAttr=%d FileSetMD5=%s "
"SpoolData=%d WritePartAfterJob=%d PreferMountedVols=%d\n";
static char use_storage[] = "use storage=%s media_type=%s pool_name=%s "
/* Storage Daemon requests */
static char Job_start[] = "3010 Job %127s start\n";
static char Job_end[] =
- "3099 Job %127s end JobStatus=%d JobFiles=%d JobBytes=%lld\n";
+ "3099 Job %127s end JobStatus=%d JobFiles=%d JobBytes=%" lld "\n";
/* Forward referenced functions */
extern "C" void *msg_thread(void *arg);
BSOCK *sd;
char auth_key[100];
POOL_MEM store_name, device_name, pool_name, pool_type, media_type;
+ POOL_MEM job_name, client_name, fileset_name;
int copy = 0;
int stripe = 0;
+ char ed1[30];
sd = jcr->store_bsock;
/*
* Now send JobId and permissions, and get back the authorization key.
*/
- bash_spaces(jcr->job->hdr.name);
- bash_spaces(jcr->client->hdr.name);
- bash_spaces(jcr->fileset->hdr.name);
+ pm_strcpy(job_name, jcr->job->hdr.name);
+ bash_spaces(job_name);
+ pm_strcpy(client_name, jcr->client->hdr.name);
+ bash_spaces(client_name);
+ pm_strcpy(fileset_name, jcr->fileset->hdr.name);
+ bash_spaces(fileset_name);
if (jcr->fileset->MD5[0] == 0) {
bstrncpy(jcr->fileset->MD5, "**Dummy**", sizeof(jcr->fileset->MD5));
}
while (bnet_recv(sd) >= 0)
{ }
}
- bnet_fsend(sd, jobcmd, jcr->JobId, jcr->Job, jcr->job->hdr.name,
- jcr->client->hdr.name, jcr->JobType, jcr->JobLevel,
- jcr->fileset->hdr.name, !jcr->pool->catalog_files,
+ bnet_fsend(sd, jobcmd, edit_int64(jcr->JobId, ed1), jcr->Job,
+ job_name.c_str(), client_name.c_str(),
+ jcr->JobType, jcr->JobLevel,
+ fileset_name.c_str(), !jcr->pool->catalog_files,
jcr->job->SpoolAttributes, jcr->fileset->MD5, jcr->spool_data,
jcr->write_part_after_job, jcr->job->PreferMountedVolumes);
Dmsg1(100, ">stored: %s\n", sd->msg);
- unbash_spaces(jcr->job->hdr.name);
- unbash_spaces(jcr->client->hdr.name);
- unbash_spaces(jcr->fileset->hdr.name);
if (bget_dirmsg(sd) > 0) {
Dmsg1(100, "<stored: %s", sd->msg);
if (sscanf(sd->msg, OKjob, &jcr->VolSessionId,
/* ****FIXME**** save actual device name */
ok = sscanf(sd->msg, OK_device, device_name.c_str()) == 1;
} else {
- POOL_MEM err_msg;
- pm_strcpy(err_msg, sd->msg); /* save message */
- Jmsg(jcr, M_FATAL, 0, _("\n"
- " Storage daemon didn't accept Device \"%s\" because:\n %s"),
- device_name.c_str(), err_msg.c_str()/* sd->msg */);
ok = false;
}
}
/* ****FIXME**** save actual device name */
ok = sscanf(sd->msg, OK_device, device_name.c_str()) == 1;
} else {
- POOL_MEM err_msg;
+ ok = false;
+ }
+ }
+ if (!ok) {
+ POOL_MEM err_msg;
+ if (sd->msg[0]) {
pm_strcpy(err_msg, sd->msg); /* save message */
Jmsg(jcr, M_FATAL, 0, _("\n"
- " Storage daemon didn't accept Device \"%s\" because:\n %s"),
- device_name.c_str(), err_msg.c_str()/* sd->msg */);
- ok = false;
+ " Storage daemon didn't accept Device \"%s\" because:\n %s"),
+ device_name.c_str(), err_msg.c_str()/* sd->msg */);
+ } else {
+ Jmsg(jcr, M_FATAL, 0, _("\n"
+ " Storage daemon didn't accept Device \"%s\" command.\n"),
+ device_name.c_str());
}
}
return ok;
# Send all messages except skipped files back to Director
Messages {
Name = Standard
- director = @hostname@-dir = all, !skipped
+ director = @hostname@-dir = all, !skipped, !restored
}
*
*/
/*
- Copyright (C) 2004-2005 Kern Sibbald
+ Copyright (C) 2004-2006 Kern Sibbald
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
Jmsg(jcr, M_ERROR, 0, _("Re-read last block at EOT failed. ERR=%s"),
dev->errmsg);
} else {
- if (lblock->BlockNumber+1 == block->BlockNumber) {
- Jmsg(jcr, M_INFO, 0, _("Re-read of last block succeeded.\n"));
- } else {
+ /*
+ * If we wrote block and the block numbers don't agree
+ * we have a possible problem.
+ */
+ if (lblock->VolSessionId == block->VolSessionId &&
+ lblock->BlockNumber+1 != block->BlockNumber) {
Jmsg(jcr, M_ERROR, 0, _(
-"Re-read of last block failed. Last block=%u Current block=%u.\n"),
+"Re-read of last block OK, but block numbers differ. Last block=%u Current block=%u.\n"),
lblock->BlockNumber, block->BlockNumber);
+ } else {
+ Jmsg(jcr, M_INFO, 0, _("Re-read of last block succeeded.\n"));
}
}
free_block(lblock);
/* 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: %s\n";
+static char BAD_job[] = "3915 Bad Job command. stat=%d CMD: %s\n";
//static char OK_query[] = "3001 OK query\n";
//static char NO_query[] = "3918 Query failed\n";
//static char BAD_query[] = "3917 Bad query command: %s\n";
POOL_MEM job_name, client_name, job, fileset_name, fileset_md5;
int JobType, level, spool_attributes, no_attributes, spool_data;
int write_part_after_job, PreferMountedVols;
-
+ int stat;
JCR *ojcr;
/*
* Get JobId and permissions from Director
*/
Dmsg1(100, "<dird: %s", dir->msg);
- if (sscanf(dir->msg, jobcmd, &JobId, job.c_str(), job_name.c_str(),
+ 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,
- &write_part_after_job, &PreferMountedVols) != 13) {
+ &write_part_after_job, &PreferMountedVols);
+ if (stat != 13) {
pm_strcpy(jcr->errmsg, dir->msg);
- bnet_fsend(dir, BAD_job, jcr->errmsg);
+ bnet_fsend(dir, BAD_job, stat, jcr->errmsg);
Dmsg1(100, ">dird: %s", dir->msg);
- Emsg1(M_FATAL, 0, _("Bad Job Command from Director: %s\n"), jcr->errmsg);
set_jcr_job_status(jcr, JS_ErrorTerminated);
return false;
}
*/
if (ok) {
bool first = true; /* print wait message once */
+ bool fail = false;
rctx.notify_dir = true;
- for ( ; !job_canceled(jcr); ) {
- lock_reservations(); /* only one thread at a time */
+ lock_reservations();
+ for ( ; !fail && !job_canceled(jcr); ) {
while ((msg = (char *)msgs->pop())) {
free(msg);
}
if ((ok = find_suitable_device_for_job(jcr, rctx))) {
break;
}
- /* Unlock before possible wait */
+ /* Keep reservations locked *except* during wait_for_device() */
unlock_reservations();
if (!rctx.suitable_device || !wait_for_device(jcr, first)) {
Dmsg0(100, "Fail. !suitable_device || !wait_for_device\n");
- break; /* Get out, failure ... */
+ fail = true;
}
+ lock_reservations();
first = false;
bnet_sig(dir, BNET_HEARTBEAT); /* Inform Dir that we are alive */
}
- /* Note if !ok then search_lock is already cleared */
- if (ok) {
- unlock_reservations();
- goto all_done;
- }
-
- /*
- * If we get here, there are no suitable devices available, which
- * means nothing configured. If a device is suitable but busy
- * with another Volume, we will not come here.
- */
- if (verbose) {
+ unlock_reservations();
+ if (!ok) {
+ /*
+ * If we get here, there are no suitable devices available, which
+ * means nothing configured. If a device is suitable but busy
+ * with another Volume, we will not come here.
+ */
unbash_spaces(dir->msg);
pm_strcpy(jcr->errmsg, dir->msg);
Jmsg(jcr, M_INFO, 0, _("Failed command: %s\n"), jcr->errmsg);
- }
- Jmsg(jcr, M_FATAL, 0, _("\n"
- " Device \"%s\" with MediaType \"%s\" requested by DIR not found in SD Device resources.\n"),
- dev_name.c_str(), media_type.c_str());
- bnet_fsend(dir, NO_device, dev_name.c_str());
+ Jmsg(jcr, M_FATAL, 0, _("\n"
+ " Device \"%s\" with MediaType \"%s\" requested by DIR not found in SD Device resources.\n"),
+ dev_name.c_str(), media_type.c_str());
+ bnet_fsend(dir, NO_device, dev_name.c_str());
- Dmsg1(100, ">dird: %s", dir->msg);
+ Dmsg1(100, ">dird: %s", dir->msg);
+ }
} else {
unbash_spaces(dir->msg);
pm_strcpy(jcr->errmsg, dir->msg);
- if (verbose) {
- Jmsg(jcr, M_INFO, 0, _("Failed command: %s\n"), jcr->errmsg);
- }
+ Jmsg(jcr, M_FATAL, 0, _("Failed command: %s\n"), jcr->errmsg);
bnet_fsend(dir, BAD_use, jcr->errmsg);
Dmsg1(100, ">dird: %s", dir->msg);
}
-all_done:
release_msgs(jcr);
return ok;
}
ASSERT(dcr);
+ /* Get locks in correct order */
+ unlock_reservations();
P(dev->mutex);
+ lock_reservations();
if (is_device_unmounted(dev)) {
Dmsg1(200, "Device %s is BLOCKED due to user unmount.\n", dev->print_name());
#undef VERSION
#define VERSION "1.39.6"
-#define BDATE "20 March 2006"
-#define LSMDATE "20Mar06"
+#define BDATE "24 March 2006"
+#define LSMDATE "24Mar06"
/* Debug flags */
#undef DEBUG