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;
68 Dmsg3(100, "Enter read_volume_label device=%s vol=%s dev_Vol=%s\n",
69 dev->print_name(), VolName, dev->VolHdr.VolumeName[0]?dev->VolHdr.VolumeName:
72 if (!dev->is_open()) {
73 Emsg0(M_ABORT, 0, _("BAD call to read_dev_volume_label\n"));
75 if (dev->is_labeled()) { /* did we already read label? */
76 /* Compare Volume Names allow special wild card */
77 if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolumeName, VolName) != 0) {
78 Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
79 dev->print_name(), VolName, dev->VolHdr.VolumeName);
81 * Cancel Job if too many label errors
84 if (!dev->poll && jcr->label_errors++ > 100) {
85 Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
87 Dmsg0(100, "return VOL_NAME_ERROR\n");
88 return VOL_NAME_ERROR;
90 Dmsg0(30, "Leave read_volume_label() VOL_OK\n");
91 return VOL_OK; /* label already read */
97 dev->label_type = B_BACULA_LABEL;
99 if (!rewind_dev(dev)) {
100 Mmsg(jcr->errmsg, _("Couldn't rewind device %s: ERR=%s\n"),
101 dev->print_name(), strerror_dev(dev));
102 Dmsg1(30, "return VOL_NO_MEDIA: %s", jcr->errmsg);
105 bstrncpy(dev->VolHdr.Id, "**error**", sizeof(dev->VolHdr.Id));
107 /* Read ANSI/IBM label if so requested */
109 want_ansi_label = dcr->VolCatInfo.LabelType != B_BACULA_LABEL ||
110 dcr->device->label_type != B_BACULA_LABEL;
111 if (want_ansi_label || dev_cap(dev, CAP_CHECKLABELS)) {
112 stat = read_ansi_ibm_label(dcr);
113 /* If we want a label and didn't find it, return error */
114 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 Dmsg1(100, "return %d\n", stat);
130 if (stat != VOL_OK) { /* Not an ANSI/IBM label, so re-read */
135 /* Read the Bacula Volume label block */
136 record = new_record();
139 Dmsg0(90, "Big if statement in read_volume_label\n");
140 if (!read_block_from_dev(dcr, NO_BLOCK_NUMBER_CHECK)) {
141 Mmsg(jcr->errmsg, _("Requested Volume \"%s\" on %s is not a Bacula "
142 "labeled Volume, because: ERR=%s"), NPRT(VolName),
143 dev->print_name(), strerror_dev(dev));
144 Dmsg1(30, "%s", jcr->errmsg);
145 } else if (!read_record_from_block(block, record)) {
146 Mmsg(jcr->errmsg, _("Could not read Volume label from block.\n"));
147 Dmsg1(30, "%s", jcr->errmsg);
148 } else if (!unser_volume_label(dev, record)) {
149 Mmsg(jcr->errmsg, _("Could not unserialize Volume label: ERR=%s\n"),
151 Dmsg1(30, "%s", jcr->errmsg);
152 } else if (strcmp(dev->VolHdr.Id, BaculaId) != 0 &&
153 strcmp(dev->VolHdr.Id, OldBaculaId) != 0) {
154 Mmsg(jcr->errmsg, _("Volume Header Id bad: %s\n"), dev->VolHdr.Id);
155 Dmsg1(30, "%s", jcr->errmsg);
159 free_record(record); /* finished reading Volume record */
160 empty_block(block); /* done with block */
163 if (forge_on || jcr->ignore_label_errors) {
164 dev->set_labeled(); /* set has Bacula label */
165 Jmsg(jcr, M_ERROR, 0, "%s", jcr->errmsg);
169 Dmsg0(100, "return VOL_NO_LABEL\n");
173 /* At this point, we have read the first Bacula block, and
174 * then read the Bacula Volume label. Now we need to
175 * make sure we have the right Volume.
178 /* If we are a streaming device, we only get one chance to read */
179 if (!dev_cap(dev, CAP_STREAM)) {
183 if (dev->VolHdr.VerNum != BaculaTapeVersion &&
184 dev->VolHdr.VerNum != OldCompatibleBaculaTapeVersion1 &&
185 dev->VolHdr.VerNum != OldCompatibleBaculaTapeVersion2) {
186 Mmsg(jcr->errmsg, _("Volume on %s has wrong Bacula version. Wanted %d got %d\n"),
187 dev->print_name(), BaculaTapeVersion, dev->VolHdr.VerNum);
188 Dmsg1(30, "VOL_VERSION_ERROR: %s", jcr->errmsg);
189 return VOL_VERSION_ERROR;
192 /* We are looking for either an unused Bacula tape (PRE_LABEL) or
193 * a Bacula volume label (VOL_LABEL)
195 if (dev->VolHdr.LabelType != PRE_LABEL && dev->VolHdr.LabelType != VOL_LABEL) {
196 Mmsg(jcr->errmsg, _("Volume on %s has bad Bacula label type: %x\n"),
197 dev->print_name(), dev->VolHdr.LabelType);
198 Dmsg1(30, "%s", jcr->errmsg);
199 if (!dev->poll && jcr->label_errors++ > 100) {
200 Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
202 Dmsg0(100, "return VOL_LABEL_ERROR\n");
203 return VOL_LABEL_ERROR;
206 dev->set_labeled(); /* set has Bacula label */
207 new_volume(dcr, dev->VolHdr.VolumeName);
209 /* Compare Volume Names */
210 Dmsg2(30, "Compare Vol names: VolName=%s hdr=%s\n", VolName?VolName:"*", dev->VolHdr.VolumeName);
211 if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolumeName, VolName) != 0) {
212 Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
213 dev->print_name(), VolName, dev->VolHdr.VolumeName);
214 Dmsg1(30, "%s", jcr->errmsg);
216 * Cancel Job if too many label errors
217 * => we are in a loop
219 if (!dev->poll && jcr->label_errors++ > 100) {
220 Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
222 Dmsg0(100, "return VOL_NAME_ERROR\n");
223 return VOL_NAME_ERROR;
225 Dmsg1(30, "Copy vol_name=%s\n", dev->VolHdr.VolumeName);
227 if (debug_level >= 10) {
228 dump_volume_label(dev);
230 Dmsg0(30, "Leave read_volume_label() VOL_OK\n");
235 * Put a volume label into the block
237 * Returns: false on failure
240 bool write_volume_label_to_block(DCR *dcr)
243 DEVICE *dev = dcr->dev;
245 DEV_BLOCK *block = dcr->block;
247 Dmsg0(20, "write Label in write_volume_label_to_block()\n");
248 memset(&rec, 0, sizeof(rec));
249 rec.data = get_memory(SER_LENGTH_Volume_Label);
250 empty_block(block); /* Volume label always at beginning */
252 create_volume_label_record(dcr, &rec);
254 block->BlockNumber = 0;
255 if (!write_record_to_block(block, &rec)) {
256 free_pool_memory(rec.data);
257 Jmsg1(jcr, M_FATAL, 0, _("Cannot write Volume label to block for device %s\n"),
261 Dmsg1(90, "Wrote label of %d bytes to block\n", rec.data_len);
263 free_pool_memory(rec.data);
269 * Write a Volume Label
270 * !!! Note, this is ONLY used for writing
271 * a fresh volume label. Any data
272 * after the label will be destroyed,
273 * in fact, we write the label 5 times !!!!
275 * This routine expects that open_device() was previously called.
277 * This routine should be used only when labeling a blank tape.
279 bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName, const char *PoolName)
281 DEVICE *dev = dcr->dev;
284 Dmsg0(99, "write_volume_label()\n");
285 empty_block(dcr->block);
287 Dmsg1(100, "Label type=%d\n", dev->label_type);
288 if (!rewind_dev(dev)) {
289 memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
290 Dmsg2(30, "Bad status on %s from rewind: ERR=%s\n", dev->print_name(), strerror_dev(dev));
296 /* Create PRE_LABEL */
297 create_volume_label(dev, VolName, PoolName);
300 * If we have already detected an ANSI label, re-read it
301 * to skip past it. Otherwise, we write a new one if
304 if (dev->label_type != B_BACULA_LABEL) {
305 if (read_ansi_ibm_label(dcr) != VOL_OK) {
309 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, VolName)) {
313 create_volume_label_record(dcr, dcr->rec);
314 dcr->rec->Stream = 0;
316 /* Temporarily mark in append state to enable writing */
318 if (!write_record_to_block(dcr->block, dcr->rec)) {
319 Dmsg2(30, "Bad Label write on %s: ERR=%s\n", dev->print_name(), strerror_dev(dev));
322 Dmsg2(30, "Wrote label of %d bytes to %s\n", dcr->rec->data_len, dev->print_name());
325 Dmsg0(99, "Call write_block_to_dev()\n");
326 if (!write_block_to_dev(dcr)) {
327 Dmsg2(30, "Bad Label write on %s: ERR=%s\n", dev->print_name(), strerror_dev(dev));
330 Dmsg0(99, " Wrote block to device\n");
332 if (weof_dev(dev, 1) == 0) {
334 write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
337 if (debug_level >= 20) {
338 dump_volume_label(dev);
340 dev->clear_append(); /* remove append since this is PRE_LABEL */
344 memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
345 dev->clear_append(); /* remove append since this is PRE_LABEL */
350 * Write a volume label. This is ONLY called if we have a valid Bacula
351 * label of type PRE_LABEL;
352 * Returns: true if OK
353 * false if unable to write it
355 bool rewrite_volume_label(DCR *dcr, bool recycle)
357 DEVICE *dev = dcr->dev;
360 Dmsg2(190, "set append found freshly labeled volume. fd=%d dev=%x\n", dev->fd, dev);
361 dev->VolHdr.LabelType = VOL_LABEL; /* set Volume label */
363 if (!write_volume_label_to_block(dcr)) {
364 Dmsg0(200, "Error from write volume label.\n");
368 * If we are not dealing with a streaming device,
369 * write the block now to ensure we have write permission.
370 * It is better to find out now rather than later.
371 * We do not write the block now if this is an ANSI label. This
372 * avoids re-writing the ANSI label, which we do not want to do.
374 if (!dev_cap(dev, CAP_STREAM)) {
375 if (!rewind_dev(dev)) {
376 Jmsg2(jcr, M_WARNING, 0, _("Rewind error on device %s: ERR=%s\n"),
377 dev->print_name(), strerror_dev(dev));
380 if (!truncate_dev(dcr)) {
381 Jmsg2(jcr, M_WARNING, 0, _("Truncate error on device %s: ERR=%s\n"),
382 dev->print_name(), strerror_dev(dev));
387 * If we have already detected an ANSI label, re-read it
388 * to skip past it. Otherwise, we write a new one if
391 if (dev->label_type != B_BACULA_LABEL) {
392 if (read_ansi_ibm_label(dcr) != VOL_OK) {
396 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, dev->VolHdr.VolumeName)) {
400 /* Attempt write to check write permission */
401 Dmsg1(200, "Attempt to write to device fd=%d.\n", dev->fd);
402 if (!write_block_to_dev(dcr)) {
403 Jmsg2(jcr, M_ERROR, 0, _("Unable to write device %s: ERR=%s\n"),
404 dev->print_name(), strerror_dev(dev));
405 Dmsg0(200, "===ERROR write block to dev\n");
409 /* Set or reset Volume statistics */
410 dev->VolCatInfo.VolCatJobs = 0;
411 dev->VolCatInfo.VolCatFiles = 0;
412 dev->VolCatInfo.VolCatBytes = 1;
413 dev->VolCatInfo.VolCatErrors = 0;
414 dev->VolCatInfo.VolCatBlocks = 0;
415 dev->VolCatInfo.VolCatRBytes = 0;
417 dev->VolCatInfo.VolCatMounts++;
418 dev->VolCatInfo.VolCatRecycles++;
420 dev->VolCatInfo.VolCatMounts = 1;
421 dev->VolCatInfo.VolCatRecycles = 0;
422 dev->VolCatInfo.VolCatWrites = 1;
423 dev->VolCatInfo.VolCatReads = 1;
425 Dmsg0(100, "dir_update_vol_info. Set Append\n");
426 bstrncpy(dev->VolCatInfo.VolCatStatus, "Append", sizeof(dev->VolCatInfo.VolCatStatus));
427 if (!dir_update_volume_info(dcr, true)) { /* indicate doing relabel */
431 Jmsg(jcr, M_INFO, 0, _("Recycled volume \"%s\" on device %s, all previous data lost.\n"),
432 dcr->VolumeName, dev->print_name());
434 Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume \"%s\" on device %s\n"),
435 dcr->VolumeName, dev->print_name());
438 * End writing real Volume label (from pre-labeled tape), or recycling
441 Dmsg0(200, "OK from rewite vol label.\n");
447 * create_volume_label_record
448 * Serialize label (from dev->VolHdr structure) into device record.
449 * Assumes that the dev->VolHdr structure is properly
452 static void create_volume_label_record(DCR *dcr, DEV_RECORD *rec)
456 DEVICE *dev = dcr->dev;
459 /* Serialize the label into the device record. */
461 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
462 ser_begin(rec->data, SER_LENGTH_Volume_Label);
463 ser_string(dev->VolHdr.Id);
465 ser_uint32(dev->VolHdr.VerNum);
467 if (dev->VolHdr.VerNum >= 11) {
468 ser_btime(dev->VolHdr.label_btime);
469 dev->VolHdr.write_btime = get_current_btime();
470 ser_btime(dev->VolHdr.write_btime);
471 dev->VolHdr.write_date = 0;
472 dev->VolHdr.write_time = 0;
474 /* OLD WAY DEPRECATED */
475 ser_float64(dev->VolHdr.label_date);
476 ser_float64(dev->VolHdr.label_time);
477 get_current_time(&dt);
478 dev->VolHdr.write_date = dt.julian_day_number;
479 dev->VolHdr.write_time = dt.julian_day_fraction;
481 ser_float64(dev->VolHdr.write_date); /* 0 if VerNum >= 11 */
482 ser_float64(dev->VolHdr.write_time); /* 0 if VerNum >= 11 */
484 ser_string(dev->VolHdr.VolumeName);
485 ser_string(dev->VolHdr.PrevVolumeName);
486 ser_string(dev->VolHdr.PoolName);
487 ser_string(dev->VolHdr.PoolType);
488 ser_string(dev->VolHdr.MediaType);
490 ser_string(dev->VolHdr.HostName);
491 ser_string(dev->VolHdr.LabelProg);
492 ser_string(dev->VolHdr.ProgVersion);
493 ser_string(dev->VolHdr.ProgDate);
495 ser_end(rec->data, SER_LENGTH_Volume_Label);
496 rec->data_len = ser_length(rec->data);
497 rec->FileIndex = dev->VolHdr.LabelType;
498 rec->VolSessionId = jcr->VolSessionId;
499 rec->VolSessionTime = jcr->VolSessionTime;
500 rec->Stream = jcr->NumVolumes;
501 Dmsg2(100, "Created Vol label rec: FI=%s len=%d\n", FI_to_ascii(rec->FileIndex),
507 * Create a volume label in memory
509 void create_volume_label(DEVICE *dev, const char *VolName, const char *PoolName)
511 DEVRES *device = (DEVRES *)dev->device;
513 Dmsg0(90, "Start create_volume_label()\n");
517 memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
519 bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
520 dev->VolHdr.VerNum = BaculaTapeVersion;
521 dev->VolHdr.LabelType = PRE_LABEL; /* Mark tape as unused */
522 bstrncpy(dev->VolHdr.VolumeName, VolName, sizeof(dev->VolHdr.VolumeName));
523 bstrncpy(dev->VolHdr.PoolName, PoolName, sizeof(dev->VolHdr.PoolName));
524 bstrncpy(dev->VolHdr.MediaType, device->media_type, sizeof(dev->VolHdr.MediaType));
526 bstrncpy(dev->VolHdr.PoolType, "Backup", sizeof(dev->VolHdr.PoolType));
528 dev->VolHdr.label_btime = get_current_btime();
529 dev->VolHdr.label_date = 0;
530 dev->VolHdr.label_time = 0;
532 if (gethostname(dev->VolHdr.HostName, sizeof(dev->VolHdr.HostName)) != 0) {
533 dev->VolHdr.HostName[0] = 0;
535 bstrncpy(dev->VolHdr.LabelProg, my_name, sizeof(dev->VolHdr.LabelProg));
536 sprintf(dev->VolHdr.ProgVersion, "Ver. %s %s", VERSION, BDATE);
537 sprintf(dev->VolHdr.ProgDate, "Build %s %s", __DATE__, __TIME__);
538 dev->set_labeled(); /* set has Bacula label */
539 if (debug_level >= 90) {
540 dump_volume_label(dev);
545 * Create session label
546 * The pool memory must be released by the calling program
548 void create_session_label(DCR *dcr, DEV_RECORD *rec, int label)
553 rec->VolSessionId = jcr->VolSessionId;
554 rec->VolSessionTime = jcr->VolSessionTime;
555 rec->Stream = jcr->JobId;
557 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
558 ser_begin(rec->data, SER_LENGTH_Session_Label);
559 ser_string(BaculaId);
560 ser_uint32(BaculaTapeVersion);
562 ser_uint32(jcr->JobId);
564 /* Changed in VerNum 11 */
565 ser_btime(get_current_btime());
568 ser_string(dcr->pool_name);
569 ser_string(dcr->pool_type);
570 ser_string(jcr->job_name); /* base Job name */
571 ser_string(jcr->client_name);
573 /* Added in VerNum 10 */
574 ser_string(jcr->Job); /* Unique name of this Job */
575 ser_string(jcr->fileset_name);
576 ser_uint32(jcr->JobType);
577 ser_uint32(jcr->JobLevel);
578 /* Added in VerNum 11 */
579 ser_string(jcr->fileset_md5);
581 if (label == EOS_LABEL) {
582 ser_uint32(jcr->JobFiles);
583 ser_uint64(jcr->JobBytes);
584 ser_uint32(dcr->StartBlock);
585 ser_uint32(dcr->EndBlock);
586 ser_uint32(dcr->StartFile);
587 ser_uint32(dcr->EndFile);
588 ser_uint32(jcr->JobErrors);
590 /* Added in VerNum 11 */
591 ser_uint32(jcr->JobStatus);
593 ser_end(rec->data, SER_LENGTH_Session_Label);
594 rec->data_len = ser_length(rec->data);
597 /* Write session label
598 * Returns: false on failure
601 bool write_session_label(DCR *dcr, int label)
604 DEVICE *dev = dcr->dev;
606 DEV_BLOCK *block = dcr->block;
609 Dmsg1(90, "session_label record=%x\n", rec);
612 if (dev->is_tape()) {
613 dcr->StartBlock = dev->block_num;
614 dcr->StartFile = dev->file;
616 dcr->StartBlock = (uint32_t)dev->file_addr;
617 dcr->StartFile = (uint32_t)(dev->file_addr >> 32);
621 if (dev->is_tape()) {
622 dcr->EndBlock = dev->EndBlock;
623 dcr->EndFile = dev->EndFile;
625 dcr->EndBlock = (uint32_t)dev->file_addr;
626 dcr->EndFile = (uint32_t)(dev->file_addr >> 32);
630 Jmsg1(jcr, M_ABORT, 0, _("Bad session label = %d\n"), label);
633 create_session_label(dcr, rec, label);
634 rec->FileIndex = label;
637 * We guarantee that the session record can totally fit
638 * into a block. If not, write the block, and put it in
639 * the next block. Having the sesssion record totally in
640 * one block makes reading them much easier (no need to
641 * read the next block).
643 if (!can_write_record_to_block(block, rec)) {
644 Dmsg0(100, "Cannot write session label to block.\n");
645 if (!write_block_to_device(dcr)) {
646 Dmsg0(90, "Got session label write_block_to_dev error.\n");
647 /* ****FIXME***** errno is not set here */
648 Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"),
649 dev_vol_name(dev), strerror(errno));
654 if (!write_record_to_block(block, rec)) {
655 Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"),
656 dev_vol_name(dev), strerror(errno));
661 Dmsg6(20, "Write sesson_label record JobId=%d FI=%s SessId=%d Strm=%s len=%d "
662 "remainder=%d\n", jcr->JobId,
663 FI_to_ascii(rec->FileIndex), rec->VolSessionId,
664 stream_to_ascii(rec->Stream, rec->FileIndex), rec->data_len,
668 Dmsg2(20, "Leave write_session_label Block=%d File=%d\n",
669 dev->block_num, dev->file);
673 /* unser_volume_label
675 * Unserialize the Bacula Volume label into the device Volume_Label
678 * Assumes that the record is already read.
680 * Returns: false on error
684 bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec)
688 if (rec->FileIndex != VOL_LABEL && rec->FileIndex != PRE_LABEL) {
689 Mmsg3(dev->errmsg, _("Expecting Volume Label, got FI=%s Stream=%s len=%d\n"),
690 FI_to_ascii(rec->FileIndex),
691 stream_to_ascii(rec->Stream, rec->FileIndex),
698 dev->VolHdr.LabelType = rec->FileIndex;
699 dev->VolHdr.LabelSize = rec->data_len;
702 /* Unserialize the record into the Volume Header */
703 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
704 ser_begin(rec->data, SER_LENGTH_Volume_Label);
705 unser_string(dev->VolHdr.Id);
706 unser_uint32(dev->VolHdr.VerNum);
708 if (dev->VolHdr.VerNum >= 11) {
709 unser_btime(dev->VolHdr.label_btime);
710 unser_btime(dev->VolHdr.write_btime);
711 } else { /* old way */
712 unser_float64(dev->VolHdr.label_date);
713 unser_float64(dev->VolHdr.label_time);
715 unser_float64(dev->VolHdr.write_date); /* Unused with VerNum >= 11 */
716 unser_float64(dev->VolHdr.write_time); /* Unused with VerNum >= 11 */
718 unser_string(dev->VolHdr.VolumeName);
719 unser_string(dev->VolHdr.PrevVolumeName);
720 unser_string(dev->VolHdr.PoolName);
721 unser_string(dev->VolHdr.PoolType);
722 unser_string(dev->VolHdr.MediaType);
724 unser_string(dev->VolHdr.HostName);
725 unser_string(dev->VolHdr.LabelProg);
726 unser_string(dev->VolHdr.ProgVersion);
727 unser_string(dev->VolHdr.ProgDate);
729 ser_end(rec->data, SER_LENGTH_Volume_Label);
730 Dmsg0(90, "unser_vol_label\n");
731 if (debug_level >= 90) {
732 dump_volume_label(dev);
738 bool unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec)
742 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
743 unser_begin(rec->data, SER_LENGTH_Session_Label);
744 unser_string(label->Id);
745 unser_uint32(label->VerNum);
746 unser_uint32(label->JobId);
747 if (label->VerNum >= 11) {
748 unser_btime(label->write_btime);
750 unser_float64(label->write_date);
752 unser_float64(label->write_time);
753 unser_string(label->PoolName);
754 unser_string(label->PoolType);
755 unser_string(label->JobName);
756 unser_string(label->ClientName);
757 if (label->VerNum >= 10) {
758 unser_string(label->Job); /* Unique name of this Job */
759 unser_string(label->FileSetName);
760 unser_uint32(label->JobType);
761 unser_uint32(label->JobLevel);
763 if (label->VerNum >= 11) {
764 unser_string(label->FileSetMD5);
766 label->FileSetMD5[0] = 0;
768 if (rec->FileIndex == EOS_LABEL) {
769 unser_uint32(label->JobFiles);
770 unser_uint64(label->JobBytes);
771 unser_uint32(label->StartBlock);
772 unser_uint32(label->EndBlock);
773 unser_uint32(label->StartFile);
774 unser_uint32(label->EndFile);
775 unser_uint32(label->JobErrors);
776 if (label->VerNum >= 11) {
777 unser_uint32(label->JobStatus);
779 label->JobStatus = JS_Terminated; /* kludge */
785 void dump_volume_label(DEVICE *dev)
787 int dbl = debug_level;
789 const char *LabelType;
796 switch (dev->VolHdr.LabelType) {
798 LabelType = "PRE_LABEL";
801 LabelType = "VOL_LABEL";
804 LabelType = "EOM_LABEL";
807 LabelType = "SOS_LABEL";
810 LabelType = "EOS_LABEL";
816 sprintf(buf, "Unknown %d", dev->VolHdr.LabelType);
820 Pmsg11(-1, "\nVolume Label:\n"
833 dev->VolHdr.Id, dev->VolHdr.VerNum,
834 dev->VolHdr.VolumeName, dev->VolHdr.PrevVolumeName,
835 File, LabelType, dev->VolHdr.LabelSize,
836 dev->VolHdr.PoolName, dev->VolHdr.MediaType,
837 dev->VolHdr.PoolType, dev->VolHdr.HostName);
839 if (dev->VolHdr.VerNum >= 11) {
841 bstrftime(dt, sizeof(dt), btime_to_unix(dev->VolHdr.label_btime));
842 Pmsg1(-1, "Date label written: %s\n", dt);
844 dt.julian_day_number = dev->VolHdr.label_date;
845 dt.julian_day_fraction = dev->VolHdr.label_time;
848 "Date label written: %04d-%02d-%02d at %02d:%02d\n",
849 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
857 static void dump_session_label(DEV_RECORD *rec, const char *type)
863 char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], ec6[30], ec7[30];
865 unser_session_label(&label, rec);
868 Pmsg7(-1, "\n%s Record:\n"
875 "", type, label.JobId, label.VerNum,
876 label.PoolName, label.PoolType,
877 label.JobName, label.ClientName);
879 if (label.VerNum >= 10) {
881 "Job (unique name) : %s\n"
885 "", label.Job, label.FileSetName, label.JobType, label.JobLevel);
888 if (rec->FileIndex == EOS_LABEL) {
899 edit_uint64_with_commas(label.JobFiles, ec1),
900 edit_uint64_with_commas(label.JobBytes, ec2),
901 edit_uint64_with_commas(label.StartBlock, ec3),
902 edit_uint64_with_commas(label.EndBlock, ec4),
903 edit_uint64_with_commas(label.StartFile, ec5),
904 edit_uint64_with_commas(label.EndFile, ec6),
905 edit_uint64_with_commas(label.JobErrors, ec7),
908 if (label.VerNum >= 11) {
910 bstrftime(dt, sizeof(dt), btime_to_unix(label.write_btime));
911 Pmsg1(-1, _("Date written : %s\n"), dt);
913 dt.julian_day_number = label.write_date;
914 dt.julian_day_fraction = label.write_time;
917 "Date written : %04d-%02d-%02d at %02d:%02d\n"),
918 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
924 void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose)
929 if (rec->FileIndex == 0 && rec->VolSessionId == 0 && rec->VolSessionTime == 0) {
934 switch (rec->FileIndex) {
936 type = _("Fresh Volume");
942 type = _("Begin Job Session");
945 type = _("End Job Session");
948 type = _("End of Media");
951 type = ("End of Tape");
958 switch (rec->FileIndex) {
961 unser_volume_label(dev, rec);
962 dump_volume_label(dev);
965 dump_session_label(rec, type);
968 dump_session_label(rec, type);
971 Pmsg7(-1, "%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n",
972 type, dev->file, dev->block_num, rec->VolSessionId,
973 rec->VolSessionTime, rec->Stream, rec->data_len);
976 Pmsg0(-1, _("End of physical tape.\n"));
979 Pmsg7(-1, "%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n",
980 type, dev->file, dev->block_num, rec->VolSessionId,
981 rec->VolSessionTime, rec->Stream, rec->data_len);
987 switch (rec->FileIndex) {
989 unser_session_label(&label, rec);
990 bstrftimes(dt, sizeof(dt), btime_to_unix(label.write_btime));
991 Pmsg6(-1, "%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n",
992 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
993 Pmsg4(-1, " Job=%s Date=%s Level=%c Type=%c\n",
994 label.Job, dt, label.JobLevel, label.JobType);
997 char ed1[30], ed2[30];
998 unser_session_label(&label, rec);
999 bstrftimes(dt, sizeof(dt), btime_to_unix(label.write_btime));
1000 Pmsg6(-1, "%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n",
1001 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1002 Pmsg7(-1, " Date=%s Level=%c Type=%c Files=%s Bytes=%s Errors=%d Status=%c\n",
1003 dt, label.JobLevel, label.JobType,
1004 edit_uint64_with_commas(label.JobFiles, ed1),
1005 edit_uint64_with_commas(label.JobBytes, ed2),
1006 label.JobErrors, (char)label.JobStatus);
1012 Pmsg7(-1, "%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n",
1013 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime,
1014 rec->Stream, rec->data_len);