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