+/*
+ * For each Volume we see, we create a Medium record
+ */
+static int create_media_record(B_DB *db, MEDIA_DBR *mr, VOLUME_LABEL *vl)
+{
+ struct date_time dt;
+ struct tm tm;
+
+ /* 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);
+ mr->LabelDate = btime_to_utime(vl->label_btime);
+ } else {
+ /* DEPRECATED DO NOT USE */
+ dt.julian_day_number = vl->write_date;
+ dt.julian_day_fraction = vl->write_time;
+ tm_decode(&dt, &tm);
+ mr->FirstWritten = mktime(&tm);
+ dt.julian_day_number = vl->label_date;
+ dt.julian_day_fraction = vl->label_time;
+ tm_decode(&dt, &tm);
+ mr->LabelDate = mktime(&tm);
+ }
+ lasttime = mr->LabelDate;
+
+ if (!update_db) {
+ return 1;
+ }
+
+ if (!db_create_media_record(bjcr, db, mr)) {
+ Pmsg1(0, _("Could not create media record. ERR=%s\n"), db_strerror(db));
+ return 0;
+ }
+ if (!db_update_media_record(bjcr, db, mr)) {
+ Pmsg1(0, _("Could not update media record. ERR=%s\n"), db_strerror(db));
+ return 0;
+ }
+ if (verbose) {
+ Pmsg1(000, _("Created Media record for Volume: %s\n"), mr->VolumeName);
+ }
+ return 1;
+
+}
+
+/*
+ * Called at end of media to update it
+ */
+static bool update_media_record(B_DB *db, MEDIA_DBR *mr)
+{
+ if (!update_db && !update_vol_info) {
+ 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 false;;
+ }
+ if (verbose) {
+ Pmsg1(000, _("Updated Media record at end of Volume: %s\n"), mr->VolumeName);
+ }
+ return true;
+
+}
+
+
+static int create_pool_record(B_DB *db, POOL_DBR *pr)
+{
+ pr->NumVols++;
+ pr->UseCatalog = 1;
+ pr->VolRetention = 355 * 3600 * 24; /* 1 year */
+
+ if (!update_db) {
+ return 1;
+ }
+ if (!db_create_pool_record(bjcr, db, pr)) {
+ Pmsg1(0, _("Could not create pool record. ERR=%s\n"), db_strerror(db));
+ return 0;
+ }
+ if (verbose) {
+ Pmsg1(000, _("Created Pool record for Pool: %s\n"), pr->Name);
+ }
+ return 1;
+
+}
+
+
+/*
+ * Called from SOS to create a client for the current Job
+ */
+static int create_client_record(B_DB *db, CLIENT_DBR *cr)
+{
+ if (!update_db) {
+ return 1;
+ }
+ if (!db_create_client_record(bjcr, db, cr)) {
+ Pmsg1(0, _("Could not create Client record. ERR=%s\n"), db_strerror(db));
+ return 0;
+ }
+ if (verbose) {
+ Pmsg1(000, _("Created Client record for Client: %s\n"), cr->Name);
+ }
+ return 1;
+}
+
+static int create_fileset_record(B_DB *db, FILESET_DBR *fsr)
+{
+ if (!update_db) {
+ return 1;
+ }
+ fsr->FileSetId = 0;
+ if (fsr->MD5[0] == 0) {
+ fsr->MD5[0] = ' '; /* Equivalent to nothing */
+ fsr->MD5[1] = 0;
+ }
+ if (db_get_fileset_record(bjcr, db, fsr)) {
+ if (verbose) {
+ Pmsg1(000, _("Fileset \"%s\" already exists.\n"), fsr->FileSet);
+ }
+ } 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;
+ }
+ if (verbose) {
+ Pmsg1(000, _("Created FileSet record \"%s\"\n"), fsr->FileSet);
+ }
+ }
+ return 1;
+}
+
+/*
+ * Simulate the two calls on the database to create
+ * 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)
+{
+ JCR *mjcr;
+ struct date_time dt;
+ struct tm tm;
+
+ jr->JobId = label->JobId;
+ jr->JobType = label->JobType;
+ jr->JobLevel = label->JobLevel;
+ jr->JobStatus = JS_Created;
+ 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 {
+ dt.julian_day_number = label->write_date;
+ dt.julian_day_fraction = label->write_time;
+ tm_decode(&dt, &tm);
+ jr->SchedTime = mktime(&tm);
+ }
+
+ jr->StartTime = jr->SchedTime;
+ jr->JobTDate = (utime_t)jr->SchedTime;
+ jr->VolSessionId = rec->VolSessionId;
+ jr->VolSessionTime = rec->VolSessionTime;
+
+ /* Now create a JCR as if starting the Job */
+ mjcr = create_jcr(jr, rec, label->JobId);
+
+ if (!update_db) {
+ return mjcr;
+ }
+
+ /* This creates the bare essentials */
+ if (!db_create_job_record(bjcr, db, jr)) {
+ Pmsg1(0, _("Could not create JobId record. ERR=%s\n"), db_strerror(db));
+ return mjcr;
+ }
+
+ /* This adds the client, StartTime, JobTDate, ... */
+ if (!db_update_job_start_record(bjcr, db, jr)) {
+ 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 */
+ return mjcr;
+}
+
+/*
+ * 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)
+{
+ struct date_time dt;
+ struct tm tm;
+ JCR *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);
+ return 0;
+ }
+ if (elabel->VerNum >= 11) {
+ jr->EndTime = btime_to_unix(elabel->write_btime);
+ } else {
+ dt.julian_day_number = elabel->write_date;
+ dt.julian_day_fraction = elabel->write_time;
+ tm_decode(&dt, &tm);
+ jr->EndTime = mktime(&tm);
+ }
+ lasttime = jr->EndTime;
+ mjcr->end_time = jr->EndTime;
+
+ jr->JobId = mjcr->JobId;
+ jr->JobStatus = elabel->JobStatus;
+ mjcr->JobStatus = elabel->JobStatus;
+ jr->JobFiles = elabel->JobFiles;
+ jr->JobBytes = elabel->JobBytes;
+ jr->VolSessionId = rec->VolSessionId;
+ jr->VolSessionTime = rec->VolSessionTime;
+ jr->JobTDate = (utime_t)mjcr->start_time;
+ jr->ClientId = mjcr->ClientId;
+
+ if (!update_db) {
+ 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);
+ }
+ if (verbose > 1) {
+ const char *term_msg;
+ static char term_code[70];
+ char sdt[50], edt[50];
+ char ec1[30], ec2[30], ec3[30];
+
+ switch (mjcr->JobStatus) {
+ case JS_Terminated:
+ term_msg = _("Backup OK");
+ break;
+ case JS_FatalError:
+ case JS_ErrorTerminated:
+ term_msg = _("*** Backup Error ***");
+ break;
+ case JS_Canceled:
+ term_msg = _("Backup Canceled");
+ break;
+ default:
+ term_msg = term_code;
+ sprintf(term_code, _("Job Termination code: %d"), mjcr->JobStatus);
+ 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);
+ }
+ free_jcr(mjcr);
+ return 1;
+}
+
+static int create_jobmedia_record(B_DB *db, JCR *mjcr)
+{
+ JOBMEDIA_DBR jmr;
+ DCR *dcr = mjcr->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);
+ }
+
+ memset(&jmr, 0, sizeof(jmr));
+ jmr.JobId = mjcr->JobId;
+ jmr.MediaId = mr.MediaId;
+ 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 1;
+ }
+
+ if (!db_create_jobmedia_record(bjcr, db, &jmr)) {
+ Pmsg1(0, _("Could not create JobMedia record. ERR=%s\n"), db_strerror(db));
+ return 0;
+ }
+ if (verbose) {
+ 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)
+{
+ JCR *mjcr;
+
+ mjcr = get_jcr_by_session(rec->VolSessionId, rec->VolSessionTime);
+ if (!mjcr) {
+ if (mr.VolJobs > 0) {
+ Pmsg2(000, _("Could not find SessId=%d SessTime=%d for MD5/SHA1 record.\n"),
+ rec->VolSessionId, rec->VolSessionTime);
+ } else {
+ ignored_msgs++;
+ }
+ return 0;
+ }
+
+ if (!update_db || mjcr->FileId == 0) {
+ free_jcr(mjcr);
+ return 1;
+ }
+
+ if (!db_add_SIG_to_file_record(bjcr, db, mjcr->FileId, SIGbuf, type)) {
+ Pmsg1(0, _("Could not add MD5/SHA1 to File record. ERR=%s\n"), db_strerror(db));
+ free_jcr(mjcr);
+ return 0;
+ }
+ if (verbose > 1) {
+ Pmsg0(000, _("Updated MD5/SHA1 record\n"));
+ }
+ free_jcr(mjcr);
+ return 1;
+}
+
+
+/*
+ * 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.
+ */
+ jobjcr = new_jcr(sizeof(JCR), bscan_free_jcr);
+ jobjcr->JobType = jr->JobType;
+ jobjcr->JobLevel = jr->JobLevel;
+ jobjcr->JobStatus = jr->JobStatus;
+ 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);
+ new_dcr(jobjcr, 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;}
+