3 * label.c Bacula routines to handle labels
11 Copyright (C) 2000-2006 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 Dmsg4(100, "Enter read_volume_label res=%d device=%s vol=%s dev_Vol=%s\n",
70 dev->reserved_device, dev->print_name(), VolName,
71 dev->VolHdr.VolumeName[0]?dev->VolHdr.VolumeName:"*NULL*");
73 if (!dev->is_open()) {
74 if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
78 if (dev->is_labeled()) { /* did we already read label? */
79 /* Compare Volume Names allow special wild card */
80 if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolumeName, VolName) != 0) {
81 Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
82 dev->print_name(), VolName, dev->VolHdr.VolumeName);
84 * Cancel Job if too many label errors
87 if (!dev->poll && jcr->label_errors++ > 100) {
88 Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
90 Dmsg0(150, "return VOL_NAME_ERROR\n");
91 stat = VOL_NAME_ERROR;
94 Dmsg0(30, "Leave read_volume_label() VOL_OK\n");
95 return VOL_OK; /* label already read */
101 dev->label_type = B_BACULA_LABEL;
103 if (!dev->rewind(dcr)) {
104 Mmsg(jcr->errmsg, _("Couldn't rewind device %s: ERR=%s\n"),
105 dev->print_name(), dev->bstrerror());
106 Dmsg1(30, "return VOL_NO_MEDIA: %s", jcr->errmsg);
109 bstrncpy(dev->VolHdr.Id, "**error**", sizeof(dev->VolHdr.Id));
111 /* Read ANSI/IBM label if so requested */
113 want_ansi_label = dcr->VolCatInfo.LabelType != B_BACULA_LABEL ||
114 dcr->device->label_type != B_BACULA_LABEL;
115 if (want_ansi_label || dev_cap(dev, CAP_CHECKLABELS)) {
116 stat = read_ansi_ibm_label(dcr);
117 /* If we want a label and didn't find it, return error */
118 if (want_ansi_label && stat != VOL_OK) {
121 if (stat == VOL_NAME_ERROR || stat == VOL_LABEL_ERROR) {
122 Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
123 dev->print_name(), VolName, dev->VolHdr.VolumeName);
124 if (!dev->poll && jcr->label_errors++ > 100) {
125 Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
129 if (stat != VOL_OK) { /* Not an ANSI/IBM label, so re-read */
132 have_ansi_label = true;
136 /* Read the Bacula Volume label block */
137 record = new_record();
140 Dmsg0(90, "Big if statement in read_volume_label\n");
141 if (!read_block_from_dev(dcr, NO_BLOCK_NUMBER_CHECK)) {
142 Mmsg(jcr->errmsg, _("Requested Volume \"%s\" on %s is not a Bacula "
143 "labeled Volume, because: ERR=%s"), NPRT(VolName),
144 dev->print_name(), dev->bstrerror());
145 Dmsg1(30, "%s", jcr->errmsg);
146 } else if (!read_record_from_block(block, record)) {
147 Mmsg(jcr->errmsg, _("Could not read Volume label from block.\n"));
148 Dmsg1(30, "%s", jcr->errmsg);
149 } else if (!unser_volume_label(dev, record)) {
150 Mmsg(jcr->errmsg, _("Could not unserialize Volume label: ERR=%s\n"),
152 Dmsg1(30, "%s", jcr->errmsg);
153 } else if (strcmp(dev->VolHdr.Id, BaculaId) != 0 &&
154 strcmp(dev->VolHdr.Id, OldBaculaId) != 0) {
155 Mmsg(jcr->errmsg, _("Volume Header Id bad: %s\n"), dev->VolHdr.Id);
156 Dmsg1(30, "%s", jcr->errmsg);
160 free_record(record); /* finished reading Volume record */
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);
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.
179 if (dev->VolHdr.VerNum != BaculaTapeVersion &&
180 dev->VolHdr.VerNum != OldCompatibleBaculaTapeVersion1 &&
181 dev->VolHdr.VerNum != OldCompatibleBaculaTapeVersion2) {
182 Mmsg(jcr->errmsg, _("Volume on %s has wrong Bacula version. Wanted %d got %d\n"),
183 dev->print_name(), BaculaTapeVersion, dev->VolHdr.VerNum);
184 Dmsg1(30, "VOL_VERSION_ERROR: %s", jcr->errmsg);
185 stat = VOL_VERSION_ERROR;
189 /* We are looking for either an unused Bacula tape (PRE_LABEL) or
190 * a Bacula volume label (VOL_LABEL)
192 if (dev->VolHdr.LabelType != PRE_LABEL && dev->VolHdr.LabelType != VOL_LABEL) {
193 Mmsg(jcr->errmsg, _("Volume on %s has bad Bacula label type: %x\n"),
194 dev->print_name(), dev->VolHdr.LabelType);
195 Dmsg1(30, "%s", jcr->errmsg);
196 if (!dev->poll && jcr->label_errors++ > 100) {
197 Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
199 Dmsg0(150, "return VOL_LABEL_ERROR\n");
200 stat = VOL_LABEL_ERROR;
204 dev->set_labeled(); /* set has Bacula label */
205 new_volume(dcr, dev->VolHdr.VolumeName);
207 /* Compare Volume Names */
208 Dmsg2(30, "Compare Vol names: VolName=%s hdr=%s\n", VolName?VolName:"*", dev->VolHdr.VolumeName);
209 if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolumeName, VolName) != 0) {
210 Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
211 dev->print_name(), VolName, dev->VolHdr.VolumeName);
212 Dmsg1(30, "%s", jcr->errmsg);
214 * Cancel Job if too many label errors
215 * => we are in a loop
217 if (!dev->poll && jcr->label_errors++ > 100) {
218 Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
220 Dmsg0(150, "return VOL_NAME_ERROR\n");
221 stat = VOL_NAME_ERROR;
224 Dmsg1(30, "Copy vol_name=%s\n", dev->VolHdr.VolumeName);
226 if (debug_level >= 10) {
227 dump_volume_label(dev);
229 Dmsg0(30, "Leave read_volume_label() VOL_OK\n");
230 /* If we are a streaming device, we only get one chance to read */
231 if (!dev_cap(dev, CAP_STREAM)) {
233 if (have_ansi_label) {
234 stat = read_ansi_ibm_label(dcr);
235 /* If we want a label and didn't find it, return error */
236 if (stat != VOL_OK) {
247 Dmsg1(150, "return %d\n", stat);
252 * Put a volume label into the block
254 * Returns: false on failure
257 bool write_volume_label_to_block(DCR *dcr)
260 DEVICE *dev = dcr->dev;
262 DEV_BLOCK *block = dcr->block;
264 Dmsg0(20, "write Label in write_volume_label_to_block()\n");
265 memset(&rec, 0, sizeof(rec));
266 rec.data = get_memory(SER_LENGTH_Volume_Label);
267 empty_block(block); /* Volume label always at beginning */
269 create_volume_label_record(dcr, &rec);
271 block->BlockNumber = 0;
272 if (!write_record_to_block(block, &rec)) {
273 free_pool_memory(rec.data);
274 Jmsg1(jcr, M_FATAL, 0, _("Cannot write Volume label to block for device %s\n"),
278 Dmsg1(90, "Wrote label of %d bytes to block\n", rec.data_len);
280 free_pool_memory(rec.data);
286 * Write a Volume Label
287 * !!! Note, this is ONLY used for writing
288 * a fresh volume label. Any data
289 * after the label will be destroyed,
290 * in fact, we write the label 5 times !!!!
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) {
303 /* If device is not tape, attempt to create it */
304 if (dev->is_tape() || dev->open(dcr, CREATE_READ_WRITE) < 0) {
308 Dmsg1(150, "Label type=%d\n", dev->label_type);
309 if (!dev->rewind(dcr)) {
311 memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
312 Dmsg2(30, "Bad status on %s from rewind: ERR=%s\n", dev->print_name(), dev->bstrerror());
318 /* Create PRE_LABEL */
319 create_volume_label(dev, VolName, PoolName);
322 * If we have already detected an ANSI label, re-read it
323 * to skip past it. Otherwise, we write a new one if
326 if (dev->label_type != B_BACULA_LABEL) {
327 if (read_ansi_ibm_label(dcr) != VOL_OK) {
331 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, VolName)) {
335 create_volume_label_record(dcr, dcr->rec);
336 dcr->rec->Stream = 0;
338 /* Temporarily mark in append state to enable writing */
340 if (!write_record_to_block(dcr->block, dcr->rec)) {
341 Dmsg2(30, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->bstrerror());
344 Dmsg2(30, "Wrote label of %d bytes to %s\n", dcr->rec->data_len, dev->print_name());
347 Dmsg0(99, "Call write_block_to_dev()\n");
348 if (!write_block_to_dev(dcr)) {
349 Dmsg2(30, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->bstrerror());
352 Dmsg0(99, " Wrote block to device\n");
356 write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
359 if (debug_level >= 20) {
360 dump_volume_label(dev);
362 new_volume(dcr, VolName);
363 dev->clear_append(); /* remove append since this is PRE_LABEL */
368 memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
369 dev->clear_append(); /* remove append since this is PRE_LABEL */
374 * Write a volume label. This is ONLY called if we have a valid Bacula
375 * label of type PRE_LABEL;
376 * Returns: true if OK
377 * false if unable to write it
379 bool rewrite_volume_label(DCR *dcr, bool recycle)
381 DEVICE *dev = dcr->dev;
383 bool can_write = true;
385 if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
386 /* If device is DVD, attempt to create it */
387 if (!dev->is_dvd()) {
390 if (dev->open(dcr, CREATE_READ_WRITE) < 0) {
391 /* We forge on for a DVD but don't do any writing */
395 Dmsg2(190, "set append found freshly labeled volume. fd=%d dev=%x\n", dev->fd, dev);
396 dev->VolHdr.LabelType = VOL_LABEL; /* set Volume label */
399 if (!write_volume_label_to_block(dcr)) {
400 Dmsg0(200, "Error from write volume label.\n");
405 * If we are not dealing with a streaming device,
406 * write the block now to ensure we have write permission.
407 * It is better to find out now rather than later.
408 * We do not write the block now if this is an ANSI label. This
409 * avoids re-writing the ANSI label, which we do not want to do.
411 if (can_write && !dev_cap(dev, CAP_STREAM)) {
412 if (!dev->rewind(dcr)) {
413 Jmsg2(jcr, M_WARNING, 0, _("Rewind error on device %s: ERR=%s\n"),
414 dev->print_name(), dev->bstrerror());
417 if (!dev->truncate(dcr)) {
418 Jmsg2(jcr, M_WARNING, 0, _("Truncate error on device %s: ERR=%s\n"),
419 dev->print_name(), dev->bstrerror());
424 * If we have already detected an ANSI label, re-read it
425 * to skip past it. Otherwise, we write a new one if
428 if (dev->label_type != B_BACULA_LABEL) {
429 if (read_ansi_ibm_label(dcr) != VOL_OK) {
433 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, dev->VolHdr.VolumeName)) {
437 /* Attempt write to check write permission */
438 Dmsg1(200, "Attempt to write to device fd=%d.\n", dev->fd);
439 if (!write_block_to_dev(dcr)) {
440 Jmsg2(jcr, M_ERROR, 0, _("Unable to write device %s: ERR=%s\n"),
441 dev->print_name(), dev->bstrerror());
442 Dmsg0(200, "===ERROR write block to dev\n");
446 /* Set or reset Volume statistics */
447 dev->VolCatInfo.VolCatJobs = 0;
448 dev->VolCatInfo.VolCatFiles = 0;
449 dev->VolCatInfo.VolCatBytes = 1;
450 dev->VolCatInfo.VolCatErrors = 0;
451 dev->VolCatInfo.VolCatBlocks = 0;
452 dev->VolCatInfo.VolCatRBytes = 0;
454 dev->VolCatInfo.VolCatMounts++;
455 dev->VolCatInfo.VolCatRecycles++;
457 dev->VolCatInfo.VolCatMounts = 1;
458 dev->VolCatInfo.VolCatRecycles = 0;
459 dev->VolCatInfo.VolCatWrites = 1;
460 dev->VolCatInfo.VolCatReads = 1;
462 Dmsg0(150, "dir_update_vol_info. Set Append\n");
463 bstrncpy(dev->VolCatInfo.VolCatStatus, "Append", sizeof(dev->VolCatInfo.VolCatStatus));
464 if (!dir_update_volume_info(dcr, true)) { /* indicate doing relabel */
468 Jmsg(jcr, M_INFO, 0, _("Recycled volume \"%s\" on device %s, all previous data lost.\n"),
469 dcr->VolumeName, dev->print_name());
471 Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume \"%s\" on device %s\n"),
472 dcr->VolumeName, dev->print_name());
475 * End writing real Volume label (from pre-labeled tape), or recycling
478 Dmsg0(200, "OK from rewite vol label.\n");
484 * create_volume_label_record
485 * Serialize label (from dev->VolHdr structure) into device record.
486 * Assumes that the dev->VolHdr structure is properly
489 static void create_volume_label_record(DCR *dcr, DEV_RECORD *rec)
493 DEVICE *dev = dcr->dev;
497 /* Serialize the label into the device record. */
499 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
500 ser_begin(rec->data, SER_LENGTH_Volume_Label);
501 ser_string(dev->VolHdr.Id);
503 ser_uint32(dev->VolHdr.VerNum);
505 if (dev->VolHdr.VerNum >= 11) {
506 ser_btime(dev->VolHdr.label_btime);
507 dev->VolHdr.write_btime = get_current_btime();
508 ser_btime(dev->VolHdr.write_btime);
509 dev->VolHdr.write_date = 0;
510 dev->VolHdr.write_time = 0;
512 /* OLD WAY DEPRECATED */
513 ser_float64(dev->VolHdr.label_date);
514 ser_float64(dev->VolHdr.label_time);
515 get_current_time(&dt);
516 dev->VolHdr.write_date = dt.julian_day_number;
517 dev->VolHdr.write_time = dt.julian_day_fraction;
519 ser_float64(dev->VolHdr.write_date); /* 0 if VerNum >= 11 */
520 ser_float64(dev->VolHdr.write_time); /* 0 if VerNum >= 11 */
522 ser_string(dev->VolHdr.VolumeName);
523 ser_string(dev->VolHdr.PrevVolumeName);
524 ser_string(dev->VolHdr.PoolName);
525 ser_string(dev->VolHdr.PoolType);
526 ser_string(dev->VolHdr.MediaType);
528 ser_string(dev->VolHdr.HostName);
529 ser_string(dev->VolHdr.LabelProg);
530 ser_string(dev->VolHdr.ProgVersion);
531 ser_string(dev->VolHdr.ProgDate);
533 ser_end(rec->data, SER_LENGTH_Volume_Label);
534 rec->data_len = ser_length(rec->data);
535 rec->FileIndex = dev->VolHdr.LabelType;
536 rec->VolSessionId = jcr->VolSessionId;
537 rec->VolSessionTime = jcr->VolSessionTime;
538 rec->Stream = jcr->NumVolumes;
539 Dmsg2(150, "Created Vol label rec: FI=%s len=%d\n", FI_to_ascii(buf, rec->FileIndex),
545 * Create a volume label in memory
547 void create_volume_label(DEVICE *dev, const char *VolName, const char *PoolName)
549 DEVRES *device = (DEVRES *)dev->device;
551 Dmsg0(90, "Start create_volume_label()\n");
555 free_volume(dev); /* release any old volume */
556 memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
558 bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
559 dev->VolHdr.VerNum = BaculaTapeVersion;
560 dev->VolHdr.LabelType = PRE_LABEL; /* Mark tape as unused */
561 bstrncpy(dev->VolHdr.VolumeName, VolName, sizeof(dev->VolHdr.VolumeName));
562 bstrncpy(dev->VolHdr.PoolName, PoolName, sizeof(dev->VolHdr.PoolName));
563 bstrncpy(dev->VolHdr.MediaType, device->media_type, sizeof(dev->VolHdr.MediaType));
565 bstrncpy(dev->VolHdr.PoolType, "Backup", sizeof(dev->VolHdr.PoolType));
567 dev->VolHdr.label_btime = get_current_btime();
568 dev->VolHdr.label_date = 0;
569 dev->VolHdr.label_time = 0;
571 if (gethostname(dev->VolHdr.HostName, sizeof(dev->VolHdr.HostName)) != 0) {
572 dev->VolHdr.HostName[0] = 0;
574 bstrncpy(dev->VolHdr.LabelProg, my_name, sizeof(dev->VolHdr.LabelProg));
575 sprintf(dev->VolHdr.ProgVersion, "Ver. %s %s", VERSION, BDATE);
576 sprintf(dev->VolHdr.ProgDate, "Build %s %s", __DATE__, __TIME__);
577 dev->set_labeled(); /* set has Bacula label */
578 if (debug_level >= 90) {
579 dump_volume_label(dev);
584 * Create session label
585 * The pool memory must be released by the calling program
587 void create_session_label(DCR *dcr, DEV_RECORD *rec, int label)
592 rec->VolSessionId = jcr->VolSessionId;
593 rec->VolSessionTime = jcr->VolSessionTime;
594 rec->Stream = jcr->JobId;
596 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
597 ser_begin(rec->data, SER_LENGTH_Session_Label);
598 ser_string(BaculaId);
599 ser_uint32(BaculaTapeVersion);
601 ser_uint32(jcr->JobId);
603 /* Changed in VerNum 11 */
604 ser_btime(get_current_btime());
607 ser_string(dcr->pool_name);
608 ser_string(dcr->pool_type);
609 ser_string(jcr->job_name); /* base Job name */
610 ser_string(jcr->client_name);
612 /* Added in VerNum 10 */
613 ser_string(jcr->Job); /* Unique name of this Job */
614 ser_string(jcr->fileset_name);
615 ser_uint32(jcr->JobType);
616 ser_uint32(jcr->JobLevel);
617 /* Added in VerNum 11 */
618 ser_string(jcr->fileset_md5);
620 if (label == EOS_LABEL) {
621 ser_uint32(jcr->JobFiles);
622 ser_uint64(jcr->JobBytes);
623 ser_uint32(dcr->StartBlock);
624 ser_uint32(dcr->EndBlock);
625 ser_uint32(dcr->StartFile);
626 ser_uint32(dcr->EndFile);
627 ser_uint32(jcr->JobErrors);
629 /* Added in VerNum 11 */
630 ser_uint32(jcr->JobStatus);
632 ser_end(rec->data, SER_LENGTH_Session_Label);
633 rec->data_len = ser_length(rec->data);
636 /* Write session label
637 * Returns: false on failure
640 bool write_session_label(DCR *dcr, int label)
643 DEVICE *dev = dcr->dev;
645 DEV_BLOCK *block = dcr->block;
646 char buf1[100], buf2[100];
649 Dmsg1(90, "session_label record=%x\n", rec);
652 if (dev->is_tape()) {
653 dcr->StartBlock = dev->block_num;
654 dcr->StartFile = dev->file;
656 dcr->StartBlock = (uint32_t)dev->file_addr;
657 dcr->StartFile = (uint32_t)(dev->file_addr >> 32);
661 if (dev->is_tape()) {
662 dcr->EndBlock = dev->EndBlock;
663 dcr->EndFile = dev->EndFile;
665 dcr->EndBlock = (uint32_t)dev->file_addr;
666 dcr->EndFile = (uint32_t)(dev->file_addr >> 32);
670 Jmsg1(jcr, M_ABORT, 0, _("Bad session label = %d\n"), label);
673 create_session_label(dcr, rec, label);
674 rec->FileIndex = label;
677 * We guarantee that the session record can totally fit
678 * into a block. If not, write the block, and put it in
679 * the next block. Having the sesssion record totally in
680 * one block makes reading them much easier (no need to
681 * read the next block).
683 if (!can_write_record_to_block(block, rec)) {
684 Dmsg0(150, "Cannot write session label to block.\n");
685 if (!write_block_to_device(dcr)) {
686 Dmsg0(90, "Got session label write_block_to_dev error.\n");
687 /* ****FIXME***** errno is not set here */
688 Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"),
689 dev_vol_name(dev), strerror(errno));
694 if (!write_record_to_block(block, rec)) {
695 Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"),
696 dev_vol_name(dev), strerror(errno));
701 Dmsg6(20, "Write sesson_label record JobId=%d FI=%s SessId=%d Strm=%s len=%d "
702 "remainder=%d\n", jcr->JobId,
703 FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
704 stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
708 Dmsg2(20, "Leave write_session_label Block=%d File=%d\n",
709 dev->block_num, dev->file);
713 /* unser_volume_label
715 * Unserialize the Bacula Volume label into the device Volume_Label
718 * Assumes that the record is already read.
720 * Returns: false on error
724 bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec)
727 char buf1[100], buf2[100];
729 if (rec->FileIndex != VOL_LABEL && rec->FileIndex != PRE_LABEL) {
730 Mmsg3(dev->errmsg, _("Expecting Volume Label, got FI=%s Stream=%s len=%d\n"),
731 FI_to_ascii(buf1, rec->FileIndex),
732 stream_to_ascii(buf2, rec->Stream, rec->FileIndex),
739 dev->VolHdr.LabelType = rec->FileIndex;
740 dev->VolHdr.LabelSize = rec->data_len;
743 /* Unserialize the record into the Volume Header */
744 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
745 ser_begin(rec->data, SER_LENGTH_Volume_Label);
746 unser_string(dev->VolHdr.Id);
747 unser_uint32(dev->VolHdr.VerNum);
749 if (dev->VolHdr.VerNum >= 11) {
750 unser_btime(dev->VolHdr.label_btime);
751 unser_btime(dev->VolHdr.write_btime);
752 } else { /* old way */
753 unser_float64(dev->VolHdr.label_date);
754 unser_float64(dev->VolHdr.label_time);
756 unser_float64(dev->VolHdr.write_date); /* Unused with VerNum >= 11 */
757 unser_float64(dev->VolHdr.write_time); /* Unused with VerNum >= 11 */
759 unser_string(dev->VolHdr.VolumeName);
760 unser_string(dev->VolHdr.PrevVolumeName);
761 unser_string(dev->VolHdr.PoolName);
762 unser_string(dev->VolHdr.PoolType);
763 unser_string(dev->VolHdr.MediaType);
765 unser_string(dev->VolHdr.HostName);
766 unser_string(dev->VolHdr.LabelProg);
767 unser_string(dev->VolHdr.ProgVersion);
768 unser_string(dev->VolHdr.ProgDate);
770 ser_end(rec->data, SER_LENGTH_Volume_Label);
771 Dmsg0(190, "unser_vol_label\n");
772 if (debug_level >= 190) {
773 dump_volume_label(dev);
779 bool unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec)
783 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
784 unser_begin(rec->data, SER_LENGTH_Session_Label);
785 unser_string(label->Id);
786 unser_uint32(label->VerNum);
787 unser_uint32(label->JobId);
788 if (label->VerNum >= 11) {
789 unser_btime(label->write_btime);
791 unser_float64(label->write_date);
793 unser_float64(label->write_time);
794 unser_string(label->PoolName);
795 unser_string(label->PoolType);
796 unser_string(label->JobName);
797 unser_string(label->ClientName);
798 if (label->VerNum >= 10) {
799 unser_string(label->Job); /* Unique name of this Job */
800 unser_string(label->FileSetName);
801 unser_uint32(label->JobType);
802 unser_uint32(label->JobLevel);
804 if (label->VerNum >= 11) {
805 unser_string(label->FileSetMD5);
807 label->FileSetMD5[0] = 0;
809 if (rec->FileIndex == EOS_LABEL) {
810 unser_uint32(label->JobFiles);
811 unser_uint64(label->JobBytes);
812 unser_uint32(label->StartBlock);
813 unser_uint32(label->EndBlock);
814 unser_uint32(label->StartFile);
815 unser_uint32(label->EndFile);
816 unser_uint32(label->JobErrors);
817 if (label->VerNum >= 11) {
818 unser_uint32(label->JobStatus);
820 label->JobStatus = JS_Terminated; /* kludge */
826 void dump_volume_label(DEVICE *dev)
828 int dbl = debug_level;
830 const char *LabelType;
837 switch (dev->VolHdr.LabelType) {
839 LabelType = "PRE_LABEL";
842 LabelType = "VOL_LABEL";
845 LabelType = "EOM_LABEL";
848 LabelType = "SOS_LABEL";
851 LabelType = "EOS_LABEL";
857 sprintf(buf, _("Unknown %d"), dev->VolHdr.LabelType);
861 Pmsg11(-1, _("\nVolume Label:\n"
874 dev->VolHdr.Id, dev->VolHdr.VerNum,
875 dev->VolHdr.VolumeName, dev->VolHdr.PrevVolumeName,
876 File, LabelType, dev->VolHdr.LabelSize,
877 dev->VolHdr.PoolName, dev->VolHdr.MediaType,
878 dev->VolHdr.PoolType, dev->VolHdr.HostName);
880 if (dev->VolHdr.VerNum >= 11) {
882 bstrftime(dt, sizeof(dt), btime_to_unix(dev->VolHdr.label_btime));
883 Pmsg1(-1, _("Date label written: %s\n"), dt);
885 dt.julian_day_number = dev->VolHdr.label_date;
886 dt.julian_day_fraction = dev->VolHdr.label_time;
889 _("Date label written: %04d-%02d-%02d at %02d:%02d\n"),
890 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
898 static void dump_session_label(DEV_RECORD *rec, const char *type)
904 char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], ec6[30], ec7[30];
906 unser_session_label(&label, rec);
909 Pmsg7(-1, _("\n%s Record:\n"
916 ""), type, label.JobId, label.VerNum,
917 label.PoolName, label.PoolType,
918 label.JobName, label.ClientName);
920 if (label.VerNum >= 10) {
922 "Job (unique name) : %s\n"
926 ""), label.Job, label.FileSetName, label.JobType, label.JobLevel);
929 if (rec->FileIndex == EOS_LABEL) {
940 edit_uint64_with_commas(label.JobFiles, ec1),
941 edit_uint64_with_commas(label.JobBytes, ec2),
942 edit_uint64_with_commas(label.StartBlock, ec3),
943 edit_uint64_with_commas(label.EndBlock, ec4),
944 edit_uint64_with_commas(label.StartFile, ec5),
945 edit_uint64_with_commas(label.EndFile, ec6),
946 edit_uint64_with_commas(label.JobErrors, ec7),
949 if (label.VerNum >= 11) {
951 bstrftime(dt, sizeof(dt), btime_to_unix(label.write_btime));
952 Pmsg1(-1, _("Date written : %s\n"), dt);
954 dt.julian_day_number = label.write_date;
955 dt.julian_day_fraction = label.write_time;
957 Pmsg5(-1, _("Date written : %04d-%02d-%02d at %02d:%02d\n"),
958 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
964 void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose)
969 if (rec->FileIndex == 0 && rec->VolSessionId == 0 && rec->VolSessionTime == 0) {
974 switch (rec->FileIndex) {
976 type = _("Fresh Volume");
982 type = _("Begin Job Session");
985 type = _("End Job Session");
988 type = _("End of Media");
991 type = _("End of Tape");
998 switch (rec->FileIndex) {
1001 unser_volume_label(dev, rec);
1002 dump_volume_label(dev);
1005 dump_session_label(rec, type);
1008 dump_session_label(rec, type);
1011 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1012 type, dev->file, dev->block_num, rec->VolSessionId,
1013 rec->VolSessionTime, rec->Stream, rec->data_len);
1016 Pmsg0(-1, _("End of physical tape.\n"));
1019 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1020 type, dev->file, dev->block_num, rec->VolSessionId,
1021 rec->VolSessionTime, rec->Stream, rec->data_len);
1025 SESSION_LABEL label;
1027 switch (rec->FileIndex) {
1029 unser_session_label(&label, rec);
1030 bstrftimes(dt, sizeof(dt), btime_to_unix(label.write_btime));
1031 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1032 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1033 Pmsg4(-1, _(" Job=%s Date=%s Level=%c Type=%c\n"),
1034 label.Job, dt, label.JobLevel, label.JobType);
1037 char ed1[30], ed2[30];
1038 unser_session_label(&label, rec);
1039 bstrftimes(dt, sizeof(dt), btime_to_unix(label.write_btime));
1040 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1041 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1042 Pmsg7(-1, _(" Date=%s Level=%c Type=%c Files=%s Bytes=%s Errors=%d Status=%c\n"),
1043 dt, label.JobLevel, label.JobType,
1044 edit_uint64_with_commas(label.JobFiles, ed1),
1045 edit_uint64_with_commas(label.JobBytes, ed2),
1046 label.JobErrors, (char)label.JobStatus);
1052 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1053 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime,
1054 rec->Stream, rec->data_len);