]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/bscan.c
Big backport from Enterprise
[bacula/bacula] / bacula / src / stored / bscan.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2017 Kern Sibbald
5
6    The original author of Bacula is Kern Sibbald, with contributions
7    from many others, a complete list can be found in the file AUTHORS.
8
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13
14    This notice must be preserved when any source code is
15    conveyed and/or propagated.
16
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20  *
21  *  Program to scan a Bacula Volume and compare it with
22  *    the catalog and optionally synchronize the catalog
23  *    with the tape.
24  *
25  *   Kern E. Sibbald, December 2001
26  */
27
28 #include "bacula.h"
29 #include "stored.h"
30 #include "findlib/find.h"
31 #include "cats/cats.h"
32
33 extern bool parse_sd_config(CONFIG *config, const char *configfile, int exit_code);
34
35 /* Forward referenced functions */
36 static void do_scan(void);
37 static bool record_cb(DCR *dcr, DEV_RECORD *rec);
38 static int  create_file_attributes_record(BDB *db, JCR *mjcr,
39                                char *fname, char *lname, int type,
40                                char *ap, DEV_RECORD *rec);
41 static int  create_media_record(BDB *db, MEDIA_DBR *mr, VOLUME_LABEL *vl);
42 static bool update_media_record(BDB *db, MEDIA_DBR *mr);
43 static int  create_pool_record(BDB *db, POOL_DBR *pr);
44 static JCR *create_job_record(BDB *db, JOB_DBR *mr, SESSION_LABEL *label, DEV_RECORD *rec);
45 static int  update_job_record(BDB *db, JOB_DBR *mr, SESSION_LABEL *elabel,
46                               DEV_RECORD *rec);
47 static int  create_client_record(BDB *db, CLIENT_DBR *cr);
48 static int  create_fileset_record(BDB *db, FILESET_DBR *fsr);
49 static int  create_jobmedia_record(BDB *db, JCR *jcr);
50 static JCR *create_jcr(JOB_DBR *jr, DEV_RECORD *rec, uint32_t JobId);
51 static int update_digest_record(BDB *db, char *digest, DEV_RECORD *rec, int type);
52
53
54 /* Local variables */
55 static DEVICE *dev = NULL;
56 static BDB *db;
57 static JCR *bjcr;                     /* jcr for bscan */
58 static BSR *bsr = NULL;
59 static MEDIA_DBR mr;
60 static POOL_DBR pr;
61 static JOB_DBR jr;
62 static CLIENT_DBR cr;
63 static FILESET_DBR fsr;
64 static ATTR_DBR ar;
65 static FILE_DBR fr;
66 static SESSION_LABEL label;
67 static SESSION_LABEL elabel;
68 static ATTR *attr;
69
70 static time_t lasttime = 0;
71
72 static const char *db_driver = "NULL";
73 static const char *db_name = "bacula";
74 static const char *db_user = "bacula";
75 static const char *db_password = "";
76 static const char *db_host = NULL;
77 static const char *db_ssl_key = NULL;
78 static const char *db_ssl_cert = NULL;
79 static const char *db_ssl_ca = NULL;
80 static const char *db_ssl_capath = NULL;
81 static const char *db_ssl_cipher = NULL;
82 static int db_port = 0;
83 static const char *wd = NULL;
84 static bool update_db = false;
85 static bool update_vol_info = false;
86 static bool list_records = false;
87 static int ignored_msgs = 0;
88
89 static uint64_t currentVolumeSize;
90 static int last_pct = -1;
91 static bool showProgress = false;
92 static int num_jobs = 0;
93 static int num_pools = 0;
94 static int num_media = 0;
95 static int num_files = 0;
96
97 static CONFIG *config;
98 #define CONFIG_FILE "bacula-sd.conf"
99
100 void *start_heap;
101 char *configfile = NULL;
102
103 static void usage()
104 {
105    fprintf(stderr, _(
106 PROG_COPYRIGHT
107 "\n%sVersion: %s (%s)\n\n"
108 "Usage: bscan [ options ] <bacula-archive>\n"
109 "       -b bootstrap      specify a bootstrap file\n"
110 "       -c <file>         specify configuration file\n"
111 "       -d <nn>           set debug level to <nn>\n"
112 "       -dt               print timestamp in debug output\n"
113 "       -m                update media info in database\n"
114 "       -D <driver name>  specify the driver database name (default NULL)\n"
115 "       -n <name>         specify the database name (default bacula)\n"
116 "       -u <user>         specify database user name (default bacula)\n"
117 "       -P <password>     specify database password (default none)\n"
118 "       -h <host>         specify database host (default NULL)\n"
119 "       -t <port>         specify database port (default 0)\n"
120 "       -p                proceed inspite of I/O errors\n"
121 "       -r                list records\n"
122 "       -s                synchronize or store in database\n"
123 "       -S                show scan progress periodically\n"
124 "       -v                verbose\n"
125 "       -V <Volumes>      specify Volume names (separated by |)\n"
126 "       -w <dir>          specify working directory (default from conf file)\n"
127 "       -?                print this message\n\n"),
128       2001, "", VERSION, BDATE);
129    exit(1);
130 }
131
132 int main (int argc, char *argv[])
133 {
134    int ch;
135    struct stat stat_buf;
136    char *VolumeName = NULL;
137    BtoolsAskDirHandler askdir_handler;
138
139    init_askdir_handler(&askdir_handler);
140    setlocale(LC_ALL, "");
141    bindtextdomain("bacula", LOCALEDIR);
142    textdomain("bacula");
143    init_stack_dump();
144    lmgr_init_thread();
145
146    my_name_is(argc, argv, "bscan");
147    init_msg(NULL, NULL);
148
149    OSDependentInit();
150
151    while ((ch = getopt(argc, argv, "b:c:d:D:h:p:mn:pP:rsSt:u:vV:w:?")) != -1) {
152       switch (ch) {
153       case 'S' :
154          showProgress = true;
155          break;
156       case 'b':
157          bsr = parse_bsr(NULL, optarg);
158          break;
159
160       case 'c':                    /* specify config file */
161          if (configfile != NULL) {
162             free(configfile);
163          }
164          configfile = bstrdup(optarg);
165          break;
166
167       case 'D':
168          db_driver = optarg;
169          break;
170
171       case 'd':                    /* debug level */
172          if (*optarg == 't') {
173             dbg_timestamp = true;
174          } else {
175             debug_level = atoi(optarg);
176             if (debug_level <= 0) {
177                debug_level = 1;
178             }
179          }
180          break;
181
182       case 'h':
183          db_host = optarg;
184          break;
185
186       case 't':
187          db_port = atoi(optarg);
188          break;
189
190       case 'm':
191          update_vol_info = true;
192          break;
193
194       case 'n':
195          db_name = optarg;
196          break;
197
198       case 'u':
199          db_user = optarg;
200          break;
201
202       case 'P':
203          db_password = optarg;
204          break;
205
206       case 'p':
207          forge_on = true;
208          break;
209
210       case 'r':
211          list_records = true;
212          break;
213
214       case 's':
215          update_db = true;
216          break;
217
218       case 'v':
219          verbose++;
220          break;
221
222       case 'V':                    /* Volume name */
223          VolumeName = optarg;
224          break;
225
226       case 'w':
227          wd = optarg;
228          break;
229
230       case '?':
231       default:
232          usage();
233
234       }
235    }
236    argc -= optind;
237    argv += optind;
238
239    if (argc != 1) {
240       Pmsg0(0, _("Wrong number of arguments: \n"));
241       usage();
242    }
243
244    if (configfile == NULL) {
245       configfile = bstrdup(CONFIG_FILE);
246    }
247
248    config = New(CONFIG());
249    parse_sd_config(config, configfile, M_ERROR_TERM);
250    setup_me();
251    load_sd_plugins(me->plugin_directory);
252
253    /* Check if -w option given, otherwise use resource for working directory */
254    if (wd) {
255       working_directory = wd;
256    } else if (!me->working_directory) {
257       Emsg1(M_ERROR_TERM, 0, _("No Working Directory defined in %s. Cannot continue.\n"),
258          configfile);
259    } else {
260       working_directory = me->working_directory;
261    }
262
263    /* Check that working directory is good */
264    if (stat(working_directory, &stat_buf) != 0) {
265       Emsg1(M_ERROR_TERM, 0, _("Working Directory: %s not found. Cannot continue.\n"),
266          working_directory);
267    }
268    if (!S_ISDIR(stat_buf.st_mode)) {
269       Emsg1(M_ERROR_TERM, 0, _("Working Directory: %s is not a directory. Cannot continue.\n"),
270          working_directory);
271    }
272
273    bjcr = setup_jcr("bscan", argv[0], bsr, VolumeName, SD_READ);
274    if (!bjcr) {
275       exit(1);
276    }
277    dev = bjcr->read_dcr->dev;
278    if (showProgress) {
279       char ed1[50];
280       struct stat sb;
281       fstat(dev->fd(), &sb);
282       currentVolumeSize = sb.st_size;
283       Pmsg1(000, _("First Volume Size = %s\n"),
284          edit_uint64(currentVolumeSize, ed1));
285    }
286
287    db = db_init_database(NULL, db_driver, db_name, db_user, db_password,
288                          db_host, db_port, NULL, 
289                          db_ssl_key, db_ssl_cert, db_ssl_ca,
290                          db_ssl_capath, db_ssl_cipher,
291                          false, false);
292    if (!db || !db_open_database(NULL, db)) {
293       Pmsg2(000, _("Could not open Catalog \"%s\", database \"%s\".\n"),
294            db_driver, db_name);
295       if (db) {
296          Jmsg(NULL, M_FATAL, 0, _("%s"), db_strerror(db));
297          Pmsg1(000, "%s", db_strerror(db));
298          db_close_database(NULL, db);
299       }
300       Jmsg(NULL, M_ERROR_TERM, 0, _("Could not open Catalog \"%s\", database \"%s\".\n"),
301            db_driver, db_name);
302    }
303    Dmsg0(200, "Database opened\n");
304    if (verbose) {
305       Pmsg2(000, _("Using Database: %s, User: %s\n"), db_name, db_user);
306    }
307
308    do_scan();
309    if (update_db) {
310       printf("Records added or updated in the catalog:\n%7d Media\n%7d Pool\n%7d Job\n%7d File\n",
311          num_media, num_pools, num_jobs, num_files);
312    } else {
313       printf("Records would have been added or updated in the catalog:\n%7d Media\n%7d Pool\n%7d Job\n%7d File\n",
314          num_media, num_pools, num_jobs, num_files);
315    }
316
317    free_jcr(bjcr);
318    dev->term(NULL);
319    return 0;
320 }
321
322 /*
323  * We are at the end of reading a Volume. Now, we simulate handling
324  *   the end of writing a Volume by wiffling through the attached
325  *   jcrs creating jobmedia records.
326  */
327 static bool bscan_mount_next_read_volume(DCR *dcr)
328 {
329    DEVICE *dev = dcr->dev;
330    DCR *mdcr;
331    Dmsg1(100, "Walk attached jcrs. Volume=%s\n", dev->getVolCatName());
332    foreach_dlist(mdcr, dev->attached_dcrs) {
333       JCR *mjcr = mdcr->jcr;
334       Dmsg1(100, "========== JobId=%u ========\n", mjcr->JobId);
335       if (mjcr->JobId == 0) {
336          continue;
337       }
338       if (verbose) {
339          Pmsg1(000, _("Create JobMedia for Job %s\n"), mjcr->Job);
340       }
341       mdcr->StartAddr = dcr->StartAddr;
342       mdcr->EndAddr = dcr->EndAddr;
343       mdcr->VolMediaId = dcr->VolMediaId;
344       mjcr->read_dcr->VolLastIndex = dcr->VolLastIndex;
345       if( mjcr->bscan_insert_jobmedia_records ) {
346          if (!create_jobmedia_record(db, mjcr)) {
347             Pmsg2(000, _("Could not create JobMedia record for Volume=%s Job=%s\n"),
348                dev->getVolCatName(), mjcr->Job);
349          }
350       }
351    }
352
353    update_media_record(db, &mr);
354
355    /* Now let common read routine get up next tape. Note,
356     * we call mount_next... with bscan's jcr because that is where we
357     * have the Volume list, but we get attached.
358     */
359    bool stat = mount_next_read_volume(dcr);
360
361    if (showProgress) {
362       char ed1[50];
363       struct stat sb;
364       fstat(dev->fd(), &sb);
365       currentVolumeSize = sb.st_size;
366       Pmsg1(000, _("First Volume Size = %s\n"),
367          edit_uint64(currentVolumeSize, ed1));
368    }
369    return stat;
370 }
371
372 static void do_scan()
373 {
374    attr = new_attr(bjcr);
375
376    memset(&ar, 0, sizeof(ar));
377    memset(&pr, 0, sizeof(pr));
378    memset(&jr, 0, sizeof(jr));
379    memset(&cr, 0, sizeof(cr));
380    memset(&fsr, 0, sizeof(fsr));
381    memset(&fr, 0, sizeof(fr));
382
383    /* Detach bscan's jcr as we are not a real Job on the tape */
384
385    read_records(bjcr->read_dcr, record_cb, bscan_mount_next_read_volume);
386
387    if (update_db) {
388       db_write_batch_file_records(bjcr); /* used by bulk batch file insert */
389    }
390    free_attr(attr);
391 }
392
393 /*
394  * Returns: true  if OK
395  *          false if error
396  */
397 static bool record_cb(DCR *dcr, DEV_RECORD *rec)
398 {
399    JCR *mjcr;
400    char ec1[30];
401    DEVICE *dev = dcr->dev;
402    JCR *bjcr = dcr->jcr;
403    DEV_BLOCK *block = dcr->block;
404    POOL_MEM sql_buffer;
405    db_int64_ctx jmr_count;
406
407    char digest[BASE64_SIZE(CRYPTO_DIGEST_MAX_SIZE)];
408
409    if (rec->data_len > 0) {
410       mr.VolBytes += rec->data_len + WRITE_RECHDR_LENGTH; /* Accumulate Volume bytes */
411       if (showProgress && currentVolumeSize > 0) {
412          int pct = (mr.VolBytes * 100) / currentVolumeSize;
413          if (pct != last_pct) {
414             fprintf(stdout, _("done: %d%%\n"), pct);
415             fflush(stdout);
416             last_pct = pct;
417          }
418       }
419    }
420
421    if (list_records) {
422       Pmsg5(000, _("Record: SessId=%u SessTim=%u FileIndex=%d Stream=%d len=%u\n"),
423             rec->VolSessionId, rec->VolSessionTime, rec->FileIndex,
424             rec->Stream, rec->data_len);
425    }
426    /*
427     * Check for Start or End of Session Record
428     *
429     */
430    if (rec->FileIndex < 0) {
431       bool save_update_db = update_db;
432
433       if (verbose > 1) {
434          dump_label_record(dev, rec, 1, false);
435       }
436       switch (rec->FileIndex) {
437       case PRE_LABEL:
438          Pmsg0(000, _("Volume is prelabeled. This tape cannot be scanned.\n"));
439          return false;
440          break;
441
442       case VOL_LABEL:
443          unser_volume_label(dev, rec);
444          /* Check Pool info */
445          bstrncpy(pr.Name, dev->VolHdr.PoolName, sizeof(pr.Name));
446          bstrncpy(pr.PoolType, dev->VolHdr.PoolType, sizeof(pr.PoolType));
447          num_pools++;
448          if (db_get_pool_numvols(bjcr, db, &pr)) {
449             if (verbose) {
450                Pmsg1(000, _("Pool record for %s found in DB.\n"), pr.Name);
451             }
452          } else {
453             if (!update_db) {
454                Pmsg1(000, _("VOL_LABEL: Pool record not found for Pool: %s\n"),
455                   pr.Name);
456             }
457             create_pool_record(db, &pr);
458          }
459          if (strcmp(pr.PoolType, dev->VolHdr.PoolType) != 0) {
460             Pmsg2(000, _("VOL_LABEL: PoolType mismatch. DB=%s Vol=%s\n"),
461                pr.PoolType, dev->VolHdr.PoolType);
462             return true;
463          } else if (verbose) {
464             Pmsg1(000, _("Pool type \"%s\" is OK.\n"), pr.PoolType);
465          }
466
467          /* Check Media Info */
468          memset(&mr, 0, sizeof(mr));
469          bstrncpy(mr.VolumeName, dev->VolHdr.VolumeName, sizeof(mr.VolumeName));
470          mr.PoolId = pr.PoolId;
471          num_media++;
472          if (db_get_media_record(bjcr, db, &mr)) {
473             if (verbose) {
474                Pmsg1(000, _("Media record for %s found in DB.\n"), mr.VolumeName);
475             }
476             /* Clear out some volume statistics that will be updated */
477             mr.VolJobs = mr.VolFiles = mr.VolBlocks = 0;
478             mr.VolBytes = rec->data_len + 20;
479          } else {
480             if (!update_db) {
481                Pmsg1(000, _("VOL_LABEL: Media record not found for Volume: %s\n"),
482                   mr.VolumeName);
483             }
484             bstrncpy(mr.MediaType, dev->VolHdr.MediaType, sizeof(mr.MediaType));
485             create_media_record(db, &mr, &dev->VolHdr);
486          }
487          if (strcmp(mr.MediaType, dev->VolHdr.MediaType) != 0) {
488             Pmsg2(000, _("VOL_LABEL: MediaType mismatch. DB=%s Vol=%s\n"),
489                mr.MediaType, dev->VolHdr.MediaType);
490             return true;              /* ignore error */
491          } else if (verbose) {
492             Pmsg1(000, _("Media type \"%s\" is OK.\n"), mr.MediaType);
493          }
494          /* Reset some DCR variables */
495          foreach_dlist(dcr, dev->attached_dcrs) {
496             dcr->VolFirstIndex = dcr->FileIndex = 0;
497             dcr->StartAddr = dcr->EndAddr = 0;
498             dcr->VolMediaId = 0;
499          }
500
501          Pmsg1(000, _("VOL_LABEL: OK for Volume: %s\n"), mr.VolumeName);
502          break;
503
504       case SOS_LABEL:
505          mr.VolJobs++;
506          num_jobs++;
507          if (ignored_msgs > 0) {
508             Pmsg1(000, _("%d \"errors\" ignored before first Start of Session record.\n"),
509                   ignored_msgs);
510             ignored_msgs = 0;
511          }
512          unser_session_label(&label, rec);
513          memset(&jr, 0, sizeof(jr));
514          bstrncpy(jr.Job, label.Job, sizeof(jr.Job));
515          if (db_get_job_record(bjcr, db, &jr)) {
516             /* Job record already exists in DB */
517             update_db = false;  /* don't change db in create_job_record */
518             if (verbose) {
519                Pmsg1(000, _("SOS_LABEL: Found Job record for JobId: %d\n"), jr.JobId);
520             }
521          } else {
522             /* Must create a Job record in DB */
523             if (!update_db) {
524                Pmsg1(000, _("SOS_LABEL: Job record not found for JobId: %d\n"),
525                   jr.JobId);
526             }
527          }
528
529          /* Create Client record if not already there */
530          bstrncpy(cr.Name, label.ClientName, sizeof(cr.Name));
531          create_client_record(db, &cr);
532          jr.ClientId = cr.ClientId;
533
534          /* process label, if Job record exists don't update db */
535          mjcr = create_job_record(db, &jr, &label, rec);
536          dcr = mjcr->read_dcr;
537          update_db = save_update_db;
538
539          jr.PoolId = pr.PoolId;
540          mjcr->start_time = jr.StartTime;
541          mjcr->setJobLevel(jr.JobLevel);
542
543          mjcr->client_name = get_pool_memory(PM_FNAME);
544          pm_strcpy(mjcr->client_name, label.ClientName);
545          mjcr->fileset_name = get_pool_memory(PM_FNAME);
546          pm_strcpy(mjcr->fileset_name, label.FileSetName);
547          bstrncpy(dcr->pool_type, label.PoolType, sizeof(dcr->pool_type));
548          bstrncpy(dcr->pool_name, label.PoolName, sizeof(dcr->pool_name));
549
550          /* Look for existing Job Media records for this job.  If there are
551             any, no new ones need be created.  This may occur if File
552             Retention has expired before Job Retention, or if the volume
553             has already been bscan'd */
554          Mmsg(sql_buffer, "SELECT count(*) from JobMedia where JobId=%d", jr.JobId);
555          db_sql_query(db, sql_buffer.c_str(), db_int64_handler, &jmr_count);
556          if( jmr_count.value > 0 ) {
557             //FIELD NAME TO BE DEFINED/CONFIRMED (maybe a struct?)
558             mjcr->bscan_insert_jobmedia_records = false;
559          } else {
560             mjcr->bscan_insert_jobmedia_records = true;
561          }
562
563          if (rec->VolSessionId != jr.VolSessionId) {
564             Pmsg3(000, _("SOS_LABEL: VolSessId mismatch for JobId=%u. DB=%d Vol=%d\n"),
565                jr.JobId,
566                jr.VolSessionId, rec->VolSessionId);
567             return true;              /* ignore error */
568          }
569          if (rec->VolSessionTime != jr.VolSessionTime) {
570             Pmsg3(000, _("SOS_LABEL: VolSessTime mismatch for JobId=%u. DB=%d Vol=%d\n"),
571                jr.JobId,
572                jr.VolSessionTime, rec->VolSessionTime);
573             return true;              /* ignore error */
574          }
575          if (jr.PoolId != pr.PoolId) {
576             Pmsg3(000, _("SOS_LABEL: PoolId mismatch for JobId=%u. DB=%d Vol=%d\n"),
577                jr.JobId,
578                jr.PoolId, pr.PoolId);
579             return true;              /* ignore error */
580          }
581          break;
582
583       case EOS_LABEL:
584          unser_session_label(&elabel, rec);
585
586          /* Create FileSet record */
587          bstrncpy(fsr.FileSet, label.FileSetName, sizeof(fsr.FileSet));
588          bstrncpy(fsr.MD5, label.FileSetMD5, sizeof(fsr.MD5));
589          create_fileset_record(db, &fsr);
590          jr.FileSetId = fsr.FileSetId;
591
592          mjcr = get_jcr_by_session(rec->VolSessionId, rec->VolSessionTime);
593          if (!mjcr) {
594             Pmsg2(000, _("Could not find SessId=%d SessTime=%d for EOS record.\n"),
595                   rec->VolSessionId, rec->VolSessionTime);
596             break;
597          }
598
599          /* Do the final update to the Job record */
600          update_job_record(db, &jr, &elabel, rec);
601
602          mjcr->end_time = jr.EndTime;
603          mjcr->JobStatus = JS_Terminated;
604
605          /* Create JobMedia record */
606          mjcr->read_dcr->VolLastIndex = dcr->VolLastIndex;
607          if( mjcr->bscan_insert_jobmedia_records ) {
608             create_jobmedia_record(db, mjcr);
609          }
610          free_dcr(mjcr->read_dcr);
611          free_jcr(mjcr);
612
613          break;
614
615       case EOM_LABEL:
616          break;
617
618       case EOT_LABEL:              /* end of all tapes */
619          /*
620           * Wiffle through all jobs still open and close
621           *   them.
622           */
623          if (update_db) {
624             DCR *mdcr;
625             foreach_dlist(mdcr, dev->attached_dcrs) {
626                JCR *mjcr = mdcr->jcr;
627                if (!mjcr || mjcr->JobId == 0) {
628                   continue;
629                }
630                jr.JobId = mjcr->JobId;
631                /* Mark Job as Error Terimined */
632                jr.JobStatus = JS_ErrorTerminated;
633                jr.JobFiles = mjcr->JobFiles;
634                jr.JobBytes = mjcr->JobBytes;
635                jr.VolSessionId = mjcr->VolSessionId;
636                jr.VolSessionTime = mjcr->VolSessionTime;
637                jr.JobTDate = (utime_t)mjcr->start_time;
638                jr.ClientId = mjcr->ClientId;
639                if (!db_update_job_end_record(bjcr, db, &jr)) {
640                   Pmsg1(0, _("Could not update job record. ERR=%s\n"), db_strerror(db));
641                }
642                mjcr->read_dcr = NULL;
643                free_jcr(mjcr);
644             }
645          }
646          mr.VolFiles = (uint32_t)(rec->Addr >> 32);
647          mr.VolBlocks = (uint32_t)rec->Addr;
648          mr.VolBytes += mr.VolBlocks * WRITE_BLKHDR_LENGTH; /* approx. */
649          mr.VolMounts++;
650          update_media_record(db, &mr);
651          Pmsg3(0, _("End of all Volumes. VolFiles=%u VolBlocks=%u VolBytes=%s\n"), mr.VolFiles,
652                     mr.VolBlocks, edit_uint64_with_commas(mr.VolBytes, ec1));
653          break;
654       default:
655          break;
656       } /* end switch */
657       return true;
658    }
659
660    mjcr = get_jcr_by_session(rec->VolSessionId, rec->VolSessionTime);
661    if (!mjcr) {
662       if (mr.VolJobs > 0) {
663          Pmsg2(000, _("Could not find Job for SessId=%d SessTime=%d record.\n"),
664                       rec->VolSessionId, rec->VolSessionTime);
665       } else {
666          ignored_msgs++;
667       }
668       return true;
669    }
670    dcr = mjcr->read_dcr;
671    if (dcr->VolFirstIndex == 0) {
672       dcr->VolFirstIndex = block->FirstIndex;
673    }
674
675    /* File Attributes stream */
676    switch (rec->maskedStream) {
677    case STREAM_UNIX_ATTRIBUTES:
678    case STREAM_UNIX_ATTRIBUTES_EX:
679
680       if (!unpack_attributes_record(bjcr, rec->Stream, rec->data, rec->data_len, attr)) {
681          Emsg0(M_ERROR_TERM, 0, _("Cannot continue.\n"));
682       }
683
684       if (verbose > 1) {
685          decode_stat(attr->attr, &attr->statp, sizeof(attr->statp), &attr->LinkFI);
686          build_attr_output_fnames(bjcr, attr);
687          print_ls_output(bjcr, attr);
688       }
689       fr.JobId = mjcr->JobId;
690       fr.FileId = 0;
691       num_files++;
692       if (verbose && (num_files & 0x7FFF) == 0) {
693          char ed1[30], ed2[30], ed3[30];
694          Pmsg3(000, _("%s file records. At addr=%s bytes=%s\n"),
695                      edit_uint64_with_commas(num_files, ed1),
696                      edit_uint64_with_commas(rec->Addr, ed2),
697                      edit_uint64_with_commas(mr.VolBytes, ed3));
698       }
699       create_file_attributes_record(db, mjcr, attr->fname, attr->lname,
700             attr->type, attr->attr, rec);
701       free_jcr(mjcr);
702       break;
703
704    case STREAM_RESTORE_OBJECT:
705    /* ****FIXME*****/
706       /* Implement putting into catalog */
707       break;
708
709    /* Data stream */
710    case STREAM_WIN32_DATA:
711    case STREAM_FILE_DATA:
712    case STREAM_SPARSE_DATA:
713    case STREAM_MACOS_FORK_DATA:
714    case STREAM_ENCRYPTED_FILE_DATA:
715    case STREAM_ENCRYPTED_WIN32_DATA:
716    case STREAM_ENCRYPTED_MACOS_FORK_DATA:
717       /*
718        * For encrypted stream, this is an approximation.
719        * The data must be decrypted to know the correct length.
720        */
721       mjcr->JobBytes += rec->data_len;
722       if (rec->maskedStream == STREAM_SPARSE_DATA) {
723          mjcr->JobBytes -= sizeof(uint64_t);
724       }
725
726       free_jcr(mjcr);                 /* done using JCR */
727       break;
728
729    case STREAM_GZIP_DATA:
730    case STREAM_COMPRESSED_DATA:
731    case STREAM_ENCRYPTED_FILE_GZIP_DATA:
732    case STREAM_ENCRYPTED_FILE_COMPRESSED_DATA:
733    case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
734    case STREAM_ENCRYPTED_WIN32_COMPRESSED_DATA:
735       /* No correct, we should (decrypt and) expand it
736          done using JCR
737       */
738       mjcr->JobBytes += rec->data_len;
739       free_jcr(mjcr);
740       break;
741
742    case STREAM_SPARSE_GZIP_DATA:
743    case STREAM_SPARSE_COMPRESSED_DATA:
744       mjcr->JobBytes += rec->data_len - sizeof(uint64_t); /* No correct, we should expand it */
745       free_jcr(mjcr);                 /* done using JCR */
746       break;
747
748    /* Win32 GZIP stream */
749    case STREAM_WIN32_GZIP_DATA:
750    case STREAM_WIN32_COMPRESSED_DATA:
751       mjcr->JobBytes += rec->data_len;
752       free_jcr(mjcr);                 /* done using JCR */
753       break;
754
755    case STREAM_MD5_DIGEST:
756       bin_to_base64(digest, sizeof(digest), (char *)rec->data, CRYPTO_DIGEST_MD5_SIZE, true);
757       if (verbose > 1) {
758          Pmsg1(000, _("Got MD5 record: %s\n"), digest);
759       }
760       update_digest_record(db, digest, rec, CRYPTO_DIGEST_MD5);
761       break;
762
763    case STREAM_SHA1_DIGEST:
764       bin_to_base64(digest, sizeof(digest), (char *)rec->data, CRYPTO_DIGEST_SHA1_SIZE, true);
765       if (verbose > 1) {
766          Pmsg1(000, _("Got SHA1 record: %s\n"), digest);
767       }
768       update_digest_record(db, digest, rec, CRYPTO_DIGEST_SHA1);
769       break;
770
771    case STREAM_SHA256_DIGEST:
772       bin_to_base64(digest, sizeof(digest), (char *)rec->data, CRYPTO_DIGEST_SHA256_SIZE, true);
773       if (verbose > 1) {
774          Pmsg1(000, _("Got SHA256 record: %s\n"), digest);
775       }
776       update_digest_record(db, digest, rec, CRYPTO_DIGEST_SHA256);
777       break;
778
779    case STREAM_SHA512_DIGEST:
780       bin_to_base64(digest, sizeof(digest), (char *)rec->data, CRYPTO_DIGEST_SHA512_SIZE, true);
781       if (verbose > 1) {
782          Pmsg1(000, _("Got SHA512 record: %s\n"), digest);
783       }
784       update_digest_record(db, digest, rec, CRYPTO_DIGEST_SHA512);
785       break;
786
787    case STREAM_ENCRYPTED_SESSION_DATA:
788       // TODO landonf: Investigate crypto support in bscan
789       if (verbose > 1) {
790          Pmsg0(000, _("Got signed digest record\n"));
791       }
792       break;
793
794    case STREAM_SIGNED_DIGEST:
795       // TODO landonf: Investigate crypto support in bscan
796       if (verbose > 1) {
797          Pmsg0(000, _("Got signed digest record\n"));
798       }
799       break;
800
801    case STREAM_PROGRAM_NAMES:
802       if (verbose) {
803          Pmsg1(000, _("Got Prog Names Stream: %s\n"), rec->data);
804       }
805       break;
806
807    case STREAM_PROGRAM_DATA:
808       if (verbose > 1) {
809          Pmsg0(000, _("Got Prog Data Stream record.\n"));
810       }
811       break;
812
813    case  STREAM_UNIX_ACCESS_ACL:          /* Deprecated Standard ACL attributes on UNIX */
814    case  STREAM_UNIX_DEFAULT_ACL:         /* Deprecated Default ACL attributes on UNIX */
815    case  STREAM_HFSPLUS_ATTRIBUTES:
816    case  STREAM_XACL_AIX_TEXT:
817    case  STREAM_XACL_DARWIN_ACCESS:
818    case  STREAM_XACL_FREEBSD_DEFAULT:
819    case  STREAM_XACL_FREEBSD_ACCESS:
820    case  STREAM_XACL_HPUX_ACL_ENTRY:
821    case  STREAM_XACL_IRIX_DEFAULT:
822    case  STREAM_XACL_IRIX_ACCESS:
823    case  STREAM_XACL_LINUX_DEFAULT:
824    case  STREAM_XACL_LINUX_ACCESS:
825    case  STREAM_XACL_TRU64_DEFAULT:
826    case  STREAM_XACL_TRU64_DEFAULT_DIR:
827    case  STREAM_XACL_TRU64_ACCESS:
828    case  STREAM_XACL_SOLARIS_POSIX:
829    case  STREAM_XACL_SOLARIS_NFS4:
830    case  STREAM_XACL_AFS_TEXT:
831    case  STREAM_XACL_AIX_AIXC:
832    case  STREAM_XACL_AIX_NFS4:
833    case  STREAM_XACL_FREEBSD_NFS4:
834    case  STREAM_XACL_HURD_DEFAULT:
835    case  STREAM_XACL_HURD_ACCESS:
836       /* Ignore Unix ACL attributes */
837       break;
838
839    case  STREAM_XACL_HURD_XATTR:
840    case  STREAM_XACL_IRIX_XATTR:
841    case  STREAM_XACL_TRU64_XATTR:
842    case  STREAM_XACL_AIX_XATTR:
843    case  STREAM_XACL_OPENBSD_XATTR:
844    case  STREAM_XACL_SOLARIS_SYS_XATTR:
845    case  STREAM_XACL_SOLARIS_XATTR:
846    case  STREAM_XACL_DARWIN_XATTR:
847    case  STREAM_XACL_FREEBSD_XATTR:
848    case  STREAM_XACL_LINUX_XATTR:
849    case  STREAM_XACL_NETBSD_XATTR:
850       /* Ignore Unix Extended attributes */
851       break;
852
853    default:
854       Pmsg2(0, _("Unknown stream type!!! stream=%d len=%i\n"), rec->Stream, rec->data_len);
855       break;
856    }
857    return true;
858 }
859
860 /*
861  * Free the Job Control Record if no one is still using it.
862  *  Called from main free_jcr() routine in src/lib/jcr.c so
863  *  that we can do our Director specific cleanup of the jcr.
864  */
865 static void bscan_free_jcr(JCR *jcr)
866 {
867    Dmsg0(200, "Start bscan free_jcr\n");
868
869    free_bsock(jcr->file_bsock);
870    free_bsock(jcr->store_bsock);
871    if (jcr->RestoreBootstrap) {
872       free(jcr->RestoreBootstrap);
873    }
874    if (jcr->dcr) {
875       free_dcr(jcr->dcr);
876       jcr->dcr = NULL;
877    }
878    if (jcr->read_dcr) {
879       free_dcr(jcr->read_dcr);
880       jcr->read_dcr = NULL;
881    }
882    Dmsg0(200, "End bscan free_jcr\n");
883 }
884
885 /*
886  * We got a File Attributes record on the tape.  Now, lookup the Job
887  *   record, and then create the attributes record.
888  */
889 static int create_file_attributes_record(BDB *db, JCR *mjcr,
890                                char *fname, char *lname, int type,
891                                char *ap, DEV_RECORD *rec)
892 {
893    DCR *dcr = mjcr->read_dcr;
894    ar.fname = fname;
895    ar.link = lname;
896    ar.ClientId = mjcr->ClientId;
897    ar.JobId = mjcr->JobId;
898    ar.Stream = rec->Stream;
899    if (type == FT_DELETED) {
900       ar.FileIndex = 0;
901    } else {
902       ar.FileIndex = rec->FileIndex;
903    }
904    ar.attr = ap;
905    if (dcr->VolFirstIndex == 0) {
906       dcr->VolFirstIndex = rec->FileIndex;
907    }
908    dcr->FileIndex = rec->FileIndex;
909    mjcr->JobFiles++;
910
911    if (!update_db) {
912       return 1;
913    }
914
915    if (!db_create_file_attributes_record(bjcr, db, &ar)) {
916       Pmsg1(0, _("Could not create File Attributes record. ERR=%s\n"), db_strerror(db));
917       return 0;
918    }
919    mjcr->FileId = ar.FileId;
920
921    if (verbose > 1) {
922       Pmsg1(000, _("Created File record: %s\n"), fname);
923    }
924    return 1;
925 }
926
927 /*
928  * For each Volume we see, we create a Medium record
929  */
930 static int create_media_record(BDB *db, MEDIA_DBR *mr, VOLUME_LABEL *vl)
931 {
932    struct date_time dt;
933    struct tm tm;
934
935    /* We mark Vols as Archive to keep them from being re-written */
936    bstrncpy(mr->VolStatus, "Archive", sizeof(mr->VolStatus));
937    mr->VolRetention = 365 * 3600 * 24; /* 1 year */
938    mr->Enabled = 1;
939    if (vl->VerNum >= 11) {
940       mr->set_first_written = true; /* Save FirstWritten during update_media */
941       mr->FirstWritten = btime_to_utime(vl->write_btime);
942       mr->LabelDate    = btime_to_utime(vl->label_btime);
943    } else {
944       /* DEPRECATED DO NOT USE */
945       dt.julian_day_number = vl->write_date;
946       dt.julian_day_fraction = vl->write_time;
947       tm_decode(&dt, &tm);
948       mr->FirstWritten = mktime(&tm);
949       dt.julian_day_number = vl->label_date;
950       dt.julian_day_fraction = vl->label_time;
951       tm_decode(&dt, &tm);
952       mr->LabelDate = mktime(&tm);
953    }
954    lasttime = mr->LabelDate;
955    if (mr->VolJobs == 0) {
956       mr->VolJobs = 1;
957    }
958    if (mr->VolMounts == 0) {
959       mr->VolMounts = 1;
960    }
961
962    if (!update_db) {
963       return 1;
964    }
965
966    if (!db_create_media_record(bjcr, db, mr)) {
967       Pmsg1(0, _("Could not create media record. ERR=%s\n"), db_strerror(db));
968       return 0;
969    }
970    if (!db_update_media_record(bjcr, db, mr)) {
971       Pmsg1(0, _("Could not update media record. ERR=%s\n"), db_strerror(db));
972       return 0;
973    }
974    if (verbose) {
975       Pmsg1(000, _("Created Media record for Volume: %s\n"), mr->VolumeName);
976    }
977    return 1;
978
979 }
980
981 /*
982  * Called at end of media to update it
983  */
984 static bool update_media_record(BDB *db, MEDIA_DBR *mr)
985 {
986    if (!update_db && !update_vol_info) {
987       return true;
988    }
989
990    mr->LastWritten = lasttime;
991    if (!db_update_media_record(bjcr, db, mr)) {
992       Pmsg1(0, _("Could not update media record. ERR=%s\n"), db_strerror(db));
993       return false;;
994    }
995    if (verbose) {
996       Pmsg1(000, _("Updated Media record at end of Volume: %s\n"), mr->VolumeName);
997    }
998    return true;
999
1000 }
1001
1002
1003 static int create_pool_record(BDB *db, POOL_DBR *pr)
1004 {
1005    pr->NumVols++;
1006    pr->UseCatalog = 1;
1007    pr->VolRetention = 355 * 3600 * 24; /* 1 year */
1008
1009    if (!update_db) {
1010       return 1;
1011    }
1012    if (!db_create_pool_record(bjcr, db, pr)) {
1013       Pmsg1(0, _("Could not create pool record. ERR=%s\n"), db_strerror(db));
1014       return 0;
1015    }
1016    if (verbose) {
1017       Pmsg1(000, _("Created Pool record for Pool: %s\n"), pr->Name);
1018    }
1019    return 1;
1020
1021 }
1022
1023
1024 /*
1025  * Called from SOS to create a client for the current Job
1026  */
1027 static int create_client_record(BDB *db, CLIENT_DBR *cr)
1028 {
1029    /*
1030     * Note, update_db can temporarily be set false while
1031     * updating the database, so we must ensure that ClientId is non-zero.
1032     */
1033    if (!update_db) {
1034       cr->ClientId = 0;
1035       if (!db_get_client_record(bjcr, db, cr)) {
1036         Pmsg1(0, _("Could not get Client record. ERR=%s\n"), db_strerror(db));
1037         return 0;
1038       }
1039       return 1;
1040    }
1041    if (!db_create_client_record(bjcr, db, cr)) {
1042       Pmsg1(0, _("Could not create Client record. ERR=%s\n"), db_strerror(db));
1043       return 0;
1044    }
1045    if (verbose) {
1046       Pmsg1(000, _("Created Client record for Client: %s\n"), cr->Name);
1047    }
1048    return 1;
1049 }
1050
1051 static int create_fileset_record(BDB *db, FILESET_DBR *fsr)
1052 {
1053    if (!update_db) {
1054       return 1;
1055    }
1056    fsr->FileSetId = 0;
1057    if (fsr->MD5[0] == 0) {
1058       fsr->MD5[0] = ' ';              /* Equivalent to nothing */
1059       fsr->MD5[1] = 0;
1060    }
1061    if (db_get_fileset_record(bjcr, db, fsr)) {
1062       if (verbose) {
1063          Pmsg1(000, _("Fileset \"%s\" already exists.\n"), fsr->FileSet);
1064       }
1065    } else {
1066       if (!db_create_fileset_record(bjcr, db, fsr)) {
1067          Pmsg2(0, _("Could not create FileSet record \"%s\". ERR=%s\n"),
1068             fsr->FileSet, db_strerror(db));
1069          return 0;
1070       }
1071       if (verbose) {
1072          Pmsg1(000, _("Created FileSet record \"%s\"\n"), fsr->FileSet);
1073       }
1074    }
1075    return 1;
1076 }
1077
1078 /*
1079  * Simulate the two calls on the database to create
1080  *  the Job record and to update it when the Job actually
1081  *  begins running.
1082  */
1083 static JCR *create_job_record(BDB *db, JOB_DBR *jr, SESSION_LABEL *label,
1084                              DEV_RECORD *rec)
1085 {
1086    JCR *mjcr;
1087    struct date_time dt;
1088    struct tm tm;
1089
1090    jr->JobId = label->JobId;
1091    jr->JobType = label->JobType;
1092    jr->JobLevel = label->JobLevel;
1093    jr->JobStatus = JS_Created;
1094    bstrncpy(jr->Name, label->JobName, sizeof(jr->Name));
1095    bstrncpy(jr->Job, label->Job, sizeof(jr->Job));
1096    if (label->VerNum >= 11) {
1097       jr->SchedTime = btime_to_unix(label->write_btime);
1098    } else {
1099       dt.julian_day_number = label->write_date;
1100       dt.julian_day_fraction = label->write_time;
1101       tm_decode(&dt, &tm);
1102       jr->SchedTime = mktime(&tm);
1103    }
1104
1105    jr->StartTime = jr->SchedTime;
1106    jr->JobTDate = (utime_t)jr->SchedTime;
1107    jr->VolSessionId = rec->VolSessionId;
1108    jr->VolSessionTime = rec->VolSessionTime;
1109
1110    /* Now create a JCR as if starting the Job */
1111    mjcr = create_jcr(jr, rec, label->JobId);
1112
1113    if (!update_db) {
1114       return mjcr;
1115    }
1116
1117    /* This creates the bare essentials */
1118    if (!db_create_job_record(bjcr, db, jr)) {
1119       Pmsg1(0, _("Could not create JobId record. ERR=%s\n"), db_strerror(db));
1120       return mjcr;
1121    }
1122
1123    /* This adds the client, StartTime, JobTDate, ... */
1124    if (!db_update_job_start_record(bjcr, db, jr)) {
1125       Pmsg1(0, _("Could not update job start record. ERR=%s\n"), db_strerror(db));
1126       return mjcr;
1127    }
1128    Pmsg2(000, _("Created new JobId=%u record for original JobId=%u\n"), jr->JobId,
1129          label->JobId);
1130    mjcr->JobId = jr->JobId;           /* set new JobId */
1131    return mjcr;
1132 }
1133
1134 /*
1135  * Simulate the database call that updates the Job
1136  *  at Job termination time.
1137  */
1138 static int update_job_record(BDB *db, JOB_DBR *jr, SESSION_LABEL *elabel,
1139                               DEV_RECORD *rec)
1140 {
1141    struct date_time dt;
1142    struct tm tm;
1143    JCR *mjcr;
1144
1145    mjcr = get_jcr_by_session(rec->VolSessionId, rec->VolSessionTime);
1146    if (!mjcr) {
1147       Pmsg2(000, _("Could not find SessId=%d SessTime=%d for EOS record.\n"),
1148                    rec->VolSessionId, rec->VolSessionTime);
1149       return 0;
1150    }
1151    if (elabel->VerNum >= 11) {
1152       jr->EndTime = btime_to_unix(elabel->write_btime);
1153    } else {
1154       dt.julian_day_number = elabel->write_date;
1155       dt.julian_day_fraction = elabel->write_time;
1156       tm_decode(&dt, &tm);
1157       jr->EndTime = mktime(&tm);
1158    }
1159    lasttime = jr->EndTime;
1160    mjcr->end_time = jr->EndTime;
1161
1162    jr->JobId = mjcr->JobId;
1163
1164    /* The JobStatus can't be 0 */
1165    if (elabel->JobStatus == 0) {
1166       Pmsg2(000, _("Could not find JobStatus for SessId=%d SessTime=%d in EOS record.\n"),
1167                    rec->VolSessionId, rec->VolSessionTime);
1168    }
1169    mjcr->JobStatus = jr->JobStatus =
1170       elabel->JobStatus ? elabel->JobStatus : JS_ErrorTerminated;
1171
1172    jr->JobFiles = elabel->JobFiles;
1173    if (jr->JobFiles > 0) {  /* If we found files, force PurgedFiles */
1174       jr->PurgedFiles = 0;
1175    }
1176    jr->JobBytes = elabel->JobBytes;
1177    jr->VolSessionId = rec->VolSessionId;
1178    jr->VolSessionTime = rec->VolSessionTime;
1179    jr->JobTDate = (utime_t)mjcr->start_time;
1180    jr->ClientId = mjcr->ClientId;
1181
1182    if (!update_db) {
1183       free_jcr(mjcr);
1184       return 1;
1185    }
1186
1187    if (!db_update_job_end_record(bjcr, db, jr)) {
1188       Pmsg2(0, _("Could not update JobId=%u record. ERR=%s\n"), jr->JobId,  db_strerror(db));
1189       free_jcr(mjcr);
1190       return 0;
1191    }
1192    if (verbose) {
1193       Pmsg3(000, _("Updated Job termination record for JobId=%u Level=%s TermStat=%c\n"),
1194          jr->JobId, job_level_to_str(mjcr->getJobLevel()), jr->JobStatus);
1195    }
1196    if (verbose > 1) {
1197       const char *term_msg;
1198       static char term_code[70];
1199       char sdt[50], edt[50];
1200       char ec1[30], ec2[30], ec3[30];
1201
1202       switch (mjcr->JobStatus) {
1203       case JS_Terminated:
1204          term_msg = _("Backup OK");
1205          break;
1206       case JS_Warnings:
1207          term_msg = _("Backup OK -- with warnings");
1208          break;
1209       case JS_FatalError:
1210       case JS_ErrorTerminated:
1211          term_msg = _("*** Backup Error ***");
1212          break;
1213       case JS_Canceled:
1214          term_msg = _("Backup Canceled");
1215          break;
1216       default:
1217          term_msg = term_code;
1218          sprintf(term_code, _("Job Termination code: %d"), mjcr->JobStatus);
1219          break;
1220       }
1221       bstrftime(sdt, sizeof(sdt), mjcr->start_time);
1222       bstrftime(edt, sizeof(edt), mjcr->end_time);
1223       Pmsg14(000,  _("%s\n"
1224 "JobId:                  %d\n"
1225 "Job:                    %s\n"
1226 "FileSet:                %s\n"
1227 "Backup Level:           %s\n"
1228 "Client:                 %s\n"
1229 "Start time:             %s\n"
1230 "End time:               %s\n"
1231 "Files Written:          %s\n"
1232 "Bytes Written:          %s\n"
1233 "Volume Session Id:      %d\n"
1234 "Volume Session Time:    %d\n"
1235 "Last Volume Bytes:      %s\n"
1236 "Termination:            %s\n\n"),
1237         edt,
1238         mjcr->JobId,
1239         mjcr->Job,
1240         mjcr->fileset_name,
1241         job_level_to_str(mjcr->getJobLevel()),
1242         mjcr->client_name,
1243         sdt,
1244         edt,
1245         edit_uint64_with_commas(mjcr->JobFiles, ec1),
1246         edit_uint64_with_commas(mjcr->JobBytes, ec2),
1247         mjcr->VolSessionId,
1248         mjcr->VolSessionTime,
1249         edit_uint64_with_commas(mr.VolBytes, ec3),
1250         term_msg);
1251    }
1252    free_jcr(mjcr);
1253    return 1;
1254 }
1255
1256 static int create_jobmedia_record(BDB *db, JCR *mjcr)
1257 {
1258    JOBMEDIA_DBR jmr;
1259    DCR *dcr = mjcr->read_dcr;
1260
1261    dcr->EndAddr = dev->EndAddr;
1262    dcr->VolMediaId = dev->VolCatInfo.VolMediaId;
1263
1264    memset(&jmr, 0, sizeof(jmr));
1265    jmr.JobId = mjcr->JobId;
1266    jmr.MediaId = mr.MediaId;
1267    jmr.FirstIndex = dcr->VolFirstIndex;
1268    jmr.LastIndex = dcr->VolLastIndex;
1269    jmr.StartBlock = (uint32_t)dcr->StartAddr;
1270    jmr.StartFile = (uint32_t)(dcr->StartAddr >> 32);
1271    jmr.EndBlock = (uint32_t)dcr->EndAddr;
1272    jmr.EndFile = (uint32_t)(dcr->EndAddr >> 32);
1273    if (!update_db) {
1274       return 1;
1275    }
1276
1277    if (!db_create_jobmedia_record(bjcr, db, &jmr)) {
1278       Pmsg1(0, _("Could not create JobMedia record. ERR=%s\n"), db_strerror(db));
1279       return 0;
1280    }
1281    if (verbose) {
1282       Pmsg2(000, _("Created JobMedia record JobId %d, MediaId %d\n"),
1283                 jmr.JobId, jmr.MediaId);
1284    }
1285    return 1;
1286 }
1287
1288 /*
1289  * Simulate the database call that updates the MD5/SHA1 record
1290  */
1291 static int update_digest_record(BDB *db, char *digest, DEV_RECORD *rec, int type)
1292 {
1293    JCR *mjcr;
1294
1295    mjcr = get_jcr_by_session(rec->VolSessionId, rec->VolSessionTime);
1296    if (!mjcr) {
1297       if (mr.VolJobs > 0) {
1298          Pmsg2(000, _("Could not find SessId=%d SessTime=%d for MD5/SHA1 record.\n"),
1299                       rec->VolSessionId, rec->VolSessionTime);
1300       } else {
1301          ignored_msgs++;
1302       }
1303       return 0;
1304    }
1305
1306    if (!update_db || mjcr->FileId == 0) {
1307       free_jcr(mjcr);
1308       return 1;
1309    }
1310
1311    if (!db_add_digest_to_file_record(bjcr, db, mjcr->FileId, digest, type)) {
1312       Pmsg1(0, _("Could not add MD5/SHA1 to File record. ERR=%s\n"), db_strerror(db));
1313       free_jcr(mjcr);
1314       return 0;
1315    }
1316    if (verbose > 1) {
1317       Pmsg0(000, _("Updated MD5/SHA1 record\n"));
1318    }
1319    free_jcr(mjcr);
1320    return 1;
1321 }
1322
1323
1324 /*
1325  * Create a JCR as if we are really starting the job
1326  */
1327 static JCR *create_jcr(JOB_DBR *jr, DEV_RECORD *rec, uint32_t JobId)
1328 {
1329    JCR *jobjcr;
1330    /*
1331     * Transfer as much as possible to the Job JCR. Most important is
1332     *   the JobId and the ClientId.
1333     */
1334    jobjcr = new_jcr(sizeof(JCR), bscan_free_jcr);
1335    jobjcr->setJobType(jr->JobType);
1336    jobjcr->setJobLevel(jr->JobLevel);
1337    jobjcr->JobStatus = jr->JobStatus;
1338    bstrncpy(jobjcr->Job, jr->Job, sizeof(jobjcr->Job));
1339    jobjcr->JobId = JobId;      /* this is JobId on tape */
1340    jobjcr->sched_time = jr->SchedTime;
1341    jobjcr->start_time = jr->StartTime;
1342    jobjcr->VolSessionId = rec->VolSessionId;
1343    jobjcr->VolSessionTime = rec->VolSessionTime;
1344    jobjcr->ClientId = jr->ClientId;
1345    jobjcr->dcr = jobjcr->read_dcr = new_dcr(jobjcr, NULL, dev, SD_READ);
1346
1347    return jobjcr;
1348 }