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 if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
305 Dmsg1(100, "Label type=%d\n", dev->label_type);
306 if (!rewind_dev(dev)) {
308 memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
309 Dmsg2(30, "Bad status on %s from rewind: ERR=%s\n", dev->print_name(), strerror_dev(dev));
315 /* Create PRE_LABEL */
316 create_volume_label(dev, VolName, PoolName);
319 * If we have already detected an ANSI label, re-read it
320 * to skip past it. Otherwise, we write a new one if
323 if (dev->label_type != B_BACULA_LABEL) {
324 if (read_ansi_ibm_label(dcr) != VOL_OK) {
328 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, VolName)) {
332 create_volume_label_record(dcr, dcr->rec);
333 dcr->rec->Stream = 0;
335 /* Temporarily mark in append state to enable writing */
337 if (!write_record_to_block(dcr->block, dcr->rec)) {
338 Dmsg2(30, "Bad Label write on %s: ERR=%s\n", dev->print_name(), strerror_dev(dev));
341 Dmsg2(30, "Wrote label of %d bytes to %s\n", dcr->rec->data_len, dev->print_name());
344 Dmsg0(99, "Call write_block_to_dev()\n");
345 if (!write_block_to_dev(dcr)) {
346 Dmsg2(30, "Bad Label write on %s: ERR=%s\n", dev->print_name(), strerror_dev(dev));
349 Dmsg0(99, " Wrote block to device\n");
351 if (weof_dev(dev, 1) == 0) {
353 write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
356 if (debug_level >= 20) {
357 dump_volume_label(dev);
359 new_volume(dcr, VolName);
360 dev->clear_append(); /* remove append since this is PRE_LABEL */
365 memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
366 dev->clear_append(); /* remove append since this is PRE_LABEL */
371 * Write a volume label. This is ONLY called if we have a valid Bacula
372 * label of type PRE_LABEL;
373 * Returns: true if OK
374 * false if unable to write it
376 bool rewrite_volume_label(DCR *dcr, bool recycle)
378 DEVICE *dev = dcr->dev;
381 if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
384 Dmsg2(190, "set append found freshly labeled volume. fd=%d dev=%x\n", dev->fd, dev);
385 dev->VolHdr.LabelType = VOL_LABEL; /* set Volume label */
387 if (!write_volume_label_to_block(dcr)) {
388 Dmsg0(200, "Error from write volume label.\n");
392 * If we are not dealing with a streaming device,
393 * write the block now to ensure we have write permission.
394 * It is better to find out now rather than later.
395 * We do not write the block now if this is an ANSI label. This
396 * avoids re-writing the ANSI label, which we do not want to do.
398 if (!dev_cap(dev, CAP_STREAM)) {
399 if (!rewind_dev(dev)) {
400 Jmsg2(jcr, M_WARNING, 0, _("Rewind error on device %s: ERR=%s\n"),
401 dev->print_name(), strerror_dev(dev));
404 if (!truncate_dev(dcr)) {
405 Jmsg2(jcr, M_WARNING, 0, _("Truncate error on device %s: ERR=%s\n"),
406 dev->print_name(), strerror_dev(dev));
411 * If we have already detected an ANSI label, re-read it
412 * to skip past it. Otherwise, we write a new one if
415 if (dev->label_type != B_BACULA_LABEL) {
416 if (read_ansi_ibm_label(dcr) != VOL_OK) {
420 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, dev->VolHdr.VolumeName)) {
424 /* Attempt write to check write permission */
425 Dmsg1(200, "Attempt to write to device fd=%d.\n", dev->fd);
426 if (!write_block_to_dev(dcr)) {
427 Jmsg2(jcr, M_ERROR, 0, _("Unable to write device %s: ERR=%s\n"),
428 dev->print_name(), strerror_dev(dev));
429 Dmsg0(200, "===ERROR write block to dev\n");
433 /* Set or reset Volume statistics */
434 dev->VolCatInfo.VolCatJobs = 0;
435 dev->VolCatInfo.VolCatFiles = 0;
436 dev->VolCatInfo.VolCatBytes = 1;
437 dev->VolCatInfo.VolCatErrors = 0;
438 dev->VolCatInfo.VolCatBlocks = 0;
439 dev->VolCatInfo.VolCatRBytes = 0;
441 dev->VolCatInfo.VolCatMounts++;
442 dev->VolCatInfo.VolCatRecycles++;
444 dev->VolCatInfo.VolCatMounts = 1;
445 dev->VolCatInfo.VolCatRecycles = 0;
446 dev->VolCatInfo.VolCatWrites = 1;
447 dev->VolCatInfo.VolCatReads = 1;
449 Dmsg0(100, "dir_update_vol_info. Set Append\n");
450 bstrncpy(dev->VolCatInfo.VolCatStatus, "Append", sizeof(dev->VolCatInfo.VolCatStatus));
451 if (!dir_update_volume_info(dcr, true)) { /* indicate doing relabel */
455 Jmsg(jcr, M_INFO, 0, _("Recycled volume \"%s\" on device %s, all previous data lost.\n"),
456 dcr->VolumeName, dev->print_name());
458 Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume \"%s\" on device %s\n"),
459 dcr->VolumeName, dev->print_name());
462 * End writing real Volume label (from pre-labeled tape), or recycling
465 Dmsg0(200, "OK from rewite vol label.\n");
471 * create_volume_label_record
472 * Serialize label (from dev->VolHdr structure) into device record.
473 * Assumes that the dev->VolHdr structure is properly
476 static void create_volume_label_record(DCR *dcr, DEV_RECORD *rec)
480 DEVICE *dev = dcr->dev;
483 /* Serialize the label into the device record. */
485 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
486 ser_begin(rec->data, SER_LENGTH_Volume_Label);
487 ser_string(dev->VolHdr.Id);
489 ser_uint32(dev->VolHdr.VerNum);
491 if (dev->VolHdr.VerNum >= 11) {
492 ser_btime(dev->VolHdr.label_btime);
493 dev->VolHdr.write_btime = get_current_btime();
494 ser_btime(dev->VolHdr.write_btime);
495 dev->VolHdr.write_date = 0;
496 dev->VolHdr.write_time = 0;
498 /* OLD WAY DEPRECATED */
499 ser_float64(dev->VolHdr.label_date);
500 ser_float64(dev->VolHdr.label_time);
501 get_current_time(&dt);
502 dev->VolHdr.write_date = dt.julian_day_number;
503 dev->VolHdr.write_time = dt.julian_day_fraction;
505 ser_float64(dev->VolHdr.write_date); /* 0 if VerNum >= 11 */
506 ser_float64(dev->VolHdr.write_time); /* 0 if VerNum >= 11 */
508 ser_string(dev->VolHdr.VolumeName);
509 ser_string(dev->VolHdr.PrevVolumeName);
510 ser_string(dev->VolHdr.PoolName);
511 ser_string(dev->VolHdr.PoolType);
512 ser_string(dev->VolHdr.MediaType);
514 ser_string(dev->VolHdr.HostName);
515 ser_string(dev->VolHdr.LabelProg);
516 ser_string(dev->VolHdr.ProgVersion);
517 ser_string(dev->VolHdr.ProgDate);
519 ser_end(rec->data, SER_LENGTH_Volume_Label);
520 rec->data_len = ser_length(rec->data);
521 rec->FileIndex = dev->VolHdr.LabelType;
522 rec->VolSessionId = jcr->VolSessionId;
523 rec->VolSessionTime = jcr->VolSessionTime;
524 rec->Stream = jcr->NumVolumes;
525 Dmsg2(100, "Created Vol label rec: FI=%s len=%d\n", FI_to_ascii(rec->FileIndex),
531 * Create a volume label in memory
533 void create_volume_label(DEVICE *dev, const char *VolName, const char *PoolName)
535 DEVRES *device = (DEVRES *)dev->device;
537 Dmsg0(90, "Start create_volume_label()\n");
541 free_volume(dev); /* release any old volume */
542 memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
544 bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
545 dev->VolHdr.VerNum = BaculaTapeVersion;
546 dev->VolHdr.LabelType = PRE_LABEL; /* Mark tape as unused */
547 bstrncpy(dev->VolHdr.VolumeName, VolName, sizeof(dev->VolHdr.VolumeName));
548 bstrncpy(dev->VolHdr.PoolName, PoolName, sizeof(dev->VolHdr.PoolName));
549 bstrncpy(dev->VolHdr.MediaType, device->media_type, sizeof(dev->VolHdr.MediaType));
551 bstrncpy(dev->VolHdr.PoolType, "Backup", sizeof(dev->VolHdr.PoolType));
553 dev->VolHdr.label_btime = get_current_btime();
554 dev->VolHdr.label_date = 0;
555 dev->VolHdr.label_time = 0;
557 if (gethostname(dev->VolHdr.HostName, sizeof(dev->VolHdr.HostName)) != 0) {
558 dev->VolHdr.HostName[0] = 0;
560 bstrncpy(dev->VolHdr.LabelProg, my_name, sizeof(dev->VolHdr.LabelProg));
561 sprintf(dev->VolHdr.ProgVersion, "Ver. %s %s", VERSION, BDATE);
562 sprintf(dev->VolHdr.ProgDate, "Build %s %s", __DATE__, __TIME__);
563 dev->set_labeled(); /* set has Bacula label */
564 if (debug_level >= 90) {
565 dump_volume_label(dev);
570 * Create session label
571 * The pool memory must be released by the calling program
573 void create_session_label(DCR *dcr, DEV_RECORD *rec, int label)
578 rec->VolSessionId = jcr->VolSessionId;
579 rec->VolSessionTime = jcr->VolSessionTime;
580 rec->Stream = jcr->JobId;
582 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
583 ser_begin(rec->data, SER_LENGTH_Session_Label);
584 ser_string(BaculaId);
585 ser_uint32(BaculaTapeVersion);
587 ser_uint32(jcr->JobId);
589 /* Changed in VerNum 11 */
590 ser_btime(get_current_btime());
593 ser_string(dcr->pool_name);
594 ser_string(dcr->pool_type);
595 ser_string(jcr->job_name); /* base Job name */
596 ser_string(jcr->client_name);
598 /* Added in VerNum 10 */
599 ser_string(jcr->Job); /* Unique name of this Job */
600 ser_string(jcr->fileset_name);
601 ser_uint32(jcr->JobType);
602 ser_uint32(jcr->JobLevel);
603 /* Added in VerNum 11 */
604 ser_string(jcr->fileset_md5);
606 if (label == EOS_LABEL) {
607 ser_uint32(jcr->JobFiles);
608 ser_uint64(jcr->JobBytes);
609 ser_uint32(dcr->StartBlock);
610 ser_uint32(dcr->EndBlock);
611 ser_uint32(dcr->StartFile);
612 ser_uint32(dcr->EndFile);
613 ser_uint32(jcr->JobErrors);
615 /* Added in VerNum 11 */
616 ser_uint32(jcr->JobStatus);
618 ser_end(rec->data, SER_LENGTH_Session_Label);
619 rec->data_len = ser_length(rec->data);
622 /* Write session label
623 * Returns: false on failure
626 bool write_session_label(DCR *dcr, int label)
629 DEVICE *dev = dcr->dev;
631 DEV_BLOCK *block = dcr->block;
634 Dmsg1(90, "session_label record=%x\n", rec);
637 if (dev->is_tape()) {
638 dcr->StartBlock = dev->block_num;
639 dcr->StartFile = dev->file;
641 dcr->StartBlock = (uint32_t)dev->file_addr;
642 dcr->StartFile = (uint32_t)(dev->file_addr >> 32);
646 if (dev->is_tape()) {
647 dcr->EndBlock = dev->EndBlock;
648 dcr->EndFile = dev->EndFile;
650 dcr->EndBlock = (uint32_t)dev->file_addr;
651 dcr->EndFile = (uint32_t)(dev->file_addr >> 32);
655 Jmsg1(jcr, M_ABORT, 0, _("Bad session label = %d\n"), label);
658 create_session_label(dcr, rec, label);
659 rec->FileIndex = label;
662 * We guarantee that the session record can totally fit
663 * into a block. If not, write the block, and put it in
664 * the next block. Having the sesssion record totally in
665 * one block makes reading them much easier (no need to
666 * read the next block).
668 if (!can_write_record_to_block(block, rec)) {
669 Dmsg0(100, "Cannot write session label to block.\n");
670 if (!write_block_to_device(dcr)) {
671 Dmsg0(90, "Got session label write_block_to_dev error.\n");
672 /* ****FIXME***** errno is not set here */
673 Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"),
674 dev_vol_name(dev), strerror(errno));
679 if (!write_record_to_block(block, rec)) {
680 Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"),
681 dev_vol_name(dev), strerror(errno));
686 Dmsg6(20, "Write sesson_label record JobId=%d FI=%s SessId=%d Strm=%s len=%d "
687 "remainder=%d\n", jcr->JobId,
688 FI_to_ascii(rec->FileIndex), rec->VolSessionId,
689 stream_to_ascii(rec->Stream, rec->FileIndex), rec->data_len,
693 Dmsg2(20, "Leave write_session_label Block=%d File=%d\n",
694 dev->block_num, dev->file);
698 /* unser_volume_label
700 * Unserialize the Bacula Volume label into the device Volume_Label
703 * Assumes that the record is already read.
705 * Returns: false on error
709 bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec)
713 if (rec->FileIndex != VOL_LABEL && rec->FileIndex != PRE_LABEL) {
714 Mmsg3(dev->errmsg, _("Expecting Volume Label, got FI=%s Stream=%s len=%d\n"),
715 FI_to_ascii(rec->FileIndex),
716 stream_to_ascii(rec->Stream, rec->FileIndex),
723 dev->VolHdr.LabelType = rec->FileIndex;
724 dev->VolHdr.LabelSize = rec->data_len;
727 /* Unserialize the record into the Volume Header */
728 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
729 ser_begin(rec->data, SER_LENGTH_Volume_Label);
730 unser_string(dev->VolHdr.Id);
731 unser_uint32(dev->VolHdr.VerNum);
733 if (dev->VolHdr.VerNum >= 11) {
734 unser_btime(dev->VolHdr.label_btime);
735 unser_btime(dev->VolHdr.write_btime);
736 } else { /* old way */
737 unser_float64(dev->VolHdr.label_date);
738 unser_float64(dev->VolHdr.label_time);
740 unser_float64(dev->VolHdr.write_date); /* Unused with VerNum >= 11 */
741 unser_float64(dev->VolHdr.write_time); /* Unused with VerNum >= 11 */
743 unser_string(dev->VolHdr.VolumeName);
744 unser_string(dev->VolHdr.PrevVolumeName);
745 unser_string(dev->VolHdr.PoolName);
746 unser_string(dev->VolHdr.PoolType);
747 unser_string(dev->VolHdr.MediaType);
749 unser_string(dev->VolHdr.HostName);
750 unser_string(dev->VolHdr.LabelProg);
751 unser_string(dev->VolHdr.ProgVersion);
752 unser_string(dev->VolHdr.ProgDate);
754 ser_end(rec->data, SER_LENGTH_Volume_Label);
755 Dmsg0(90, "unser_vol_label\n");
756 if (debug_level >= 90) {
757 dump_volume_label(dev);
763 bool unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec)
767 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
768 unser_begin(rec->data, SER_LENGTH_Session_Label);
769 unser_string(label->Id);
770 unser_uint32(label->VerNum);
771 unser_uint32(label->JobId);
772 if (label->VerNum >= 11) {
773 unser_btime(label->write_btime);
775 unser_float64(label->write_date);
777 unser_float64(label->write_time);
778 unser_string(label->PoolName);
779 unser_string(label->PoolType);
780 unser_string(label->JobName);
781 unser_string(label->ClientName);
782 if (label->VerNum >= 10) {
783 unser_string(label->Job); /* Unique name of this Job */
784 unser_string(label->FileSetName);
785 unser_uint32(label->JobType);
786 unser_uint32(label->JobLevel);
788 if (label->VerNum >= 11) {
789 unser_string(label->FileSetMD5);
791 label->FileSetMD5[0] = 0;
793 if (rec->FileIndex == EOS_LABEL) {
794 unser_uint32(label->JobFiles);
795 unser_uint64(label->JobBytes);
796 unser_uint32(label->StartBlock);
797 unser_uint32(label->EndBlock);
798 unser_uint32(label->StartFile);
799 unser_uint32(label->EndFile);
800 unser_uint32(label->JobErrors);
801 if (label->VerNum >= 11) {
802 unser_uint32(label->JobStatus);
804 label->JobStatus = JS_Terminated; /* kludge */
810 void dump_volume_label(DEVICE *dev)
812 int dbl = debug_level;
814 const char *LabelType;
821 switch (dev->VolHdr.LabelType) {
823 LabelType = "PRE_LABEL";
826 LabelType = "VOL_LABEL";
829 LabelType = "EOM_LABEL";
832 LabelType = "SOS_LABEL";
835 LabelType = "EOS_LABEL";
841 sprintf(buf, _("Unknown %d"), dev->VolHdr.LabelType);
845 Pmsg11(-1, _("\nVolume Label:\n"
858 dev->VolHdr.Id, dev->VolHdr.VerNum,
859 dev->VolHdr.VolumeName, dev->VolHdr.PrevVolumeName,
860 File, LabelType, dev->VolHdr.LabelSize,
861 dev->VolHdr.PoolName, dev->VolHdr.MediaType,
862 dev->VolHdr.PoolType, dev->VolHdr.HostName);
864 if (dev->VolHdr.VerNum >= 11) {
866 bstrftime(dt, sizeof(dt), btime_to_unix(dev->VolHdr.label_btime));
867 Pmsg1(-1, _("Date label written: %s\n"), dt);
869 dt.julian_day_number = dev->VolHdr.label_date;
870 dt.julian_day_fraction = dev->VolHdr.label_time;
873 _("Date label written: %04d-%02d-%02d at %02d:%02d\n"),
874 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
882 static void dump_session_label(DEV_RECORD *rec, const char *type)
888 char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], ec6[30], ec7[30];
890 unser_session_label(&label, rec);
893 Pmsg7(-1, _("\n%s Record:\n"
900 ""), type, label.JobId, label.VerNum,
901 label.PoolName, label.PoolType,
902 label.JobName, label.ClientName);
904 if (label.VerNum >= 10) {
906 "Job (unique name) : %s\n"
910 ""), label.Job, label.FileSetName, label.JobType, label.JobLevel);
913 if (rec->FileIndex == EOS_LABEL) {
924 edit_uint64_with_commas(label.JobFiles, ec1),
925 edit_uint64_with_commas(label.JobBytes, ec2),
926 edit_uint64_with_commas(label.StartBlock, ec3),
927 edit_uint64_with_commas(label.EndBlock, ec4),
928 edit_uint64_with_commas(label.StartFile, ec5),
929 edit_uint64_with_commas(label.EndFile, ec6),
930 edit_uint64_with_commas(label.JobErrors, ec7),
933 if (label.VerNum >= 11) {
935 bstrftime(dt, sizeof(dt), btime_to_unix(label.write_btime));
936 Pmsg1(-1, _("Date written : %s\n"), dt);
938 dt.julian_day_number = label.write_date;
939 dt.julian_day_fraction = label.write_time;
941 Pmsg5(-1, _("Date written : %04d-%02d-%02d at %02d:%02d\n"),
942 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
948 void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose)
953 if (rec->FileIndex == 0 && rec->VolSessionId == 0 && rec->VolSessionTime == 0) {
958 switch (rec->FileIndex) {
960 type = _("Fresh Volume");
966 type = _("Begin Job Session");
969 type = _("End Job Session");
972 type = _("End of Media");
975 type = _("End of Tape");
982 switch (rec->FileIndex) {
985 unser_volume_label(dev, rec);
986 dump_volume_label(dev);
989 dump_session_label(rec, type);
992 dump_session_label(rec, type);
995 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
996 type, dev->file, dev->block_num, rec->VolSessionId,
997 rec->VolSessionTime, rec->Stream, rec->data_len);
1000 Pmsg0(-1, _("End of physical tape.\n"));
1003 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1004 type, dev->file, dev->block_num, rec->VolSessionId,
1005 rec->VolSessionTime, rec->Stream, rec->data_len);
1009 SESSION_LABEL label;
1011 switch (rec->FileIndex) {
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 Pmsg4(-1, _(" Job=%s Date=%s Level=%c Type=%c\n"),
1018 label.Job, dt, label.JobLevel, label.JobType);
1021 char ed1[30], ed2[30];
1022 unser_session_label(&label, rec);
1023 bstrftimes(dt, sizeof(dt), btime_to_unix(label.write_btime));
1024 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1025 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1026 Pmsg7(-1, _(" Date=%s Level=%c Type=%c Files=%s Bytes=%s Errors=%d Status=%c\n"),
1027 dt, label.JobLevel, label.JobType,
1028 edit_uint64_with_commas(label.JobFiles, ed1),
1029 edit_uint64_with_commas(label.JobBytes, ed2),
1030 label.JobErrors, (char)label.JobStatus);
1036 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1037 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime,
1038 rec->Stream, rec->data_len);