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