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