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