--- /dev/null
+Index: src/dird/migrate.c
+===================================================================
+--- src/dird/migrate.c (revision 7926)
++++ src/dird/migrate.c (working copy)
+@@ -402,14 +402,6 @@
+ }
+
+ migration_cleanup(jcr, jcr->JobStatus);
+- if (mig_jcr) {
+- char jobid[50];
+- UAContext *ua = new_ua_context(jcr);
+- edit_uint64(jcr->previous_jr.JobId, jobid);
+- /* Purge all old file records, but leave Job record */
+- purge_files_from_jobs(ua, jobid);
+- free_ua_context(ua);
+- }
+ return true;
+ }
+
+@@ -1087,11 +1079,26 @@
+ edit_uint64(mig_jcr->jr.JobId, ec2));
+ db_sql_query(mig_jcr->db, query.c_str(), NULL, NULL);
+
+- /* Now mark the previous job as migrated if it terminated normally */
+- if (jcr->JobStatus == JS_Terminated) {
++ /*
++ * If we terminated a migration normally:
++ * - mark the previous job as migrated
++ * - move any Log records to the new JobId
++ * - Purge the File records from the previous job
++ */
++ if (jcr->JobType == JT_MIGRATE && jcr->JobStatus == JS_Terminated) {
++ char old_jobid[50], new_jobid[50];
+ Mmsg(query, "UPDATE Job SET Type='%c' WHERE JobId=%s",
+- (char)JT_MIGRATED_JOB, edit_uint64(jcr->previous_jr.JobId, ec1));
++ (char)JT_MIGRATED_JOB, edit_uint64(jcr->previous_jr.JobId, new_jobid));
+ db_sql_query(mig_jcr->db, query.c_str(), NULL, NULL);
++ UAContext *ua = new_ua_context(jcr);
++ /* Move JobLog to new JobId */
++ Mmsg(query, "UPDATE Log SET JobId=%s WHERE JobId=%s",
++ new_jobid,
++ edit_uint64(jcr->previous_jr.JobId, old_jobid));
++ db_sql_query(mig_jcr->db, query.c_str(), NULL, NULL);
++ /* Purge all old file records, but leave Job record */
++ purge_files_from_jobs(ua, old_jobid);
++ free_ua_context(ua);
+ }
+
+ if (!db_get_job_record(jcr, jcr->db, &jcr->jr)) {
+@@ -1100,7 +1107,6 @@
+ set_jcr_job_status(jcr, JS_ErrorTerminated);
+ }
+
+-
+ update_bootstrap_file(mig_jcr);
+
+ if (!db_get_job_volume_names(mig_jcr, mig_jcr->db, mig_jcr->jr.JobId, &mig_jcr->VolumeName)) {
--- /dev/null
+
+ This patch should prevent migration jobs from attempting to migrate
+ jobs that failed. Apply it to Bacula 2.4.3 (possibly earlier versions)
+ with:
+
+ cd <bacula-source>
+ patch -p0 <2.4.3-migrate.patch
+ ./configure <your-options>
+ make
+ ...
+ make install
+
+
+Index: src/dird/migrate.c
+===================================================================
+--- src/dird/migrate.c (revision 7757)
++++ src/dird/migrate.c (working copy)
+@@ -377,7 +377,7 @@
+ * to avoid two threads from using the BSOCK structure at
+ * the same time.
+ */
+- if (!bnet_fsend(sd, "run")) {
++ if (!sd->fsend("run")) {
+ return false;
+ }
+
+@@ -520,6 +520,7 @@
+ "SELECT DISTINCT Job.JobId,Job.StartTime FROM Job,Pool,Client"
+ " WHERE Client.Name='%s' AND Pool.Name='%s' AND Job.PoolId=Pool.PoolId"
+ " AND Job.ClientId=Client.ClientId AND Job.Type='B'"
++ " AND Job.JobStatus = 'T'"
+ " ORDER by Job.StartTime";
+
+ /* Get Volume names in Pool */
+@@ -533,9 +534,9 @@
+ "SELECT DISTINCT Job.JobId,Job.StartTime FROM Media,JobMedia,Job"
+ " WHERE Media.VolumeName='%s' AND Media.MediaId=JobMedia.MediaId"
+ " AND JobMedia.JobId=Job.JobId AND Job.Type='B'"
++ " AND Job.JobStatus = 'T' AND Media.Enabled=1"
+ " ORDER by Job.StartTime";
+
+-
+ const char *sql_smallest_vol =
+ "SELECT Media.MediaId FROM Media,Pool,JobMedia WHERE"
+ " Media.MediaId in (SELECT DISTINCT MediaId from JobMedia) AND"
+@@ -570,7 +571,6 @@
+ const char *sql_job_bytes =
+ "SELECT SUM(JobBytes) FROM Job WHERE JobId IN (%s)";
+
+-
+ /* Get Media Ids in Pool */
+ const char *sql_mediaids =
+ "SELECT MediaId FROM Media,Pool WHERE"
--- /dev/null
+
+ This patch should fix the bug reported on the bacula-users list where
+ a retention period of 100 years does immediate prunning.
+ Apply it to 2.4.3 (or earlier versions) with:
+
+ cd <bacula-source>
+ patch -p0 <2.4.3-prune.patch
+ ./configure <your-options>
+ make
+ ...
+ make install
+
+Index: src/dird/ua_prune.c
+===================================================================
+--- src/dird/ua_prune.c (revision 7757)
++++ src/dird/ua_prune.c (working copy)
+@@ -202,7 +202,7 @@
+ now = (utime_t)time(NULL);
+
+ /* Select Jobs -- for counting */
+- Mmsg(query, count_select_job, edit_uint64(now - period, ed1),
++ Mmsg(query, count_select_job, edit_int64(now - period, ed1),
+ edit_int64(cr.ClientId, ed2));
+ Dmsg3(050, "select now=%u period=%u sql=%s\n", (uint32_t)now,
+ (uint32_t)period, query.c_str());
+@@ -230,7 +230,7 @@
+ del.JobId = (JobId_t *)malloc(sizeof(JobId_t) * del.max_ids);
+
+ /* Now process same set but making a delete list */
+- Mmsg(query, select_job, edit_uint64(now - period, ed1),
++ Mmsg(query, select_job, edit_int64(now - period, ed1),
+ edit_int64(cr.ClientId, ed2));
+ db_sql_query(ua->db, query.c_str(), file_delete_handler, (void *)&del);
+
+@@ -318,7 +318,7 @@
+ * Select all files that are older than the JobRetention period
+ * and stuff them into the "DeletionCandidates" table.
+ */
+- edit_uint64(now - period, ed1);
++ edit_int64(now - period, ed1);
+ Mmsg(query, insert_delcand, (char)JobType, ed1,
+ edit_int64(cr.ClientId, ed2));
+ if (!db_sql_query(ua->db, query.c_str(), NULL, (void *)NULL)) {
+@@ -443,10 +443,10 @@
+ edit_int64(mr->MediaId, ed1);
+ period = mr->VolRetention;
+ now = (utime_t)time(NULL);
+- edit_uint64(now-period, ed2);
++ edit_int64(now-period, ed2);
+ Mmsg(query, sel_JobMedia, ed1, ed2);
+- Dmsg3(250, "Now=%d period=%d now-period=%d\n", (int)now, (int)period,
+- (int)(now-period));
++ Dmsg3(250, "Now=%d period=%d now-period=%s\n", (int)now, (int)period,
++ ed2);
+
+ Dmsg1(050, "Query=%s\n", query.c_str());
+ if (!db_sql_query(ua->db, query.c_str(), file_delete_handler, (void *)del)) {
/* Extra stuff not in DB */
int limit; /* limit records to display */
faddr_t rec_addr;
+ uint32_t FileIndex; /* added during Verify */
};
/* Job Media information used to create the media records
* Note in this routine, we do not use Jmsg because it may be
* called to get attributes of a non-existent file, which is
* "normal" if a new file is found during Verify.
+ *
+ * The following is a bit of a kludge: because we always backup a
+ * directory entry, we can end up with two copies of the directory
+ * in the backup. One is when we encounter the directory and find
+ * we cannot recurse into it, and the other is when we find an
+ * explicit mention of the directory. This can also happen if the
+ * use includes the directory twice. In this case, Verify
+ * VolumeToCatalog fails because we have two copies in the catalog,
+ * and only the first one is marked (twice). So, when calling from Verify,
+ * jr is not NULL and we know jr->FileIndex is the fileindex
+ * of the version of the directory/file we actually want and do
+ * a more explicit SQL search.
*/
static
int db_get_file_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr, FILE_DBR *fdbr)
edit_int64(fdbr->FilenameId, ed2),
edit_int64(jr->ClientId,ed3));
+ } else if (jr != NULL) {
+ /* Called from Verify so jr->FileIndex is valid */
+ Mmsg(mdb->cmd,
+"SELECT FileId, LStat, MD5 FROM File WHERE File.JobId=%s AND File.PathId=%s AND "
+"File.FilenameId=%s AND FileIndex=%u",
+ edit_int64(fdbr->JobId, ed1),
+ edit_int64(fdbr->PathId, ed2),
+ edit_int64(fdbr->FilenameId,ed3),
+ jr->FileIndex);
} else {
Mmsg(mdb->cmd,
"SELECT FileId, LStat, MD5 FROM File WHERE File.JobId=%s AND File.PathId=%s AND "
edit_int64(fdbr->PathId, ed2),
edit_int64(fdbr->FilenameId,ed3));
}
- Dmsg3(050, "Get_file_record JobId=%u FilenameId=%u PathId=%u\n",
+ Dmsg3(450, "Get_file_record JobId=%u FilenameId=%u PathId=%u\n",
fdbr->JobId, fdbr->FilenameId, fdbr->PathId);
Dmsg1(100, "Query=%s\n", mdb->cmd);
if (mdb->num_rows > 1) {
Mmsg1(mdb->errmsg, _("get_file_record want 1 got rows=%d\n"),
mdb->num_rows);
+ Dmsg1(000, "=== Problem! %s", mdb->errmsg);
}
if (mdb->num_rows >= 1) {
if ((row = sql_fetch_row(mdb)) == NULL) {
}
migration_cleanup(jcr, jcr->JobStatus);
- if (jcr->get_JobType() == JT_MIGRATE && mig_jcr) {
- char jobid[50];
- UAContext *ua = new_ua_context(jcr);
- edit_uint64(jcr->previous_jr.JobId, jobid);
- /* Purge all old file records, but leave Job record */
- purge_files_from_jobs(ua, jobid);
- free_ua_context(ua);
- }
+
return true;
}
edit_uint64(mig_jcr->jr.JobId, ec2));
db_sql_query(mig_jcr->db, query.c_str(), NULL, NULL);
- /* Now mark the previous job as migrated if it terminated normally */
+ /*
+ * If we terminated a migration normally:
+ * - mark the previous job as migrated
+ * - move any Log records to the new JobId
+ * - Purge the File records from the previous job
+ */
if (jcr->get_JobType() == JT_MIGRATE && jcr->JobStatus == JS_Terminated) {
+ char old_jobid[50], new_jobid[50];
Mmsg(query, "UPDATE Job SET Type='%c' WHERE JobId=%s",
- (char)JT_MIGRATED_JOB, edit_uint64(jcr->previous_jr.JobId, ec1));
+ (char)JT_MIGRATED_JOB, edit_uint64(jcr->previous_jr.JobId, new_jobid));
+ db_sql_query(mig_jcr->db, query.c_str(), NULL, NULL);
+ UAContext *ua = new_ua_context(jcr);
+ /* Move JobLog to new JobId */
+ Mmsg(query, "UPDATE Log SET JobId=%s WHERE JobId=%s",
+ new_jobid,
+ edit_uint64(jcr->previous_jr.JobId, old_jobid));
db_sql_query(mig_jcr->db, query.c_str(), NULL, NULL);
+ /* Purge all old file records, but leave Job record */
+ purge_files_from_jobs(ua, old_jobid);
+ free_ua_context(ua);
}
if (!db_get_job_record(jcr, jcr->db, &jcr->jr)) {
extern bool send_bootstrap_file(JCR *jcr, BSOCK *sock);
extern bool send_level_command(JCR *jcr);
extern int get_attributes_and_put_in_catalog(JCR *jcr);
-extern int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId);
+extern void get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId);
extern int put_file_into_catalog(JCR *jcr, long file_index, char *fname,
char *link, char *attr, int stream);
extern void get_level_since_time(JCR *jcr, char *since, int since_len);
TermCode = JS_ErrorTerminated;
}
- /* If no files were expected, there can be no error */
- if (jcr->get_JobLevel() == L_VERIFY_VOLUME_TO_CATALOG &&
- jcr->ExpectedFiles == 0) {
- TermCode = JS_Terminated;
- }
-
JobId = jcr->jr.JobId;
update_job_end(jcr, TermCode);
/*
* This routine is called only during a Verify
*/
-int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId)
+void get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId)
{
BSOCK *fd;
int n, len;
FILE_DBR fdbr;
struct stat statf; /* file stat */
struct stat statc; /* catalog stat */
- int stat = JS_Terminated;
char buf[MAXSTRING];
POOLMEM *fname = get_pool_memory(PM_MESSAGE);
int do_Digest = CRYPTO_DIGEST_NONE;
char Opts_Digest[MAXSTRING]; /* Verify Opts or MD5/SHA1 digest */
if (job_canceled(jcr)) {
- return false;
+ return;
}
fname = check_pool_memory_size(fname, fd->msglen);
jcr->fname = check_pool_memory_size(jcr->fname, fd->msglen);
fname)) != 3) {
Jmsg3(jcr, M_FATAL, 0, _("bird<filed: bad attributes, expected 3 fields got %d\n"
" mslen=%d msg=%s\n"), len, fd->msglen, fd->msg);
- return false;
+ return;
}
/*
* We read the Options or Signature into fname
Dmsg2(400, "file_index=%d attr=%s\n", file_index, attr);
jcr->JobFiles++;
jcr->FileIndex = file_index; /* remember attribute file_index */
+ jcr->previous_jr.FileIndex = file_index;
decode_stat(attr, &statf, &LinkFIf); /* decode file stat packet */
do_Digest = CRYPTO_DIGEST_NONE;
jcr->fn_printed = false;
&jcr->previous_jr, &fdbr)) {
Jmsg(jcr, M_INFO, 0, _("New file: %s\n"), jcr->fname);
Dmsg1(020, _("File not in catalog: %s\n"), jcr->fname);
- stat = JS_Differences;
+ set_jcr_job_status(jcr, JS_Differences);
continue;
} else {
/*
Jmsg(jcr, M_INFO, 0, _(" st_ino differ. Cat: %s File: %s\n"),
edit_uint64((uint64_t)statc.st_ino, ed1),
edit_uint64((uint64_t)statf.st_ino, ed2));
- stat = JS_Differences;
+ set_jcr_job_status(jcr, JS_Differences);
}
break;
case 'p': /* permissions bits */
prt_fname(jcr);
Jmsg(jcr, M_INFO, 0, _(" st_mode differ. Cat: %x File: %x\n"),
(uint32_t)statc.st_mode, (uint32_t)statf.st_mode);
- stat = JS_Differences;
+ set_jcr_job_status(jcr, JS_Differences);
}
break;
case 'n': /* number of links */
prt_fname(jcr);
Jmsg(jcr, M_INFO, 0, _(" st_nlink differ. Cat: %d File: %d\n"),
(uint32_t)statc.st_nlink, (uint32_t)statf.st_nlink);
- stat = JS_Differences;
+ set_jcr_job_status(jcr, JS_Differences);
}
break;
case 'u': /* user id */
prt_fname(jcr);
Jmsg(jcr, M_INFO, 0, _(" st_uid differ. Cat: %u File: %u\n"),
(uint32_t)statc.st_uid, (uint32_t)statf.st_uid);
- stat = JS_Differences;
+ set_jcr_job_status(jcr, JS_Differences);
}
break;
case 'g': /* group id */
prt_fname(jcr);
Jmsg(jcr, M_INFO, 0, _(" st_gid differ. Cat: %u File: %u\n"),
(uint32_t)statc.st_gid, (uint32_t)statf.st_gid);
- stat = JS_Differences;
+ set_jcr_job_status(jcr, JS_Differences);
}
break;
case 's': /* size */
Jmsg(jcr, M_INFO, 0, _(" st_size differ. Cat: %s File: %s\n"),
edit_uint64((uint64_t)statc.st_size, ed1),
edit_uint64((uint64_t)statf.st_size, ed2));
- stat = JS_Differences;
+ set_jcr_job_status(jcr, JS_Differences);
}
break;
case 'a': /* access time */
if (statc.st_atime != statf.st_atime) {
prt_fname(jcr);
Jmsg(jcr, M_INFO, 0, _(" st_atime differs\n"));
- stat = JS_Differences;
+ set_jcr_job_status(jcr, JS_Differences);
}
break;
case 'm':
if (statc.st_mtime != statf.st_mtime) {
prt_fname(jcr);
Jmsg(jcr, M_INFO, 0, _(" st_mtime differs\n"));
- stat = JS_Differences;
+ set_jcr_job_status(jcr, JS_Differences);
}
break;
case 'c': /* ctime */
if (statc.st_ctime != statf.st_ctime) {
prt_fname(jcr);
Jmsg(jcr, M_INFO, 0, _(" st_ctime differs\n"));
- stat = JS_Differences;
+ set_jcr_job_status(jcr, JS_Differences);
}
break;
case 'd': /* file size decrease */
Jmsg(jcr, M_INFO, 0, _(" st_size decrease. Cat: %s File: %s\n"),
edit_uint64((uint64_t)statc.st_size, ed1),
edit_uint64((uint64_t)statf.st_size, ed2));
- stat = JS_Differences;
+ set_jcr_job_status(jcr, JS_Differences);
}
break;
case '5': /* compare MD5 */
if (jcr->FileIndex != (uint32_t)file_index) {
Jmsg2(jcr, M_FATAL, 0, _("MD5/SHA1 index %d not same as attributes %d\n"),
file_index, jcr->FileIndex);
- return false;
+ return;
}
if (do_Digest != CRYPTO_DIGEST_NONE) {
db_escape_string(jcr, jcr->db, buf, Opts_Digest, strlen(Opts_Digest));
prt_fname(jcr);
Jmsg(jcr, M_INFO, 0, _(" %s differs. File=%s Cat=%s\n"),
stream_to_ascii(stream), buf, fdbr.Digest);
- stat = JS_Differences;
+ set_jcr_job_status(jcr, JS_Differences);
}
do_Digest = CRYPTO_DIGEST_NONE;
}
berrno be;
Jmsg2(jcr, M_FATAL, 0, _("bdird<filed: bad attributes from filed n=%d : %s\n"),
n, be.bstrerror());
- return false;
+ return;
}
/* Now find all the files that are missing -- i.e. all files in
/* missing_handler is called for each file found */
db_sql_query(jcr->db, buf, missing_handler, (void *)jcr);
if (jcr->fn_printed) {
- stat = JS_Differences;
+ set_jcr_job_status(jcr, JS_Differences);
}
free_pool_memory(fname);
- if (!job_canceled(jcr)) {
- jcr->JobStatus = stat;
- }
- return stat == JS_Terminated;
}
/*
return 1;
}
if (!jcr->fn_printed) {
- Qmsg(jcr, M_INFO, 0, _("\nThe following files are in the Catalog but not on %s:\n"),
- jcr->get_JobLevel() == L_VERIFY_VOLUME_TO_CATALOG ? "the Volume(s)" : "disk");
+ Qmsg(jcr, M_WARNING, 0, _("The following files are in the Catalog but not on %s:\n"),
+ jcr->get_JobLevel() == L_VERIFY_VOLUME_TO_CATALOG ? "the Volume(s)" : "disk");
jcr->fn_printed = true;
}
Qmsg(jcr, M_INFO, 0, " %s%s\n", row[0]?row[0]:"", row[1]?row[1]:"");
return jcr;
}
+/*
+ * Priority runs from 0 (lowest) to 10 (highest)
+ */
+static int get_status_priority(int JobStatus)
+{
+ int priority = 0;
+ switch (JobStatus) {
+ case JS_ErrorTerminated:
+ case JS_FatalError:
+ priority = 10;
+ break;
+ case JS_Canceled:
+ priority = 9;
+ break;
+ case JS_Error:
+ priority = 8;
+ break;
+ case JS_Differences:
+ priority = 7;
+ break;
+ }
+ return priority;
+}
+
void set_jcr_job_status(JCR *jcr, int JobStatus)
{
bool set_waittime = false;
int oldJobStatus = jcr->JobStatus;
+ int priority, old_priority;
+
+ priority = get_status_priority(JobStatus);
+ old_priority = get_status_priority(oldJobStatus);
Dmsg2(800, "set_jcr_job_status(%s, %c)\n", jcr->Job, JobStatus);
/* if wait state is new, we keep current time for watchdog MaxWaitTime */
*/
Dmsg3(300, "jid=%u OnEntry JobStatus=%c set=%c\n", (uint32_t)jcr->JobId,
jcr->JobStatus, JobStatus);
- switch (jcr->JobStatus) {
- case JS_ErrorTerminated:
- case JS_FatalError:
- case JS_Canceled:
- break;
- case JS_Error:
- case JS_Differences:
- switch (JobStatus) {
- case JS_ErrorTerminated:
- case JS_FatalError:
- case JS_Canceled:
- /* Override more minor status */
- jcr->JobStatus = JobStatus;
- break;
- default:
- break;
- }
+ if (priority >= old_priority) {
+ jcr->JobStatus = JobStatus; /* replace with new priority */
+ }
/*
- * For a set of Wait situation, keep old time.
+ * If we were previously waiting and are not any more
+ * we want to update the wait_time variable, which is
+ * the start of waiting.
*/
+ switch (oldJobStatus) {
case JS_WaitFD:
case JS_WaitSD:
case JS_WaitMedia:
case JS_WaitPriority:
set_waittime = false; /* keep old time */
default:
- jcr->JobStatus = JobStatus;
if (set_waittime) {
- /* set it before JobStatus */
Dmsg0(800, "Setting wait_time\n");
jcr->wait_time = time(NULL);
}
if (dev->at_weot()) {
Dmsg0(100, "return write_block_to_dev with ST_WEOT\n");
dev->dev_errno = ENOSPC;
- Jmsg(jcr, M_FATAL, 0, _("Cannot write block. Device at EOM.\n"));
+ Jmsg0(jcr, M_FATAL, 0, _("Cannot write block. Device at EOM.\n"));
return false;
}
if (!dev->can_append()) {
/*
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.
fd->fsend(NOT_opened);
return false;
}
- set_jcr_job_status(jcr, JS_Terminated);
return fd->fsend(OK_end);
}
if (!ok) {
Jmsg2(jcr, M_FATAL, 0, _("Fatal append error on device %s: ERR=%s\n"),
dcr->dev->print_name(), dcr->dev->bstrerror());
+ Dmsg2(000, "Fatal append error on device %s: ERR=%s\n",
+ dcr->dev->print_name(), dcr->dev->bstrerror());
}
Dmsg3(800, "Write block ok=%d FI=%d LI=%d\n", ok, block->FirstIndex, block->LastIndex);
}
vol = (VOLRES *)read_vol_list->binary_insert(nvol, read_compare);
if (vol != nvol) {
free_vol_item(nvol);
- Dmsg2(1, "read_vol=%s JobId=%d already in list.\n", VolumeName, jcr->JobId);
+ Dmsg2(dbglvl, "read_vol=%s JobId=%d already in list.\n", VolumeName, jcr->JobId);
} else {
- Dmsg2(1, "add read_vol=%s JobId=%d\n", VolumeName, jcr->JobId);
+ Dmsg2(dbglvl, "add read_vol=%s JobId=%d\n", VolumeName, jcr->JobId);
}
unlock_read_volumes();
}
vol.set_jobid(jcr->JobId);
fvol = (VOLRES *)read_vol_list->binary_search(&vol, read_compare);
free(vol.vol_name);
- Dmsg3(1, "remove_read_vol=%s JobId=%d found=%d\n", VolumeName, jcr->JobId, fvol!=NULL);
+ if (fvol) {
+ Dmsg3(dbglvl, "remove_read_vol=%s JobId=%d found=%d\n", VolumeName, jcr->JobId, fvol!=NULL);
+ }
debug_list_volumes("remove_read_volume");
if (fvol) {
read_vol_list->remove(fvol);
General:
28Oct08
+kes Fix bug #1046 VolumeToCatalog incorrectly reports mounted
+ filesystems as missing on the Volume.
+kes Rewrite the set_jcr_job_status() code to include job status
+ priorities so that more important status changes occur but
+ lower priority status changes will not overwrite something
+ more serious. This could possibly cause reporting incorrect status
+ reporting in some cases. More testing is needed to ensure
+ I have the right priorities. This vastly simplifies the previous
+ contorted logic.
+ Verify Diff status should now be correctly reported, whereas it
+ was previously lost.
+kes Reduce some debug output.
kes Apply Joao's patch to SQLite tables to make chars work.
27Oct08
ebl Fix #1175 About update slots that don't reset InChanger flag when