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;
484 /* Serialize the label into the device record. */
486 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
487 ser_begin(rec->data, SER_LENGTH_Volume_Label);
488 ser_string(dev->VolHdr.Id);
490 ser_uint32(dev->VolHdr.VerNum);
492 if (dev->VolHdr.VerNum >= 11) {
493 ser_btime(dev->VolHdr.label_btime);
494 dev->VolHdr.write_btime = get_current_btime();
495 ser_btime(dev->VolHdr.write_btime);
496 dev->VolHdr.write_date = 0;
497 dev->VolHdr.write_time = 0;
499 /* OLD WAY DEPRECATED */
500 ser_float64(dev->VolHdr.label_date);
501 ser_float64(dev->VolHdr.label_time);
502 get_current_time(&dt);
503 dev->VolHdr.write_date = dt.julian_day_number;
504 dev->VolHdr.write_time = dt.julian_day_fraction;
506 ser_float64(dev->VolHdr.write_date); /* 0 if VerNum >= 11 */
507 ser_float64(dev->VolHdr.write_time); /* 0 if VerNum >= 11 */
509 ser_string(dev->VolHdr.VolumeName);
510 ser_string(dev->VolHdr.PrevVolumeName);
511 ser_string(dev->VolHdr.PoolName);
512 ser_string(dev->VolHdr.PoolType);
513 ser_string(dev->VolHdr.MediaType);
515 ser_string(dev->VolHdr.HostName);
516 ser_string(dev->VolHdr.LabelProg);
517 ser_string(dev->VolHdr.ProgVersion);
518 ser_string(dev->VolHdr.ProgDate);
520 ser_end(rec->data, SER_LENGTH_Volume_Label);
521 rec->data_len = ser_length(rec->data);
522 rec->FileIndex = dev->VolHdr.LabelType;
523 rec->VolSessionId = jcr->VolSessionId;
524 rec->VolSessionTime = jcr->VolSessionTime;
525 rec->Stream = jcr->NumVolumes;
526 Dmsg2(100, "Created Vol label rec: FI=%s len=%d\n", FI_to_ascii(buf, rec->FileIndex),
532 * Create a volume label in memory
534 void create_volume_label(DEVICE *dev, const char *VolName, const char *PoolName)
536 DEVRES *device = (DEVRES *)dev->device;
538 Dmsg0(90, "Start create_volume_label()\n");
542 free_volume(dev); /* release any old volume */
543 memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
545 bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
546 dev->VolHdr.VerNum = BaculaTapeVersion;
547 dev->VolHdr.LabelType = PRE_LABEL; /* Mark tape as unused */
548 bstrncpy(dev->VolHdr.VolumeName, VolName, sizeof(dev->VolHdr.VolumeName));
549 bstrncpy(dev->VolHdr.PoolName, PoolName, sizeof(dev->VolHdr.PoolName));
550 bstrncpy(dev->VolHdr.MediaType, device->media_type, sizeof(dev->VolHdr.MediaType));
552 bstrncpy(dev->VolHdr.PoolType, "Backup", sizeof(dev->VolHdr.PoolType));
554 dev->VolHdr.label_btime = get_current_btime();
555 dev->VolHdr.label_date = 0;
556 dev->VolHdr.label_time = 0;
558 if (gethostname(dev->VolHdr.HostName, sizeof(dev->VolHdr.HostName)) != 0) {
559 dev->VolHdr.HostName[0] = 0;
561 bstrncpy(dev->VolHdr.LabelProg, my_name, sizeof(dev->VolHdr.LabelProg));
562 sprintf(dev->VolHdr.ProgVersion, "Ver. %s %s", VERSION, BDATE);
563 sprintf(dev->VolHdr.ProgDate, "Build %s %s", __DATE__, __TIME__);
564 dev->set_labeled(); /* set has Bacula label */
565 if (debug_level >= 90) {
566 dump_volume_label(dev);
571 * Create session label
572 * The pool memory must be released by the calling program
574 void create_session_label(DCR *dcr, DEV_RECORD *rec, int label)
579 rec->VolSessionId = jcr->VolSessionId;
580 rec->VolSessionTime = jcr->VolSessionTime;
581 rec->Stream = jcr->JobId;
583 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
584 ser_begin(rec->data, SER_LENGTH_Session_Label);
585 ser_string(BaculaId);
586 ser_uint32(BaculaTapeVersion);
588 ser_uint32(jcr->JobId);
590 /* Changed in VerNum 11 */
591 ser_btime(get_current_btime());
594 ser_string(dcr->pool_name);
595 ser_string(dcr->pool_type);
596 ser_string(jcr->job_name); /* base Job name */
597 ser_string(jcr->client_name);
599 /* Added in VerNum 10 */
600 ser_string(jcr->Job); /* Unique name of this Job */
601 ser_string(jcr->fileset_name);
602 ser_uint32(jcr->JobType);
603 ser_uint32(jcr->JobLevel);
604 /* Added in VerNum 11 */
605 ser_string(jcr->fileset_md5);
607 if (label == EOS_LABEL) {
608 ser_uint32(jcr->JobFiles);
609 ser_uint64(jcr->JobBytes);
610 ser_uint32(dcr->StartBlock);
611 ser_uint32(dcr->EndBlock);
612 ser_uint32(dcr->StartFile);
613 ser_uint32(dcr->EndFile);
614 ser_uint32(jcr->JobErrors);
616 /* Added in VerNum 11 */
617 ser_uint32(jcr->JobStatus);
619 ser_end(rec->data, SER_LENGTH_Session_Label);
620 rec->data_len = ser_length(rec->data);
623 /* Write session label
624 * Returns: false on failure
627 bool write_session_label(DCR *dcr, int label)
630 DEVICE *dev = dcr->dev;
632 DEV_BLOCK *block = dcr->block;
633 char buf1[100], buf2[100];
636 Dmsg1(90, "session_label record=%x\n", rec);
639 if (dev->is_tape()) {
640 dcr->StartBlock = dev->block_num;
641 dcr->StartFile = dev->file;
643 dcr->StartBlock = (uint32_t)dev->file_addr;
644 dcr->StartFile = (uint32_t)(dev->file_addr >> 32);
648 if (dev->is_tape()) {
649 dcr->EndBlock = dev->EndBlock;
650 dcr->EndFile = dev->EndFile;
652 dcr->EndBlock = (uint32_t)dev->file_addr;
653 dcr->EndFile = (uint32_t)(dev->file_addr >> 32);
657 Jmsg1(jcr, M_ABORT, 0, _("Bad session label = %d\n"), label);
660 create_session_label(dcr, rec, label);
661 rec->FileIndex = label;
664 * We guarantee that the session record can totally fit
665 * into a block. If not, write the block, and put it in
666 * the next block. Having the sesssion record totally in
667 * one block makes reading them much easier (no need to
668 * read the next block).
670 if (!can_write_record_to_block(block, rec)) {
671 Dmsg0(100, "Cannot write session label to block.\n");
672 if (!write_block_to_device(dcr)) {
673 Dmsg0(90, "Got session label write_block_to_dev error.\n");
674 /* ****FIXME***** errno is not set here */
675 Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"),
676 dev_vol_name(dev), strerror(errno));
681 if (!write_record_to_block(block, rec)) {
682 Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"),
683 dev_vol_name(dev), strerror(errno));
688 Dmsg6(20, "Write sesson_label record JobId=%d FI=%s SessId=%d Strm=%s len=%d "
689 "remainder=%d\n", jcr->JobId,
690 FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
691 stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
695 Dmsg2(20, "Leave write_session_label Block=%d File=%d\n",
696 dev->block_num, dev->file);
700 /* unser_volume_label
702 * Unserialize the Bacula Volume label into the device Volume_Label
705 * Assumes that the record is already read.
707 * Returns: false on error
711 bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec)
714 char buf1[100], buf2[100];
716 if (rec->FileIndex != VOL_LABEL && rec->FileIndex != PRE_LABEL) {
717 Mmsg3(dev->errmsg, _("Expecting Volume Label, got FI=%s Stream=%s len=%d\n"),
718 FI_to_ascii(buf1, rec->FileIndex),
719 stream_to_ascii(buf2, rec->Stream, rec->FileIndex),
726 dev->VolHdr.LabelType = rec->FileIndex;
727 dev->VolHdr.LabelSize = rec->data_len;
730 /* Unserialize the record into the Volume Header */
731 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
732 ser_begin(rec->data, SER_LENGTH_Volume_Label);
733 unser_string(dev->VolHdr.Id);
734 unser_uint32(dev->VolHdr.VerNum);
736 if (dev->VolHdr.VerNum >= 11) {
737 unser_btime(dev->VolHdr.label_btime);
738 unser_btime(dev->VolHdr.write_btime);
739 } else { /* old way */
740 unser_float64(dev->VolHdr.label_date);
741 unser_float64(dev->VolHdr.label_time);
743 unser_float64(dev->VolHdr.write_date); /* Unused with VerNum >= 11 */
744 unser_float64(dev->VolHdr.write_time); /* Unused with VerNum >= 11 */
746 unser_string(dev->VolHdr.VolumeName);
747 unser_string(dev->VolHdr.PrevVolumeName);
748 unser_string(dev->VolHdr.PoolName);
749 unser_string(dev->VolHdr.PoolType);
750 unser_string(dev->VolHdr.MediaType);
752 unser_string(dev->VolHdr.HostName);
753 unser_string(dev->VolHdr.LabelProg);
754 unser_string(dev->VolHdr.ProgVersion);
755 unser_string(dev->VolHdr.ProgDate);
757 ser_end(rec->data, SER_LENGTH_Volume_Label);
758 Dmsg0(190, "unser_vol_label\n");
759 if (debug_level >= 190) {
760 dump_volume_label(dev);
766 bool unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec)
770 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
771 unser_begin(rec->data, SER_LENGTH_Session_Label);
772 unser_string(label->Id);
773 unser_uint32(label->VerNum);
774 unser_uint32(label->JobId);
775 if (label->VerNum >= 11) {
776 unser_btime(label->write_btime);
778 unser_float64(label->write_date);
780 unser_float64(label->write_time);
781 unser_string(label->PoolName);
782 unser_string(label->PoolType);
783 unser_string(label->JobName);
784 unser_string(label->ClientName);
785 if (label->VerNum >= 10) {
786 unser_string(label->Job); /* Unique name of this Job */
787 unser_string(label->FileSetName);
788 unser_uint32(label->JobType);
789 unser_uint32(label->JobLevel);
791 if (label->VerNum >= 11) {
792 unser_string(label->FileSetMD5);
794 label->FileSetMD5[0] = 0;
796 if (rec->FileIndex == EOS_LABEL) {
797 unser_uint32(label->JobFiles);
798 unser_uint64(label->JobBytes);
799 unser_uint32(label->StartBlock);
800 unser_uint32(label->EndBlock);
801 unser_uint32(label->StartFile);
802 unser_uint32(label->EndFile);
803 unser_uint32(label->JobErrors);
804 if (label->VerNum >= 11) {
805 unser_uint32(label->JobStatus);
807 label->JobStatus = JS_Terminated; /* kludge */
813 void dump_volume_label(DEVICE *dev)
815 int dbl = debug_level;
817 const char *LabelType;
824 switch (dev->VolHdr.LabelType) {
826 LabelType = "PRE_LABEL";
829 LabelType = "VOL_LABEL";
832 LabelType = "EOM_LABEL";
835 LabelType = "SOS_LABEL";
838 LabelType = "EOS_LABEL";
844 sprintf(buf, _("Unknown %d"), dev->VolHdr.LabelType);
848 Pmsg11(-1, _("\nVolume Label:\n"
861 dev->VolHdr.Id, dev->VolHdr.VerNum,
862 dev->VolHdr.VolumeName, dev->VolHdr.PrevVolumeName,
863 File, LabelType, dev->VolHdr.LabelSize,
864 dev->VolHdr.PoolName, dev->VolHdr.MediaType,
865 dev->VolHdr.PoolType, dev->VolHdr.HostName);
867 if (dev->VolHdr.VerNum >= 11) {
869 bstrftime(dt, sizeof(dt), btime_to_unix(dev->VolHdr.label_btime));
870 Pmsg1(-1, _("Date label written: %s\n"), dt);
872 dt.julian_day_number = dev->VolHdr.label_date;
873 dt.julian_day_fraction = dev->VolHdr.label_time;
876 _("Date label written: %04d-%02d-%02d at %02d:%02d\n"),
877 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
885 static void dump_session_label(DEV_RECORD *rec, const char *type)
891 char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], ec6[30], ec7[30];
893 unser_session_label(&label, rec);
896 Pmsg7(-1, _("\n%s Record:\n"
903 ""), type, label.JobId, label.VerNum,
904 label.PoolName, label.PoolType,
905 label.JobName, label.ClientName);
907 if (label.VerNum >= 10) {
909 "Job (unique name) : %s\n"
913 ""), label.Job, label.FileSetName, label.JobType, label.JobLevel);
916 if (rec->FileIndex == EOS_LABEL) {
927 edit_uint64_with_commas(label.JobFiles, ec1),
928 edit_uint64_with_commas(label.JobBytes, ec2),
929 edit_uint64_with_commas(label.StartBlock, ec3),
930 edit_uint64_with_commas(label.EndBlock, ec4),
931 edit_uint64_with_commas(label.StartFile, ec5),
932 edit_uint64_with_commas(label.EndFile, ec6),
933 edit_uint64_with_commas(label.JobErrors, ec7),
936 if (label.VerNum >= 11) {
938 bstrftime(dt, sizeof(dt), btime_to_unix(label.write_btime));
939 Pmsg1(-1, _("Date written : %s\n"), dt);
941 dt.julian_day_number = label.write_date;
942 dt.julian_day_fraction = label.write_time;
944 Pmsg5(-1, _("Date written : %04d-%02d-%02d at %02d:%02d\n"),
945 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
951 void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose)
956 if (rec->FileIndex == 0 && rec->VolSessionId == 0 && rec->VolSessionTime == 0) {
961 switch (rec->FileIndex) {
963 type = _("Fresh Volume");
969 type = _("Begin Job Session");
972 type = _("End Job Session");
975 type = _("End of Media");
978 type = _("End of Tape");
985 switch (rec->FileIndex) {
988 unser_volume_label(dev, rec);
989 dump_volume_label(dev);
992 dump_session_label(rec, type);
995 dump_session_label(rec, type);
998 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
999 type, dev->file, dev->block_num, rec->VolSessionId,
1000 rec->VolSessionTime, rec->Stream, rec->data_len);
1003 Pmsg0(-1, _("End of physical tape.\n"));
1006 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1007 type, dev->file, dev->block_num, rec->VolSessionId,
1008 rec->VolSessionTime, rec->Stream, rec->data_len);
1012 SESSION_LABEL label;
1014 switch (rec->FileIndex) {
1016 unser_session_label(&label, rec);
1017 bstrftimes(dt, sizeof(dt), btime_to_unix(label.write_btime));
1018 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1019 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1020 Pmsg4(-1, _(" Job=%s Date=%s Level=%c Type=%c\n"),
1021 label.Job, dt, label.JobLevel, label.JobType);
1024 char ed1[30], ed2[30];
1025 unser_session_label(&label, rec);
1026 bstrftimes(dt, sizeof(dt), btime_to_unix(label.write_btime));
1027 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1028 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1029 Pmsg7(-1, _(" Date=%s Level=%c Type=%c Files=%s Bytes=%s Errors=%d Status=%c\n"),
1030 dt, label.JobLevel, label.JobType,
1031 edit_uint64_with_commas(label.JobFiles, ed1),
1032 edit_uint64_with_commas(label.JobBytes, ed2),
1033 label.JobErrors, (char)label.JobStatus);
1039 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1040 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime,
1041 rec->Stream, rec->data_len);