1 /*
2    Bacula(R) - The Network Backup Solution
3 
4    Copyright (C) 2000-2020 Kern Sibbald
5 
6    The original author of Bacula is Kern Sibbald, with contributions
7    from many others, a complete list can be found in the file AUTHORS.
8 
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13 
14    This notice must be preserved when any source code is
15    conveyed and/or propagated.
16 
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20  *
21  *  label.c  Bacula routines to handle labels
22  *
23  *   Kern Sibbald, MM
24  *
25  */
26 
27 #include "bacula.h"                   /* pull in global headers */
28 #include "stored.h"                   /* pull in Storage Deamon headers */
29 
30 static const int dbglvl = 100;
31 
32 /* Forward referenced functions */
33 static void create_volume_label_record(DCR *dcr, DEVICE *dev, DEV_RECORD *rec, bool adata);
34 
35 /*
36  * Read the volume label
37  *
38  *  If dcr->VolumeName == NULL, we accept any Bacula Volume
39  *  If dcr->VolumeName[0] == 0, we accept any Bacula Volume
40  *  otherwise dcr->VolumeName must match the Volume.
41  *
42  *  If VolName given, ensure that it matches
43  *
44  *  Returns VOL_  code as defined in record.h
45  *    VOL_NOT_READ
46  *    VOL_OK                          good label found
47  *    VOL_NO_LABEL                    volume not labeled
48  *    VOL_IO_ERROR                    I/O error reading tape
49  *    VOL_NAME_ERROR                  label has wrong name
50  *    VOL_CREATE_ERROR                Error creating label
51  *    VOL_VERSION_ERROR               label has wrong version
52  *    VOL_LABEL_ERROR                 bad label type
53  *    VOL_NO_MEDIA                    no media in drive
54  *    VOL_TYPE_ERROR                  aligned/non-aligned/dedup error
55  *
56  *  The dcr block is emptied on return, and the Volume is
57  *    rewound.
58  *
59  *  Handle both the ameta and adata volumes.
60  */
read_dev_volume_label(DCR * dcr)61 int DEVICE::read_dev_volume_label(DCR *dcr)
62 {
63    JCR *jcr = dcr->jcr;
64    char *VolName = dcr->VolumeName;
65    DEV_RECORD *record;
66    bool ok = false;
67    int stat;
68    bool want_ansi_label;
69    bool have_ansi_label = false;
70 
71    Enter(dbglvl);
72    Dmsg5(dbglvl, "Enter read_volume_label adata=%d res=%d device=%s vol=%s dev_Vol=%s\n",
73          dcr->block->adata, num_reserved(), print_name(), VolName,
74       VolHdr.VolumeName[0]?VolHdr.VolumeName:"*NULL*");
75 
76 
77    if (!is_open()) {
78       if (!open_device(dcr, OPEN_READ_ONLY)) {
79          Leave(dbglvl);
80          return VOL_IO_ERROR;
81       }
82    }
83 
84    clear_labeled();
85    clear_append();
86    clear_read();
87    label_type = B_BACULA_LABEL;
88    set_worm(get_tape_worm(dcr));
89    Dmsg1(dbglvl, "==== worm=%d ====\n", is_worm());
90 
91    if (!rewind(dcr)) {
92       Mmsg(jcr->errmsg, _("Couldn't rewind %s device %s: ERR=%s\n"),
93          print_type(), print_name(), print_errmsg());
94       Dmsg1(dbglvl, "return VOL_NO_MEDIA: %s", jcr->errmsg);
95       Leave(dbglvl);
96       return VOL_NO_MEDIA;
97    }
98    bstrncpy(VolHdr.Id, "**error**", sizeof(VolHdr.Id));
99 
100   /* Read ANSI/IBM label if so requested */
101   want_ansi_label = dcr->VolCatInfo.LabelType != B_BACULA_LABEL ||
102                     dcr->device->label_type != B_BACULA_LABEL;
103   if (want_ansi_label || has_cap(CAP_CHECKLABELS)) {
104       stat = read_ansi_ibm_label(dcr);
105       /* If we want a label and didn't find it, return error */
106       if (want_ansi_label && stat != VOL_OK) {
107          goto bail_out;
108       }
109       if (stat == VOL_NAME_ERROR || stat == VOL_LABEL_ERROR) {
110          Mmsg(jcr->errmsg, _("Wrong Volume mounted on %s device %s: Wanted %s have %s\n"),
111               print_type(), print_name(), VolName, VolHdr.VolumeName);
112          if (!poll && jcr->label_errors++ > 100) {
113             Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
114          }
115          goto bail_out;
116       }
117       if (stat != VOL_OK) {           /* Not an ANSI/IBM label, so re-read */
118          rewind(dcr);
119       } else {
120          have_ansi_label = true;
121       }
122    }
123 
124    /* Read the Bacula Volume label block */
125    record = new_record();
126    empty_block(dcr->block);
127 
128    Dmsg0(130, "Big if statement in read_volume_label\n");
129    dcr->reading_label = true;
130    if (!dcr->read_block_from_dev(NO_BLOCK_NUMBER_CHECK)) {
131       Mmsg(jcr->errmsg, _("Read label block failed: requested Volume \"%s\" on %s device %s is not a Bacula "
132            "labeled Volume, because: ERR=%s"), NPRT(VolName),
133            print_type(), print_name(), print_errmsg());
134       Dmsg1(dbglvl, "%s", jcr->errmsg);
135    } else if (!read_record_from_block(dcr, record)) {
136       Mmsg(jcr->errmsg, _("Could not read Volume label from block.\n"));
137       Dmsg1(dbglvl, "%s", jcr->errmsg);
138    } else if (!unser_volume_label(this, record)) {
139       Mmsg(jcr->errmsg, _("Could not unserialize Volume label: ERR=%s\n"),
140          print_errmsg());
141       Dmsg1(dbglvl, "%s", jcr->errmsg);
142    } else if (strcmp(VolHdr.Id, BaculaId) != 0 &&
143               strcmp(VolHdr.Id, OldBaculaId) != 0 &&
144               strcmp(VolHdr.Id, BaculaMetaDataId) != 0 &&
145               strcmp(VolHdr.Id, BaculaAlignedDataId) != 0 &&
146               strcmp(VolHdr.Id, BaculaDedupMetaDataId) != 0 &&
147               strcmp(VolHdr.Id, BaculaS3CloudId) != 0) {
148       Mmsg(jcr->errmsg, _("Volume Header Id bad: %s\n"), VolHdr.Id);
149       Dmsg1(dbglvl, "%s", jcr->errmsg);
150    } else {
151       ok = true;
152       Dmsg1(dbglvl, "VolHdr.Id OK: %s\n", VolHdr.Id);
153    }
154    dcr->reading_label = false;
155    free_record(record);               /* finished reading Volume record */
156 
157    if (!is_volume_to_unload()) {
158       clear_unload();
159    }
160 
161    if (!ok) {
162       if (jcr->ignore_label_errors) {
163          set_labeled();         /* set has Bacula label */
164          if (jcr->errmsg[0]) {
165             Jmsg(jcr, M_ERROR, 0, "%s", jcr->errmsg);
166          }
167          empty_block(dcr->block);
168          Leave(dbglvl);
169          return VOL_OK;
170       }
171       Dmsg0(dbglvl, "No volume label - bailing out\n");
172       stat = VOL_NO_LABEL;
173       goto bail_out;
174    }
175 
176    /* At this point, we have read the first Bacula block, and
177     * then read the Bacula Volume label. Now we need to
178     * make sure we have the right Volume.
179     */
180    if (VolHdr.VerNum != BaculaTapeVersion &&
181        VolHdr.VerNum != BaculaMetaDataVersion &&
182        VolHdr.VerNum != BaculaDedupMetaDataVersion &&
183        VolHdr.VerNum != BaculaS3CloudVersion &&
184        VolHdr.VerNum != OldCompatibleBaculaTapeVersion1 &&
185        VolHdr.VerNum != OldCompatibleBaculaTapeVersion2) {
186       Mmsg(jcr->errmsg, _("Volume on %s device %s has wrong Bacula version. Wanted %d got %d\n"),
187          print_type(), print_name(), BaculaTapeVersion, VolHdr.VerNum);
188       Dmsg1(dbglvl, "VOL_VERSION_ERROR: %s", jcr->errmsg);
189       stat = VOL_VERSION_ERROR;
190       goto bail_out;
191    }
192    Dmsg1(dbglvl, "VolHdr.VerNum=%ld OK.\n", VolHdr.VerNum);
193 
194    /* We are looking for either an unused Bacula tape (PRE_LABEL) or
195     * a Bacula volume label (VOL_LABEL)
196     */
197    if (VolHdr.LabelType != PRE_LABEL && VolHdr.LabelType != VOL_LABEL) {
198       Mmsg(jcr->errmsg, _("Volume on %s device %s has bad Bacula label type: %ld\n"),
199           print_type(), print_name(), VolHdr.LabelType);
200       Dmsg1(dbglvl, "%s", jcr->errmsg);
201       if (!poll && jcr->label_errors++ > 100) {
202          Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
203       }
204       Dmsg0(dbglvl, "return VOL_LABEL_ERROR\n");
205       stat = VOL_LABEL_ERROR;
206       goto bail_out;
207    }
208 
209    set_labeled();               /* set has Bacula label */
210 
211    /* Compare Volume Names */
212    Dmsg2(130, "Compare Vol names: VolName=%s hdr=%s\n", VolName?VolName:"*", VolHdr.VolumeName);
213    if (VolName && *VolName && *VolName != '*' && strcmp(VolHdr.VolumeName, VolName) != 0) {
214       Mmsg(jcr->errmsg, _("Wrong Volume mounted on %s device %s: Wanted %s have %s\n"),
215            print_type(), print_name(), VolName, VolHdr.VolumeName);
216       Dmsg1(dbglvl, "%s", jcr->errmsg);
217       /*
218        * Cancel Job if too many label errors
219        *  => we are in a loop
220        */
221       if (!poll && jcr->label_errors++ > 100) {
222          Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
223       }
224       Dmsg0(dbglvl, "return VOL_NAME_ERROR\n");
225       stat = VOL_NAME_ERROR;
226       goto bail_out;
227    }
228 
229    /* Compare VolType to Device Type */
230    switch (dev_type) {
231    case B_DEDUP_DEV:
232       if (strcmp(VolHdr.Id, BaculaDedupMetaDataId) != 0) {
233          Mmsg(jcr->errmsg, _("Wrong Volume Type. Wanted a Dedup Volume %s on device %s, but got: %s\n"),
234             VolHdr.VolumeName, print_name(), VolHdr.Id);
235          stat = VOL_TYPE_ERROR;
236          goto bail_out;
237       }
238       break;
239    case B_FILE_DEV:
240       if (strcmp(VolHdr.Id, BaculaId) != 0) {
241          Mmsg(jcr->errmsg, _("Wrong Volume Type. Wanted a File or Tape Volume %s on device %s, but got: %s\n"),
242             VolHdr.VolumeName, print_name(), VolHdr.Id);
243          stat = VOL_TYPE_ERROR;
244          goto bail_out;
245       }
246       break;
247    case B_ALIGNED_DEV:
248    case B_ADATA_DEV:
249       if (strcmp(VolHdr.Id, BaculaMetaDataId) != 0) {
250          Mmsg(jcr->errmsg, _("Wrong Volume Type. Wanted an Aligned Volume %s on device %s, but got: %s\n"),
251             VolHdr.VolumeName, print_name(), VolHdr.Id);
252          stat = VOL_TYPE_ERROR;
253          goto bail_out;
254       }
255       break;
256    case B_CLOUD_DEV:
257       if (strcmp(VolHdr.Id, BaculaS3CloudId) != 0) {
258          Mmsg(jcr->errmsg, _("Wrong Volume Type. Wanted a Cloud Volume %s on device %s, but got: %s\n"),
259             VolHdr.VolumeName, print_name(), VolHdr.Id);
260          stat = VOL_TYPE_ERROR;
261          goto bail_out;
262       }
263    default:
264       break;
265    }
266 
267    if (chk_dbglvl(100)) {
268       dump_volume_label();
269    }
270    Dmsg0(dbglvl, "Leave read_volume_label() VOL_OK\n");
271    /* If we are a streaming device, we only get one chance to read */
272    if (!has_cap(CAP_STREAM)) {
273       rewind(dcr);
274       if (have_ansi_label) {
275          stat = read_ansi_ibm_label(dcr);
276          /* If we want a label and didn't find it, return error */
277          if (stat != VOL_OK) {
278             goto bail_out;
279          }
280       }
281    }
282 
283    Dmsg1(100, "Call reserve_volume=%s\n", VolHdr.VolumeName);
284    if (reserve_volume(dcr, VolHdr.VolumeName) == NULL) {
285       if (!jcr->errmsg[0]) {
286          Mmsg3(jcr->errmsg, _("Could not reserve volume %s on %s device %s\n"),
287               VolHdr.VolumeName, print_type(), print_name());
288       }
289       Dmsg2(dbglvl, "Could not reserve volume %s on %s\n", VolHdr.VolumeName, print_name());
290       stat = VOL_NAME_ERROR;
291       goto bail_out;
292    }
293 
294    if (dcr->is_writing()) {
295        empty_block(dcr->block);
296    }
297 
298    Leave(dbglvl);
299    return VOL_OK;
300 
301 bail_out:
302    empty_block(dcr->block);
303    rewind(dcr);
304    Dmsg2(dbglvl, "return stat=%d %s", stat, jcr->errmsg);
305    Leave(dbglvl);
306    return stat;
307 }
308 
309 
310 /*
311  * Create and put a volume label into the block
312  *
313  *  Returns: false on failure
314  *           true  on success
315  *
316  *  Handle both the ameta and adata volumes.
317  */
write_volume_label_to_block(DCR * dcr)318 bool DEVICE::write_volume_label_to_block(DCR *dcr)
319 {
320    DEVICE *dev;
321    DEV_RECORD rec;
322    JCR *jcr = dcr->jcr;
323    bool ok = true;
324 
325    Enter(100);
326    dev = dcr->dev;
327    memset(&rec, 0, sizeof(rec));
328    rec.data = get_memory(SER_LENGTH_Volume_Label);
329    memset(rec.data, 0, SER_LENGTH_Volume_Label);
330    empty_block(dcr->block);     /* Volume label always at beginning */
331 
332    create_volume_label_record(dcr, dcr->dev, &rec, dcr->block->adata);
333 
334    dcr->block->BlockNumber = 0;
335    /* Note for adata this also writes to disk */
336    Dmsg1(100, "write_record_to_block adata=%d\n", dcr->dev->adata);
337    if (!write_record_to_block(dcr, &rec)) {
338       free_pool_memory(rec.data);
339       Jmsg2(jcr, M_FATAL, 0, _("Cannot write Volume label to block for %s device %s\n"),
340          dev->print_type(), dev->print_name());
341       ok = false;
342       goto get_out;
343    } else {
344       Dmsg4(100, "Wrote fd=%d adata=%d label of %d bytes to block. Vol=%s\n",
345          dev->fd(), dcr->block->adata, rec.data_len, dcr->VolumeName);
346    }
347    free_pool_memory(rec.data);
348 
349 get_out:
350    Leave(100);
351    return ok;
352 }
353 
354 /*
355  * Write a Volume Label
356  *  !!! Note, this is ONLY used for writing
357  *            a fresh volume label.  Any data
358  *            after the label will be destroyed,
359  *            in fact, we write the label 5 times !!!!
360  *
361  *  This routine should be used only when labeling a blank tape or
362  *  when recylcing a volume.
363  *
364  *  Handle both the ameta and adata volumes.
365  */
write_volume_label(DCR * dcr,const char * VolName,const char * PoolName,bool relabel,bool no_prelabel)366 bool DEVICE::write_volume_label(DCR *dcr, const char *VolName,
367                const char *PoolName, bool relabel, bool no_prelabel)
368 {
369    DEVICE *dev;
370 
371    Enter(100);
372    Dmsg4(230, "Write:  block=%p ameta=%p dev=%p ameta_dev=%p\n",
373          dcr->block, dcr->ameta_block, dcr->dev, dcr->ameta_dev);
374    dcr->set_ameta();
375    dev = dcr->dev;
376 
377    Dmsg0(150, "write_volume_label()\n");
378    if (*VolName == 0) {
379       if (dcr->jcr) {
380          Mmsg(dcr->jcr->errmsg, "ERROR: new_volume_label_to_dev called with NULL VolName\n");
381       }
382       Pmsg0(0, "=== ERROR: write_volume_label called with NULL VolName\n");
383       goto bail_out;
384    }
385 
386    if (relabel) {
387       volume_unused(dcr);             /* mark current volume unused */
388       /* Truncate device */
389       if (!dev->truncate(dcr)) {
390          goto bail_out;
391       }
392       dev->close_part(dcr);          /* make sure closed for rename */
393    }
394 
395    /* Set the new filename for open, ... */
396    dev->setVolCatName(VolName);
397    dcr->setVolCatName(VolName);
398    dev->clearVolCatBytes();
399 
400    Dmsg1(100, "New VolName=%s\n", VolName);
401    if (!dev->open_device(dcr, OPEN_READ_WRITE)) {
402       /* If device is not tape, attempt to create it */
403       if (dev->is_tape() || !dev->open_device(dcr, CREATE_READ_WRITE)) {
404          Jmsg4(dcr->jcr, M_WARNING, 0, _("Open %s device %s Volume \"%s\" failed: ERR=%s"),
405                dev->print_type(), dev->print_name(), dcr->VolumeName, dev->bstrerror());
406          goto bail_out;
407       }
408    }
409    Dmsg1(150, "Label type=%d\n", dev->label_type);
410 
411    if (!write_volume_label_to_dev(dcr, VolName, PoolName, relabel, no_prelabel)) {
412       goto bail_out;
413    }
414 
415    if (!dev->is_aligned()) {
416       /* Not aligned data */
417       if (dev->weof(dcr, 1)) {
418          dev->set_labeled();
419       }
420 
421       if (chk_dbglvl(100))  {
422          dev->dump_volume_label();
423       }
424       Dmsg0(50, "Call reserve_volume\n");
425       /**** ***FIXME*** if dev changes, dcr must be updated */
426       if (reserve_volume(dcr, VolName) == NULL) {
427          if (!dcr->jcr->errmsg[0]) {
428             Mmsg3(dcr->jcr->errmsg, _("Could not reserve volume %s on %s device %s\n"),
429                  dev->VolHdr.VolumeName, dev->print_type(), dev->print_name());
430          }
431          Dmsg1(50, "%s", dcr->jcr->errmsg);
432          goto bail_out;
433       }
434       dev = dcr->dev;                 /* may have changed in reserve_volume */
435    }
436    dev->clear_append();               /* remove append since this is PRE_LABEL */
437    Leave(100);
438    return true;
439 
440 bail_out:
441    dcr->adata_label = false;
442    dcr->set_ameta();
443    volume_unused(dcr);
444    dcr->dev->clear_append();            /* remove append since this is PRE_LABEL */
445    Leave(100);
446    return false;
447 }
448 
write_volume_label_to_dev(DCR * dcr,const char * VolName,const char * PoolName,bool relabel,bool no_prelabel)449 bool DEVICE::write_volume_label_to_dev(DCR *dcr, const char *VolName,
450               const char *PoolName, bool relabel, bool no_prelabel)
451 {
452    DEVICE *dev, *ameta_dev;
453    DEV_RECORD *rec = new_record();
454    bool rtn = false;
455 
456    Enter(100);
457    dev = dcr->dev;
458    ameta_dev = dcr->ameta_dev;
459 
460    empty_block(dcr->block);
461    if (!dev->rewind(dcr)) {
462       Dmsg2(130, "Bad status on %s from rewind: ERR=%s\n", dev->print_name(), dev->print_errmsg());
463       goto bail_out;
464    }
465 
466    /* Temporarily mark in append state to enable writing */
467    dev->set_append();
468 
469    /* Create PRE_LABEL or VOL_LABEL */
470    create_volume_header(dev, VolName, PoolName, no_prelabel);
471 
472    /*
473     * If we have already detected an ANSI label, re-read it
474     *   to skip past it. Otherwise, we write a new one if
475     *   so requested.
476     */
477    if (!dcr->block->adata) {
478       if (dev->label_type != B_BACULA_LABEL) {
479          if (read_ansi_ibm_label(dcr) != VOL_OK) {
480             dev->rewind(dcr);
481             goto bail_out;
482          }
483       } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, VolName)) {
484          goto bail_out;
485       }
486    }
487 
488    create_volume_label_record(dcr, dev, rec, dcr->block->adata);
489    rec->Stream = 0;
490    rec->maskedStream = 0;
491 
492    Dmsg2(100, "write_record_to_block adata=%d FI=%d\n", dcr->dev->adata,
493       rec->FileIndex);
494 
495    /* For adata label this also writes to disk */
496    if (!write_record_to_block(dcr, rec)) {
497       Dmsg2(40, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
498       goto bail_out;
499    } else {
500       Dmsg3(100, "Wrote label=%d bytes adata=%d block: %s\n", rec->data_len, dcr->block->adata, dev->print_name());
501    }
502    Dmsg3(100, "New label adata=%d VolCatBytes=%lld VolCatStatus=%s\n",
503       dev->adata, ameta_dev->VolCatInfo.VolCatBytes, ameta_dev->VolCatInfo.VolCatStatus);
504 
505    if (dcr->block->adata) {
506       /* Empty block and set data start address */
507       empty_block(dcr->adata_block);
508    } else {
509       Dmsg4(130, "Call write_block_to_dev() fd=%d adata=%d block=%p Addr=%lld\n",
510          dcr->dev->fd(), dcr->block->adata, dcr->block, dcr->block->dev->lseek(dcr, 0, SEEK_CUR));
511       Dmsg1(100, "write_record_to_dev adata=%d\n", dcr->dev->adata);
512       /* Write ameta block to device */
513       if (!dcr->write_block_to_dev()) {
514          Dmsg2(40, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
515          goto bail_out;
516       }
517    }
518    Dmsg3(100, "Wrote new Vol label adata=%d VolCatBytes=%lld VolCatStatus=%s\n",
519       dev->adata, ameta_dev->VolCatInfo.VolCatBytes, ameta_dev->VolCatInfo.VolCatStatus);
520    rtn = true;
521 
522 bail_out:
523    free_record(rec);
524    Leave(100);
525    return rtn;
526 }
527 
528 /*
529  * Write a volume label. This is ONLY called if we have a valid Bacula
530  *   label of type PRE_LABEL or we are recyling an existing Volume.
531  *
532  * By calling write_volume_label_to_block, both ameta and adata
533  *   are updated.
534  *
535  *  Returns: true if OK
536  *           false if unable to write it
537  */
rewrite_volume_label(DCR * dcr,bool recycle)538 bool DEVICE::rewrite_volume_label(DCR *dcr, bool recycle)
539 {
540    char ed1[50];
541    JCR *jcr = dcr->jcr;
542 
543    Enter(100);
544    ASSERT2(dcr->VolumeName[0], "Empty Volume name");
545    ASSERT(!dcr->block->adata);
546    if (is_worm()) {
547       Jmsg3(jcr, M_FATAL, 0,  _("Cannot relabel worm %s device %s Volume \"%s\"\n"),
548              print_type(), print_name(), dcr->VolumeName);
549       Leave(100);
550       return false;
551    }
552    if (!open_device(dcr, OPEN_READ_WRITE)) {
553        Jmsg4(jcr, M_WARNING, 0, _("Open %s device %s Volume \"%s\" failed: ERR=%s\n"),
554              print_type(), print_name(), dcr->VolumeName, bstrerror());
555       Leave(100);
556       return false;
557    }
558    Dmsg2(190, "set append found freshly labeled volume. fd=%d dev=%x\n", fd(), this);
559    VolHdr.LabelType = VOL_LABEL; /* set Volume label */
560    set_append();
561    Dmsg0(100, "Rewrite_volume_label set volcatbytes=0\n");
562    clearVolCatBytes();           /* resets both ameta and adata byte counts */
563    setVolCatStatus("Append");    /* set append status */
564 
565    if (!has_cap(CAP_STREAM)) {
566       if (!rewind(dcr)) {
567          Jmsg3(jcr, M_FATAL, 0, _("Rewind error on %s device %s: ERR=%s\n"),
568                print_type(), print_name(), print_errmsg());
569          Leave(100);
570          return false;
571       }
572       if (recycle) {
573          Dmsg1(150, "Doing recycle. Vol=%s\n", dcr->VolumeName);
574          if (!truncate(dcr)) {
575             Jmsg3(jcr, M_FATAL, 0, _("Truncate error on %s device %s: ERR=%s\n"),
576                   print_type(), print_name(), print_errmsg());
577             Leave(100);
578             return false;
579          }
580          if (!open_device(dcr, OPEN_READ_WRITE)) {
581             Jmsg3(jcr, M_FATAL, 0,
582                _("Failed to re-open device after truncate on %s device %s: ERR=%s"),
583                print_type(), print_name(), print_errmsg());
584             Leave(100);
585             return false;
586          }
587       }
588    }
589 
590    if (!write_volume_label_to_block(dcr)) {
591       Dmsg0(150, "Error from write volume label.\n");
592       Leave(100);
593       return false;
594    }
595    Dmsg2(100, "wrote vol label to block. adata=%d Vol=%s\n", dcr->block->adata, dcr->VolumeName);
596 
597    ASSERT2(dcr->VolumeName[0], "Empty Volume name");
598    setVolCatInfo(false);
599 
600    /*
601     * If we are not dealing with a streaming device,
602     *  write the block now to ensure we have write permission.
603     *  It is better to find out now rather than later.
604     * We do not write the block now if this is an ANSI label. This
605     *  avoids re-writing the ANSI label, which we do not want to do.
606     */
607    if (!has_cap(CAP_STREAM)) {
608       /*
609        * If we have already detected an ANSI label, re-read it
610        *   to skip past it. Otherwise, we write a new one if
611        *   so requested.
612        */
613       if (label_type != B_BACULA_LABEL) {
614          if (read_ansi_ibm_label(dcr) != VOL_OK) {
615             rewind(dcr);
616             Leave(100);
617             return false;
618          }
619       } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, VolHdr.VolumeName)) {
620          Leave(100);
621          return false;
622       }
623 
624       /* Attempt write to check write permission */
625       Dmsg1(200, "Attempt to write to device fd=%d.\n", fd());
626       if (!dcr->write_block_to_dev()) {
627          Jmsg3(jcr, M_ERROR, 0, _("Unable to write %s device %s: ERR=%s\n"),
628             print_type(), print_name(), print_errmsg());
629          Dmsg0(200, "===ERROR write block to dev\n");
630          Leave(100);
631          return false;
632       }
633    }
634    ASSERT2(dcr->VolumeName[0], "Empty Volume name");
635    setVolCatName(dcr->VolumeName);
636    if (!dir_get_volume_info(dcr, dcr->VolumeName, GET_VOL_INFO_FOR_WRITE)) {
637       Leave(100);
638       return false;
639    }
640    set_labeled();
641    /* Set or reset Volume statistics */
642    VolCatInfo.VolCatJobs = 0;
643    VolCatInfo.VolCatFiles = 0;
644    VolCatInfo.VolCatErrors = 0;
645    VolCatInfo.VolCatBlocks = 0;
646    VolCatInfo.VolCatRBytes = 0;
647    VolCatInfo.VolCatCloudParts = 0;
648    VolCatInfo.VolLastPartBytes = 0;
649    VolCatInfo.VolCatType = 0; /* Will be set by dir_update_volume_info() */
650    if (recycle) {
651       VolCatInfo.VolCatMounts++;
652       VolCatInfo.VolCatRecycles++;
653    } else {
654       VolCatInfo.VolCatMounts = 1;
655       VolCatInfo.VolCatRecycles = 0;
656       VolCatInfo.VolCatWrites = 1;
657       VolCatInfo.VolCatReads = 1;
658    }
659    dcr->VolMediaId = dcr->VolCatInfo.VolMediaId;  /* make create_jobmedia work */
660    dir_create_jobmedia_record(dcr, true);
661    Dmsg1(100, "dir_update_vol_info. Set Append vol=%s\n", dcr->VolumeName);
662    VolCatInfo.VolFirstWritten = time(NULL);
663    setVolCatStatus("Append");
664    if (!dir_update_volume_info(dcr, true, true)) {  /* indicate relabel */
665       Leave(100);
666       return false;
667    }
668    if (recycle) {
669       Jmsg(jcr, M_INFO, 0, _("Recycled volume \"%s\" on %s device %s, all previous data lost.\n"),
670          dcr->VolumeName, print_type(), print_name());
671    } else {
672       Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume \"%s\" on %s device %s\n"),
673          dcr->VolumeName, print_type(), print_name());
674    }
675    /*
676     * End writing real Volume label (from pre-labeled tape), or recycling
677     *  the volume.
678     */
679    Dmsg4(100, "OK rewrite vol label. Addr=%s adata=%d slot=%d Vol=%s\n",
680       print_addr(ed1, sizeof(ed1)), dcr->block->adata, VolCatInfo.Slot, dcr->VolumeName);
681    Leave(100);
682    return true;
683 }
684 
685 
686 /*
687  *  create_volume_label_record
688  *   Note: it is assumed that you have created the volume_header
689  *     (label) prior to calling this subroutine.
690  *   Serialize label (from dev->VolHdr structure) into device record.
691  *   Assumes that the dev->VolHdr structure is properly
692  *   initialized.
693 */
create_volume_label_record(DCR * dcr,DEVICE * dev,DEV_RECORD * rec,bool adata)694 static void create_volume_label_record(DCR *dcr, DEVICE *dev,
695      DEV_RECORD *rec, bool adata)
696 {
697    ser_declare;
698    struct date_time dt;
699    JCR *jcr = dcr->jcr;
700    char buf[100];
701 
702    /* Serialize the label into the device record. */
703 
704    Enter(100);
705    rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
706    memset(rec->data, 0, SER_LENGTH_Volume_Label);
707    ser_begin(rec->data, SER_LENGTH_Volume_Label);
708    ser_string(dev->VolHdr.Id);
709 
710    ser_uint32(dev->VolHdr.VerNum);
711 
712    if (dev->VolHdr.VerNum >= 11) {
713       ser_btime(dev->VolHdr.label_btime);
714       dev->VolHdr.write_btime = get_current_btime();
715       ser_btime(dev->VolHdr.write_btime);
716       dev->VolHdr.write_date = 0;
717       dev->VolHdr.write_time = 0;
718    } else {
719       /* OLD WAY DEPRECATED */
720       ser_float64(dev->VolHdr.label_date);
721       ser_float64(dev->VolHdr.label_time);
722       get_current_time(&dt);
723       dev->VolHdr.write_date = dt.julian_day_number;
724       dev->VolHdr.write_time = dt.julian_day_fraction;
725    }
726    ser_float64(dev->VolHdr.write_date);   /* 0 if VerNum >= 11 */
727    ser_float64(dev->VolHdr.write_time);   /* 0  if VerNum >= 11 */
728 
729    ser_string(dev->VolHdr.VolumeName);
730    ser_string(dev->VolHdr.PrevVolumeName);
731    ser_string(dev->VolHdr.PoolName);
732    ser_string(dev->VolHdr.PoolType);
733    ser_string(dev->VolHdr.MediaType);
734 
735    ser_string(dev->VolHdr.HostName);
736    ser_string(dev->VolHdr.LabelProg);
737    ser_string(dev->VolHdr.ProgVersion);
738    ser_string(dev->VolHdr.ProgDate);
739    /* ***FIXME*** */
740    dev->VolHdr.AlignedVolumeName[0] = 0;
741    ser_string(dev->VolHdr.AlignedVolumeName);
742 
743    /* This is adata Volume information */
744    ser_uint64(dev->VolHdr.FirstData);
745    ser_uint32(dev->VolHdr.FileAlignment);
746    ser_uint32(dev->VolHdr.PaddingSize);
747    /* adata and dedup volumes */
748    ser_uint32(dev->VolHdr.BlockSize);
749 
750    ser_end(rec->data, SER_LENGTH_Volume_Label);
751    if (!adata) {
752       bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName));
753    }
754    ASSERT2(dcr->VolumeName[0], "Empty Volume name");
755    rec->data_len = ser_length(rec->data);
756    rec->FileIndex = dev->VolHdr.LabelType;
757    Dmsg2(100, "LabelType=%d adata=%d\n", dev->VolHdr.LabelType, dev->adata);
758    rec->VolSessionId = jcr->VolSessionId;
759    rec->VolSessionTime = jcr->VolSessionTime;
760    rec->Stream = jcr->NumWriteVolumes;
761    rec->maskedStream = jcr->NumWriteVolumes;
762    Dmsg3(100, "Created adata=%d Vol label rec: FI=%s len=%d\n", adata, FI_to_ascii(buf, rec->FileIndex),
763       rec->data_len);
764    Dmsg2(100, "reclen=%d recdata=%s", rec->data_len, rec->data);
765    Leave(100);
766 }
767 
768 
769 /*
770  * Create a volume header (label) in memory
771  *   The volume record is created after this header (label)
772  *   is created.
773  */
create_volume_header(DEVICE * dev,const char * VolName,const char * PoolName,bool no_prelabel)774 void create_volume_header(DEVICE *dev, const char *VolName,
775                          const char *PoolName, bool no_prelabel)
776 {
777    DEVRES *device = (DEVRES *)dev->device;
778 
779    Enter(130);
780 
781    ASSERT2(dev != NULL, "dev ptr is NULL");
782 
783    if (dev->is_aligned()) {
784       bstrncpy(dev->VolHdr.Id, BaculaMetaDataId, sizeof(dev->VolHdr.Id));
785       dev->VolHdr.VerNum = BaculaMetaDataVersion;
786       dev->VolHdr.FirstData = dev->file_alignment;
787       dev->VolHdr.FileAlignment = dev->file_alignment;
788       dev->VolHdr.PaddingSize = dev->padding_size;
789       dev->VolHdr.BlockSize = dev->adata_size;
790    } else if (dev->is_adata()) {
791       bstrncpy(dev->VolHdr.Id, BaculaAlignedDataId, sizeof(dev->VolHdr.Id));
792       dev->VolHdr.VerNum = BaculaAlignedDataVersion;
793       dev->VolHdr.FirstData = dev->file_alignment;
794       dev->VolHdr.FileAlignment = dev->file_alignment;
795       dev->VolHdr.PaddingSize = dev->padding_size;
796       dev->VolHdr.BlockSize = dev->adata_size;
797    } else if (dev->is_dedup()) {
798       bstrncpy(dev->VolHdr.Id, BaculaDedupMetaDataId, sizeof(dev->VolHdr.Id));
799       dev->VolHdr.VerNum = BaculaDedupMetaDataVersion;
800       dev->VolHdr.BlockSize = dev->max_block_size;
801    } else if (dev->is_cloud()) {
802       bstrncpy(dev->VolHdr.Id, BaculaS3CloudId, sizeof(dev->VolHdr.Id));
803       dev->VolHdr.VerNum = BaculaS3CloudVersion;
804       dev->VolHdr.BlockSize = dev->max_block_size;
805       dev->VolHdr.MaxPartSize = dev->max_part_size;
806    } else {
807       bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
808       dev->VolHdr.VerNum = BaculaTapeVersion;
809       dev->VolHdr.BlockSize = dev->max_block_size;
810    }
811 
812    if ((dev->has_cap(CAP_STREAM) && no_prelabel) || dev->is_worm()) {
813       /* We do not want to re-label so write VOL_LABEL now */
814       dev->VolHdr.LabelType = VOL_LABEL;
815    } else {
816       dev->VolHdr.LabelType = PRE_LABEL;  /* Mark Volume as unused */
817    }
818    bstrncpy(dev->VolHdr.VolumeName, VolName, sizeof(dev->VolHdr.VolumeName));
819    bstrncpy(dev->VolHdr.PoolName, PoolName, sizeof(dev->VolHdr.PoolName));
820    bstrncpy(dev->VolHdr.MediaType, device->media_type, sizeof(dev->VolHdr.MediaType));
821 
822    bstrncpy(dev->VolHdr.PoolType, "Backup", sizeof(dev->VolHdr.PoolType));
823 
824    dev->VolHdr.label_btime = get_current_btime();
825    dev->VolHdr.label_date = 0;
826    dev->VolHdr.label_time = 0;
827 
828    if (gethostname(dev->VolHdr.HostName, sizeof(dev->VolHdr.HostName)) != 0) {
829       dev->VolHdr.HostName[0] = 0;
830    }
831    bstrncpy(dev->VolHdr.LabelProg, my_name, sizeof(dev->VolHdr.LabelProg));
832    sprintf(dev->VolHdr.ProgVersion, "Ver. %s %s ", VERSION, BDATE);
833    sprintf(dev->VolHdr.ProgDate, "Build %s %s ", __DATE__, __TIME__);
834    dev->set_labeled();               /* set has Bacula label */
835    if (chk_dbglvl(100)) {
836       dev->dump_volume_label();
837    }
838 }
839 
840 /*
841  * Create session (Job) label
842  *  The pool memory must be released by the calling program
843  */
create_session_label(DCR * dcr,DEV_RECORD * rec,int label)844 void create_session_label(DCR *dcr, DEV_RECORD *rec, int label)
845 {
846    JCR *jcr = dcr->jcr;
847    ser_declare;
848 
849    Enter(100);
850    rec->VolSessionId   = jcr->VolSessionId;
851    rec->VolSessionTime = jcr->VolSessionTime;
852    rec->Stream         = jcr->JobId;
853    rec->maskedStream   = jcr->JobId;
854 
855    rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
856    ser_begin(rec->data, SER_LENGTH_Session_Label);
857    ser_string(BaculaId);
858    ser_uint32(BaculaTapeVersion);
859 
860    ser_uint32(jcr->JobId);
861 
862    /* Changed in VerNum 11 */
863    ser_btime(get_current_btime());
864    ser_float64(0);
865 
866    ser_string(dcr->pool_name);
867    ser_string(dcr->pool_type);
868    ser_string(jcr->job_name);         /* base Job name */
869    ser_string(jcr->client_name);
870 
871    /* Added in VerNum 10 */
872    ser_string(jcr->Job);              /* Unique name of this Job */
873    ser_string(jcr->fileset_name);
874    ser_uint32(jcr->getJobType());
875    ser_uint32(jcr->getJobLevel());
876    /* Added in VerNum 11 */
877    ser_string(jcr->fileset_md5);
878 
879    if (label == EOS_LABEL) {
880       ser_uint32(jcr->JobFiles);
881       ser_uint64(jcr->JobBytes);
882       ser_uint32((uint32_t)dcr->StartAddr);       /* Start Block */
883       ser_uint32((uint32_t)dcr->EndAddr);         /* End Block */
884       ser_uint32((uint32_t)(dcr->StartAddr>>32)); /* Start File */
885       ser_uint32((uint32_t)(dcr->EndAddr>>32));   /* End File */
886       ser_uint32(jcr->JobErrors);
887 
888       /* Added in VerNum 11 */
889       ser_uint32(jcr->JobStatus);
890    }
891    ser_end(rec->data, SER_LENGTH_Session_Label);
892    rec->data_len = ser_length(rec->data);
893    Leave(100);
894 }
895 
896 /* Write session (Job) label
897  *  Returns: false on failure
898  *           true  on success
899  */
write_session_label(DCR * dcr,int label)900 bool write_session_label(DCR *dcr, int label)
901 {
902    JCR *jcr = dcr->jcr;
903    DEVICE *dev = dcr->dev;
904    DEV_RECORD *rec;
905    DEV_BLOCK *block = dcr->block;
906    char buf1[100], buf2[100];
907 
908    Enter(100);
909    dev->Lock();
910    Dmsg2(140, "=== write_session_label label=%d Vol=%s.\n", label, dev->getVolCatName());
911    if (!check_for_newvol_or_newfile(dcr)) {
912       Pmsg0(000, "ERR: !check_for_new_vol_or_newfile\n");
913       dev->Unlock();
914       return false;
915    }
916 
917    rec = new_record();
918    Dmsg1(130, "session_label record=%x\n", rec);
919    switch (label) {
920    case SOS_LABEL:
921       set_start_vol_position(dcr);
922       break;
923    case EOS_LABEL:
924       dcr->EndAddr = dev->get_full_addr();
925       break;
926    default:
927       Jmsg1(jcr, M_ABORT, 0, _("Bad Volume session label request=%d\n"), label);
928       break;
929    }
930 
931    create_session_label(dcr, rec, label);
932    rec->FileIndex = label;
933    dev->Unlock();
934 
935    /*
936     * We guarantee that the session record can totally fit
937     *  into a block. If not, write the block, and put it in
938     *  the next block. Having the sesssion record totally in
939     *  one block makes reading them much easier (no need to
940     *  read the next block).
941     */
942    if (!can_write_record_to_block(block, rec)) {
943       Dmsg0(150, "Cannot write session label to block.\n");
944       if (!dcr->write_block_to_device()) {
945          Dmsg0(130, "Got session label write_block_to_dev error.\n");
946          free_record(rec);
947          Leave(100);
948          return false;
949       }
950    }
951    /*
952     * We use write_record() because it handles the case that
953     *  the maximum user size has been reached.
954     */
955    if (!dcr->write_record(rec)) {
956       Dmsg0(150, "Bad return from write_record\n");
957       free_record(rec);
958       Leave(100);
959       return false;
960    }
961 
962    Dmsg6(150, "Write sesson_label record JobId=%d FI=%s SessId=%d Strm=%s len=%d "
963              "remainder=%d\n", jcr->JobId,
964       FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
965       stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
966       rec->remainder);
967 
968    free_record(rec);
969    Dmsg2(150, "Leave write_session_label Block=%u File=%u\n",
970       dev->get_block_num(), dev->get_file());
971    Leave(100);
972    return true;
973 }
974 
975 /*  unser_volume_label
976  *
977  * Unserialize the Bacula Volume label into the device Volume_Label
978  * structure.
979  *
980  * Assumes that the record is already read.
981  *
982  * Returns: false on error
983  *          true  on success
984 */
985 
unser_volume_label(DEVICE * dev,DEV_RECORD * rec)986 bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec)
987 {
988    ser_declare;
989    char buf1[100], buf2[100];
990 
991    Enter(100);
992    if (rec->FileIndex != VOL_LABEL && rec->FileIndex != PRE_LABEL) {
993       Mmsg3(dev->errmsg, _("Expecting Volume Label, got FI=%s Stream=%s len=%d\n"),
994               FI_to_ascii(buf1, rec->FileIndex),
995               stream_to_ascii(buf2, rec->Stream, rec->FileIndex),
996               rec->data_len);
997       if (!forge_on) {
998          Leave(100);
999          return false;
1000       }
1001    }
1002 
1003    dev->VolHdr.LabelType = rec->FileIndex;
1004    dev->VolHdr.LabelSize = rec->data_len;
1005 
1006 
1007    /* Unserialize the record into the Volume Header */
1008    Dmsg2(100, "reclen=%d recdata=%s", rec->data_len, rec->data);
1009    rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
1010    Dmsg2(100, "reclen=%d recdata=%s", rec->data_len, rec->data);
1011    ser_begin(rec->data, SER_LENGTH_Volume_Label);
1012    unser_string(dev->VolHdr.Id);
1013    unser_uint32(dev->VolHdr.VerNum);
1014 
1015    if (dev->VolHdr.VerNum >= 11) {
1016       unser_btime(dev->VolHdr.label_btime);
1017       unser_btime(dev->VolHdr.write_btime);
1018    } else { /* old way */
1019       unser_float64(dev->VolHdr.label_date);
1020       unser_float64(dev->VolHdr.label_time);
1021    }
1022    unser_float64(dev->VolHdr.write_date);    /* Unused with VerNum >= 11 */
1023    unser_float64(dev->VolHdr.write_time);    /* Unused with VerNum >= 11 */
1024 
1025    unser_string(dev->VolHdr.VolumeName);
1026    unser_string(dev->VolHdr.PrevVolumeName);
1027    unser_string(dev->VolHdr.PoolName);
1028    unser_string(dev->VolHdr.PoolType);
1029    unser_string(dev->VolHdr.MediaType);
1030 
1031    unser_string(dev->VolHdr.HostName);
1032    unser_string(dev->VolHdr.LabelProg);
1033    unser_string(dev->VolHdr.ProgVersion);
1034    unser_string(dev->VolHdr.ProgDate);
1035 
1036 //   unser_string(dev->VolHdr.AlignedVolumeName);
1037    dev->VolHdr.AlignedVolumeName[0] = 0;
1038    unser_uint64(dev->VolHdr.FirstData);
1039    unser_uint32(dev->VolHdr.FileAlignment);
1040    unser_uint32(dev->VolHdr.PaddingSize);
1041    unser_uint32(dev->VolHdr.BlockSize);
1042 
1043    ser_end(rec->data, SER_LENGTH_Volume_Label);
1044    Dmsg0(190, "unser_vol_label\n");
1045    if (chk_dbglvl(100)) {
1046       dev->dump_volume_label();
1047    }
1048    Leave(100);
1049    return true;
1050 }
1051 
1052 
unser_session_label(SESSION_LABEL * label,DEV_RECORD * rec)1053 bool unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec)
1054 {
1055    ser_declare;
1056 
1057    Enter(100);
1058    rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
1059    unser_begin(rec->data, SER_LENGTH_Session_Label);
1060    unser_string(label->Id);
1061    unser_uint32(label->VerNum);
1062    unser_uint32(label->JobId);
1063    if (label->VerNum >= 11) {
1064       unser_btime(label->write_btime);
1065    } else {
1066       unser_float64(label->write_date);
1067    }
1068    unser_float64(label->write_time);
1069    unser_string(label->PoolName);
1070    unser_string(label->PoolType);
1071    unser_string(label->JobName);
1072    unser_string(label->ClientName);
1073    if (label->VerNum >= 10) {
1074       unser_string(label->Job);          /* Unique name of this Job */
1075       unser_string(label->FileSetName);
1076       unser_uint32(label->JobType);
1077       unser_uint32(label->JobLevel);
1078    }
1079    if (label->VerNum >= 11) {
1080       unser_string(label->FileSetMD5);
1081    } else {
1082       label->FileSetMD5[0] = 0;
1083    }
1084    if (rec->FileIndex == EOS_LABEL) {
1085       unser_uint32(label->JobFiles);
1086       unser_uint64(label->JobBytes);
1087       unser_uint32(label->StartBlock);
1088       unser_uint32(label->EndBlock);
1089       unser_uint32(label->StartFile);
1090       unser_uint32(label->EndFile);
1091       unser_uint32(label->JobErrors);
1092       if (label->VerNum >= 11) {
1093          unser_uint32(label->JobStatus);
1094       } else {
1095          label->JobStatus = JS_Terminated; /* kludge */
1096       }
1097    }
1098    Leave(100);
1099    return true;
1100 }
1101 
dump_volume_label()1102 void DEVICE::dump_volume_label()
1103 {
1104    int64_t dbl = debug_level;
1105    uint32_t File;
1106    const char *LabelType;
1107    char buf[30];
1108    struct tm tm;
1109    struct date_time dt;
1110 
1111    debug_level = 1;
1112    File = file;
1113    switch (VolHdr.LabelType) {
1114    case PRE_LABEL:
1115       LabelType = "PRE_LABEL";
1116       break;
1117    case VOL_LABEL:
1118       LabelType = "VOL_LABEL";
1119       break;
1120    case EOM_LABEL:
1121       LabelType = "EOM_LABEL";
1122       break;
1123    case SOS_LABEL:
1124       LabelType = "SOS_LABEL";
1125       break;
1126    case EOS_LABEL:
1127       LabelType = "EOS_LABEL";
1128       break;
1129    case EOT_LABEL:
1130       goto bail_out;
1131    default:
1132       LabelType = buf;
1133       sprintf(buf, _("Unknown %d"), VolHdr.LabelType);
1134       break;
1135    }
1136 
1137    Pmsg12(-1, _("\nVolume Label:\n"
1138 "Adata             : %d\n"
1139 "Id                : %s"
1140 "VerNo             : %d\n"
1141 "VolName           : %s\n"
1142 "PrevVolName       : %s\n"
1143 "VolFile           : %d\n"
1144 "LabelType         : %s\n"
1145 "LabelSize         : %d\n"
1146 "PoolName          : %s\n"
1147 "MediaType         : %s\n"
1148 "PoolType          : %s\n"
1149 "HostName          : %s\n"
1150 ""),
1151              adata,
1152              VolHdr.Id, VolHdr.VerNum,
1153              VolHdr.VolumeName, VolHdr.PrevVolumeName,
1154              File, LabelType, VolHdr.LabelSize,
1155              VolHdr.PoolName, VolHdr.MediaType,
1156              VolHdr.PoolType, VolHdr.HostName);
1157 
1158    if (VolHdr.VerNum >= 11) {
1159       char dt[50];
1160       bstrftime(dt, sizeof(dt), btime_to_utime(VolHdr.label_btime));
1161       Pmsg1(-1, _("Date label written: %s\n"), dt);
1162    } else {
1163       dt.julian_day_number   = VolHdr.label_date;
1164       dt.julian_day_fraction = VolHdr.label_time;
1165       tm_decode(&dt, &tm);
1166       Pmsg5(-1,
1167             _("Date label written: %04d-%02d-%02d at %02d:%02d\n"),
1168               tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
1169    }
1170 
1171 bail_out:
1172    debug_level = dbl;
1173 }
1174 
1175 
dump_session_label(DEV_RECORD * rec,const char * type)1176 static void dump_session_label(DEV_RECORD *rec, const char *type)
1177 {
1178    int64_t dbl;
1179    struct date_time dt;
1180    struct tm tm;
1181    SESSION_LABEL label;
1182    char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], ec6[30], ec7[30];
1183 
1184    unser_session_label(&label, rec);
1185    dbl = debug_level;
1186    debug_level = 1;
1187    Pmsg7(-1, _("\n%s Record:\n"
1188 "JobId             : %d\n"
1189 "VerNum            : %d\n"
1190 "PoolName          : %s\n"
1191 "PoolType          : %s\n"
1192 "JobName           : %s\n"
1193 "ClientName        : %s\n"
1194 ""),    type, label.JobId, label.VerNum,
1195       label.PoolName, label.PoolType,
1196       label.JobName, label.ClientName);
1197 
1198    if (label.VerNum >= 10) {
1199       Pmsg4(-1, _(
1200 "Job (unique name) : %s\n"
1201 "FileSet           : %s\n"
1202 "JobType           : %c\n"
1203 "JobLevel          : %c\n"
1204 ""), label.Job, label.FileSetName, label.JobType, label.JobLevel);
1205    }
1206 
1207    if (rec->FileIndex == EOS_LABEL) {
1208       Pmsg8(-1, _(
1209 "JobFiles          : %s\n"
1210 "JobBytes          : %s\n"
1211 "StartBlock        : %s\n"
1212 "EndBlock          : %s\n"
1213 "StartFile         : %s\n"
1214 "EndFile           : %s\n"
1215 "JobErrors         : %s\n"
1216 "JobStatus         : %c\n"
1217 ""),
1218          edit_uint64_with_commas(label.JobFiles, ec1),
1219          edit_uint64_with_commas(label.JobBytes, ec2),
1220          edit_uint64_with_commas(label.StartBlock, ec3),
1221          edit_uint64_with_commas(label.EndBlock, ec4),
1222          edit_uint64_with_commas(label.StartFile, ec5),
1223          edit_uint64_with_commas(label.EndFile, ec6),
1224          edit_uint64_with_commas(label.JobErrors, ec7),
1225          label.JobStatus);
1226    }
1227    if (label.VerNum >= 11) {
1228       char dt[50];
1229       bstrftime(dt, sizeof(dt), btime_to_utime(label.write_btime));
1230       Pmsg1(-1, _("Date written      : %s\n"), dt);
1231    } else {
1232       dt.julian_day_number   = label.write_date;
1233       dt.julian_day_fraction = label.write_time;
1234       tm_decode(&dt, &tm);
1235       Pmsg5(-1, _("Date written      : %04d-%02d-%02d at %02d:%02d\n"),
1236       tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
1237    }
1238 
1239    debug_level = dbl;
1240 }
1241 
check_label(SESSION_LABEL * label)1242 static int check_label(SESSION_LABEL *label)
1243 {
1244    int  errors = 0;
1245 
1246    if (label->JobId > 10000000 || label->JobId < 0) {
1247       Pmsg0(-1, _("***** ERROR ****** : Found error with the JobId\n"));
1248       errors++;
1249    }
1250 
1251    if (!errors) {
1252       switch (label->JobLevel) {
1253       case L_FULL:
1254       case L_INCREMENTAL:
1255       case L_DIFFERENTIAL:
1256       case L_SINCE:
1257       case L_VERIFY_CATALOG:
1258       case L_VERIFY_INIT:
1259       case L_VERIFY_VOLUME_TO_CATALOG:
1260       case L_VERIFY_DISK_TO_CATALOG:
1261       case L_VERIFY_DATA:
1262       case L_BASE:
1263       case L_NONE:
1264       case L_VIRTUAL_FULL:
1265          break;
1266       default:
1267          Pmsg0(-1, _("***** ERROR ****** : Found error with the JobLevel\n"));
1268          errors++;
1269       }
1270    }
1271    if (!errors) {
1272       switch (label->JobType) {
1273       case JT_BACKUP:
1274             case JT_MIGRATED_JOB:
1275       case JT_VERIFY:
1276       case JT_RESTORE:
1277       case JT_CONSOLE:
1278       case JT_SYSTEM:
1279       case JT_ADMIN:
1280       case JT_ARCHIVE:
1281       case JT_JOB_COPY:
1282       case JT_COPY:
1283       case JT_MIGRATE:
1284       case JT_SCAN:
1285                break;
1286       default:
1287          Pmsg0(-1, _("***** ERROR ****** : Found error with the JobType\n"));
1288          errors++;
1289       }
1290    }
1291    if (!errors) {
1292       POOLMEM *err = get_pool_memory(PM_EMSG);
1293       if (!is_name_valid(label->Job, &err)) {
1294          Pmsg1(-1, _("***** ERROR ****** : Found error with the Job name %s\n"), err);
1295          errors++;
1296       }
1297       free_pool_memory(err);
1298    }
1299    return errors;
1300 }
1301 
dump_label_record(DEVICE * dev,DEV_RECORD * rec,int verbose,bool check_err)1302 int dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose, bool check_err)
1303 {
1304    const char *type;
1305    int64_t dbl;
1306    int errors = 0;
1307 
1308    if (rec->FileIndex == 0 && rec->VolSessionId == 0 && rec->VolSessionTime == 0) {
1309       return 0;
1310    }
1311    dbl = debug_level;
1312    debug_level = 1;
1313    switch (rec->FileIndex) {
1314    case PRE_LABEL:
1315       type = _("Fresh Volume");
1316       break;
1317    case VOL_LABEL:
1318       type = _("Volume");
1319       break;
1320    case SOS_LABEL:
1321       type = _("Begin Job Session");
1322       break;
1323    case EOS_LABEL:
1324       type = _("End Job Session");
1325       break;
1326    case EOM_LABEL:
1327       type = _("End of Media");
1328       break;
1329    case EOT_LABEL:
1330       type = _("End of Tape");
1331       break;
1332    default:
1333       type = _("Unknown");
1334       break;
1335    }
1336    if (verbose) {
1337       switch (rec->FileIndex) {
1338       case PRE_LABEL:
1339       case VOL_LABEL:
1340          unser_volume_label(dev, rec);
1341          dev->dump_volume_label();
1342          break;
1343 
1344       case EOS_LABEL:
1345       case SOS_LABEL:
1346          dump_session_label(rec, type);
1347          break;
1348       case EOM_LABEL:
1349          Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1350             type, dev->file, dev->block_num, rec->VolSessionId,
1351             rec->VolSessionTime, rec->Stream, rec->data_len);
1352          break;
1353       case EOT_LABEL:
1354          Pmsg0(-1, _("Bacula \"End of Tape\" label found.\n"));
1355          break;
1356       default:
1357          Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1358             type, dev->file, dev->block_num, rec->VolSessionId,
1359             rec->VolSessionTime, rec->Stream, rec->data_len);
1360          break;
1361       }
1362    } else {
1363       SESSION_LABEL label;
1364       char dt[50];
1365       switch (rec->FileIndex) {
1366       case SOS_LABEL:
1367          unser_session_label(&label, rec);
1368          bstrftimes(dt, sizeof(dt), btime_to_utime(label.write_btime));
1369          Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1370             type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1371          Pmsg4(-1, _("   Job=%s Date=%s Level=%c Type=%c\n"),
1372             label.Job, dt, label.JobLevel, label.JobType);
1373          if (check_err) {
1374             errors += check_label(&label);
1375          }
1376          break;
1377       case EOS_LABEL:
1378          char ed1[30], ed2[30];
1379          unser_session_label(&label, rec);
1380          bstrftimes(dt, sizeof(dt), btime_to_utime(label.write_btime));
1381          Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1382             type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1383          Pmsg7(-1, _("   Date=%s Level=%c Type=%c Files=%s Bytes=%s Errors=%d Status=%c\n"),
1384             dt, label.JobLevel, label.JobType,
1385             edit_uint64_with_commas(label.JobFiles, ed1),
1386             edit_uint64_with_commas(label.JobBytes, ed2),
1387             label.JobErrors, (char)label.JobStatus);
1388          if (check_err) {
1389             errors += check_label(&label);
1390          }
1391          break;
1392       case EOM_LABEL:
1393       case PRE_LABEL:
1394       case VOL_LABEL:
1395       default:
1396          Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1397             type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime,
1398             rec->Stream, rec->data_len);
1399          break;
1400       case EOT_LABEL:
1401          break;
1402       }
1403    }
1404    debug_level = dbl;
1405    return errors;
1406 }
1407