bool do_admin_init(JCR *jcr)
{
free_rstorage(jcr);
+ if (!allow_duplicate_job(jcr)) {
+ return false;
+ }
return true;
}
apply_pool_overrides(jcr);
+ if (!allow_duplicate_job(jcr)) {
+ return false;
+ }
+
jcr->jr.PoolId = get_or_create_pool_record(jcr, jcr->pool->name());
if (jcr->jr.PoolId == 0) {
return false;
{"maximumconcurrentjobs", store_pint, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
{"rescheduleonerror", store_bool, ITEM(res_job.RescheduleOnError), 0, ITEM_DEFAULT, false},
{"rescheduleinterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
- {"rescheduletimes", store_pint, ITEM(res_job.RescheduleTimes), 0, 0, 0},
- {"priority", store_pint, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
- {"writepartafterjob", store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, true},
- {"selectionpattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
- {"runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0},
- {"selectiontype", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
- {"accurate", store_bool, ITEM(res_job.accurate), 0,0,0},
- {"allowduplicatejobs", store_bool, ITEM(res_job.AllowDuplicateJobs), 0, ITEM_DEFAULT, false},
- {"allowhigherduplicates", store_bool, ITEM(res_job.AllowHigherDuplicates), 0, ITEM_DEFAULT, true},
+ {"rescheduletimes", store_pint, ITEM(res_job.RescheduleTimes), 0, 0, 0},
+ {"priority", store_pint, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
+ {"writepartafterjob", store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, true},
+ {"selectionpattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
+ {"runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0},
+ {"selectiontype", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
+ {"accurate", store_bool, ITEM(res_job.accurate), 0,0,0},
+ {"allowduplicatejobs", store_bool, ITEM(res_job.AllowDuplicateJobs), 0, ITEM_DEFAULT, false},
+ {"allowhigherduplicates", store_bool, ITEM(res_job.AllowHigherDuplicates), 0, ITEM_DEFAULT, true},
{"cancelqueuedduplicates", store_bool, ITEM(res_job.CancelQueuedDuplicates), 0, ITEM_DEFAULT, true},
{"cancelrunningduplicates", store_bool, ITEM(res_job.CancelRunningDuplicates), 0, ITEM_DEFAULT, false},
{"pluginoptions", store_str, ITEM(res_job.PluginOptions), 0, 0, 0},
while (!db_get_pool_record(jcr, jcr->db, &pr)) { /* get by Name */
/* Try to create the pool */
if (create_pool(jcr, jcr->db, jcr->pool, POOL_OP_CREATE) < 0) {
- Jmsg(jcr, M_FATAL, 0, _("Pool %s not in database. %s"), pr.Name,
+ Jmsg(jcr, M_FATAL, 0, _("Pool \"%s\" not in database. ERR=%s"), pr.Name,
db_strerror(jcr->db));
return 0;
} else {
- Jmsg(jcr, M_INFO, 0, _("Pool %s created in database.\n"), pr.Name);
+ Jmsg(jcr, M_INFO, 0, _("Created database record for Pool \"%s\".\n"), pr.Name);
}
}
return pr.PoolId;
}
+/*
+ * Check for duplicate jobs.
+ * Returns: true if current job should continue
+ * false if current job should terminate
+ */
+bool allow_duplicate_job(JCR *jcr)
+{
+ JOB *job = jcr->job;
+ JCR *djcr; /* possible duplicate */
+
+ if (job->AllowDuplicateJobs) {
+ return true;
+ }
+ if (!job->AllowHigherDuplicates) {
+ foreach_jcr(djcr) {
+ if (strcmp(job->name(), djcr->job->name()) == 0) {
+ bool cancel_queued = false;
+ if (job->DuplicateJobProximity > 0) {
+ time_t now = time(NULL);
+ if ((now - djcr->start_time) > job->DuplicateJobProximity) {
+ continue; /* not really a duplicate */
+ }
+ }
+ /* Cancel */
+ if (!(job->CancelQueuedDuplicates || job->CancelRunningDuplicates)) {
+ /* Zap current job */
+ Jmsg(jcr, M_FATAL, 0, _("Duplicate job not allowed.\n"));
+ return false;
+ }
+ /* If CancelQueuedDuplicates is set do so only if job is queued */
+ if (job->CancelQueuedDuplicates) {
+ switch (djcr->JobStatus) {
+ case JS_Created:
+ case JS_WaitJobRes:
+ case JS_WaitClientRes:
+ case JS_WaitStoreRes:
+ case JS_WaitPriority:
+ case JS_WaitMaxJobs:
+ case JS_WaitStartTime:
+ cancel_queued = true;
+ break;
+ default:
+ break;
+ }
+ }
+ if (cancel_queued || job->CancelRunningDuplicates) {
+ UAContext *ua = new_ua_context(djcr);
+ char ec1[50];
+ Jmsg(jcr, M_INFO, 0, _("Cancelling duplicate JobId=%s.\n"),
+ edit_uint64(djcr->JobId, ec1));
+ ua->jcr = djcr;
+ cancel_job(ua, djcr);
+ free_ua_context(ua);
+ Dmsg2(800, "Have cancelled JCR %p Job=%d\n", djcr, djcr->JobId);
+ }
+ }
+ }
+ }
+ return true;
+}
+
void apply_pool_overrides(JCR *jcr)
{
bool pool_override = false;
apply_pool_overrides(jcr);
+ if (!allow_duplicate_job(jcr)) {
+ return false;
+ }
+
jcr->jr.PoolId = get_or_create_pool_record(jcr, jcr->pool->name());
if (jcr->jr.PoolId == 0) {
Dmsg1(dbglevel, "JobId=%d no PoolId\n", (int)jcr->JobId);
extern bool response(JCR *jcr, BSOCK *fd, char *resp, const char *cmd, e_prtmsg prtmsg);
/* job.c */
+extern bool allow_duplicate_job(JCR *jcr);
extern void set_jcr_defaults(JCR *jcr, JOB *job);
extern void create_unique_job_name(JCR *jcr, const char *base_name);
extern void update_job_end_record(JCR *jcr);
/*
Bacula® - The Network Backup Solution
- Copyright (C) 2000-20087 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.
{
BSOCK *fd;
JOB_DBR rjr; /* restore job record */
+ char replace, *where, *cmd;
+ char empty = '\0';
+ int stat;
free_wstorage(jcr); /* we don't write */
+ if (!allow_duplicate_job(jcr)) {
+ goto bail_out;
+ }
+
memset(&rjr, 0, sizeof(rjr));
jcr->jr.JobLevel = L_FULL; /* Full restore */
if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
- restore_cleanup(jcr, JS_ErrorTerminated);
- return false;
+ goto bail_out;
}
Dmsg0(20, "Updated job start record\n");
Jmsg0(jcr, M_FATAL, 0, _("Cannot restore without a bootstrap file.\n"
"You probably ran a restore job directly. All restore jobs must\n"
"be run using the restore command.\n"));
- restore_cleanup(jcr, JS_ErrorTerminated);
- return false;
+ goto bail_out;
}
* Start conversation with Storage daemon
*/
if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
- restore_cleanup(jcr, JS_ErrorTerminated);
- return false;
+ goto bail_out;
}
/*
* Now start a job with the Storage daemon
*/
if (!start_storage_daemon_job(jcr, jcr->rstorage, NULL)) {
- restore_cleanup(jcr, JS_ErrorTerminated);
- return false;
+ goto bail_out;
}
if (!jcr->store_bsock->fsend("run")) {
- return false;
+ goto bail_out;
}
/*
* Now start a Storage daemon message thread
*/
if (!start_storage_daemon_message_thread(jcr)) {
- restore_cleanup(jcr, JS_ErrorTerminated);
- return false;
+ goto bail_out;
}
Dmsg0(50, "Storage daemon connection OK\n");
*/
set_jcr_job_status(jcr, JS_WaitFD);
if (!connect_to_file_daemon(jcr, 10, FDConnectTimeout, 1)) {
- restore_cleanup(jcr, JS_ErrorTerminated);
- return false;
+ goto bail_out;
}
fd = jcr->file_bsock;
fd->fsend(storaddr, jcr->rstore->address, jcr->rstore->SDDport);
Dmsg1(6, "dird>filed: %s\n", fd->msg);
if (!response(jcr, fd, OKstore, "Storage", DISPLAY_ERROR)) {
- restore_cleanup(jcr, JS_ErrorTerminated);
- return false;
+ goto bail_out;
}
/*
*/
if (!send_bootstrap_file(jcr, fd) ||
!response(jcr, fd, OKbootstrap, "Bootstrap", DISPLAY_ERROR)) {
- restore_cleanup(jcr, JS_ErrorTerminated);
- return false;
+ goto bail_out;
}
if (!send_runscripts_commands(jcr)) {
- restore_cleanup(jcr, JS_ErrorTerminated);
- return false;
+ goto bail_out;
}
/* Send restore command */
- char replace, *where, *cmd;
- char empty = '\0';
if (jcr->replace != 0) {
replace = jcr->replace;
unbash_spaces(where);
if (!response(jcr, fd, OKrestore, "Restore", DISPLAY_ERROR)) {
- restore_cleanup(jcr, JS_ErrorTerminated);
- return false;
+ goto bail_out;
}
/* Wait for Job Termination */
- int stat = wait_for_job_termination(jcr);
+ stat = wait_for_job_termination(jcr);
restore_cleanup(jcr, stat);
-
return true;
+
+bail_out:
+ restore_cleanup(jcr, JS_ErrorTerminated);
+ return false;
}
bool do_restore_init(JCR *jcr)
/*
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.
*/
bool do_verify_init(JCR *jcr)
{
+ if (!allow_duplicate_job(jcr)) {
+ return false;
+ }
return true;
}
/*
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.
dev->vol = vol; /* point dev at vol */
dev->VolHdr.VolumeName[0] = 0;
} else {
- Dmsg3(dbglvl, "Volume busy could not swap vol=%s from dev=%s to %s\n",
+ Dmsg3(dbglvl, "==== Swap not possible Vol busy vol=%s from dev=%s to %s\n",
VolumeName, vol->dev->print_name(), dev->print_name());
vol = NULL; /* device busy */
goto get_out;
*/
#undef VERSION
-#define VERSION "2.3.11"
-#define BDATE "04 March 2008"
-#define LSMDATE "04Mar08"
+#define VERSION "2.3.12"
+#define BDATE "06 March 2008"
+#define LSMDATE "06Mar08"
#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.3
General:
+06Mar08
+kes First cut at Duplicate Job implementation.
05Mar08
kes Fix bugs in MaxFullInterval and Implement MaxDiffInterval.
kes Start PluginOptions string, and refactor a bit of ua_run.c