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