+/*
+ Bacula® - The Network Backup Solution
+
+ Copyright (C) 2001-2010 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 and included
+ 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 Kern Sibbald.
+ The licensor of Bacula is the Free Software Foundation Europe
+ (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
+ Switzerland, email:ftf@fsfeurope.org.
+*/
/*
*
* Program to scan a Bacula Volume and compare it with
*
* Kern E. Sibbald, December 2001
*
- *
- * Version $Id$
- */
-/*
- Copyright (C) 2001-2004 Kern Sibbald and John Walker
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of
- the License, or (at your option) any later version.
-
- 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., 59 Temple Place - Suite 330, Boston,
- MA 02111-1307, USA.
-
*/
#include "bacula.h"
#include "stored.h"
#include "findlib/find.h"
#include "cats/cats.h"
+
+/* Dummy functions */
+int generate_daemon_event(JCR *jcr, const char *event) { return 1; }
+extern bool parse_sd_config(CONFIG *config, const char *configfile, int exit_code);
/* Forward referenced functions */
static void do_scan(void);
static bool record_cb(DCR *dcr, DEV_RECORD *rec);
-static int create_file_attributes_record(B_DB *db, JCR *mjcr,
- char *fname, char *lname, int type,
- char *ap, DEV_RECORD *rec);
+static int create_file_attributes_record(B_DB *db, JCR *mjcr,
+ char *fname, char *lname, int type,
+ char *ap, DEV_RECORD *rec);
static int create_media_record(B_DB *db, MEDIA_DBR *mr, VOLUME_LABEL *vl);
static bool update_media_record(B_DB *db, MEDIA_DBR *mr);
static int create_pool_record(B_DB *db, POOL_DBR *pr);
static JCR *create_job_record(B_DB *db, JOB_DBR *mr, SESSION_LABEL *label, DEV_RECORD *rec);
-static int update_job_record(B_DB *db, JOB_DBR *mr, SESSION_LABEL *elabel,
- DEV_RECORD *rec);
+static int update_job_record(B_DB *db, JOB_DBR *mr, SESSION_LABEL *elabel,
+ DEV_RECORD *rec);
static int create_client_record(B_DB *db, CLIENT_DBR *cr);
static int create_fileset_record(B_DB *db, FILESET_DBR *fsr);
static int create_jobmedia_record(B_DB *db, JCR *jcr);
static JCR *create_jcr(JOB_DBR *jr, DEV_RECORD *rec, uint32_t JobId);
-static int update_SIG_record(B_DB *db, char *SIGbuf, DEV_RECORD *rec, int type);
-
-
-/* Global variables */
-STORES *me;
-#if defined(HAVE_CYGWIN) || defined(HAVE_WIN32)
-int win32_client = 1;
-#else
-int win32_client = 0;
-#endif
+static int update_digest_record(B_DB *db, char *digest, DEV_RECORD *rec, int type);
/* Local variables */
static DEVICE *dev = NULL;
static B_DB *db;
-static JCR *bjcr; /* jcr for bscan */
+static JCR *bjcr; /* jcr for bscan */
static BSR *bsr = NULL;
static MEDIA_DBR mr;
static POOL_DBR pr;
static time_t lasttime = 0;
+static const char *db_driver = "NULL";
static const char *db_name = "bacula";
static const char *db_user = "bacula";
static const char *db_password = "";
static const char *db_host = NULL;
+static int db_port = 0;
static const char *wd = NULL;
static bool update_db = false;
static bool update_vol_info = false;
static int ignored_msgs = 0;
static uint64_t currentVolumeSize;
-static int64_t last_pct = -1;
+static int last_pct = -1;
static bool showProgress = false;
static int num_jobs = 0;
static int num_pools = 0;
static int num_media = 0;
static int num_files = 0;
+static CONFIG *config;
#define CONFIG_FILE "bacula-sd.conf"
-char *configfile;
-bool forge_on = false;
+char *configfile = NULL;
+STORES *me = NULL; /* our Global resource */
+bool forge_on = false; /* proceed inspite of I/O errors */
+pthread_mutex_t device_release_mutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_cond_t wait_device_release = PTHREAD_COND_INITIALIZER;
static void usage()
{
fprintf(stderr, _(
-"Copyright (C) 2001-2004 Kern Sibbald and John Walker.\n"
-"\nVersion: " VERSION " (" BDATE ")\n\n"
+PROG_COPYRIGHT
+"\nVersion: %s (%s)\n\n"
"Usage: bscan [ options ] <bacula-archive>\n"
" -b bootstrap specify a bootstrap file\n"
" -c <file> specify configuration file\n"
-" -d <nn> set debug level to nn\n"
+" -d <nn> set debug level to <nn>\n"
+" -dt print timestamp in debug output\n"
" -m update media info in database\n"
+" -D <driver name> specify the driver database name (default NULL)\n"
" -n <name> specify the database name (default bacula)\n"
" -u <user> specify database user name (default bacula)\n"
-" -P <password specify database password (default none)\n"
+" -P <password> specify database password (default none)\n"
" -h <host> specify database host (default NULL)\n"
+" -t <port> specify database port (default 0)\n"
" -p proceed inspite of I/O errors\n"
" -r list records\n"
" -s synchronize or store in database\n"
+" -S show scan progress periodically\n"
" -v verbose\n"
" -V <Volumes> specify Volume names (separated by |)\n"
" -w <dir> specify working directory (default from conf file)\n"
-" -? print this message\n\n"));
+" -? print this message\n\n"), 2001, VERSION, BDATE);
exit(1);
}
struct stat stat_buf;
char *VolumeName = NULL;
+ setlocale(LC_ALL, "");
+ bindtextdomain("bacula", LOCALEDIR);
+ textdomain("bacula");
+ init_stack_dump();
+ lmgr_init_thread();
+
my_name_is(argc, argv, "bscan");
init_msg(NULL, NULL);
+ OSDependentInit();
- while ((ch = getopt(argc, argv, "b:c:d:h:mn:pP:rsSu:vV:w:?")) != -1) {
+ while ((ch = getopt(argc, argv, "b:c:d:D:h:p:mn:pP:rsSt:u:vV:w:?")) != -1) {
switch (ch) {
case 'S' :
- showProgress = true;
- break;
+ showProgress = true;
+ break;
case 'b':
- bsr = parse_bsr(NULL, optarg);
- break;
+ bsr = parse_bsr(NULL, optarg);
+ break;
case 'c': /* specify config file */
- if (configfile != NULL) {
- free(configfile);
- }
- configfile = bstrdup(optarg);
- break;
+ if (configfile != NULL) {
+ free(configfile);
+ }
+ configfile = bstrdup(optarg);
+ break;
+
+ case 'D':
+ db_driver = optarg;
+ break;
case 'd': /* debug level */
- debug_level = atoi(optarg);
- if (debug_level <= 0)
- debug_level = 1;
- break;
+ if (*optarg == 't') {
+ dbg_timestamp = true;
+ } else {
+ debug_level = atoi(optarg);
+ if (debug_level <= 0) {
+ debug_level = 1;
+ }
+ }
+ break;
case 'h':
- db_host = optarg;
- break;
+ db_host = optarg;
+ break;
+
+ case 't':
+ db_port = atoi(optarg);
+ break;
case 'm':
- update_vol_info = true;
- break;
+ update_vol_info = true;
+ break;
case 'n':
- db_name = optarg;
- break;
+ db_name = optarg;
+ break;
case 'u':
- db_user = optarg;
- break;
+ db_user = optarg;
+ break;
case 'P':
- db_password = optarg;
- break;
+ db_password = optarg;
+ break;
case 'p':
- forge_on = true;
- break;
+ forge_on = true;
+ break;
case 'r':
- list_records = true;
- break;
+ list_records = true;
+ break;
case 's':
- update_db = true;
- break;
+ update_db = true;
+ break;
case 'v':
- verbose++;
- break;
+ verbose++;
+ break;
case 'V': /* Volume name */
- VolumeName = optarg;
- break;
+ VolumeName = optarg;
+ break;
case 'w':
- wd = optarg;
- break;
+ wd = optarg;
+ break;
case '?':
default:
- usage();
+ usage();
- }
+ }
}
argc -= optind;
argv += optind;
configfile = bstrdup(CONFIG_FILE);
}
- parse_config(configfile);
+ config = new_config_parser();
+ parse_sd_config(config, configfile, M_ERROR_TERM);
LockRes();
me = (STORES *)GetNextRes(R_STORAGE, NULL);
if (!me) {
UnlockRes();
- Emsg1(M_ERROR_TERM, 0, _("No Storage resource defined in %s. Cannot continue.\n"),
- configfile);
+ Emsg1(M_ERROR_TERM, 0, _("No Storage resource defined in %s. Cannot continue.\n"),
+ configfile);
}
UnlockRes();
/* Check if -w option given, otherwise use resource for working directory */
- if (wd) {
+ if (wd) {
working_directory = wd;
} else if (!me->working_directory) {
Emsg1(M_ERROR_TERM, 0, _("No Working Directory defined in %s. Cannot continue.\n"),
- configfile);
+ configfile);
} else {
working_directory = me->working_directory;
}
/* Check that working directory is good */
if (stat(working_directory, &stat_buf) != 0) {
Emsg1(M_ERROR_TERM, 0, _("Working Directory: %s not found. Cannot continue.\n"),
- working_directory);
+ working_directory);
}
if (!S_ISDIR(stat_buf.st_mode)) {
Emsg1(M_ERROR_TERM, 0, _("Working Directory: %s is not a directory. Cannot continue.\n"),
- working_directory);
+ working_directory);
}
bjcr = setup_jcr("bscan", argv[0], bsr, VolumeName, 1); /* read device */
- if (!bjcr) {
+ if (!bjcr) {
exit(1);
}
- dev = bjcr->dcr->dev;
+ dev = bjcr->read_dcr->dev;
if (showProgress) {
+ char ed1[50];
struct stat sb;
- fstat(dev->fd, &sb);
+ fstat(dev->fd(), &sb);
currentVolumeSize = sb.st_size;
- Pmsg1(000, _("Current Volume Size = %" llu "\n"), currentVolumeSize);
+ Pmsg1(000, _("First Volume Size = %s\n"),
+ edit_uint64(currentVolumeSize, ed1));
}
- if ((db=db_init_database(NULL, db_name, db_user, db_password,
- db_host, 0, NULL, 0)) == NULL) {
+ if ((db=db_init(NULL, db_driver, db_name, db_user, db_password,
+ db_host, db_port, NULL, 0)) == NULL) {
Emsg0(M_ERROR_TERM, 0, _("Could not init Bacula database\n"));
}
if (!db_open_database(NULL, db)) {
}
do_scan();
- printf("Records %sadded to catalog:\n%7d Media\n%7d Pool\n%7d Job\n%7d File\n",
- update_db?"":"would have been ",
- num_media, num_pools, num_jobs, num_files);
+ if (update_db) {
+ printf("Records added or updated in the catalog:\n%7d Media\n%7d Pool\n%7d Job\n%7d File\n",
+ num_media, num_pools, num_jobs, num_files);
+ } else {
+ printf("Records would have been added or updated in the catalog:\n%7d Media\n%7d Pool\n%7d Job\n%7d File\n",
+ num_media, num_pools, num_jobs, num_files);
+ }
free_jcr(bjcr);
- term_dev(dev);
+ dev->term();
return 0;
}
-
-/*
+
+/*
* We are at the end of reading a tape. Now, we simulate handling
* the end of writing a tape by wiffling through the attached
* jcrs creating jobmedia records.
{
DEVICE *dev = dcr->dev;
DCR *mdcr;
- Dmsg1(100, "Walk attached jcrs. Volume=%s\n", dev->VolCatInfo.VolCatName);
+ Dmsg1(100, "Walk attached jcrs. Volume=%s\n", dev->getVolCatName());
foreach_dlist(mdcr, dev->attached_dcrs) {
JCR *mjcr = mdcr->jcr;
+ Dmsg1(000, "========== JobId=%u ========\n", mjcr->JobId);
if (mjcr->JobId == 0) {
- continue;
+ continue;
}
if (verbose) {
Pmsg1(000, _("Create JobMedia for Job %s\n"), mjcr->Job);
}
- if (dev->state & ST_TAPE) {
- mdcr->EndBlock = dev->EndBlock;
- mdcr->EndFile = dev->EndFile;
- } else {
- mdcr->EndBlock = (uint32_t)dev->file_addr;
- mdcr->EndFile = (uint32_t)(dev->file_addr >> 32);
- }
+ mdcr->StartBlock = dcr->StartBlock;
+ mdcr->StartFile = dcr->StartFile;
+ mdcr->EndBlock = dcr->EndBlock;
+ mdcr->EndFile = dcr->EndFile;
+ mdcr->VolMediaId = dcr->VolMediaId;
+ mjcr->read_dcr->VolLastIndex = dcr->VolLastIndex;
if (!create_jobmedia_record(db, mjcr)) {
Pmsg2(000, _("Could not create JobMedia record for Volume=%s Job=%s\n"),
- dev->VolCatInfo.VolCatName, mjcr->Job);
+ dev->getVolCatName(), mjcr->Job);
}
- }
+ }
+
+ update_media_record(db, &mr);
+
/* Now let common read routine get up next tape. Note,
* we call mount_next... with bscan's jcr because that is where we
* have the Volume list, but we get attached.
bool stat = mount_next_read_volume(dcr);
if (showProgress) {
+ char ed1[50];
struct stat sb;
- fstat(dev->fd, &sb);
+ fstat(dev->fd(), &sb);
currentVolumeSize = sb.st_size;
- Pmsg1(000, _("Current Volume Size = %" llu "\n"), currentVolumeSize);
+ Pmsg1(000, _("First Volume Size = %s\n"),
+ edit_uint64(currentVolumeSize, ed1));
}
return stat;
}
-static void do_scan()
+static void do_scan()
{
- attr = new_attr();
+ attr = new_attr(bjcr);
memset(&ar, 0, sizeof(ar));
memset(&pr, 0, sizeof(pr));
/* Detach bscan's jcr as we are not a real Job on the tape */
- read_records(bjcr->dcr, record_cb, bscan_mount_next_read_volume);
+ read_records(bjcr->read_dcr, record_cb, bscan_mount_next_read_volume);
+ if (update_db) {
+ db_write_batch_file_records(bjcr); /* used by bulk batch file insert */
+ }
free_attr(attr);
}
/*
* Returns: true if OK
- * false if error
+ * false if error
*/
static bool record_cb(DCR *dcr, DEV_RECORD *rec)
{
DEVICE *dev = dcr->dev;
JCR *bjcr = dcr->jcr;
DEV_BLOCK *block = dcr->block;
+ char digest[BASE64_SIZE(CRYPTO_DIGEST_MAX_SIZE)];
if (rec->data_len > 0) {
mr.VolBytes += rec->data_len + WRITE_RECHDR_LENGTH; /* Accumulate Volume bytes */
- if (showProgress) {
- int64_t pct = (mr.VolBytes * 100) / currentVolumeSize;
- if (pct != last_pct) {
- fprintf(stdout, "done: %" lld "\n", pct);
- fflush(stdout);
- last_pct = pct;
- }
+ if (showProgress && currentVolumeSize > 0) {
+ int pct = (mr.VolBytes * 100) / currentVolumeSize;
+ if (pct != last_pct) {
+ fprintf(stdout, _("done: %d%%\n"), pct);
+ fflush(stdout);
+ last_pct = pct;
+ }
}
}
-
+
if (list_records) {
Pmsg5(000, _("Record: SessId=%u SessTim=%u FileIndex=%d Stream=%d len=%u\n"),
- rec->VolSessionId, rec->VolSessionTime, rec->FileIndex,
- rec->Stream, rec->data_len);
+ rec->VolSessionId, rec->VolSessionTime, rec->FileIndex,
+ rec->Stream, rec->data_len);
}
- /*
- * Check for Start or End of Session Record
+ /*
+ * Check for Start or End of Session Record
*
*/
if (rec->FileIndex < 0) {
bool save_update_db = update_db;
if (verbose > 1) {
- dump_label_record(dev, rec, 1);
+ dump_label_record(dev, rec, 1);
}
switch (rec->FileIndex) {
case PRE_LABEL:
Pmsg0(000, _("Volume is prelabeled. This tape cannot be scanned.\n"));
- return false;
- break;
+ return false;
+ break;
case VOL_LABEL:
- unser_volume_label(dev, rec);
- /* Check Pool info */
- bstrncpy(pr.Name, dev->VolHdr.PoolName, sizeof(pr.Name));
- bstrncpy(pr.PoolType, dev->VolHdr.PoolType, sizeof(pr.PoolType));
- num_pools++;
- if (db_get_pool_record(bjcr, db, &pr)) {
- if (verbose) {
+ unser_volume_label(dev, rec);
+ /* Check Pool info */
+ bstrncpy(pr.Name, dev->VolHdr.PoolName, sizeof(pr.Name));
+ bstrncpy(pr.PoolType, dev->VolHdr.PoolType, sizeof(pr.PoolType));
+ num_pools++;
+ if (db_get_pool_record(bjcr, db, &pr)) {
+ if (verbose) {
Pmsg1(000, _("Pool record for %s found in DB.\n"), pr.Name);
- }
- } else {
- if (!update_db) {
+ }
+ } else {
+ if (!update_db) {
Pmsg1(000, _("VOL_LABEL: Pool record not found for Pool: %s\n"),
- pr.Name);
- }
- create_pool_record(db, &pr);
- }
- if (strcmp(pr.PoolType, dev->VolHdr.PoolType) != 0) {
+ pr.Name);
+ }
+ create_pool_record(db, &pr);
+ }
+ if (strcmp(pr.PoolType, dev->VolHdr.PoolType) != 0) {
Pmsg2(000, _("VOL_LABEL: PoolType mismatch. DB=%s Vol=%s\n"),
- pr.PoolType, dev->VolHdr.PoolType);
- return true;
- } else if (verbose) {
+ pr.PoolType, dev->VolHdr.PoolType);
+ return true;
+ } else if (verbose) {
Pmsg1(000, _("Pool type \"%s\" is OK.\n"), pr.PoolType);
- }
-
- /* Check Media Info */
- memset(&mr, 0, sizeof(mr));
- bstrncpy(mr.VolumeName, dev->VolHdr.VolName, sizeof(mr.VolumeName));
- mr.PoolId = pr.PoolId;
- num_media++;
- if (db_get_media_record(bjcr, db, &mr)) {
- if (verbose) {
+ }
+
+ /* Check Media Info */
+ memset(&mr, 0, sizeof(mr));
+ bstrncpy(mr.VolumeName, dev->VolHdr.VolumeName, sizeof(mr.VolumeName));
+ mr.PoolId = pr.PoolId;
+ num_media++;
+ if (db_get_media_record(bjcr, db, &mr)) {
+ if (verbose) {
Pmsg1(000, _("Media record for %s found in DB.\n"), mr.VolumeName);
- }
- /* Clear out some volume statistics that will be updated */
- mr.VolJobs = mr.VolFiles = mr.VolBlocks = 0;
- mr.VolBytes = rec->data_len + 20;
- } else {
- if (!update_db) {
+ }
+ /* Clear out some volume statistics that will be updated */
+ mr.VolJobs = mr.VolFiles = mr.VolBlocks = 0;
+ mr.VolBytes = rec->data_len + 20;
+ } else {
+ if (!update_db) {
Pmsg1(000, _("VOL_LABEL: Media record not found for Volume: %s\n"),
- mr.VolumeName);
- }
- bstrncpy(mr.MediaType, dev->VolHdr.MediaType, sizeof(mr.MediaType));
- create_media_record(db, &mr, &dev->VolHdr);
- }
- if (strcmp(mr.MediaType, dev->VolHdr.MediaType) != 0) {
+ mr.VolumeName);
+ }
+ bstrncpy(mr.MediaType, dev->VolHdr.MediaType, sizeof(mr.MediaType));
+ create_media_record(db, &mr, &dev->VolHdr);
+ }
+ if (strcmp(mr.MediaType, dev->VolHdr.MediaType) != 0) {
Pmsg2(000, _("VOL_LABEL: MediaType mismatch. DB=%s Vol=%s\n"),
- mr.MediaType, dev->VolHdr.MediaType);
- return true; /* ignore error */
- } else if (verbose) {
+ mr.MediaType, dev->VolHdr.MediaType);
+ return true; /* ignore error */
+ } else if (verbose) {
Pmsg1(000, _("Media type \"%s\" is OK.\n"), mr.MediaType);
- }
- /* Reset some JCR variables */
- foreach_dlist(dcr, dev->attached_dcrs) {
- dcr->VolFirstIndex = dcr->FileIndex = 0;
- dcr->StartBlock = dcr->EndBlock = 0;
- dcr->StartFile = dcr->EndFile = 0;
- }
+ }
+ /* Reset some DCR variables */
+ foreach_dlist(dcr, dev->attached_dcrs) {
+ dcr->VolFirstIndex = dcr->FileIndex = 0;
+ dcr->StartBlock = dcr->EndBlock = 0;
+ dcr->StartFile = dcr->EndFile = 0;
+ dcr->VolMediaId = 0;
+ }
Pmsg1(000, _("VOL_LABEL: OK for Volume: %s\n"), mr.VolumeName);
- break;
+ break;
case SOS_LABEL:
- mr.VolJobs++;
- num_jobs++;
- if (ignored_msgs > 0) {
- Pmsg1(000, _("%d \"errors\" ignored before first Start of Session record.\n"),
- ignored_msgs);
- ignored_msgs = 0;
- }
- unser_session_label(&label, rec);
- memset(&jr, 0, sizeof(jr));
- bstrncpy(jr.Job, label.Job, sizeof(jr.Job));
- if (db_get_job_record(bjcr, db, &jr)) {
- /* Job record already exists in DB */
+ mr.VolJobs++;
+ num_jobs++;
+ if (ignored_msgs > 0) {
+ Pmsg1(000, _("%d \"errors\" ignored before first Start of Session record.\n"),
+ ignored_msgs);
+ ignored_msgs = 0;
+ }
+ unser_session_label(&label, rec);
+ memset(&jr, 0, sizeof(jr));
+ bstrncpy(jr.Job, label.Job, sizeof(jr.Job));
+ if (db_get_job_record(bjcr, db, &jr)) {
+ /* Job record already exists in DB */
update_db = false; /* don't change db in create_job_record */
- if (verbose) {
+ if (verbose) {
Pmsg1(000, _("SOS_LABEL: Found Job record for JobId: %d\n"), jr.JobId);
- }
- } else {
- /* Must create a Job record in DB */
- if (!update_db) {
+ }
+ } else {
+ /* Must create a Job record in DB */
+ if (!update_db) {
Pmsg1(000, _("SOS_LABEL: Job record not found for JobId: %d\n"),
- jr.JobId);
- }
- }
- /* Create Client record if not already there */
- bstrncpy(cr.Name, label.ClientName, sizeof(cr.Name));
- create_client_record(db, &cr);
- jr.ClientId = cr.ClientId;
+ jr.JobId);
+ }
+ }
+ /* Create Client record if not already there */
+ bstrncpy(cr.Name, label.ClientName, sizeof(cr.Name));
+ create_client_record(db, &cr);
+ jr.ClientId = cr.ClientId;
/* process label, if Job record exists don't update db */
- mjcr = create_job_record(db, &jr, &label, rec);
- dcr = mjcr->dcr;
- update_db = save_update_db;
-
- jr.PoolId = pr.PoolId;
- /* Set start positions into JCR */
- if (dev->state & ST_TAPE) {
- /*
- * Note, we have already advanced past current block,
- * so the correct number is block_num - 1
- */
- dcr->StartBlock = dev->block_num - 1;
- dcr->StartFile = dev->file;
- } else {
- dcr->StartBlock = (uint32_t)dev->file_addr;
- dcr->StartFile = (uint32_t)(dev->file_addr >> 32);
- }
- mjcr->start_time = jr.StartTime;
- mjcr->JobLevel = jr.JobLevel;
-
- mjcr->client_name = get_pool_memory(PM_FNAME);
- pm_strcpy(mjcr->client_name, label.ClientName);
- mjcr->fileset_name = get_pool_memory(PM_FNAME);
- pm_strcpy(mjcr->fileset_name, label.FileSetName);
- bstrncpy(dcr->pool_type, label.PoolType, sizeof(dcr->pool_type));
- bstrncpy(dcr->pool_name, label.PoolName, sizeof(dcr->pool_name));
-
- if (rec->VolSessionId != jr.VolSessionId) {
+ mjcr = create_job_record(db, &jr, &label, rec);
+ dcr = mjcr->read_dcr;
+ update_db = save_update_db;
+
+ jr.PoolId = pr.PoolId;
+ mjcr->start_time = jr.StartTime;
+ mjcr->set_JobLevel(jr.JobLevel);
+
+ mjcr->client_name = get_pool_memory(PM_FNAME);
+ pm_strcpy(mjcr->client_name, label.ClientName);
+ mjcr->fileset_name = get_pool_memory(PM_FNAME);
+ pm_strcpy(mjcr->fileset_name, label.FileSetName);
+ bstrncpy(dcr->pool_type, label.PoolType, sizeof(dcr->pool_type));
+ bstrncpy(dcr->pool_name, label.PoolName, sizeof(dcr->pool_name));
+
+ if (rec->VolSessionId != jr.VolSessionId) {
Pmsg3(000, _("SOS_LABEL: VolSessId mismatch for JobId=%u. DB=%d Vol=%d\n"),
- jr.JobId,
- jr.VolSessionId, rec->VolSessionId);
- return true; /* ignore error */
- }
- if (rec->VolSessionTime != jr.VolSessionTime) {
+ jr.JobId,
+ jr.VolSessionId, rec->VolSessionId);
+ return true; /* ignore error */
+ }
+ if (rec->VolSessionTime != jr.VolSessionTime) {
Pmsg3(000, _("SOS_LABEL: VolSessTime mismatch for JobId=%u. DB=%d Vol=%d\n"),
- jr.JobId,
- jr.VolSessionTime, rec->VolSessionTime);
- return true; /* ignore error */
- }
- if (jr.PoolId != pr.PoolId) {
+ jr.JobId,
+ jr.VolSessionTime, rec->VolSessionTime);
+ return true; /* ignore error */
+ }
+ if (jr.PoolId != pr.PoolId) {
Pmsg3(000, _("SOS_LABEL: PoolId mismatch for JobId=%u. DB=%d Vol=%d\n"),
- jr.JobId,
- jr.PoolId, pr.PoolId);
- return true; /* ignore error */
- }
- break;
+ jr.JobId,
+ jr.PoolId, pr.PoolId);
+ return true; /* ignore error */
+ }
+ break;
case EOS_LABEL:
- unser_session_label(&elabel, rec);
+ unser_session_label(&elabel, rec);
- /* Create FileSet record */
- bstrncpy(fsr.FileSet, label.FileSetName, sizeof(fsr.FileSet));
- bstrncpy(fsr.MD5, label.FileSetMD5, sizeof(fsr.MD5));
- create_fileset_record(db, &fsr);
- jr.FileSetId = fsr.FileSetId;
+ /* Create FileSet record */
+ bstrncpy(fsr.FileSet, label.FileSetName, sizeof(fsr.FileSet));
+ bstrncpy(fsr.MD5, label.FileSetMD5, sizeof(fsr.MD5));
+ create_fileset_record(db, &fsr);
+ jr.FileSetId = fsr.FileSetId;
- mjcr = get_jcr_by_session(rec->VolSessionId, rec->VolSessionTime);
- if (!mjcr) {
+ mjcr = get_jcr_by_session(rec->VolSessionId, rec->VolSessionTime);
+ if (!mjcr) {
Pmsg2(000, _("Could not find SessId=%d SessTime=%d for EOS record.\n"),
- rec->VolSessionId, rec->VolSessionTime);
- break;
- }
+ rec->VolSessionId, rec->VolSessionTime);
+ break;
+ }
- /* Do the final update to the Job record */
- update_job_record(db, &jr, &elabel, rec);
+ /* Do the final update to the Job record */
+ update_job_record(db, &jr, &elabel, rec);
- mjcr->end_time = jr.EndTime;
- mjcr->JobStatus = JS_Terminated;
+ mjcr->end_time = jr.EndTime;
+ mjcr->JobStatus = JS_Terminated;
- /* Create JobMedia record */
- create_jobmedia_record(db, mjcr);
- dev->attached_dcrs->remove(mjcr->dcr);
- free_jcr(mjcr);
+ /* Create JobMedia record */
+ mjcr->read_dcr->VolLastIndex = dcr->VolLastIndex;
+ create_jobmedia_record(db, mjcr);
+ free_dcr(mjcr->read_dcr);
+ free_jcr(mjcr);
- break;
+ break;
case EOM_LABEL:
- break;
-
- case EOT_LABEL: /* end of all tapes */
- /*
- * Wiffle through all jobs still open and close
- * them.
- */
- if (update_db) {
- DCR *mdcr;
- foreach_dlist(mdcr, dev->attached_dcrs) {
- JCR *mjcr = mdcr->jcr;
- if (!mjcr || mjcr->JobId == 0) {
- continue;
- }
- jr.JobId = mjcr->JobId;
- /* Mark Job as Error Terimined */
- jr.JobStatus = JS_ErrorTerminated;
- jr.JobFiles = mjcr->JobFiles;
- jr.JobBytes = mjcr->JobBytes;
- jr.VolSessionId = mjcr->VolSessionId;
- jr.VolSessionTime = mjcr->VolSessionTime;
- jr.JobTDate = (utime_t)mjcr->start_time;
- jr.ClientId = mjcr->ClientId;
- if (!db_update_job_end_record(bjcr, db, &jr)) {
+ break;
+
+ case EOT_LABEL: /* end of all tapes */
+ /*
+ * Wiffle through all jobs still open and close
+ * them.
+ */
+ if (update_db) {
+ DCR *mdcr;
+ foreach_dlist(mdcr, dev->attached_dcrs) {
+ JCR *mjcr = mdcr->jcr;
+ if (!mjcr || mjcr->JobId == 0) {
+ continue;
+ }
+ jr.JobId = mjcr->JobId;
+ /* Mark Job as Error Terimined */
+ jr.JobStatus = JS_ErrorTerminated;
+ jr.JobFiles = mjcr->JobFiles;
+ jr.JobBytes = mjcr->JobBytes;
+ jr.VolSessionId = mjcr->VolSessionId;
+ jr.VolSessionTime = mjcr->VolSessionTime;
+ jr.JobTDate = (utime_t)mjcr->start_time;
+ jr.ClientId = mjcr->ClientId;
+ if (!db_update_job_end_record(bjcr, db, &jr)) {
Pmsg1(0, _("Could not update job record. ERR=%s\n"), db_strerror(db));
- }
- mjcr->dcr = NULL;
- free_jcr(mjcr);
- }
- }
- mr.VolFiles = rec->File;
- mr.VolBlocks = rec->Block;
- mr.VolBytes += mr.VolBlocks * WRITE_BLKHDR_LENGTH; /* approx. */
- mr.VolMounts++;
- update_media_record(db, &mr);
+ }
+ mjcr->read_dcr = NULL;
+ free_jcr(mjcr);
+ }
+ }
+ mr.VolFiles = rec->File;
+ mr.VolBlocks = rec->Block;
+ mr.VolBytes += mr.VolBlocks * WRITE_BLKHDR_LENGTH; /* approx. */
+ mr.VolMounts++;
+ update_media_record(db, &mr);
Pmsg3(0, _("End of all Volumes. VolFiles=%u VolBlocks=%u VolBytes=%s\n"), mr.VolFiles,
- mr.VolBlocks, edit_uint64_with_commas(mr.VolBytes, ec1));
- break;
+ mr.VolBlocks, edit_uint64_with_commas(mr.VolBytes, ec1));
+ break;
default:
- break;
+ break;
} /* end switch */
return true;
}
if (!mjcr) {
if (mr.VolJobs > 0) {
Pmsg2(000, _("Could not find Job for SessId=%d SessTime=%d record.\n"),
- rec->VolSessionId, rec->VolSessionTime);
+ rec->VolSessionId, rec->VolSessionTime);
} else {
- ignored_msgs++;
+ ignored_msgs++;
}
return true;
}
- dcr = mjcr->dcr;
+ dcr = mjcr->read_dcr;
if (dcr->VolFirstIndex == 0) {
dcr->VolFirstIndex = block->FirstIndex;
}
/* File Attributes stream */
switch (rec->Stream) {
- case STREAM_UNIX_ATTRIBUTES:
- case STREAM_UNIX_ATTRIBUTES_EX:
+ case STREAM_UNIX_ATTRIBUTES:
+ case STREAM_UNIX_ATTRIBUTES_EX:
- if (!unpack_attributes_record(bjcr, rec->Stream, rec->data, attr)) {
+ if (!unpack_attributes_record(bjcr, rec->Stream, rec->data, rec->data_len, attr)) {
Emsg0(M_ERROR_TERM, 0, _("Cannot continue.\n"));
}
- if (attr->file_index != rec->FileIndex) {
- Emsg2(M_ERROR_TERM, 0, _("Record header file index %ld not equal record index %ld\n"),
- rec->FileIndex, attr->file_index);
- }
-
if (verbose > 1) {
- decode_stat(attr->attr, &attr->statp, &attr->LinkFI);
- build_attr_output_fnames(bjcr, attr);
- print_ls_output(bjcr, attr);
+ decode_stat(attr->attr, &attr->statp, &attr->LinkFI);
+ build_attr_output_fnames(bjcr, attr);
+ print_ls_output(bjcr, attr);
}
fr.JobId = mjcr->JobId;
fr.FileId = 0;
num_files++;
if (verbose && (num_files & 0x7FFF) == 0) {
- char ed1[30], ed2[30], ed3[30], ed4[30];
+ char ed1[30], ed2[30], ed3[30], ed4[30];
Pmsg4(000, _("%s file records. At file:blk=%s:%s bytes=%s\n"),
- edit_uint64_with_commas(num_files, ed1),
- edit_uint64_with_commas(rec->File, ed2),
- edit_uint64_with_commas(rec->Block, ed3),
- edit_uint64_with_commas(mr.VolBytes, ed4));
- }
- create_file_attributes_record(db, mjcr, attr->fname, attr->lname,
- attr->type, attr->attr, rec);
+ edit_uint64_with_commas(num_files, ed1),
+ edit_uint64_with_commas(rec->File, ed2),
+ edit_uint64_with_commas(rec->Block, ed3),
+ edit_uint64_with_commas(mr.VolBytes, ed4));
+ }
+ create_file_attributes_record(db, mjcr, attr->fname, attr->lname,
+ attr->type, attr->attr, rec);
free_jcr(mjcr);
break;
+ case STREAM_RESTORE_OBJECT:
+ /* ****FIXME*****/
+ /* Implement putting into catalog */
+ break;
+
/* Data stream */
case STREAM_WIN32_DATA:
case STREAM_FILE_DATA:
case STREAM_SPARSE_DATA:
+ case STREAM_ENCRYPTED_FILE_DATA:
+ case STREAM_ENCRYPTED_WIN32_DATA:
+ case STREAM_ENCRYPTED_MACOS_FORK_DATA:
+ /*
+ * For encrypted stream, this is an approximation.
+ * The data must be decrypted to know the correct length.
+ */
mjcr->JobBytes += rec->data_len;
if (rec->Stream == STREAM_SPARSE_DATA) {
- mjcr->JobBytes -= sizeof(uint64_t);
+ mjcr->JobBytes -= sizeof(uint64_t);
}
-
- free_jcr(mjcr); /* done using JCR */
+
+ free_jcr(mjcr); /* done using JCR */
break;
case STREAM_GZIP_DATA:
- mjcr->JobBytes += rec->data_len; /* No correct, we should expand it */
- free_jcr(mjcr); /* done using JCR */
+ case STREAM_ENCRYPTED_FILE_GZIP_DATA:
+ case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
+ /* No correct, we should (decrypt and) expand it
+ done using JCR
+ */
+ mjcr->JobBytes += rec->data_len;
+ free_jcr(mjcr);
break;
case STREAM_SPARSE_GZIP_DATA:
mjcr->JobBytes += rec->data_len - sizeof(uint64_t); /* No correct, we should expand it */
- free_jcr(mjcr); /* done using JCR */
+ free_jcr(mjcr); /* done using JCR */
break;
/* Win32 GZIP stream */
case STREAM_WIN32_GZIP_DATA:
mjcr->JobBytes += rec->data_len;
- free_jcr(mjcr); /* done using JCR */
+ free_jcr(mjcr); /* done using JCR */
+ break;
+
+ case STREAM_MD5_DIGEST:
+ bin_to_base64(digest, sizeof(digest), (char *)rec->data, CRYPTO_DIGEST_MD5_SIZE, true);
+ if (verbose > 1) {
+ Pmsg1(000, _("Got MD5 record: %s\n"), digest);
+ }
+ update_digest_record(db, digest, rec, CRYPTO_DIGEST_MD5);
break;
- case STREAM_MD5_SIGNATURE:
- char MD5buf[50];
- bin_to_base64(MD5buf, (char *)rec->data, 16); /* encode 16 bytes */
+ case STREAM_SHA1_DIGEST:
+ bin_to_base64(digest, sizeof(digest), (char *)rec->data, CRYPTO_DIGEST_SHA1_SIZE, true);
if (verbose > 1) {
- Pmsg1(000, _("Got MD5 record: %s\n"), MD5buf);
+ Pmsg1(000, _("Got SHA1 record: %s\n"), digest);
}
- update_SIG_record(db, MD5buf, rec, MD5_SIG);
+ update_digest_record(db, digest, rec, CRYPTO_DIGEST_SHA1);
break;
- case STREAM_SHA1_SIGNATURE:
- char SIGbuf[50];
- bin_to_base64(SIGbuf, (char *)rec->data, 20); /* encode 20 bytes */
+ case STREAM_SHA256_DIGEST:
+ bin_to_base64(digest, sizeof(digest), (char *)rec->data, CRYPTO_DIGEST_SHA256_SIZE, true);
if (verbose > 1) {
- Pmsg1(000, _("Got SHA1 record: %s\n"), SIGbuf);
+ Pmsg1(000, _("Got SHA256 record: %s\n"), digest);
}
- update_SIG_record(db, SIGbuf, rec, SHA1_SIG);
+ update_digest_record(db, digest, rec, CRYPTO_DIGEST_SHA256);
break;
+ case STREAM_SHA512_DIGEST:
+ bin_to_base64(digest, sizeof(digest), (char *)rec->data, CRYPTO_DIGEST_SHA512_SIZE, true);
+ if (verbose > 1) {
+ Pmsg1(000, _("Got SHA512 record: %s\n"), digest);
+ }
+ update_digest_record(db, digest, rec, CRYPTO_DIGEST_SHA512);
+ break;
+
+ case STREAM_ENCRYPTED_SESSION_DATA:
+ // TODO landonf: Investigate crypto support in bscan
+ if (verbose > 1) {
+ Pmsg0(000, _("Got signed digest record\n"));
+ }
+ break;
+
+ case STREAM_SIGNED_DIGEST:
+ // TODO landonf: Investigate crypto support in bscan
+ if (verbose > 1) {
+ Pmsg0(000, _("Got signed digest record\n"));
+ }
+ break;
case STREAM_PROGRAM_NAMES:
if (verbose) {
Pmsg0(000, _("Got Prog Data Stream record.\n"));
}
break;
+
+ case STREAM_UNIX_ACCESS_ACL: /* Deprecated Standard ACL attributes on UNIX */
+ case STREAM_UNIX_DEFAULT_ACL: /* Deprecated Default ACL attributes on UNIX */
+ case STREAM_ACL_AIX_TEXT:
+ case STREAM_ACL_DARWIN_ACCESS_ACL:
+ case STREAM_ACL_FREEBSD_DEFAULT_ACL:
+ case STREAM_ACL_FREEBSD_ACCESS_ACL:
+ case STREAM_ACL_HPUX_ACL_ENTRY:
+ case STREAM_ACL_IRIX_DEFAULT_ACL:
+ case STREAM_ACL_IRIX_ACCESS_ACL:
+ case STREAM_ACL_LINUX_DEFAULT_ACL:
+ case STREAM_ACL_LINUX_ACCESS_ACL:
+ case STREAM_ACL_TRU64_DEFAULT_ACL:
+ case STREAM_ACL_TRU64_DEFAULT_DIR_ACL:
+ case STREAM_ACL_TRU64_ACCESS_ACL:
+ case STREAM_ACL_SOLARIS_ACLENT:
+ case STREAM_ACL_SOLARIS_ACE:
+ /* Ignore Unix ACL attributes */
+ break;
+
+ case STREAM_XATTR_OPENBSD:
+ case STREAM_XATTR_SOLARIS_SYS:
+ case STREAM_XATTR_SOLARIS:
+ case STREAM_XATTR_DARWIN:
+ case STREAM_XATTR_FREEBSD:
+ case STREAM_XATTR_LINUX:
+ case STREAM_XATTR_NETBSD:
+ /* Ignore Unix Extended attributes */
+ break;
+
default:
- Pmsg2(0, _("Unknown stream type!!! stream=%d data=%s\n"), rec->Stream, rec->data);
+ Pmsg2(0, _("Unknown stream type!!! stream=%d len=%i\n"), rec->Stream, rec->data_len);
break;
}
return true;
*/
static void bscan_free_jcr(JCR *jcr)
{
- Dmsg0(200, "Start dird free_jcr\n");
+ Dmsg0(200, "Start bscan free_jcr\n");
if (jcr->file_bsock) {
Dmsg0(200, "Close File bsock\n");
free_dcr(jcr->dcr);
jcr->dcr = NULL;
}
- Dmsg0(200, "End dird free_jcr\n");
+ if (jcr->read_dcr) {
+ free_dcr(jcr->read_dcr);
+ jcr->read_dcr = NULL;
+ }
+ Dmsg0(200, "End bscan free_jcr\n");
}
/*
* record, and then create the attributes record.
*/
static int create_file_attributes_record(B_DB *db, JCR *mjcr,
- char *fname, char *lname, int type,
- char *ap, DEV_RECORD *rec)
+ char *fname, char *lname, int type,
+ char *ap, DEV_RECORD *rec)
{
- DCR *dcr = mjcr->dcr;
+ DCR *dcr = mjcr->read_dcr;
ar.fname = fname;
ar.link = lname;
ar.ClientId = mjcr->ClientId;
ar.JobId = mjcr->JobId;
ar.Stream = rec->Stream;
- ar.FileIndex = rec->FileIndex;
+ if (type == FT_DELETED) {
+ ar.FileIndex = 0;
+ } else {
+ ar.FileIndex = rec->FileIndex;
+ }
ar.attr = ap;
if (dcr->VolFirstIndex == 0) {
dcr->VolFirstIndex = rec->FileIndex;
mjcr->FileId = ar.FileId;
if (verbose > 1) {
- Pmsg1(000, _("Created File record: %s\n"), fname);
+ Pmsg1(000, _("Created File record: %s\n"), fname);
}
return 1;
}
/* We mark Vols as Archive to keep them from being re-written */
bstrncpy(mr->VolStatus, "Archive", sizeof(mr->VolStatus));
mr->VolRetention = 365 * 3600 * 24; /* 1 year */
+ mr->Enabled = 1;
if (vl->VerNum >= 11) {
+ mr->set_first_written = true; /* Save FirstWritten during update_media */
mr->FirstWritten = btime_to_utime(vl->write_btime);
mr->LabelDate = btime_to_utime(vl->label_btime);
} else {
mr->LabelDate = mktime(&tm);
}
lasttime = mr->LabelDate;
+ if (mr->VolJobs == 0) {
+ mr->VolJobs = 1;
+ }
+ if (mr->VolMounts == 0) {
+ mr->VolMounts = 1;
+ }
if (!update_db) {
return 1;
/*
- * Called from SOS to create a client for the current Job
+ * Called from SOS to create a client for the current Job
*/
static int create_client_record(B_DB *db, CLIENT_DBR *cr)
{
+ /*
+ * Note, update_db can temporarily be set false while
+ * updating the database, so we must ensure that ClientId is non-zero.
+ */
if (!update_db) {
+ cr->ClientId = 0;
+ if (!db_get_client_record(bjcr, db, cr)) {
+ Pmsg1(0, _("Could not get Client record. ERR=%s\n"), db_strerror(db));
+ return 0;
+ }
return 1;
}
if (!db_create_client_record(bjcr, db, cr)) {
}
} else {
if (!db_create_fileset_record(bjcr, db, fsr)) {
- Pmsg2(0, _("Could not create FileSet record \"%s\". ERR=%s\n"),
- fsr->FileSet, db_strerror(db));
- return 0;
+ Pmsg2(0, _("Could not create FileSet record \"%s\". ERR=%s\n"),
+ fsr->FileSet, db_strerror(db));
+ return 0;
}
if (verbose) {
Pmsg1(000, _("Created FileSet record \"%s\"\n"), fsr->FileSet);
* the Job record and to update it when the Job actually
* begins running.
*/
-static JCR *create_job_record(B_DB *db, JOB_DBR *jr, SESSION_LABEL *label,
- DEV_RECORD *rec)
+static JCR *create_job_record(B_DB *db, JOB_DBR *jr, SESSION_LABEL *label,
+ DEV_RECORD *rec)
{
JCR *mjcr;
struct date_time dt;
Pmsg1(0, _("Could not update job start record. ERR=%s\n"), db_strerror(db));
return mjcr;
}
- Pmsg2(000, _("Created new JobId=%u record for original JobId=%u\n"), jr->JobId,
- label->JobId);
- mjcr->JobId = jr->JobId; /* set new JobId */
+ Pmsg2(000, _("Created new JobId=%u record for original JobId=%u\n"), jr->JobId,
+ label->JobId);
+ mjcr->JobId = jr->JobId; /* set new JobId */
return mjcr;
}
-/*
- * Simulate the database call that updates the Job
+/*
+ * Simulate the database call that updates the Job
* at Job termination time.
*/
static int update_job_record(B_DB *db, JOB_DBR *jr, SESSION_LABEL *elabel,
- DEV_RECORD *rec)
+ DEV_RECORD *rec)
{
struct date_time dt;
struct tm tm;
mjcr = get_jcr_by_session(rec->VolSessionId, rec->VolSessionTime);
if (!mjcr) {
Pmsg2(000, _("Could not find SessId=%d SessTime=%d for EOS record.\n"),
- rec->VolSessionId, rec->VolSessionTime);
+ rec->VolSessionId, rec->VolSessionTime);
return 0;
}
if (elabel->VerNum >= 11) {
free_jcr(mjcr);
return 1;
}
-
+
if (!db_update_job_end_record(bjcr, db, jr)) {
Pmsg2(0, _("Could not update JobId=%u record. ERR=%s\n"), jr->JobId, db_strerror(db));
free_jcr(mjcr);
return 0;
}
if (verbose) {
- Pmsg2(000, _("Updated Job termination record for JobId=%u TermStat=%c\n"), jr->JobId,
- jr->JobStatus);
+ Pmsg3(000, _("Updated Job termination record for JobId=%u Level=%s TermStat=%c\n"),
+ jr->JobId, job_level_to_str(mjcr->getJobLevel()), jr->JobStatus);
}
if (verbose > 1) {
const char *term_msg;
switch (mjcr->JobStatus) {
case JS_Terminated:
term_msg = _("Backup OK");
- break;
+ break;
+ case JS_Warnings:
+ term_msg = _("Backup OK -- with warnings");
+ break;
case JS_FatalError:
case JS_ErrorTerminated:
term_msg = _("*** Backup Error ***");
- break;
+ break;
case JS_Canceled:
term_msg = _("Backup Canceled");
- break;
+ break;
default:
- term_msg = term_code;
+ term_msg = term_code;
sprintf(term_code, _("Job Termination code: %d"), mjcr->JobStatus);
- break;
+ break;
}
bstrftime(sdt, sizeof(sdt), mjcr->start_time);
bstrftime(edt, sizeof(edt), mjcr->end_time);
- Pmsg14(000, _("%s\n\
-JobId: %d\n\
-Job: %s\n\
-FileSet: %s\n\
-Backup Level: %s\n\
-Client: %s\n\
-Start time: %s\n\
-End time: %s\n\
-Files Written: %s\n\
-Bytes Written: %s\n\
-Volume Session Id: %d\n\
-Volume Session Time: %d\n\
-Last Volume Bytes: %s\n\
-Termination: %s\n\n"),
- edt,
- mjcr->JobId,
- mjcr->Job,
- mjcr->fileset_name,
- job_level_to_str(mjcr->JobLevel),
- mjcr->client_name,
- sdt,
- edt,
- edit_uint64_with_commas(mjcr->JobFiles, ec1),
- edit_uint64_with_commas(mjcr->JobBytes, ec2),
- mjcr->VolSessionId,
- mjcr->VolSessionTime,
- edit_uint64_with_commas(mr.VolBytes, ec3),
- term_msg);
+ Pmsg14(000, _("%s\n"
+"JobId: %d\n"
+"Job: %s\n"
+"FileSet: %s\n"
+"Backup Level: %s\n"
+"Client: %s\n"
+"Start time: %s\n"
+"End time: %s\n"
+"Files Written: %s\n"
+"Bytes Written: %s\n"
+"Volume Session Id: %d\n"
+"Volume Session Time: %d\n"
+"Last Volume Bytes: %s\n"
+"Termination: %s\n\n"),
+ edt,
+ mjcr->JobId,
+ mjcr->Job,
+ mjcr->fileset_name,
+ job_level_to_str(mjcr->getJobLevel()),
+ mjcr->client_name,
+ sdt,
+ edt,
+ edit_uint64_with_commas(mjcr->JobFiles, ec1),
+ edit_uint64_with_commas(mjcr->JobBytes, ec2),
+ mjcr->VolSessionId,
+ mjcr->VolSessionTime,
+ edit_uint64_with_commas(mr.VolBytes, ec3),
+ term_msg);
}
free_jcr(mjcr);
return 1;
static int create_jobmedia_record(B_DB *db, JCR *mjcr)
{
JOBMEDIA_DBR jmr;
- DCR *dcr = mjcr->dcr;
+ DCR *dcr = mjcr->read_dcr;
- if (dev->state & ST_TAPE) {
- dcr->EndBlock = dev->EndBlock;
- dcr->EndFile = dev->EndFile;
- } else {
- dcr->EndBlock = (uint32_t)dev->file_addr;
- dcr->EndFile = (uint32_t)(dev->file_addr >> 32);
- }
+ dcr->EndBlock = dev->EndBlock;
+ dcr->EndFile = dev->EndFile;
+ dcr->VolMediaId = dev->VolCatInfo.VolMediaId;
memset(&jmr, 0, sizeof(jmr));
jmr.JobId = mjcr->JobId;
jmr.MediaId = mr.MediaId;
jmr.FirstIndex = dcr->VolFirstIndex;
- jmr.LastIndex = dcr->FileIndex;
+ jmr.LastIndex = dcr->VolLastIndex;
jmr.StartFile = dcr->StartFile;
jmr.EndFile = dcr->EndFile;
jmr.StartBlock = dcr->StartBlock;
return 0;
}
if (verbose) {
- Pmsg2(000, _("Created JobMedia record JobId %d, MediaId %d\n"),
- jmr.JobId, jmr.MediaId);
+ Pmsg2(000, _("Created JobMedia record JobId %d, MediaId %d\n"),
+ jmr.JobId, jmr.MediaId);
}
return 1;
}
-/*
+/*
* Simulate the database call that updates the MD5/SHA1 record
*/
-static int update_SIG_record(B_DB *db, char *SIGbuf, DEV_RECORD *rec, int type)
+static int update_digest_record(B_DB *db, char *digest, DEV_RECORD *rec, int type)
{
JCR *mjcr;
if (!mjcr) {
if (mr.VolJobs > 0) {
Pmsg2(000, _("Could not find SessId=%d SessTime=%d for MD5/SHA1 record.\n"),
- rec->VolSessionId, rec->VolSessionTime);
+ rec->VolSessionId, rec->VolSessionTime);
} else {
- ignored_msgs++;
+ ignored_msgs++;
}
return 0;
}
free_jcr(mjcr);
return 1;
}
-
- if (!db_add_SIG_to_file_record(bjcr, db, mjcr->FileId, SIGbuf, type)) {
+
+ if (!db_add_digest_to_file_record(bjcr, db, mjcr->FileId, digest, type)) {
Pmsg1(0, _("Could not add MD5/SHA1 to File record. ERR=%s\n"), db_strerror(db));
free_jcr(mjcr);
return 0;
}
-/*
+/*
* Create a JCR as if we are really starting the job
*/
static JCR *create_jcr(JOB_DBR *jr, DEV_RECORD *rec, uint32_t JobId)
JCR *jobjcr;
/*
* Transfer as much as possible to the Job JCR. Most important is
- * the JobId and the ClientId.
+ * the JobId and the ClientId.
*/
jobjcr = new_jcr(sizeof(JCR), bscan_free_jcr);
- jobjcr->JobType = jr->JobType;
- jobjcr->JobLevel = jr->JobLevel;
+ jobjcr->set_JobType(jr->JobType);
+ jobjcr->set_JobLevel(jr->JobLevel);
jobjcr->JobStatus = jr->JobStatus;
bstrncpy(jobjcr->Job, jr->Job, sizeof(jobjcr->Job));
jobjcr->JobId = JobId; /* this is JobId on tape */
jobjcr->VolSessionId = rec->VolSessionId;
jobjcr->VolSessionTime = rec->VolSessionTime;
jobjcr->ClientId = jr->ClientId;
-// attach_jcr_to_device(dev, jobjcr);
- new_dcr(jobjcr, dev);
+ jobjcr->dcr = jobjcr->read_dcr = new_dcr(jobjcr, NULL, dev);
+
return jobjcr;
}
/* Dummies to replace askdir.c */
-bool dir_get_volume_info(DCR *dcr, enum get_vol_info_rw writing) { return 1;}
-bool dir_find_next_appendable_volume(DCR *dcr) { return 1;}
-bool dir_update_volume_info(DCR *dcr, bool relabel) { return 1; }
-bool dir_create_jobmedia_record(DCR *dcr) { return 1; }
-bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; }
-bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;}
-bool dir_send_job_status(JCR *jcr) {return 1;}
-
-
-bool dir_ask_sysop_to_mount_volume(DCR *dcr)
+bool dir_find_next_appendable_volume(DCR *dcr) { return 1;}
+bool dir_update_volume_info(DCR *dcr, bool relabel, bool update_LastWritten) { return 1; }
+bool dir_create_jobmedia_record(DCR *dcr, bool zero) { return 1; }
+bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; }
+bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;}
+bool dir_send_job_status(JCR *jcr) {return 1;}
+int generate_job_event(JCR *jcr, const char *event) { return 1; }
+
+bool dir_ask_sysop_to_mount_volume(DCR *dcr, int /*mode*/)
{
DEVICE *dev = dcr->dev;
Dmsg0(20, "Enter dir_ask_sysop_to_mount_volume\n");
/* Close device so user can use autochanger if desired */
- if (dev_cap(dev, CAP_OFFLINEUNMOUNT)) {
- offline_dev(dev);
- }
- force_close_dev(dev);
- fprintf(stderr, "Mount Volume \"%s\" on device %s and press return when ready: ",
- dcr->VolumeName, dev_name(dev));
- getchar();
+ fprintf(stderr, _("Mount Volume \"%s\" on device %s and press return when ready: "),
+ dcr->VolumeName, dev->print_name());
+ dev->close();
+ getchar();
return true;
}
+bool dir_get_volume_info(DCR *dcr, enum get_vol_info_rw writing)
+{
+ Dmsg0(100, "Fake dir_get_volume_info\n");
+ dcr->setVolCatName(dcr->VolumeName);
+ dcr->VolCatInfo.VolCatParts = find_num_dvd_parts(dcr);
+ Dmsg2(500, "Vol=%s num_parts=%d\n", dcr->getVolCatName(), dcr->VolCatInfo.VolCatParts);
+ return 1;
+}