* Version $Id$
*/
/*
- 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
- version 2 as amended with additional clauses defined in the
- file LICENSE in the main source directory.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- the file LICENSE for additional details.
-
- */
+ Bacula® - The Network Backup Solution
+
+ Copyright (C) 2004-2006 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.
+ This program is Free Software; you can redistribute it and/or
+ modify it under the terms of version two of the GNU General Public
+ License as published by the Free Software Foundation plus additions
+ that are listed in the file LICENSE.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+
+ Bacula® is a registered trademark of John Walker.
+ The licensor of Bacula is the Free Software Foundation Europe
+ (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
+ Switzerland, email:ftf@fsfeurope.org.
+*/
#include "bacula.h"
#include "dird.h"
#include <regex.h>
#endif
-static const int dbglevel = 100;
+static const int dbglevel = 10;
static char OKbootstrap[] = "3000 OK bootstrap\n";
static bool get_job_to_migrate(JCR *jcr);
/*
* Called here before the job is run to do the job
- * specific setup.
+ * specific setup. Note, one of the important things to
+ * complete in this init code is to make the definitive
+ * choice of input and output storage devices. This is
+ * because immediately after the init, the job is queued
+ * in the jobq.c code, and it checks that all the resources
+ * (storage resources in particular) are available, so these
+ * must all be properly defined.
+ *
+ * previous_jr refers to the job DB record of the Job that is
+ * going to be migrated.
+ * prev_job refers to the job resource of the Job that is
+ * going to be migrated.
+ * jcr is the jcr for the current "migration" job. It is a
+ * control job that is put in the DB as a migration job, which
+ * means that this job migrated a previous job to a new job.
+ * No Volume or File data is associated with this control
+ * job.
+ * mig_jcr refers to the newly migrated job that is run by
+ * the current jcr. It is a backup job that moves (migrates) the
+ * data written for the previous_jr into the new pool. This
+ * job (mig_jcr) becomes the new backup job that replaces
+ * the original backup job.
*/
bool do_migration_init(JCR *jcr)
{
+ POOL_DBR pr;
+ POOL *pool;
+ char ed1[100];
+ JOB *job, *prev_job;
+ JCR *mig_jcr; /* newly migrated job */
+
/* If we find a job or jobs to migrate it is previous_jr.JobId */
if (!get_job_to_migrate(jcr)) {
return false;
}
+ Dmsg1(dbglevel, "Back from get_job_to_migrate JobId=%d\n", (int)jcr->JobId);
if (jcr->previous_jr.JobId == 0) {
+ Dmsg1(dbglevel, "JobId=%d no previous JobId\n", (int)jcr->JobId);
+ Jmsg(jcr, M_INFO, 0, _("No previous Job found to migrate.\n"));
return true; /* no work */
}
if (!get_or_create_fileset_record(jcr)) {
+ Dmsg1(dbglevel, "JobId=%d no FileSet\n", (int)jcr->JobId);
+ Jmsg(jcr, M_FATAL, 0, _("Could not get or create the FileSet record.\n"));
return false;
}
jcr->jr.PoolId = get_or_create_pool_record(jcr, jcr->pool->hdr.name);
if (jcr->jr.PoolId == 0) {
- return false;
- }
-
- /* If pool storage specified, use it instead of job storage */
- copy_wstorage(jcr, jcr->pool->storage, _("Pool resource"));
-
- if (!jcr->wstorage) {
- Jmsg(jcr, M_FATAL, 0, _("No Storage specification found in Job or Pool.\n"));
+ Dmsg1(dbglevel, "JobId=%d no PoolId\n", (int)jcr->JobId);
+ Jmsg(jcr, M_FATAL, 0, _("Could not get or create a Pool record.\n"));
return false;
}
create_restore_bootstrap_file(jcr);
- return true;
-}
-
-/*
- * Do a Migration of a previous job
- *
- * Returns: false on failure
- * true on success
- */
-bool do_migration(JCR *jcr)
-{
- POOL_DBR pr;
- POOL *pool;
- char ed1[100];
- BSOCK *sd;
- JOB *job, *prev_job;
- JCR *mig_jcr; /* newly migrated job */
- /*
- * previous_jr refers to the job DB record of the Job that is
- * going to be migrated.
- * prev_job refers to the job resource of the Job that is
- * going to be migrated.
- * jcr is the jcr for the current "migration" job. It is a
- * control job that is put in the DB as a migration job, which
- * means that this job migrated a previous job to a new job.
- * No Volume or File data is associated with this control
- * job.
- * mig_jcr refers to the newly migrated job that is run by
- * the current jcr. It is a backup job that moves (migrates) the
- * data written for the previous_jr into the new pool. This
- * job (mig_jcr) becomes the new backup job that replaces
- * the original backup job.
- */
if (jcr->previous_jr.JobId == 0 || jcr->ExpectedFiles == 0) {
set_jcr_job_status(jcr, JS_Terminated);
- migration_cleanup(jcr, jcr->JobStatus);
+ Dmsg1(dbglevel, "JobId=%d expected files == 0\n", (int)jcr->JobId);
+ if (jcr->previous_jr.JobId == 0) {
+ Jmsg(jcr, M_INFO, 0, _("No previous Job found to migrate.\n"));
+ } else {
+ Jmsg(jcr, M_INFO, 0, _("Previous Job has no data to migrate.\n"));
+ }
return true; /* no work */
}
- Dmsg4(dbglevel, "Previous: Name=%s JobId=%d Type=%c Level=%c\n",
- jcr->previous_jr.Name, jcr->previous_jr.JobId,
+ Dmsg5(dbglevel, "JobId=%d: Previous: Name=%s JobId=%d Type=%c Level=%c\n",
+ (int)jcr->JobId,
+ jcr->previous_jr.Name, (int)jcr->previous_jr.JobId,
jcr->previous_jr.JobType, jcr->previous_jr.JobLevel);
- Dmsg4(dbglevel, "Current: Name=%s JobId=%d Type=%c Level=%c\n",
- jcr->jr.Name, jcr->jr.JobId,
+ Dmsg5(dbglevel, "JobId=%d: Current: Name=%s JobId=%d Type=%c Level=%c\n",
+ (int)jcr->JobId,
+ jcr->jr.Name, (int)jcr->jr.JobId,
jcr->jr.JobType, jcr->jr.JobLevel);
LockRes();
job = (JOB *)GetResWithName(R_JOB, jcr->jr.Name);
prev_job = (JOB *)GetResWithName(R_JOB, jcr->previous_jr.Name);
UnlockRes();
- if (!job || !prev_job) {
+ if (!job) {
+ Jmsg(jcr, M_FATAL, 0, _("Job resource not found for \"%s\".\n"), jcr->jr.Name);
+ return false;
+ }
+ if (!prev_job) {
+ Jmsg(jcr, M_FATAL, 0, _("Previous Job resource not found for \"%s\".\n"),
+ jcr->previous_jr.Name);
return false;
}
*/
set_jcr_defaults(mig_jcr, prev_job);
if (!setup_job(mig_jcr)) {
+ Jmsg(jcr, M_FATAL, 0, _("setup job failed.\n"));
return false;
}
mig_jcr->jr.JobId = mig_jcr->JobId;
Dmsg4(dbglevel, "mig_jcr: Name=%s JobId=%d Type=%c Level=%c\n",
- mig_jcr->jr.Name, mig_jcr->jr.JobId,
+ mig_jcr->jr.Name, (int)mig_jcr->jr.JobId,
mig_jcr->jr.JobType, mig_jcr->jr.JobLevel);
/*
mig_jcr->pool = jcr->pool = pool->NextPool;
mig_jcr->jr.PoolId = jcr->jr.PoolId;
pm_strcpy(jcr->pool_source, _("NextPool in Pool resource"));
+ } else {
+ Jmsg(jcr, M_FATAL, 0, _("No Next Pool specification found in Pool \"%s\".\n"),
+ pool->hdr.name);
+ return false;
+ }
+
+ if (!jcr->pool->storage || jcr->pool->storage->size() == 0) {
+ Jmsg(jcr, M_FATAL, 0, _("No Storage specification found in Next Pool \"%s\".\n"),
+ jcr->pool->hdr.name);
+ return false;
}
/* If pool storage specified, use it instead of job storage for backup */
- copy_wstorage(jcr, jcr->pool->storage, _("Pool resource"));
+ copy_wstorage(jcr, jcr->pool->storage, _("NextPool in Pool resource"));
+
+ return true;
+}
+
+/*
+ * Do a Migration of a previous job
+ *
+ * Returns: false on failure
+ * true on success
+ */
+bool do_migration(JCR *jcr)
+{
+ char ed1[100];
+ BSOCK *sd;
+ JCR *mig_jcr = jcr->mig_jcr; /* newly migrated job */
+
+ if (!mig_jcr) {
+ return false;
+ }
/* Print Job Start message */
Jmsg(jcr, M_INFO, 0, _("Start Migration JobId %s, Job=%s\n"),
set_jcr_job_status(jcr, JS_Running);
set_jcr_job_status(mig_jcr, JS_Running);
- Dmsg2(dbglevel, "JobId=%d JobLevel=%c\n", jcr->jr.JobId, jcr->jr.JobLevel);
+ Dmsg2(dbglevel, "JobId=%d JobLevel=%c\n", (int)jcr->jr.JobId, jcr->jr.JobLevel);
/* Update job start record for this migration control job */
if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
}
Dmsg4(dbglevel, "mig_jcr: Name=%s JobId=%d Type=%c Level=%c\n",
- mig_jcr->jr.Name, mig_jcr->jr.JobId,
+ mig_jcr->jr.Name, (int)mig_jcr->jr.JobId,
mig_jcr->jr.JobType, mig_jcr->jr.JobLevel);
/* Update job start record for the real migration backup job */
Dmsg2(dbglevel, "Read store=%s, write store=%s\n",
((STORE *)jcr->rstorage->first())->name(),
((STORE *)jcr->wstorage->first())->name());
+ if (((STORE *)jcr->rstorage->first())->name() == ((STORE *)jcr->wstorage->first())->name()) {
+ Jmsg(jcr, M_FATAL, 0, _("Read storage \"%s\" same as write storage.\n"),
+ ((STORE *)jcr->rstorage->first())->name());
+ return false;
+ }
if (!start_storage_daemon_job(jcr, jcr->rstorage, jcr->wstorage)) {
return false;
}
uint32_t count;
};
-/*
- * Callback handler make list of DB Ids
- */
-static int dbid_handler(void *ctx, int num_fields, char **row)
+/* Add an item to the list if it is unique */
+static void add_unique_id(idpkt *ids, char *item)
{
- idpkt *ids = (idpkt *)ctx;
-
- Dmsg3(dbglevel, "count=%d Ids=%p %s\n", ids->count, ids->list, ids->list);
+ char id[30];
+ char *q = ids->list;
+
+ /* Walk through current list to see if each item is the same as item */
+ for ( ; *q; ) {
+ id[0] = 0;
+ for (int i=0; i<(int)sizeof(id); i++) {
+ if (*q == 0) {
+ break;
+ } else if (*q == ',') {
+ q++;
+ break;
+ }
+ id[i] = *q++;
+ id[i+1] = 0;
+ }
+ if (strcmp(item, id) == 0) {
+ return;
+ }
+ }
+ /* Did not find item, so add it to list */
if (ids->count == 0) {
ids->list[0] = 0;
} else {
pm_strcat(ids->list, ",");
}
- pm_strcat(ids->list, row[0]);
+ pm_strcat(ids->list, item);
ids->count++;
+// Dmsg3(0, "add_uniq count=%d Ids=%p %s\n", ids->count, ids->list, ids->list);
+ return;
+}
+
+/*
+ * Callback handler make list of DB Ids
+ */
+static int unique_dbid_handler(void *ctx, int num_fields, char **row)
+{
+ idpkt *ids = (idpkt *)ctx;
+
+ add_unique_id(ids, row[0]);
+ Dmsg3(dbglevel, "dbid_hdlr count=%d Ids=%p %s\n", ids->count, ids->list, ids->list);
return 0;
}
memset(new_item, 0, sizeof(uitem));
new_item->item = bstrdup(row[0]);
- Dmsg1(dbglevel, "Item=%s\n", row[0]);
- item = (uitem *)list->binary_insert((void *)new_item, item_compare);
- if (item != new_item) { /* already in list */
- free(new_item->item);
- free((char *)new_item);
- return 0;
- }
- return 0;
-}
-
-#ifdef xxx /* in development */
-static int unique_dbid_handler(void *ctx, int num_fields, char **row)
-{
- dlist *list = (dlist *)ctx;
-
- uitem *new_item = (uitem *)malloc(sizeof(uitem));
- uitem *item;
-
- memset(new_item, 0, sizeof(uitem));
- new_item->item = bstrdup(row[0]);
- Dmsg1(dbglevel, "Item=%s\n", row[0]);
+ Dmsg1(dbglevel, "Unique_name_hdlr Item=%s\n", row[0]);
item = (uitem *)list->binary_insert((void *)new_item, item_compare);
if (item != new_item) { /* already in list */
free(new_item->item);
}
return 0;
}
-#endif
-
-
/* Get Job names in Pool */
const char *sql_job =
}
Dmsg1(dbglevel, "SQL=%s\n", jcr->job->selection_pattern);
if (!db_sql_query(jcr->db, jcr->job->selection_pattern,
- dbid_handler, (void *)&ids)) {
+ unique_dbid_handler, (void *)&ids)) {
Jmsg(jcr, M_FATAL, 0,
_("SQL failed. ERR=%s\n"), db_strerror(jcr->db));
goto bail_out;
ids.count = 0;
/* Find a list of MediaIds that could be migrated */
Mmsg(query, sql_mediaids, jcr->pool->hdr.name);
-// Dmsg1(dbglevel, "query=%s\n", query.c_str());
- if (!db_sql_query(jcr->db, query.c_str(), dbid_handler, (void *)&ids)) {
+ Dmsg1(dbglevel, "query=%s\n", query.c_str());
+ if (!db_sql_query(jcr->db, query.c_str(), unique_dbid_handler, (void *)&ids)) {
Jmsg(jcr, M_FATAL, 0, _("SQL failed. ERR=%s\n"), db_strerror(jcr->db));
goto bail_out;
}
ids.count = 0;
Mmsg(query, sql_pool_time, jcr->pool->hdr.name, dt);
-// Dmsg1(000, "query=%s\n", query.c_str());
- if (!db_sql_query(jcr->db, query.c_str(), dbid_handler, (void *)&ids)) {
+ Dmsg1(dbglevel, "query=%s\n", query.c_str());
+ if (!db_sql_query(jcr->db, query.c_str(), unique_dbid_handler, (void *)&ids)) {
Jmsg(jcr, M_FATAL, 0, _("SQL failed. ERR=%s\n"), db_strerror(jcr->db));
goto bail_out;
}
* for each of them. For the last JobId, we handle it below.
*/
p = ids.list;
- Jmsg(jcr, M_INFO, 0, _("The following %u JobIds will be migrated: %s\n"),
- ids.count, ids.list);
+ if (ids.count == 0) {
+ Jmsg(jcr, M_INFO, 0, _("No JobIds found to migrate.\n"));
+ goto ok_out;
+ }
+ Jmsg(jcr, M_INFO, 0, _("The following %u JobId%s will be migrated: %s\n"),
+ ids.count, ids.count==0?"":"s", ids.list);
+ Dmsg2(dbglevel, "Before loop count=%d ids=%s\n", ids.count, ids.list);
for (int i=1; i < (int)ids.count; i++) {
JobId = 0;
stat = get_next_jobid_from_list(&p, &JobId);
- Dmsg2(dbglevel, "get_next_jobid stat=%d JobId=%u\n", stat, JobId);
+ Dmsg3(dbglevel, "get_jobid_no=%d stat=%d JobId=%u\n", i, stat, JobId);
jcr->MigrateJobId = JobId;
start_migration_job(jcr);
+ Dmsg0(dbglevel, "Back from start_migration_job\n");
if (stat < 0) {
Jmsg(jcr, M_FATAL, 0, _("Invalid JobId found.\n"));
goto bail_out;
} else if (stat == 0) {
Jmsg(jcr, M_INFO, 0, _("No JobIds found to migrate.\n"));
- goto ok_out;
+ goto bail_out;
}
}
/* Now get the last JobId and handle it in the current job */
JobId = 0;
stat = get_next_jobid_from_list(&p, &JobId);
- Dmsg2(dbglevel, "Last get_next_jobid stat=%d JobId=%u\n", stat, JobId);
+ Dmsg2(dbglevel, "Last get_next_jobid stat=%d JobId=%u\n", stat, (int)JobId);
if (stat < 0) {
Jmsg(jcr, M_FATAL, 0, _("Invalid JobId found.\n"));
goto bail_out;
} else if (stat == 0) {
Jmsg(jcr, M_INFO, 0, _("No JobIds found to migrate.\n"));
- goto ok_out;
+ goto bail_out;
}
jcr->previous_jr.JobId = JobId;
- Dmsg1(100, "Previous jobid=%d\n", jcr->previous_jr.JobId);
+ Dmsg1(dbglevel, "Previous jobid=%d\n", (int)jcr->previous_jr.JobId);
if (!db_get_job_record(jcr, jcr->db, &jcr->previous_jr)) {
Jmsg(jcr, M_FATAL, 0, _("Could not get job record for JobId %s to migrate. ERR=%s"),
db_strerror(jcr->db));
goto bail_out;
}
- Jmsg(jcr, M_INFO, 0, _("Migration using JobId=%d Job=%s\n"),
- jcr->previous_jr.JobId, jcr->previous_jr.Job);
+ Jmsg(jcr, M_INFO, 0, _("Migration using JobId=%s Job=%s\n"),
+ edit_int64(jcr->previous_jr.JobId, ed1), jcr->previous_jr.Job);
+ Dmsg3(dbglevel, "Migration JobId=%d using JobId=%s Job=%s\n",
+ jcr->JobId,
+ edit_int64(jcr->previous_jr.JobId, ed1), jcr->previous_jr.Job);
ok_out:
- free_pool_memory(ids.list);
- free_pool_memory(mid.list);
- free_pool_memory(jids.list);
- return true;
+ ok = true;
+ goto out;
bail_out:
+ ok = false;
+
+out:
free_pool_memory(ids.list);
free_pool_memory(mid.list);
free_pool_memory(jids.list);
- return false;
+ return ok;
}
static void start_migration_job(JCR *jcr)
ids->count = 0;
/* Basic query for MediaId */
Mmsg(query, query1, jcr->pool->hdr.name);
- if (!db_sql_query(jcr->db, query.c_str(), dbid_handler, (void *)ids)) {
+ if (!db_sql_query(jcr->db, query.c_str(), unique_dbid_handler, (void *)ids)) {
Jmsg(jcr, M_FATAL, 0, _("SQL failed. ERR=%s\n"), db_strerror(jcr->db));
goto bail_out;
}
Mmsg(query, sql_jobids_from_mediaid, ids->list);
ids->count = 0;
- if (!db_sql_query(jcr->db, query.c_str(), dbid_handler, (void *)ids)) {
+ if (!db_sql_query(jcr->db, query.c_str(), unique_dbid_handler, (void *)ids)) {
Jmsg(jcr, M_FATAL, 0, _("SQL failed. ERR=%s\n"), db_strerror(jcr->db));
goto bail_out;
}
}
/* Basic query for names */
Mmsg(query, query1, jcr->pool->hdr.name);
- Dmsg1(dbglevel, "query1=%s\n", query.c_str());
+ Dmsg1(dbglevel, "get name query1=%s\n", query.c_str());
if (!db_sql_query(jcr->db, query.c_str(), unique_name_handler,
(void *)item_chain)) {
Jmsg(jcr, M_FATAL, 0,
free(last_item->item);
item_chain->remove(last_item);
}
- Dmsg1(dbglevel, "Item=%s\n", item->item);
+ Dmsg1(dbglevel, "get name Item=%s\n", item->item);
rc = regexec(&preg, item->item, nmatch, pmatch, 0);
if (rc == 0) {
last_item = NULL; /* keep this one */
foreach_dlist(item, item_chain) {
Dmsg2(dbglevel, "Got %s: %s\n", type, item->item);
Mmsg(query, query2, item->item, jcr->pool->hdr.name);
- Dmsg1(dbglevel, "query2=%s\n", query.c_str());
- if (!db_sql_query(jcr->db, query.c_str(), dbid_handler, (void *)ids)) {
+ Dmsg1(dbglevel, "get id from name query2=%s\n", query.c_str());
+ if (!db_sql_query(jcr->db, query.c_str(), unique_dbid_handler, (void *)ids)) {
Jmsg(jcr, M_FATAL, 0,
_("SQL failed. ERR=%s\n"), db_strerror(jcr->db));
goto bail_out;
char ec6[50], ec7[50], ec8[50];
char term_code[100], sd_term_msg[100];
const char *term_msg;
- int msg_type;
+ int msg_type = M_INFO;
MEDIA_DBR mr;
double kbps;
utime_t RunTime;
}
mig_jcr->VolumeName[0] = 0; /* none */
}
- }
-
- msg_type = M_INFO; /* by default INFO message */
- switch (jcr->JobStatus) {
- case JS_Terminated:
- if (jcr->Errors || jcr->SDErrors) {
- term_msg = _("%s OK -- with warnings");
- } else {
- term_msg = _("%s OK");
- }
- break;
- case JS_FatalError:
- case JS_ErrorTerminated:
- term_msg = _("*** %s Error ***");
- msg_type = M_ERROR; /* Generate error message */
- if (jcr->store_bsock) {
- bnet_sig(jcr->store_bsock, BNET_TERMINATE);
- if (jcr->SD_msg_chan) {
- pthread_cancel(jcr->SD_msg_chan);
+ switch (jcr->JobStatus) {
+ case JS_Terminated:
+ if (jcr->Errors || jcr->SDErrors) {
+ term_msg = _("%s OK -- with warnings");
+ } else {
+ term_msg = _("%s OK");
}
- }
- break;
- case JS_Canceled:
- term_msg = _("%s Canceled");
- if (jcr->store_bsock) {
- bnet_sig(jcr->store_bsock, BNET_TERMINATE);
- if (jcr->SD_msg_chan) {
- pthread_cancel(jcr->SD_msg_chan);
+ break;
+ case JS_FatalError:
+ case JS_ErrorTerminated:
+ term_msg = _("*** %s Error ***");
+ msg_type = M_ERROR; /* Generate error message */
+ if (jcr->store_bsock) {
+ bnet_sig(jcr->store_bsock, BNET_TERMINATE);
+ if (jcr->SD_msg_chan) {
+ pthread_cancel(jcr->SD_msg_chan);
+ }
+ }
+ break;
+ case JS_Canceled:
+ term_msg = _("%s Canceled");
+ if (jcr->store_bsock) {
+ bnet_sig(jcr->store_bsock, BNET_TERMINATE);
+ if (jcr->SD_msg_chan) {
+ pthread_cancel(jcr->SD_msg_chan);
+ }
}
+ break;
+ default:
+ term_msg = _("Inappropriate %s term code");
+ break;
}
- break;
- default:
- term_msg = _("Inappropriate %s term code");
- break;
- }
+ } else {
+ term_msg = _("%s -- no files to migrate");
+ }
+
bsnprintf(term_code, sizeof(term_code), term_msg, "Migration");
bstrftimes(sdt, sizeof(sdt), jcr->jr.StartTime);
bstrftimes(edt, sizeof(edt), jcr->jr.EndTime);
" Client: %s\n"
" FileSet: \"%s\" %s\n"
" Pool: \"%s\" (From %s)\n"
-" Storage: \"%s\" (From %s)\n"
+" Read Storage: \"%s\" (From %s)\n"
+" Write Storage: \"%s\" (From %s)\n"
" Start time: %s\n"
" End time: %s\n"
" Elapsed time: %s\n"
VERSION,
LSMDATE,
edt,
- mig_jcr ? edit_uint64(jcr->previous_jr.JobId, ec6) : "0",
+ edit_uint64(jcr->previous_jr.JobId, ec6),
mig_jcr ? edit_uint64(mig_jcr->jr.JobId, ec7) : "0",
edit_uint64(jcr->jr.JobId, ec8),
jcr->jr.Job,
jcr->client->name(),
jcr->fileset->name(), jcr->FSCreateTime,
jcr->pool->name(), jcr->pool_source,
- jcr->wstore->name(), jcr->storage_source,
+ jcr->rstore?jcr->rstore->name():"*None*",
+ NPRT(jcr->rstore_source),
+ jcr->wstore?jcr->wstore->name():"*None*",
+ NPRT(jcr->wstore_source),
sdt,
edt,
edit_utime(RunTime, elapsed, sizeof(elapsed)),