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