3 * label.c Bacula routines to handle labels
11 Copyright (C) 2000-2005 Kern Sibbald
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License
15 version 2 as amended with additional clauses defined in the
16 file LICENSE in the main source directory.
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 the file LICENSE for additional details.
25 #include "bacula.h" /* pull in global headers */
26 #include "stored.h" /* pull in Storage Deamon headers */
28 /* Forward referenced functions */
29 static void create_volume_label_record(DCR *dcr, DEV_RECORD *rec);
31 extern char my_name[];
32 extern int debug_level;
35 * Read the volume label
37 * If dcr->VolumeName == NULL, we accept any Bacula Volume
38 * If dcr->VolumeName[0] == 0, we accept any Bacula Volume
39 * otherwise dcr->VolumeName must match the Volume.
41 * If VolName given, ensure that it matches
43 * Returns VOL_ code as defined in record.h
45 * VOL_OK good label found
46 * VOL_NO_LABEL volume not labeled
47 * VOL_IO_ERROR I/O error reading tape
48 * VOL_NAME_ERROR label has wrong name
49 * VOL_CREATE_ERROR Error creating label
50 * VOL_VERSION_ERROR label has wrong version
51 * VOL_LABEL_ERROR bad label type
52 * VOL_NO_MEDIA no media in drive
54 * The dcr block is emptied on return, and the Volume is
57 int read_dev_volume_label(DCR *dcr)
60 DEVICE *dev = dcr->dev;
61 char *VolName = dcr->VolumeName;
64 DEV_BLOCK *block = dcr->block;
67 bool have_ansi_label = false;
69 Dmsg3(100, "Enter read_volume_label device=%s vol=%s dev_Vol=%s\n",
70 dev->print_name(), VolName, dev->VolHdr.VolumeName[0]?dev->VolHdr.VolumeName:
73 if (!dev->is_open()) {
74 Emsg0(M_ABORT, 0, _("BAD call to read_dev_volume_label\n"));
76 if (dev->is_labeled()) { /* did we already read label? */
77 /* Compare Volume Names allow special wild card */
78 if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolumeName, VolName) != 0) {
79 Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
80 dev->print_name(), VolName, dev->VolHdr.VolumeName);
82 * Cancel Job if too many label errors
85 if (!dev->poll && jcr->label_errors++ > 100) {
86 Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
88 Dmsg0(100, "return VOL_NAME_ERROR\n");
89 stat = VOL_NAME_ERROR;
92 Dmsg0(30, "Leave read_volume_label() VOL_OK\n");
93 return VOL_OK; /* label already read */
99 dev->label_type = B_BACULA_LABEL;
101 if (!rewind_dev(dev)) {
102 Mmsg(jcr->errmsg, _("Couldn't rewind device %s: ERR=%s\n"),
103 dev->print_name(), strerror_dev(dev));
104 Dmsg1(30, "return VOL_NO_MEDIA: %s", jcr->errmsg);
107 bstrncpy(dev->VolHdr.Id, "**error**", sizeof(dev->VolHdr.Id));
109 /* Read ANSI/IBM label if so requested */
111 want_ansi_label = dcr->VolCatInfo.LabelType != B_BACULA_LABEL ||
112 dcr->device->label_type != B_BACULA_LABEL;
113 if (want_ansi_label || dev_cap(dev, CAP_CHECKLABELS)) {
114 stat = read_ansi_ibm_label(dcr);
115 /* If we want a label and didn't find it, return error */
116 if (want_ansi_label && stat != VOL_OK) {
119 if (stat == VOL_NAME_ERROR || stat == VOL_LABEL_ERROR) {
120 Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
121 dev->print_name(), VolName, dev->VolHdr.VolumeName);
122 if (!dev->poll && jcr->label_errors++ > 100) {
123 Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
127 if (stat != VOL_OK) { /* Not an ANSI/IBM label, so re-read */
130 have_ansi_label = true;
134 /* Read the Bacula Volume label block */
135 record = new_record();
138 Dmsg0(90, "Big if statement in read_volume_label\n");
139 if (!read_block_from_dev(dcr, NO_BLOCK_NUMBER_CHECK)) {
140 Mmsg(jcr->errmsg, _("Requested Volume \"%s\" on %s is not a Bacula "
141 "labeled Volume, because: ERR=%s"), NPRT(VolName),
142 dev->print_name(), strerror_dev(dev));
143 Dmsg1(30, "%s", jcr->errmsg);
144 } else if (!read_record_from_block(block, record)) {
145 Mmsg(jcr->errmsg, _("Could not read Volume label from block.\n"));
146 Dmsg1(30, "%s", jcr->errmsg);
147 } else if (!unser_volume_label(dev, record)) {
148 Mmsg(jcr->errmsg, _("Could not unserialize Volume label: ERR=%s\n"),
150 Dmsg1(30, "%s", jcr->errmsg);
151 } else if (strcmp(dev->VolHdr.Id, BaculaId) != 0 &&
152 strcmp(dev->VolHdr.Id, OldBaculaId) != 0) {
153 Mmsg(jcr->errmsg, _("Volume Header Id bad: %s\n"), dev->VolHdr.Id);
154 Dmsg1(30, "%s", jcr->errmsg);
158 free_record(record); /* finished reading Volume record */
161 if (forge_on || jcr->ignore_label_errors) {
162 dev->set_labeled(); /* set has Bacula label */
163 Jmsg(jcr, M_ERROR, 0, "%s", jcr->errmsg);
171 /* At this point, we have read the first Bacula block, and
172 * then read the Bacula Volume label. Now we need to
173 * make sure we have the right Volume.
177 if (dev->VolHdr.VerNum != BaculaTapeVersion &&
178 dev->VolHdr.VerNum != OldCompatibleBaculaTapeVersion1 &&
179 dev->VolHdr.VerNum != OldCompatibleBaculaTapeVersion2) {
180 Mmsg(jcr->errmsg, _("Volume on %s has wrong Bacula version. Wanted %d got %d\n"),
181 dev->print_name(), BaculaTapeVersion, dev->VolHdr.VerNum);
182 Dmsg1(30, "VOL_VERSION_ERROR: %s", jcr->errmsg);
183 stat = VOL_VERSION_ERROR;
187 /* We are looking for either an unused Bacula tape (PRE_LABEL) or
188 * a Bacula volume label (VOL_LABEL)
190 if (dev->VolHdr.LabelType != PRE_LABEL && dev->VolHdr.LabelType != VOL_LABEL) {
191 Mmsg(jcr->errmsg, _("Volume on %s has bad Bacula label type: %x\n"),
192 dev->print_name(), dev->VolHdr.LabelType);
193 Dmsg1(30, "%s", jcr->errmsg);
194 if (!dev->poll && jcr->label_errors++ > 100) {
195 Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
197 Dmsg0(100, "return VOL_LABEL_ERROR\n");
198 stat = VOL_LABEL_ERROR;
202 dev->set_labeled(); /* set has Bacula label */
203 new_volume(dcr, dev->VolHdr.VolumeName);
205 /* Compare Volume Names */
206 Dmsg2(30, "Compare Vol names: VolName=%s hdr=%s\n", VolName?VolName:"*", dev->VolHdr.VolumeName);
207 if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolumeName, VolName) != 0) {
208 Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
209 dev->print_name(), VolName, dev->VolHdr.VolumeName);
210 Dmsg1(30, "%s", jcr->errmsg);
212 * Cancel Job if too many label errors
213 * => we are in a loop
215 if (!dev->poll && jcr->label_errors++ > 100) {
216 Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
218 Dmsg0(100, "return VOL_NAME_ERROR\n");
219 stat = VOL_NAME_ERROR;
222 Dmsg1(30, "Copy vol_name=%s\n", dev->VolHdr.VolumeName);
224 if (debug_level >= 10) {
225 dump_volume_label(dev);
227 Dmsg0(30, "Leave read_volume_label() VOL_OK\n");
228 /* If we are a streaming device, we only get one chance to read */
229 if (!dev_cap(dev, CAP_STREAM)) {
231 if (have_ansi_label) {
232 stat = read_ansi_ibm_label(dcr);
233 /* If we want a label and didn't find it, return error */
234 if (stat != VOL_OK) {
245 Dmsg1(100, "return %d\n", stat);
250 * Put a volume label into the block
252 * Returns: false on failure
255 bool write_volume_label_to_block(DCR *dcr)
258 DEVICE *dev = dcr->dev;
260 DEV_BLOCK *block = dcr->block;
262 Dmsg0(20, "write Label in write_volume_label_to_block()\n");
263 memset(&rec, 0, sizeof(rec));
264 rec.data = get_memory(SER_LENGTH_Volume_Label);
265 empty_block(block); /* Volume label always at beginning */
267 create_volume_label_record(dcr, &rec);
269 block->BlockNumber = 0;
270 if (!write_record_to_block(block, &rec)) {
271 free_pool_memory(rec.data);
272 Jmsg1(jcr, M_FATAL, 0, _("Cannot write Volume label to block for device %s\n"),
276 Dmsg1(90, "Wrote label of %d bytes to block\n", rec.data_len);
278 free_pool_memory(rec.data);
284 * Write a Volume Label
285 * !!! Note, this is ONLY used for writing
286 * a fresh volume label. Any data
287 * after the label will be destroyed,
288 * in fact, we write the label 5 times !!!!
290 * This routine expects that open_device() was previously called.
292 * This routine should be used only when labeling a blank tape.
294 bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName, const char *PoolName)
296 DEVICE *dev = dcr->dev;
299 Dmsg0(99, "write_volume_label()\n");
300 empty_block(dcr->block);
302 Dmsg1(100, "Label type=%d\n", dev->label_type);
303 if (!rewind_dev(dev)) {
305 memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
306 Dmsg2(30, "Bad status on %s from rewind: ERR=%s\n", dev->print_name(), strerror_dev(dev));
312 /* Create PRE_LABEL */
313 create_volume_label(dev, VolName, PoolName);
316 * If we have already detected an ANSI label, re-read it
317 * to skip past it. Otherwise, we write a new one if
320 if (dev->label_type != B_BACULA_LABEL) {
321 if (read_ansi_ibm_label(dcr) != VOL_OK) {
325 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, VolName)) {
329 create_volume_label_record(dcr, dcr->rec);
330 dcr->rec->Stream = 0;
332 /* Temporarily mark in append state to enable writing */
334 if (!write_record_to_block(dcr->block, dcr->rec)) {
335 Dmsg2(30, "Bad Label write on %s: ERR=%s\n", dev->print_name(), strerror_dev(dev));
338 Dmsg2(30, "Wrote label of %d bytes to %s\n", dcr->rec->data_len, dev->print_name());
341 Dmsg0(99, "Call write_block_to_dev()\n");
342 if (!write_block_to_dev(dcr)) {
343 Dmsg2(30, "Bad Label write on %s: ERR=%s\n", dev->print_name(), strerror_dev(dev));
346 Dmsg0(99, " Wrote block to device\n");
348 if (weof_dev(dev, 1) == 0) {
350 write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
353 if (debug_level >= 20) {
354 dump_volume_label(dev);
356 new_volume(dcr, VolName);
357 dev->clear_append(); /* remove append since this is PRE_LABEL */
362 memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
363 dev->clear_append(); /* remove append since this is PRE_LABEL */
368 * Write a volume label. This is ONLY called if we have a valid Bacula
369 * label of type PRE_LABEL;
370 * Returns: true if OK
371 * false if unable to write it
373 bool rewrite_volume_label(DCR *dcr, bool recycle)
375 DEVICE *dev = dcr->dev;
378 Dmsg2(190, "set append found freshly labeled volume. fd=%d dev=%x\n", dev->fd, dev);
379 dev->VolHdr.LabelType = VOL_LABEL; /* set Volume label */
381 if (!write_volume_label_to_block(dcr)) {
382 Dmsg0(200, "Error from write volume label.\n");
386 * If we are not dealing with a streaming device,
387 * write the block now to ensure we have write permission.
388 * It is better to find out now rather than later.
389 * We do not write the block now if this is an ANSI label. This
390 * avoids re-writing the ANSI label, which we do not want to do.
392 if (!dev_cap(dev, CAP_STREAM)) {
393 if (!rewind_dev(dev)) {
394 Jmsg2(jcr, M_WARNING, 0, _("Rewind error on device %s: ERR=%s\n"),
395 dev->print_name(), strerror_dev(dev));
398 if (!truncate_dev(dcr)) {
399 Jmsg2(jcr, M_WARNING, 0, _("Truncate error on device %s: ERR=%s\n"),
400 dev->print_name(), strerror_dev(dev));
405 * If we have already detected an ANSI label, re-read it
406 * to skip past it. Otherwise, we write a new one if
409 if (dev->label_type != B_BACULA_LABEL) {
410 if (read_ansi_ibm_label(dcr) != VOL_OK) {
414 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, dev->VolHdr.VolumeName)) {
418 /* Attempt write to check write permission */
419 Dmsg1(200, "Attempt to write to device fd=%d.\n", dev->fd);
420 if (!write_block_to_dev(dcr)) {
421 Jmsg2(jcr, M_ERROR, 0, _("Unable to write device %s: ERR=%s\n"),
422 dev->print_name(), strerror_dev(dev));
423 Dmsg0(200, "===ERROR write block to dev\n");
427 /* Set or reset Volume statistics */
428 dev->VolCatInfo.VolCatJobs = 0;
429 dev->VolCatInfo.VolCatFiles = 0;
430 dev->VolCatInfo.VolCatBytes = 1;
431 dev->VolCatInfo.VolCatErrors = 0;
432 dev->VolCatInfo.VolCatBlocks = 0;
433 dev->VolCatInfo.VolCatRBytes = 0;
435 dev->VolCatInfo.VolCatMounts++;
436 dev->VolCatInfo.VolCatRecycles++;
438 dev->VolCatInfo.VolCatMounts = 1;
439 dev->VolCatInfo.VolCatRecycles = 0;
440 dev->VolCatInfo.VolCatWrites = 1;
441 dev->VolCatInfo.VolCatReads = 1;
443 Dmsg0(100, "dir_update_vol_info. Set Append\n");
444 bstrncpy(dev->VolCatInfo.VolCatStatus, "Append", sizeof(dev->VolCatInfo.VolCatStatus));
445 if (!dir_update_volume_info(dcr, true)) { /* indicate doing relabel */
449 Jmsg(jcr, M_INFO, 0, _("Recycled volume \"%s\" on device %s, all previous data lost.\n"),
450 dcr->VolumeName, dev->print_name());
452 Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume \"%s\" on device %s\n"),
453 dcr->VolumeName, dev->print_name());
456 * End writing real Volume label (from pre-labeled tape), or recycling
459 Dmsg0(200, "OK from rewite vol label.\n");
465 * create_volume_label_record
466 * Serialize label (from dev->VolHdr structure) into device record.
467 * Assumes that the dev->VolHdr structure is properly
470 static void create_volume_label_record(DCR *dcr, DEV_RECORD *rec)
474 DEVICE *dev = dcr->dev;
477 /* Serialize the label into the device record. */
479 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
480 ser_begin(rec->data, SER_LENGTH_Volume_Label);
481 ser_string(dev->VolHdr.Id);
483 ser_uint32(dev->VolHdr.VerNum);
485 if (dev->VolHdr.VerNum >= 11) {
486 ser_btime(dev->VolHdr.label_btime);
487 dev->VolHdr.write_btime = get_current_btime();
488 ser_btime(dev->VolHdr.write_btime);
489 dev->VolHdr.write_date = 0;
490 dev->VolHdr.write_time = 0;
492 /* OLD WAY DEPRECATED */
493 ser_float64(dev->VolHdr.label_date);
494 ser_float64(dev->VolHdr.label_time);
495 get_current_time(&dt);
496 dev->VolHdr.write_date = dt.julian_day_number;
497 dev->VolHdr.write_time = dt.julian_day_fraction;
499 ser_float64(dev->VolHdr.write_date); /* 0 if VerNum >= 11 */
500 ser_float64(dev->VolHdr.write_time); /* 0 if VerNum >= 11 */
502 ser_string(dev->VolHdr.VolumeName);
503 ser_string(dev->VolHdr.PrevVolumeName);
504 ser_string(dev->VolHdr.PoolName);
505 ser_string(dev->VolHdr.PoolType);
506 ser_string(dev->VolHdr.MediaType);
508 ser_string(dev->VolHdr.HostName);
509 ser_string(dev->VolHdr.LabelProg);
510 ser_string(dev->VolHdr.ProgVersion);
511 ser_string(dev->VolHdr.ProgDate);
513 ser_end(rec->data, SER_LENGTH_Volume_Label);
514 rec->data_len = ser_length(rec->data);
515 rec->FileIndex = dev->VolHdr.LabelType;
516 rec->VolSessionId = jcr->VolSessionId;
517 rec->VolSessionTime = jcr->VolSessionTime;
518 rec->Stream = jcr->NumVolumes;
519 Dmsg2(100, "Created Vol label rec: FI=%s len=%d\n", FI_to_ascii(rec->FileIndex),
525 * Create a volume label in memory
527 void create_volume_label(DEVICE *dev, const char *VolName, const char *PoolName)
529 DEVRES *device = (DEVRES *)dev->device;
531 Dmsg0(90, "Start create_volume_label()\n");
535 free_volume(dev); /* release any old volume */
536 memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
538 bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
539 dev->VolHdr.VerNum = BaculaTapeVersion;
540 dev->VolHdr.LabelType = PRE_LABEL; /* Mark tape as unused */
541 bstrncpy(dev->VolHdr.VolumeName, VolName, sizeof(dev->VolHdr.VolumeName));
542 bstrncpy(dev->VolHdr.PoolName, PoolName, sizeof(dev->VolHdr.PoolName));
543 bstrncpy(dev->VolHdr.MediaType, device->media_type, sizeof(dev->VolHdr.MediaType));
545 bstrncpy(dev->VolHdr.PoolType, "Backup", sizeof(dev->VolHdr.PoolType));
547 dev->VolHdr.label_btime = get_current_btime();
548 dev->VolHdr.label_date = 0;
549 dev->VolHdr.label_time = 0;
551 if (gethostname(dev->VolHdr.HostName, sizeof(dev->VolHdr.HostName)) != 0) {
552 dev->VolHdr.HostName[0] = 0;
554 bstrncpy(dev->VolHdr.LabelProg, my_name, sizeof(dev->VolHdr.LabelProg));
555 sprintf(dev->VolHdr.ProgVersion, "Ver. %s %s", VERSION, BDATE);
556 sprintf(dev->VolHdr.ProgDate, "Build %s %s", __DATE__, __TIME__);
557 dev->set_labeled(); /* set has Bacula label */
558 if (debug_level >= 90) {
559 dump_volume_label(dev);
564 * Create session label
565 * The pool memory must be released by the calling program
567 void create_session_label(DCR *dcr, DEV_RECORD *rec, int label)
572 rec->VolSessionId = jcr->VolSessionId;
573 rec->VolSessionTime = jcr->VolSessionTime;
574 rec->Stream = jcr->JobId;
576 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
577 ser_begin(rec->data, SER_LENGTH_Session_Label);
578 ser_string(BaculaId);
579 ser_uint32(BaculaTapeVersion);
581 ser_uint32(jcr->JobId);
583 /* Changed in VerNum 11 */
584 ser_btime(get_current_btime());
587 ser_string(dcr->pool_name);
588 ser_string(dcr->pool_type);
589 ser_string(jcr->job_name); /* base Job name */
590 ser_string(jcr->client_name);
592 /* Added in VerNum 10 */
593 ser_string(jcr->Job); /* Unique name of this Job */
594 ser_string(jcr->fileset_name);
595 ser_uint32(jcr->JobType);
596 ser_uint32(jcr->JobLevel);
597 /* Added in VerNum 11 */
598 ser_string(jcr->fileset_md5);
600 if (label == EOS_LABEL) {
601 ser_uint32(jcr->JobFiles);
602 ser_uint64(jcr->JobBytes);
603 ser_uint32(dcr->StartBlock);
604 ser_uint32(dcr->EndBlock);
605 ser_uint32(dcr->StartFile);
606 ser_uint32(dcr->EndFile);
607 ser_uint32(jcr->JobErrors);
609 /* Added in VerNum 11 */
610 ser_uint32(jcr->JobStatus);
612 ser_end(rec->data, SER_LENGTH_Session_Label);
613 rec->data_len = ser_length(rec->data);
616 /* Write session label
617 * Returns: false on failure
620 bool write_session_label(DCR *dcr, int label)
623 DEVICE *dev = dcr->dev;
625 DEV_BLOCK *block = dcr->block;
628 Dmsg1(90, "session_label record=%x\n", rec);
631 if (dev->is_tape()) {
632 dcr->StartBlock = dev->block_num;
633 dcr->StartFile = dev->file;
635 dcr->StartBlock = (uint32_t)dev->file_addr;
636 dcr->StartFile = (uint32_t)(dev->file_addr >> 32);
640 if (dev->is_tape()) {
641 dcr->EndBlock = dev->EndBlock;
642 dcr->EndFile = dev->EndFile;
644 dcr->EndBlock = (uint32_t)dev->file_addr;
645 dcr->EndFile = (uint32_t)(dev->file_addr >> 32);
649 Jmsg1(jcr, M_ABORT, 0, _("Bad session label = %d\n"), label);
652 create_session_label(dcr, rec, label);
653 rec->FileIndex = label;
656 * We guarantee that the session record can totally fit
657 * into a block. If not, write the block, and put it in
658 * the next block. Having the sesssion record totally in
659 * one block makes reading them much easier (no need to
660 * read the next block).
662 if (!can_write_record_to_block(block, rec)) {
663 Dmsg0(100, "Cannot write session label to block.\n");
664 if (!write_block_to_device(dcr)) {
665 Dmsg0(90, "Got session label write_block_to_dev error.\n");
666 /* ****FIXME***** errno is not set here */
667 Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"),
668 dev_vol_name(dev), strerror(errno));
673 if (!write_record_to_block(block, rec)) {
674 Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"),
675 dev_vol_name(dev), strerror(errno));
680 Dmsg6(20, "Write sesson_label record JobId=%d FI=%s SessId=%d Strm=%s len=%d "
681 "remainder=%d\n", jcr->JobId,
682 FI_to_ascii(rec->FileIndex), rec->VolSessionId,
683 stream_to_ascii(rec->Stream, rec->FileIndex), rec->data_len,
687 Dmsg2(20, "Leave write_session_label Block=%d File=%d\n",
688 dev->block_num, dev->file);
692 /* unser_volume_label
694 * Unserialize the Bacula Volume label into the device Volume_Label
697 * Assumes that the record is already read.
699 * Returns: false on error
703 bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec)
707 if (rec->FileIndex != VOL_LABEL && rec->FileIndex != PRE_LABEL) {
708 Mmsg3(dev->errmsg, _("Expecting Volume Label, got FI=%s Stream=%s len=%d\n"),
709 FI_to_ascii(rec->FileIndex),
710 stream_to_ascii(rec->Stream, rec->FileIndex),
717 dev->VolHdr.LabelType = rec->FileIndex;
718 dev->VolHdr.LabelSize = rec->data_len;
721 /* Unserialize the record into the Volume Header */
722 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
723 ser_begin(rec->data, SER_LENGTH_Volume_Label);
724 unser_string(dev->VolHdr.Id);
725 unser_uint32(dev->VolHdr.VerNum);
727 if (dev->VolHdr.VerNum >= 11) {
728 unser_btime(dev->VolHdr.label_btime);
729 unser_btime(dev->VolHdr.write_btime);
730 } else { /* old way */
731 unser_float64(dev->VolHdr.label_date);
732 unser_float64(dev->VolHdr.label_time);
734 unser_float64(dev->VolHdr.write_date); /* Unused with VerNum >= 11 */
735 unser_float64(dev->VolHdr.write_time); /* Unused with VerNum >= 11 */
737 unser_string(dev->VolHdr.VolumeName);
738 unser_string(dev->VolHdr.PrevVolumeName);
739 unser_string(dev->VolHdr.PoolName);
740 unser_string(dev->VolHdr.PoolType);
741 unser_string(dev->VolHdr.MediaType);
743 unser_string(dev->VolHdr.HostName);
744 unser_string(dev->VolHdr.LabelProg);
745 unser_string(dev->VolHdr.ProgVersion);
746 unser_string(dev->VolHdr.ProgDate);
748 ser_end(rec->data, SER_LENGTH_Volume_Label);
749 Dmsg0(90, "unser_vol_label\n");
750 if (debug_level >= 90) {
751 dump_volume_label(dev);
757 bool unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec)
761 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
762 unser_begin(rec->data, SER_LENGTH_Session_Label);
763 unser_string(label->Id);
764 unser_uint32(label->VerNum);
765 unser_uint32(label->JobId);
766 if (label->VerNum >= 11) {
767 unser_btime(label->write_btime);
769 unser_float64(label->write_date);
771 unser_float64(label->write_time);
772 unser_string(label->PoolName);
773 unser_string(label->PoolType);
774 unser_string(label->JobName);
775 unser_string(label->ClientName);
776 if (label->VerNum >= 10) {
777 unser_string(label->Job); /* Unique name of this Job */
778 unser_string(label->FileSetName);
779 unser_uint32(label->JobType);
780 unser_uint32(label->JobLevel);
782 if (label->VerNum >= 11) {
783 unser_string(label->FileSetMD5);
785 label->FileSetMD5[0] = 0;
787 if (rec->FileIndex == EOS_LABEL) {
788 unser_uint32(label->JobFiles);
789 unser_uint64(label->JobBytes);
790 unser_uint32(label->StartBlock);
791 unser_uint32(label->EndBlock);
792 unser_uint32(label->StartFile);
793 unser_uint32(label->EndFile);
794 unser_uint32(label->JobErrors);
795 if (label->VerNum >= 11) {
796 unser_uint32(label->JobStatus);
798 label->JobStatus = JS_Terminated; /* kludge */
804 void dump_volume_label(DEVICE *dev)
806 int dbl = debug_level;
808 const char *LabelType;
815 switch (dev->VolHdr.LabelType) {
817 LabelType = "PRE_LABEL";
820 LabelType = "VOL_LABEL";
823 LabelType = "EOM_LABEL";
826 LabelType = "SOS_LABEL";
829 LabelType = "EOS_LABEL";
835 sprintf(buf, _("Unknown %d"), dev->VolHdr.LabelType);
839 Pmsg11(-1, _("\nVolume Label:\n"
852 dev->VolHdr.Id, dev->VolHdr.VerNum,
853 dev->VolHdr.VolumeName, dev->VolHdr.PrevVolumeName,
854 File, LabelType, dev->VolHdr.LabelSize,
855 dev->VolHdr.PoolName, dev->VolHdr.MediaType,
856 dev->VolHdr.PoolType, dev->VolHdr.HostName);
858 if (dev->VolHdr.VerNum >= 11) {
860 bstrftime(dt, sizeof(dt), btime_to_unix(dev->VolHdr.label_btime));
861 Pmsg1(-1, _("Date label written: %s\n"), dt);
863 dt.julian_day_number = dev->VolHdr.label_date;
864 dt.julian_day_fraction = dev->VolHdr.label_time;
867 _("Date label written: %04d-%02d-%02d at %02d:%02d\n"),
868 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
876 static void dump_session_label(DEV_RECORD *rec, const char *type)
882 char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], ec6[30], ec7[30];
884 unser_session_label(&label, rec);
887 Pmsg7(-1, _("\n%s Record:\n"
894 ""), type, label.JobId, label.VerNum,
895 label.PoolName, label.PoolType,
896 label.JobName, label.ClientName);
898 if (label.VerNum >= 10) {
900 "Job (unique name) : %s\n"
904 ""), label.Job, label.FileSetName, label.JobType, label.JobLevel);
907 if (rec->FileIndex == EOS_LABEL) {
918 edit_uint64_with_commas(label.JobFiles, ec1),
919 edit_uint64_with_commas(label.JobBytes, ec2),
920 edit_uint64_with_commas(label.StartBlock, ec3),
921 edit_uint64_with_commas(label.EndBlock, ec4),
922 edit_uint64_with_commas(label.StartFile, ec5),
923 edit_uint64_with_commas(label.EndFile, ec6),
924 edit_uint64_with_commas(label.JobErrors, ec7),
927 if (label.VerNum >= 11) {
929 bstrftime(dt, sizeof(dt), btime_to_unix(label.write_btime));
930 Pmsg1(-1, _("Date written : %s\n"), dt);
932 dt.julian_day_number = label.write_date;
933 dt.julian_day_fraction = label.write_time;
935 Pmsg5(-1, _("Date written : %04d-%02d-%02d at %02d:%02d\n"),
936 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
942 void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose)
947 if (rec->FileIndex == 0 && rec->VolSessionId == 0 && rec->VolSessionTime == 0) {
952 switch (rec->FileIndex) {
954 type = _("Fresh Volume");
960 type = _("Begin Job Session");
963 type = _("End Job Session");
966 type = _("End of Media");
969 type = _("End of Tape");
976 switch (rec->FileIndex) {
979 unser_volume_label(dev, rec);
980 dump_volume_label(dev);
983 dump_session_label(rec, type);
986 dump_session_label(rec, type);
989 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
990 type, dev->file, dev->block_num, rec->VolSessionId,
991 rec->VolSessionTime, rec->Stream, rec->data_len);
994 Pmsg0(-1, _("End of physical tape.\n"));
997 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
998 type, dev->file, dev->block_num, rec->VolSessionId,
999 rec->VolSessionTime, rec->Stream, rec->data_len);
1003 SESSION_LABEL label;
1005 switch (rec->FileIndex) {
1007 unser_session_label(&label, rec);
1008 bstrftimes(dt, sizeof(dt), btime_to_unix(label.write_btime));
1009 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1010 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1011 Pmsg4(-1, _(" Job=%s Date=%s Level=%c Type=%c\n"),
1012 label.Job, dt, label.JobLevel, label.JobType);
1015 char ed1[30], ed2[30];
1016 unser_session_label(&label, rec);
1017 bstrftimes(dt, sizeof(dt), btime_to_unix(label.write_btime));
1018 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1019 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1020 Pmsg7(-1, _(" Date=%s Level=%c Type=%c Files=%s Bytes=%s Errors=%d Status=%c\n"),
1021 dt, label.JobLevel, label.JobType,
1022 edit_uint64_with_commas(label.JobFiles, ed1),
1023 edit_uint64_with_commas(label.JobBytes, ed2),
1024 label.JobErrors, (char)label.JobStatus);
1030 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1031 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime,
1032 rec->Stream, rec->data_len);