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