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