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