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)) {
304 memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
305 Dmsg2(30, "Bad status on %s from rewind: ERR=%s\n", dev->print_name(), strerror_dev(dev));
311 /* Create PRE_LABEL */
312 create_volume_label(dev, VolName, PoolName);
315 * If we have already detected an ANSI label, re-read it
316 * to skip past it. Otherwise, we write a new one if
319 if (dev->label_type != B_BACULA_LABEL) {
320 if (read_ansi_ibm_label(dcr) != VOL_OK) {
324 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, VolName)) {
328 create_volume_label_record(dcr, dcr->rec);
329 dcr->rec->Stream = 0;
331 /* Temporarily mark in append state to enable writing */
333 if (!write_record_to_block(dcr->block, dcr->rec)) {
334 Dmsg2(30, "Bad Label write on %s: ERR=%s\n", dev->print_name(), strerror_dev(dev));
337 Dmsg2(30, "Wrote label of %d bytes to %s\n", dcr->rec->data_len, dev->print_name());
340 Dmsg0(99, "Call write_block_to_dev()\n");
341 if (!write_block_to_dev(dcr)) {
342 Dmsg2(30, "Bad Label write on %s: ERR=%s\n", dev->print_name(), strerror_dev(dev));
345 Dmsg0(99, " Wrote block to device\n");
347 if (weof_dev(dev, 1) == 0) {
349 write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
352 if (debug_level >= 20) {
353 dump_volume_label(dev);
355 dev->clear_append(); /* remove append since this is PRE_LABEL */
359 memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
360 dev->clear_append(); /* remove append since this is PRE_LABEL */
365 * Write a volume label. This is ONLY called if we have a valid Bacula
366 * label of type PRE_LABEL;
367 * Returns: true if OK
368 * false if unable to write it
370 bool rewrite_volume_label(DCR *dcr, bool recycle)
372 DEVICE *dev = dcr->dev;
375 Dmsg2(190, "set append found freshly labeled volume. fd=%d dev=%x\n", dev->fd, dev);
376 dev->VolHdr.LabelType = VOL_LABEL; /* set Volume label */
378 if (!write_volume_label_to_block(dcr)) {
379 Dmsg0(200, "Error from write volume label.\n");
383 * If we are not dealing with a streaming device,
384 * write the block now to ensure we have write permission.
385 * It is better to find out now rather than later.
386 * We do not write the block now if this is an ANSI label. This
387 * avoids re-writing the ANSI label, which we do not want to do.
389 if (!dev_cap(dev, CAP_STREAM)) {
390 if (!rewind_dev(dev)) {
391 Jmsg2(jcr, M_WARNING, 0, _("Rewind error on device %s: ERR=%s\n"),
392 dev->print_name(), strerror_dev(dev));
395 if (!truncate_dev(dcr)) {
396 Jmsg2(jcr, M_WARNING, 0, _("Truncate error on device %s: ERR=%s\n"),
397 dev->print_name(), strerror_dev(dev));
402 * If we have already detected an ANSI label, re-read it
403 * to skip past it. Otherwise, we write a new one if
406 if (dev->label_type != B_BACULA_LABEL) {
407 if (read_ansi_ibm_label(dcr) != VOL_OK) {
411 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, dev->VolHdr.VolumeName)) {
415 /* Attempt write to check write permission */
416 Dmsg1(200, "Attempt to write to device fd=%d.\n", dev->fd);
417 if (!write_block_to_dev(dcr)) {
418 Jmsg2(jcr, M_ERROR, 0, _("Unable to write device %s: ERR=%s\n"),
419 dev->print_name(), strerror_dev(dev));
420 Dmsg0(200, "===ERROR write block to dev\n");
424 /* Set or reset Volume statistics */
425 dev->VolCatInfo.VolCatJobs = 0;
426 dev->VolCatInfo.VolCatFiles = 0;
427 dev->VolCatInfo.VolCatBytes = 1;
428 dev->VolCatInfo.VolCatErrors = 0;
429 dev->VolCatInfo.VolCatBlocks = 0;
430 dev->VolCatInfo.VolCatRBytes = 0;
432 dev->VolCatInfo.VolCatMounts++;
433 dev->VolCatInfo.VolCatRecycles++;
435 dev->VolCatInfo.VolCatMounts = 1;
436 dev->VolCatInfo.VolCatRecycles = 0;
437 dev->VolCatInfo.VolCatWrites = 1;
438 dev->VolCatInfo.VolCatReads = 1;
440 Dmsg0(100, "dir_update_vol_info. Set Append\n");
441 bstrncpy(dev->VolCatInfo.VolCatStatus, "Append", sizeof(dev->VolCatInfo.VolCatStatus));
442 if (!dir_update_volume_info(dcr, true)) { /* indicate doing relabel */
446 Jmsg(jcr, M_INFO, 0, _("Recycled volume \"%s\" on device %s, all previous data lost.\n"),
447 dcr->VolumeName, dev->print_name());
449 Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume \"%s\" on device %s\n"),
450 dcr->VolumeName, dev->print_name());
453 * End writing real Volume label (from pre-labeled tape), or recycling
456 Dmsg0(200, "OK from rewite vol label.\n");
462 * create_volume_label_record
463 * Serialize label (from dev->VolHdr structure) into device record.
464 * Assumes that the dev->VolHdr structure is properly
467 static void create_volume_label_record(DCR *dcr, DEV_RECORD *rec)
471 DEVICE *dev = dcr->dev;
474 /* Serialize the label into the device record. */
476 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
477 ser_begin(rec->data, SER_LENGTH_Volume_Label);
478 ser_string(dev->VolHdr.Id);
480 ser_uint32(dev->VolHdr.VerNum);
482 if (dev->VolHdr.VerNum >= 11) {
483 ser_btime(dev->VolHdr.label_btime);
484 dev->VolHdr.write_btime = get_current_btime();
485 ser_btime(dev->VolHdr.write_btime);
486 dev->VolHdr.write_date = 0;
487 dev->VolHdr.write_time = 0;
489 /* OLD WAY DEPRECATED */
490 ser_float64(dev->VolHdr.label_date);
491 ser_float64(dev->VolHdr.label_time);
492 get_current_time(&dt);
493 dev->VolHdr.write_date = dt.julian_day_number;
494 dev->VolHdr.write_time = dt.julian_day_fraction;
496 ser_float64(dev->VolHdr.write_date); /* 0 if VerNum >= 11 */
497 ser_float64(dev->VolHdr.write_time); /* 0 if VerNum >= 11 */
499 ser_string(dev->VolHdr.VolumeName);
500 ser_string(dev->VolHdr.PrevVolumeName);
501 ser_string(dev->VolHdr.PoolName);
502 ser_string(dev->VolHdr.PoolType);
503 ser_string(dev->VolHdr.MediaType);
505 ser_string(dev->VolHdr.HostName);
506 ser_string(dev->VolHdr.LabelProg);
507 ser_string(dev->VolHdr.ProgVersion);
508 ser_string(dev->VolHdr.ProgDate);
510 ser_end(rec->data, SER_LENGTH_Volume_Label);
511 rec->data_len = ser_length(rec->data);
512 rec->FileIndex = dev->VolHdr.LabelType;
513 rec->VolSessionId = jcr->VolSessionId;
514 rec->VolSessionTime = jcr->VolSessionTime;
515 rec->Stream = jcr->NumVolumes;
516 Dmsg2(100, "Created Vol label rec: FI=%s len=%d\n", FI_to_ascii(rec->FileIndex),
522 * Create a volume label in memory
524 void create_volume_label(DEVICE *dev, const char *VolName, const char *PoolName)
526 DEVRES *device = (DEVRES *)dev->device;
528 Dmsg0(90, "Start create_volume_label()\n");
532 memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
534 bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
535 dev->VolHdr.VerNum = BaculaTapeVersion;
536 dev->VolHdr.LabelType = PRE_LABEL; /* Mark tape as unused */
537 bstrncpy(dev->VolHdr.VolumeName, VolName, sizeof(dev->VolHdr.VolumeName));
538 bstrncpy(dev->VolHdr.PoolName, PoolName, sizeof(dev->VolHdr.PoolName));
539 bstrncpy(dev->VolHdr.MediaType, device->media_type, sizeof(dev->VolHdr.MediaType));
541 bstrncpy(dev->VolHdr.PoolType, "Backup", sizeof(dev->VolHdr.PoolType));
543 dev->VolHdr.label_btime = get_current_btime();
544 dev->VolHdr.label_date = 0;
545 dev->VolHdr.label_time = 0;
547 if (gethostname(dev->VolHdr.HostName, sizeof(dev->VolHdr.HostName)) != 0) {
548 dev->VolHdr.HostName[0] = 0;
550 bstrncpy(dev->VolHdr.LabelProg, my_name, sizeof(dev->VolHdr.LabelProg));
551 sprintf(dev->VolHdr.ProgVersion, "Ver. %s %s", VERSION, BDATE);
552 sprintf(dev->VolHdr.ProgDate, "Build %s %s", __DATE__, __TIME__);
553 dev->set_labeled(); /* set has Bacula label */
554 if (debug_level >= 90) {
555 dump_volume_label(dev);
560 * Create session label
561 * The pool memory must be released by the calling program
563 void create_session_label(DCR *dcr, DEV_RECORD *rec, int label)
568 rec->VolSessionId = jcr->VolSessionId;
569 rec->VolSessionTime = jcr->VolSessionTime;
570 rec->Stream = jcr->JobId;
572 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
573 ser_begin(rec->data, SER_LENGTH_Session_Label);
574 ser_string(BaculaId);
575 ser_uint32(BaculaTapeVersion);
577 ser_uint32(jcr->JobId);
579 /* Changed in VerNum 11 */
580 ser_btime(get_current_btime());
583 ser_string(dcr->pool_name);
584 ser_string(dcr->pool_type);
585 ser_string(jcr->job_name); /* base Job name */
586 ser_string(jcr->client_name);
588 /* Added in VerNum 10 */
589 ser_string(jcr->Job); /* Unique name of this Job */
590 ser_string(jcr->fileset_name);
591 ser_uint32(jcr->JobType);
592 ser_uint32(jcr->JobLevel);
593 /* Added in VerNum 11 */
594 ser_string(jcr->fileset_md5);
596 if (label == EOS_LABEL) {
597 ser_uint32(jcr->JobFiles);
598 ser_uint64(jcr->JobBytes);
599 ser_uint32(dcr->StartBlock);
600 ser_uint32(dcr->EndBlock);
601 ser_uint32(dcr->StartFile);
602 ser_uint32(dcr->EndFile);
603 ser_uint32(jcr->JobErrors);
605 /* Added in VerNum 11 */
606 ser_uint32(jcr->JobStatus);
608 ser_end(rec->data, SER_LENGTH_Session_Label);
609 rec->data_len = ser_length(rec->data);
612 /* Write session label
613 * Returns: false on failure
616 bool write_session_label(DCR *dcr, int label)
619 DEVICE *dev = dcr->dev;
621 DEV_BLOCK *block = dcr->block;
624 Dmsg1(90, "session_label record=%x\n", rec);
627 if (dev->is_tape()) {
628 dcr->StartBlock = dev->block_num;
629 dcr->StartFile = dev->file;
631 dcr->StartBlock = (uint32_t)dev->file_addr;
632 dcr->StartFile = (uint32_t)(dev->file_addr >> 32);
636 if (dev->is_tape()) {
637 dcr->EndBlock = dev->EndBlock;
638 dcr->EndFile = dev->EndFile;
640 dcr->EndBlock = (uint32_t)dev->file_addr;
641 dcr->EndFile = (uint32_t)(dev->file_addr >> 32);
645 Jmsg1(jcr, M_ABORT, 0, _("Bad session label = %d\n"), label);
648 create_session_label(dcr, rec, label);
649 rec->FileIndex = label;
652 * We guarantee that the session record can totally fit
653 * into a block. If not, write the block, and put it in
654 * the next block. Having the sesssion record totally in
655 * one block makes reading them much easier (no need to
656 * read the next block).
658 if (!can_write_record_to_block(block, rec)) {
659 Dmsg0(100, "Cannot write session label to block.\n");
660 if (!write_block_to_device(dcr)) {
661 Dmsg0(90, "Got session label write_block_to_dev error.\n");
662 /* ****FIXME***** errno is not set here */
663 Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"),
664 dev_vol_name(dev), strerror(errno));
669 if (!write_record_to_block(block, rec)) {
670 Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"),
671 dev_vol_name(dev), strerror(errno));
676 Dmsg6(20, "Write sesson_label record JobId=%d FI=%s SessId=%d Strm=%s len=%d "
677 "remainder=%d\n", jcr->JobId,
678 FI_to_ascii(rec->FileIndex), rec->VolSessionId,
679 stream_to_ascii(rec->Stream, rec->FileIndex), rec->data_len,
683 Dmsg2(20, "Leave write_session_label Block=%d File=%d\n",
684 dev->block_num, dev->file);
688 /* unser_volume_label
690 * Unserialize the Bacula Volume label into the device Volume_Label
693 * Assumes that the record is already read.
695 * Returns: false on error
699 bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec)
703 if (rec->FileIndex != VOL_LABEL && rec->FileIndex != PRE_LABEL) {
704 Mmsg3(dev->errmsg, _("Expecting Volume Label, got FI=%s Stream=%s len=%d\n"),
705 FI_to_ascii(rec->FileIndex),
706 stream_to_ascii(rec->Stream, rec->FileIndex),
713 dev->VolHdr.LabelType = rec->FileIndex;
714 dev->VolHdr.LabelSize = rec->data_len;
717 /* Unserialize the record into the Volume Header */
718 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
719 ser_begin(rec->data, SER_LENGTH_Volume_Label);
720 unser_string(dev->VolHdr.Id);
721 unser_uint32(dev->VolHdr.VerNum);
723 if (dev->VolHdr.VerNum >= 11) {
724 unser_btime(dev->VolHdr.label_btime);
725 unser_btime(dev->VolHdr.write_btime);
726 } else { /* old way */
727 unser_float64(dev->VolHdr.label_date);
728 unser_float64(dev->VolHdr.label_time);
730 unser_float64(dev->VolHdr.write_date); /* Unused with VerNum >= 11 */
731 unser_float64(dev->VolHdr.write_time); /* Unused with VerNum >= 11 */
733 unser_string(dev->VolHdr.VolumeName);
734 unser_string(dev->VolHdr.PrevVolumeName);
735 unser_string(dev->VolHdr.PoolName);
736 unser_string(dev->VolHdr.PoolType);
737 unser_string(dev->VolHdr.MediaType);
739 unser_string(dev->VolHdr.HostName);
740 unser_string(dev->VolHdr.LabelProg);
741 unser_string(dev->VolHdr.ProgVersion);
742 unser_string(dev->VolHdr.ProgDate);
744 ser_end(rec->data, SER_LENGTH_Volume_Label);
745 Dmsg0(90, "unser_vol_label\n");
746 if (debug_level >= 90) {
747 dump_volume_label(dev);
753 bool unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec)
757 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
758 unser_begin(rec->data, SER_LENGTH_Session_Label);
759 unser_string(label->Id);
760 unser_uint32(label->VerNum);
761 unser_uint32(label->JobId);
762 if (label->VerNum >= 11) {
763 unser_btime(label->write_btime);
765 unser_float64(label->write_date);
767 unser_float64(label->write_time);
768 unser_string(label->PoolName);
769 unser_string(label->PoolType);
770 unser_string(label->JobName);
771 unser_string(label->ClientName);
772 if (label->VerNum >= 10) {
773 unser_string(label->Job); /* Unique name of this Job */
774 unser_string(label->FileSetName);
775 unser_uint32(label->JobType);
776 unser_uint32(label->JobLevel);
778 if (label->VerNum >= 11) {
779 unser_string(label->FileSetMD5);
781 label->FileSetMD5[0] = 0;
783 if (rec->FileIndex == EOS_LABEL) {
784 unser_uint32(label->JobFiles);
785 unser_uint64(label->JobBytes);
786 unser_uint32(label->StartBlock);
787 unser_uint32(label->EndBlock);
788 unser_uint32(label->StartFile);
789 unser_uint32(label->EndFile);
790 unser_uint32(label->JobErrors);
791 if (label->VerNum >= 11) {
792 unser_uint32(label->JobStatus);
794 label->JobStatus = JS_Terminated; /* kludge */
800 void dump_volume_label(DEVICE *dev)
802 int dbl = debug_level;
804 const char *LabelType;
811 switch (dev->VolHdr.LabelType) {
813 LabelType = "PRE_LABEL";
816 LabelType = "VOL_LABEL";
819 LabelType = "EOM_LABEL";
822 LabelType = "SOS_LABEL";
825 LabelType = "EOS_LABEL";
831 sprintf(buf, "Unknown %d", dev->VolHdr.LabelType);
835 Pmsg11(-1, "\nVolume Label:\n"
848 dev->VolHdr.Id, dev->VolHdr.VerNum,
849 dev->VolHdr.VolumeName, dev->VolHdr.PrevVolumeName,
850 File, LabelType, dev->VolHdr.LabelSize,
851 dev->VolHdr.PoolName, dev->VolHdr.MediaType,
852 dev->VolHdr.PoolType, dev->VolHdr.HostName);
854 if (dev->VolHdr.VerNum >= 11) {
856 bstrftime(dt, sizeof(dt), btime_to_unix(dev->VolHdr.label_btime));
857 Pmsg1(-1, "Date label written: %s\n", dt);
859 dt.julian_day_number = dev->VolHdr.label_date;
860 dt.julian_day_fraction = dev->VolHdr.label_time;
863 "Date label written: %04d-%02d-%02d at %02d:%02d\n",
864 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
872 static void dump_session_label(DEV_RECORD *rec, const char *type)
878 char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], ec6[30], ec7[30];
880 unser_session_label(&label, rec);
883 Pmsg7(-1, "\n%s Record:\n"
890 "", type, label.JobId, label.VerNum,
891 label.PoolName, label.PoolType,
892 label.JobName, label.ClientName);
894 if (label.VerNum >= 10) {
896 "Job (unique name) : %s\n"
900 "", label.Job, label.FileSetName, label.JobType, label.JobLevel);
903 if (rec->FileIndex == EOS_LABEL) {
914 edit_uint64_with_commas(label.JobFiles, ec1),
915 edit_uint64_with_commas(label.JobBytes, ec2),
916 edit_uint64_with_commas(label.StartBlock, ec3),
917 edit_uint64_with_commas(label.EndBlock, ec4),
918 edit_uint64_with_commas(label.StartFile, ec5),
919 edit_uint64_with_commas(label.EndFile, ec6),
920 edit_uint64_with_commas(label.JobErrors, ec7),
923 if (label.VerNum >= 11) {
925 bstrftime(dt, sizeof(dt), btime_to_unix(label.write_btime));
926 Pmsg1(-1, _("Date written : %s\n"), dt);
928 dt.julian_day_number = label.write_date;
929 dt.julian_day_fraction = label.write_time;
932 "Date written : %04d-%02d-%02d at %02d:%02d\n"),
933 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
939 void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose)
944 if (rec->FileIndex == 0 && rec->VolSessionId == 0 && rec->VolSessionTime == 0) {
949 switch (rec->FileIndex) {
951 type = _("Fresh Volume");
957 type = _("Begin Job Session");
960 type = _("End Job Session");
963 type = _("End of Media");
966 type = ("End of Tape");
973 switch (rec->FileIndex) {
976 unser_volume_label(dev, rec);
977 dump_volume_label(dev);
980 dump_session_label(rec, type);
983 dump_session_label(rec, type);
986 Pmsg7(-1, "%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n",
987 type, dev->file, dev->block_num, rec->VolSessionId,
988 rec->VolSessionTime, rec->Stream, rec->data_len);
991 Pmsg0(-1, _("End of physical tape.\n"));
994 Pmsg7(-1, "%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n",
995 type, dev->file, dev->block_num, rec->VolSessionId,
996 rec->VolSessionTime, rec->Stream, rec->data_len);
1000 SESSION_LABEL label;
1002 switch (rec->FileIndex) {
1004 unser_session_label(&label, rec);
1005 bstrftimes(dt, sizeof(dt), btime_to_unix(label.write_btime));
1006 Pmsg6(-1, "%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n",
1007 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1008 Pmsg4(-1, " Job=%s Date=%s Level=%c Type=%c\n",
1009 label.Job, dt, label.JobLevel, label.JobType);
1012 char ed1[30], ed2[30];
1013 unser_session_label(&label, rec);
1014 bstrftimes(dt, sizeof(dt), btime_to_unix(label.write_btime));
1015 Pmsg6(-1, "%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n",
1016 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1017 Pmsg7(-1, " Date=%s Level=%c Type=%c Files=%s Bytes=%s Errors=%d Status=%c\n",
1018 dt, label.JobLevel, label.JobType,
1019 edit_uint64_with_commas(label.JobFiles, ed1),
1020 edit_uint64_with_commas(label.JobBytes, ed2),
1021 label.JobErrors, (char)label.JobStatus);
1027 Pmsg7(-1, "%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n",
1028 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime,
1029 rec->Stream, rec->data_len);