* Version $Id$
*/
/*
- Copyright (C) 2001, 2002 Kern Sibbald and John Walker
+ 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
/* Forward referenced functions */
static void do_scan(void);
-static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec);
+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_media_record(B_DB *db, MEDIA_DBR *mr, VOLUME_LABEL *vl);
-static int update_media_record(B_DB *db, MEDIA_DBR *mr);
+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,
/* Global variables */
-static STORES *me;
+STORES *me;
+#if defined(HAVE_CYGWIN) || defined(HAVE_WIN32)
+int win32_client = 1;
+#else
+int win32_client = 0;
+#endif
+
+
+/* Local variables */
static DEVICE *dev = NULL;
static B_DB *db;
static JCR *bjcr; /* jcr for bscan */
static BSR *bsr = NULL;
-static struct stat statp;
-static int type;
-static long record_file_index;
-static POOLMEM *fname; /* original file name */
-static POOLMEM *ofile; /* output name with prefix */
-static POOLMEM *lname; /* link name */
static MEDIA_DBR mr;
static POOL_DBR pr;
static JOB_DBR jr;
static FILE_DBR fr;
static SESSION_LABEL label;
static SESSION_LABEL elabel;
+static ATTR *attr;
static time_t lasttime = 0;
-static char *db_name = "bacula";
-static char *db_user = "bacula";
-static char *db_password = "";
-static char *wd = NULL;
-static int update_db = 0;
-static int update_vol_info = 0;
-static int list_records = 0;
+static const char *db_name = "bacula";
+static const char *db_user = "bacula";
+static const char *db_password = "";
+static const char *db_host = NULL;
+static const char *wd = NULL;
+static bool update_db = false;
+static bool update_vol_info = false;
+static bool list_records = false;
static int ignored_msgs = 0;
+static uint64_t currentVolumeSize;
+static int64_t 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;
+
#define CONFIG_FILE "bacula-sd.conf"
char *configfile;
-
+bool forge_on = false;
static void usage()
{
fprintf(stderr, _(
+"Copyright (C) 2001-2004 Kern Sibbald and John Walker.\n"
"\nVersion: " VERSION " (" BDATE ")\n\n"
-"Usage: bscan [-d debug_level] <bacula-archive>\n"
+"Usage: bscan [ options ] <bacula-archive>\n"
" -b bootstrap specify a bootstrap file\n"
" -c <file> specify configuration file\n"
-" -dnn set debug level to nn\n"
+" -d <nn> set debug level to nn\n"
" -m update media info in database\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"
+" -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"
+" -h <host> specify database host (default NULL)\n"
+" -p proceed inspite of I/O errors\n"
" -r list records\n"
" -s synchronize or store in database\n"
" -v verbose\n"
-" -V specify Volume names (separated by |)\n"
-" -w dir specify working directory (default from conf file)\n"
+" -V <Volumes> specify Volume names (separated by |)\n"
+" -w <dir> specify working directory (default from conf file)\n"
" -? print this message\n\n"));
exit(1);
}
init_msg(NULL, NULL);
- while ((ch = getopt(argc, argv, "b:c:d:mn:p:rsu:vw:?")) != -1) {
+ while ((ch = getopt(argc, argv, "b:c:d:h:mn:pP:rsSu:vV:w:?")) != -1) {
switch (ch) {
- case 'b':
- bsr = parse_bsr(NULL, optarg);
- break;
+ case 'S' :
+ showProgress = true;
+ break;
+ case 'b':
+ bsr = parse_bsr(NULL, optarg);
+ break;
- case 'c': /* specify config file */
- if (configfile != NULL) {
- free(configfile);
- }
- configfile = bstrdup(optarg);
- break;
+ case 'c': /* specify config file */
+ if (configfile != NULL) {
+ free(configfile);
+ }
+ configfile = bstrdup(optarg);
+ break;
- case 'd': /* debug level */
- debug_level = atoi(optarg);
- if (debug_level <= 0)
- debug_level = 1;
- break;
+ case 'd': /* debug level */
+ debug_level = atoi(optarg);
+ if (debug_level <= 0)
+ debug_level = 1;
+ break;
- case 'm':
- update_vol_info = 1;
- break;
+ case 'h':
+ db_host = optarg;
+ break;
- case 'n':
- db_name = optarg;
- break;
+ case 'm':
+ update_vol_info = true;
+ break;
- case 'u':
- db_user = optarg;
- break;
+ case 'n':
+ db_name = optarg;
+ break;
- case 'p':
- db_password = optarg;
- break;
+ case 'u':
+ db_user = optarg;
+ break;
- case 'r':
- list_records = 1;
- break;
+ case 'P':
+ db_password = optarg;
+ break;
- case 's':
- update_db = 1;
- break;
+ case 'p':
+ forge_on = true;
+ break;
- case 'v':
- verbose++;
- break;
+ case 'r':
+ list_records = true;
+ break;
- case 'V': /* Volume name */
- VolumeName = optarg;
- break;
+ case 's':
+ update_db = true;
+ break;
- case 'w':
- wd = optarg;
- break;
+ case 'v':
+ verbose++;
+ break;
- case '?':
- default:
- usage();
+ case 'V': /* Volume name */
+ VolumeName = optarg;
+ break;
+
+ case 'w':
+ wd = optarg;
+ break;
+
+ case '?':
+ default:
+ usage();
}
}
working_directory);
}
- bjcr = setup_jcr("bscan", argv[0], bsr, VolumeName);
- dev = setup_to_access_device(bjcr, 1); /* read device */
- if (!dev) {
+ bjcr = setup_jcr("bscan", argv[0], bsr, VolumeName, 1); /* read device */
+ if (!bjcr) {
exit(1);
}
+ dev = bjcr->dcr->dev;
+ if (showProgress) {
+ struct stat sb;
+ fstat(dev->fd, &sb);
+ currentVolumeSize = sb.st_size;
+ Pmsg1(000, _("Current Volume Size = %" llu "\n"), currentVolumeSize);
+ }
- if ((db=db_init_database(NULL, db_name, db_user, db_password, NULL, 0, NULL)) == NULL) {
+ if ((db=db_init_database(NULL, db_name, db_user, db_password,
+ db_host, 0, 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);
free_jcr(bjcr);
+ term_dev(dev);
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.
+ */
+static bool bscan_mount_next_read_volume(DCR *dcr)
+{
+ DEVICE *dev = dcr->dev;
+ DCR *mdcr;
+ Dmsg1(100, "Walk attached jcrs. Volume=%s\n", dev->VolCatInfo.VolCatName);
+ foreach_dlist(mdcr, dev->attached_dcrs) {
+ JCR *mjcr = mdcr->jcr;
+ if (mjcr->JobId == 0) {
+ 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);
+ }
+ if (!create_jobmedia_record(db, mjcr)) {
+ Pmsg2(000, _("Could not create JobMedia record for Volume=%s Job=%s\n"),
+ dev->VolCatInfo.VolCatName, mjcr->Job);
+ }
+ }
+ /* 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) {
+ struct stat sb;
+ fstat(dev->fd, &sb);
+ currentVolumeSize = sb.st_size;
+ Pmsg1(000, _("Current Volume Size = %" llu "\n"), currentVolumeSize);
+ }
+ return stat;
+}
static void do_scan()
{
- fname = get_pool_memory(PM_FNAME);
- ofile = get_pool_memory(PM_FNAME);
- lname = get_pool_memory(PM_FNAME);
+ attr = new_attr();
memset(&ar, 0, sizeof(ar));
memset(&pr, 0, sizeof(pr));
memset(&fsr, 0, sizeof(fsr));
memset(&fr, 0, sizeof(fr));
- detach_jcr_from_device(dev, bjcr);
+ /* Detach bscan's jcr as we are not a real Job on the tape */
- read_records(bjcr, dev, record_cb, mount_next_read_volume);
- release_device(bjcr, dev);
+ read_records(bjcr->dcr, record_cb, bscan_mount_next_read_volume);
- free_pool_memory(fname);
- free_pool_memory(ofile);
- free_pool_memory(lname);
- term_dev(dev);
+ free_attr(attr);
}
-static void record_cb(JCR *bjcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
+/*
+ * Returns: true if OK
+ * false if error
+ */
+static bool record_cb(DCR *dcr, DEV_RECORD *rec)
{
JCR *mjcr;
char ec1[30];
+ DEVICE *dev = dcr->dev;
+ JCR *bjcr = dcr->jcr;
+ DEV_BLOCK *block = dcr->block;
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 (list_records) {
Pmsg5(000, _("Record: SessId=%u SessTim=%u FileIndex=%d Stream=%d len=%u\n"),
rec->VolSessionId, rec->VolSessionTime, rec->FileIndex,
*
*/
if (rec->FileIndex < 0) {
- int save_update_db = update_db;
+ bool save_update_db = update_db;
if (verbose > 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;
- break;
- case VOL_LABEL:
- unser_volume_label(dev, rec);
- /* Check Pool info */
- strcpy(pr.Name, dev->VolHdr.PoolName);
- strcpy(pr.PoolType, dev->VolHdr.PoolType);
- 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) {
- 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) {
- Pmsg2(000, _("VOL_LABEL: PoolType mismatch. DB=%s Vol=%s\n"),
- pr.PoolType, dev->VolHdr.PoolType);
- return;
- } else if (verbose) {
- Pmsg1(000, _("Pool type \"%s\" is OK.\n"), pr.PoolType);
- }
+ case PRE_LABEL:
+ Pmsg0(000, _("Volume is prelabeled. This tape cannot be scanned.\n"));
+ return false;
+ break;
- /* Check Media Info */
- memset(&mr, 0, sizeof(mr));
- strcpy(mr.VolumeName, dev->VolHdr.VolName);
- mr.PoolId = pr.PoolId;
- 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) {
- Pmsg1(000, _("VOL_LABEL: Media record not found for Volume: %s\n"),
- mr.VolumeName);
- }
- strcpy(mr.MediaType, dev->VolHdr.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;
- } else if (verbose) {
- Pmsg1(000, _("Media type \"%s\" is OK.\n"), mr.MediaType);
+ 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) {
+ Pmsg1(000, _("Pool record for %s found in DB.\n"), pr.Name);
}
- /* Reset some JCR variables */
- for (mjcr=NULL; (mjcr=next_attached_jcr(dev, mjcr)); ) {
- mjcr->VolFirstFile = mjcr->FileIndex = 0;
- mjcr->StartBlock = mjcr->EndBlock = 0;
- mjcr->StartFile = mjcr->EndFile = 0;
+ } 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) {
+ Pmsg2(000, _("VOL_LABEL: PoolType mismatch. DB=%s Vol=%s\n"),
+ pr.PoolType, dev->VolHdr.PoolType);
+ return true;
+ } else if (verbose) {
+ Pmsg1(000, _("Pool type \"%s\" is OK.\n"), pr.PoolType);
+ }
- Pmsg1(000, _("VOL_LABEL: OK for Volume: %s\n"), mr.VolumeName);
- break;
- case SOS_LABEL:
- mr.VolJobs++;
- 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));
- jr.JobId = label.JobId;
- if (db_get_job_record(bjcr, db, &jr)) {
- /* Job record already exists in DB */
- update_db = 0; /* don't change db in create_job_record */
- 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) {
- Pmsg1(000, _("SOS_LABEL: Job record not found for JobId: %d\n"),
- jr.JobId);
- }
- }
- /* Create Client record if not already there */
- strcpy(cr.Name, label.ClientName);
- 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);
- update_db = save_update_db;
-
- jr.PoolId = pr.PoolId;
- /* Set start positions into JCR */
- if (dev->state & ST_TAPE) {
- mjcr->StartBlock = dev->block_num;
- mjcr->StartFile = dev->file;
- } else {
- mjcr->StartBlock = (uint32_t)dev->file_addr;
- mjcr->StartFile = (uint32_t)(dev->file_addr >> 32);
+ /* 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) {
+ Pmsg1(000, _("Media record for %s found in DB.\n"), mr.VolumeName);
}
- mjcr->start_time = jr.StartTime;
- mjcr->JobLevel = jr.Level;
-
- mjcr->client_name = get_pool_memory(PM_FNAME);
- pm_strcpy(&mjcr->client_name, label.ClientName);
- mjcr->pool_type = get_pool_memory(PM_FNAME);
- pm_strcpy(&mjcr->pool_type, label.PoolType);
- mjcr->fileset_name = get_pool_memory(PM_FNAME);
- pm_strcpy(&mjcr->fileset_name, label.FileSetName);
- mjcr->pool_name = get_pool_memory(PM_FNAME);
- pm_strcpy(&mjcr->pool_name, label.PoolName);
-
- 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;
+ /* 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);
}
- 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;
+ 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) {
+ 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;
+ }
+
+ Pmsg1(000, _("VOL_LABEL: OK for Volume: %s\n"), mr.VolumeName);
+ 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 */
+ update_db = false; /* don't change db in create_job_record */
+ if (verbose) {
+ Pmsg1(000, _("SOS_LABEL: Found Job record for JobId: %d\n"), jr.JobId);
}
- 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;
+ } 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;
+
+ /* 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) {
+ 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) {
+ 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) {
+ 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;
+
+ case EOS_LABEL:
+ 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;
+
+ 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;
- case EOS_LABEL:
- unser_session_label(&elabel, rec);
-
- /* Create FileSet record */
- strcpy(fsr.FileSet, label.FileSetName);
- strcpy(fsr.MD5, label.FileSetMD5);
- create_fileset_record(db, &fsr);
- jr.FileSetId = fsr.FileSetId;
-
- 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;
- }
+ }
- /* 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);
- detach_jcr_from_device(dev, mjcr);
- free_jcr(mjcr);
+ /* Create JobMedia record */
+ create_jobmedia_record(db, mjcr);
+ dev->attached_dcrs->remove(mjcr->dcr);
+ free_jcr(mjcr);
- break;
- case EOM_LABEL:
- break;
- case EOT_LABEL: /* end of all tapes */
- /*
- * Wiffle through all jobs still open and close
- * them.
- */
- if (update_db) {
- for (mjcr=NULL; (mjcr=next_attached_jcr(dev, mjcr)); ) {
- jr.JobId = mjcr->JobId;
- 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;
- free_jcr(mjcr);
- if (!db_update_job_end_record(bjcr, db, &jr)) {
- Pmsg1(0, _("Could not update job record. ERR=%s\n"), db_strerror(db));
- }
+ 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)) {
+ 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);
- Pmsg3(0, _("End of Volume. VolFiles=%u VolBlocks=%u VolBytes=%s\n"), mr.VolFiles,
- mr.VolBlocks, edit_uint64_with_commas(mr.VolBytes, ec1));
- break;
- default:
- break;
- }
- return;
+ }
+ 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;
+ default:
+ break;
+ } /* end switch */
+ return true;
}
+ mjcr = get_jcr_by_session(rec->VolSessionId, rec->VolSessionTime);
+ if (!mjcr) {
+ if (mr.VolJobs > 0) {
+ Pmsg2(000, _("Could not find Job for SessId=%d SessTime=%d record.\n"),
+ rec->VolSessionId, rec->VolSessionTime);
+ } else {
+ ignored_msgs++;
+ }
+ return true;
+ }
+ dcr = mjcr->dcr;
+ if (dcr->VolFirstIndex == 0) {
+ dcr->VolFirstIndex = block->FirstIndex;
+ }
/* File Attributes stream */
- if (rec->Stream == STREAM_UNIX_ATTRIBUTES || rec->Stream == STREAM_WIN32_ATTRIBUTES) {
- char *ap, *lp, *fp;
+ switch (rec->Stream) {
+ case STREAM_UNIX_ATTRIBUTES:
+ case STREAM_UNIX_ATTRIBUTES_EX:
- if (sizeof_pool_memory(fname) < rec->data_len) {
- fname = realloc_pool_memory(fname, rec->data_len + 1);
- }
- if (sizeof_pool_memory(lname) < rec->data_len) {
- lname = realloc_pool_memory(lname, rec->data_len + 1);
+ if (!unpack_attributes_record(bjcr, rec->Stream, rec->data, attr)) {
+ Emsg0(M_ERROR_TERM, 0, _("Cannot continue.\n"));
}
- *fname = 0;
- *lname = 0;
-
- /*
- * An Attributes record consists of:
- * File_index
- * Type (FT_types)
- * Filename
- * Attributes
- * Link name (if file linked i.e. FT_LNK)
- *
- */
- sscanf(rec->data, "%ld %d", &record_file_index, &type);
- if (record_file_index != rec->FileIndex)
- Emsg2(M_ERROR_TERM, 0, "Record header file index %ld not equal record index %ld\n",
- rec->FileIndex, record_file_index);
- ap = rec->data;
- while (*ap++ != ' ') /* skip record file index */
- ;
- while (*ap++ != ' ') /* skip type */
- ;
- /* Save filename and position to attributes */
- fp = fname;
- while (*ap != 0) {
- *fp++ = *ap++;
- }
- *fp = *ap++; /* terminate filename & point to attribs */
- /* Skip through attributes to link name */
- lp = ap;
- while (*lp++ != 0) {
- ;
+ 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);
}
- strcat(lname, lp); /* "save" link name */
+
if (verbose > 1) {
- uint32_t LinkFI;
- decode_stat(ap, &statp, &LinkFI);
- print_ls_output(fname, lname, type, &statp);
- }
- mjcr = get_jcr_by_session(rec->VolSessionId, rec->VolSessionTime);
- if (!mjcr) {
- if (mr.VolJobs > 0) {
- Pmsg2(000, _("Could not find Job SessId=%d SessTime=%d for Attributes record.\n"),
- rec->VolSessionId, rec->VolSessionTime);
- } else {
- ignored_msgs++;
- }
- return;
+ 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;
- if (db_get_file_attributes_record(bjcr, db, fname, &fr)) {
- if (verbose > 1) {
- Pmsg1(000, _("File record already exists for: %s\n"), fname);
- }
- } else {
- create_file_attributes_record(db, mjcr, fname, lname, type, ap, rec);
- }
+ num_files++;
+ if (verbose && (num_files & 0x7FFF) == 0) {
+ 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);
free_jcr(mjcr);
+ break;
/* Data stream */
- } else if (rec->Stream == STREAM_FILE_DATA) {
- mjcr = get_jcr_by_session(rec->VolSessionId, rec->VolSessionTime);
- if (!mjcr) {
- if (mr.VolJobs > 0) {
- Pmsg2(000, _("Could not find Job SessId=%d SessTime=%d for File Data record.\n"),
- rec->VolSessionId, rec->VolSessionTime);
- } else {
- ignored_msgs++;
- }
- return;
- }
+ case STREAM_WIN32_DATA:
+ case STREAM_FILE_DATA:
+ case STREAM_SPARSE_DATA:
mjcr->JobBytes += rec->data_len;
- free_jcr(mjcr); /* done using JCR */
-
- } else if (rec->Stream == STREAM_SPARSE_DATA) {
- mjcr = get_jcr_by_session(rec->VolSessionId, rec->VolSessionTime);
- if (!mjcr) {
- if (mr.VolJobs > 0) {
- Pmsg2(000, _("Could not find Job SessId=%d SessTime=%d for Sparse Data record.\n"),
- rec->VolSessionId, rec->VolSessionTime);
- } else {
- ignored_msgs++;
- }
- return;
+ if (rec->Stream == STREAM_SPARSE_DATA) {
+ mjcr->JobBytes -= sizeof(uint64_t);
}
- mjcr->JobBytes += rec->data_len - sizeof(uint64_t);
+
free_jcr(mjcr); /* done using JCR */
+ break;
- } else if (rec->Stream == STREAM_GZIP_DATA) {
- mjcr = get_jcr_by_session(rec->VolSessionId, rec->VolSessionTime);
- if (!mjcr) {
- if (mr.VolJobs > 0) {
- Pmsg2(000, _("Could not find Job SessId=%d SessTime=%d for GZIP Data record.\n"),
- rec->VolSessionId, rec->VolSessionTime);
- } else {
- ignored_msgs++;
- }
- return;
- }
+ case STREAM_GZIP_DATA:
mjcr->JobBytes += rec->data_len; /* No correct, we should expand it */
free_jcr(mjcr); /* done using JCR */
+ break;
- } else if (rec->Stream == STREAM_SPARSE_GZIP_DATA) {
- mjcr = get_jcr_by_session(rec->VolSessionId, rec->VolSessionTime);
- if (!mjcr) {
- if (mr.VolJobs > 0) {
- Pmsg2(000, _("Could not find Job SessId=%d SessTime=%d for Sparse GZIP Data record.\n"),
- rec->VolSessionId, rec->VolSessionTime);
- } else {
- ignored_msgs++;
- }
- return;
- }
+ 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 */
+ break;
+ /* Win32 GZIP stream */
+ case STREAM_WIN32_GZIP_DATA:
+ mjcr->JobBytes += rec->data_len;
+ free_jcr(mjcr); /* done using JCR */
+ break;
- } else if (rec->Stream == STREAM_MD5_SIGNATURE) {
+ case STREAM_MD5_SIGNATURE:
char MD5buf[50];
bin_to_base64(MD5buf, (char *)rec->data, 16); /* encode 16 bytes */
if (verbose > 1) {
Pmsg1(000, _("Got MD5 record: %s\n"), MD5buf);
}
update_SIG_record(db, MD5buf, rec, MD5_SIG);
+ break;
- } else if (rec->Stream == STREAM_SHA1_SIGNATURE) {
+ case STREAM_SHA1_SIGNATURE:
char SIGbuf[50];
bin_to_base64(SIGbuf, (char *)rec->data, 20); /* encode 20 bytes */
if (verbose > 1) {
Pmsg1(000, _("Got SHA1 record: %s\n"), SIGbuf);
}
update_SIG_record(db, SIGbuf, rec, SHA1_SIG);
+ break;
- } else if (rec->Stream == STREAM_PROGRAM_NAMES) {
+ case STREAM_PROGRAM_NAMES:
if (verbose) {
Pmsg1(000, _("Got Prog Names Stream: %s\n"), rec->data);
}
- } else if (rec->Stream == STREAM_PROGRAM_DATA) {
+ break;
+
+ case STREAM_PROGRAM_DATA:
if (verbose > 1) {
Pmsg0(000, _("Got Prog Data Stream record.\n"));
}
- } else {
+ break;
+ default:
Pmsg2(0, _("Unknown stream type!!! stream=%d data=%s\n"), rec->Stream, rec->data);
+ break;
}
- return;
+ return true;
}
/*
* Called from main free_jcr() routine in src/lib/jcr.c so
* that we can do our Director specific cleanup of the jcr.
*/
-static void dird_free_jcr(JCR *jcr)
+static void bscan_free_jcr(JCR *jcr)
{
Dmsg0(200, "Start dird free_jcr\n");
if (jcr->RestoreBootstrap) {
free(jcr->RestoreBootstrap);
}
+ if (jcr->dcr) {
+ free_dcr(jcr->dcr);
+ jcr->dcr = NULL;
+ }
Dmsg0(200, "End dird free_jcr\n");
}
char *fname, char *lname, int type,
char *ap, DEV_RECORD *rec)
{
-
+ DCR *dcr = mjcr->dcr;
ar.fname = fname;
ar.link = lname;
ar.ClientId = mjcr->ClientId;
ar.Stream = rec->Stream;
ar.FileIndex = rec->FileIndex;
ar.attr = ap;
- if (mjcr->VolFirstFile == 0) {
- mjcr->VolFirstFile = rec->FileIndex;
+ if (dcr->VolFirstIndex == 0) {
+ dcr->VolFirstIndex = rec->FileIndex;
}
- mjcr->FileIndex = rec->FileIndex;
+ dcr->FileIndex = rec->FileIndex;
mjcr->JobFiles++;
if (!update_db) {
struct date_time dt;
struct tm tm;
- strcpy(mr->VolStatus, "Full");
+ /* 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 */
if (vl->VerNum >= 11) {
mr->FirstWritten = btime_to_utime(vl->write_btime);
/*
* Called at end of media to update it
*/
-static int update_media_record(B_DB *db, MEDIA_DBR *mr)
+static bool update_media_record(B_DB *db, MEDIA_DBR *mr)
{
if (!update_db && !update_vol_info) {
- return 1;
+ return true;
}
mr->LastWritten = lasttime;
if (!db_update_media_record(bjcr, db, mr)) {
Pmsg1(0, _("Could not update media record. ERR=%s\n"), db_strerror(db));
- return 0;
+ return false;;
}
if (verbose) {
Pmsg1(000, _("Updated Media record at end of Volume: %s\n"), mr->VolumeName);
}
- return 1;
+ return true;
}
struct tm tm;
jr->JobId = label->JobId;
- jr->Type = label->JobType;
- jr->Level = label->JobLevel;
+ jr->JobType = label->JobType;
+ jr->JobLevel = label->JobLevel;
jr->JobStatus = JS_Created;
- strcpy(jr->Name, label->JobName);
- strcpy(jr->Job, label->Job);
+ bstrncpy(jr->Name, label->JobName, sizeof(jr->Name));
+ bstrncpy(jr->Job, label->Job, sizeof(jr->Job));
if (label->VerNum >= 11) {
jr->SchedTime = btime_to_unix(label->write_btime);
} else {
return 0;
}
if (verbose) {
- Pmsg1(000, _("Updated Job termination record for new JobId=%u\n"), jr->JobId);
+ Pmsg2(000, _("Updated Job termination record for JobId=%u TermStat=%c\n"), jr->JobId,
+ jr->JobStatus);
}
if (verbose > 1) {
- char *term_msg;
+ const char *term_msg;
static char term_code[70];
char sdt[50], edt[50];
char ec1[30], ec2[30], ec3[30];
case JS_ErrorTerminated:
term_msg = _("*** Backup Error ***");
break;
- case JS_Cancelled:
+ case JS_Canceled:
term_msg = _("Backup Canceled");
break;
default:
static int create_jobmedia_record(B_DB *db, JCR *mjcr)
{
JOBMEDIA_DBR jmr;
+ DCR *dcr = mjcr->dcr;
if (dev->state & ST_TAPE) {
- mjcr->EndBlock = dev->EndBlock;
- mjcr->EndFile = dev->EndFile;
+ dcr->EndBlock = dev->EndBlock;
+ dcr->EndFile = dev->EndFile;
} else {
- mjcr->EndBlock = (uint32_t)dev->file_addr;
- mjcr->EndFile = (uint32_t)(dev->file_addr >> 32);
+ dcr->EndBlock = (uint32_t)dev->file_addr;
+ dcr->EndFile = (uint32_t)(dev->file_addr >> 32);
}
memset(&jmr, 0, sizeof(jmr));
jmr.JobId = mjcr->JobId;
jmr.MediaId = mr.MediaId;
- jmr.FirstIndex = mjcr->VolFirstFile;
- jmr.LastIndex = mjcr->FileIndex;
- jmr.StartFile = mjcr->StartFile;
- jmr.EndFile = mjcr->EndFile;
- jmr.StartBlock = mjcr->StartBlock;
- jmr.EndBlock = mjcr->EndBlock;
+ jmr.FirstIndex = dcr->VolFirstIndex;
+ jmr.LastIndex = dcr->FileIndex;
+ jmr.StartFile = dcr->StartFile;
+ jmr.EndFile = dcr->EndFile;
+ jmr.StartBlock = dcr->StartBlock;
+ jmr.EndBlock = dcr->EndBlock;
if (!update_db) {
return 0;
}
- if (!update_db) {
+ if (!update_db || mjcr->FileId == 0) {
free_jcr(mjcr);
return 1;
}
* Transfer as much as possible to the Job JCR. Most important is
* the JobId and the ClientId.
*/
- jobjcr = new_jcr(sizeof(JCR), dird_free_jcr);
- jobjcr->JobType = jr->Type;
- jobjcr->JobLevel = jr->Level;
+ jobjcr = new_jcr(sizeof(JCR), bscan_free_jcr);
+ jobjcr->JobType = jr->JobType;
+ jobjcr->JobLevel = jr->JobLevel;
jobjcr->JobStatus = jr->JobStatus;
- strcpy(jobjcr->Job, jr->Job);
+ bstrncpy(jobjcr->Job, jr->Job, sizeof(jobjcr->Job));
jobjcr->JobId = JobId; /* this is JobId on tape */
jobjcr->sched_time = jr->SchedTime;
jobjcr->start_time = jr->StartTime;
jobjcr->VolSessionId = rec->VolSessionId;
jobjcr->VolSessionTime = rec->VolSessionTime;
jobjcr->ClientId = jr->ClientId;
- attach_jcr_to_device(dev, jobjcr);
+// attach_jcr_to_device(dev, jobjcr);
+ new_dcr(jobjcr, dev);
return jobjcr;
}
/* Dummies to replace askdir.c */
-int dir_get_volume_info(JCR *jcr, int writing) { return 1;}
-int dir_find_next_appendable_volume(JCR *jcr) { return 1;}
-int dir_update_volume_info(JCR *jcr, VOLUME_CAT_INFO *vol, int relabel) { return 1; }
-int dir_create_jobmedia_record(JCR *jcr) { return 1; }
-int dir_ask_sysop_to_mount_next_volume(JCR *jcr, DEVICE *dev) { return 1; }
-int dir_update_file_attributes(JCR *jcr, DEV_RECORD *rec) { return 1;}
-int dir_send_job_status(JCR *jcr) {return 1;}
+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;}
-int dir_ask_sysop_to_mount_volume(JCR *jcr, DEVICE *dev)
+bool dir_ask_sysop_to_mount_volume(DCR *dcr)
{
- /*
- * 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.
- */
- Dmsg1(100, "Walk attached jcrs. Volume=%s\n", dev->VolCatInfo.VolCatName);
- for (JCR *mjcr=NULL; (mjcr=next_attached_jcr(dev, mjcr)); ) {
- if (verbose) {
- Pmsg1(000, _("Create JobMedia for Job %s\n"), mjcr->Job);
- }
- if (dev->state & ST_TAPE) {
- mjcr->EndBlock = dev->EndBlock;
- mjcr->EndFile = dev->EndFile;
- } else {
- mjcr->EndBlock = (uint32_t)dev->file_addr;
- mjcr->StartBlock = (uint32_t)(dev->file_addr >> 32);
- }
- if (!create_jobmedia_record(db, mjcr)) {
- Pmsg2(000, _("Could not create JobMedia record for Volume=%s Job=%s\n"),
- dev->VolCatInfo.VolCatName, mjcr->Job);
- }
- }
-
- fprintf(stderr, _("Mount Volume %s on device %s and press return when ready: "),
+ DEVICE *dev = dcr->dev;
+ JCR *jcr = dcr->jcr;
+ fprintf(stderr, _("Mount Volume \"%s\" on device \"%s\" and press return when ready: "),
jcr->VolumeName, dev_name(dev));
getchar();
return 1;