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