2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2017 Kern Sibbald
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
21 * label.c Bacula routines to handle labels
27 #include "bacula.h" /* pull in global headers */
28 #include "stored.h" /* pull in Storage Deamon headers */
30 static const int dbglvl = 100;
32 /* Forward referenced functions */
33 static void create_volume_label_record(DCR *dcr, DEVICE *dev, DEV_RECORD *rec, bool adata);
36 * Read the volume label
38 * If dcr->VolumeName == NULL, we accept any Bacula Volume
39 * If dcr->VolumeName[0] == 0, we accept any Bacula Volume
40 * otherwise dcr->VolumeName must match the Volume.
42 * If VolName given, ensure that it matches
44 * Returns VOL_ code as defined in record.h
46 * VOL_OK good label found
47 * VOL_NO_LABEL volume not labeled
48 * VOL_IO_ERROR I/O error reading tape
49 * VOL_NAME_ERROR label has wrong name
50 * VOL_CREATE_ERROR Error creating label
51 * VOL_VERSION_ERROR label has wrong version
52 * VOL_LABEL_ERROR bad label type
53 * VOL_NO_MEDIA no media in drive
54 * VOL_TYPE_ERROR aligned/non-aligned/dedup error
56 * The dcr block is emptied on return, and the Volume is
59 * Handle both the ameta and adata volumes.
61 int DEVICE::read_dev_volume_label(DCR *dcr)
64 char *VolName = dcr->VolumeName;
67 DEV_BLOCK *block = dcr->block;
70 bool have_ansi_label = false;
73 Dmsg5(dbglvl, "Enter read_volume_label adata=%d res=%d device=%s vol=%s dev_Vol=%s\n",
74 block->adata, num_reserved(), print_name(), VolName,
75 VolHdr.VolumeName[0]?VolHdr.VolumeName:"*NULL*");
78 if (!open_device(dcr, OPEN_READ_ONLY)) {
87 label_type = B_BACULA_LABEL;
90 Mmsg(jcr->errmsg, _("Couldn't rewind %s device %s: ERR=%s\n"),
91 print_type(), print_name(), print_errmsg());
92 Dmsg1(dbglvl, "return VOL_NO_MEDIA: %s", jcr->errmsg);
96 bstrncpy(VolHdr.Id, "**error**", sizeof(VolHdr.Id));
98 /* Read ANSI/IBM label if so requested */
99 want_ansi_label = dcr->VolCatInfo.LabelType != B_BACULA_LABEL ||
100 dcr->device->label_type != B_BACULA_LABEL;
101 if (want_ansi_label || has_cap(CAP_CHECKLABELS)) {
102 stat = read_ansi_ibm_label(dcr);
103 /* If we want a label and didn't find it, return error */
104 if (want_ansi_label && stat != VOL_OK) {
107 if (stat == VOL_NAME_ERROR || stat == VOL_LABEL_ERROR) {
108 Mmsg(jcr->errmsg, _("Wrong Volume mounted on %s device %s: Wanted %s have %s\n"),
109 print_type(), print_name(), VolName, VolHdr.VolumeName);
110 if (!poll && jcr->label_errors++ > 100) {
111 Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
115 if (stat != VOL_OK) { /* Not an ANSI/IBM label, so re-read */
118 have_ansi_label = true;
122 /* Read the Bacula Volume label block */
123 record = new_record();
126 Dmsg0(130, "Big if statement in read_volume_label\n");
127 dcr->reading_label = true;
128 if (!dcr->read_block_from_dev(NO_BLOCK_NUMBER_CHECK)) {
129 Mmsg(jcr->errmsg, _("Read label block failed: requested Volume \"%s\" on %s device %s is not a Bacula "
130 "labeled Volume, because: ERR=%s"), NPRT(VolName),
131 print_type(), print_name(), print_errmsg());
132 Dmsg1(dbglvl, "%s", jcr->errmsg);
133 } else if (!read_record_from_block(dcr, record)) {
134 Mmsg(jcr->errmsg, _("Could not read Volume label from block.\n"));
135 Dmsg1(dbglvl, "%s", jcr->errmsg);
136 } else if (!unser_volume_label(this, record)) {
137 Mmsg(jcr->errmsg, _("Could not unserialize Volume label: ERR=%s\n"),
139 Dmsg1(dbglvl, "%s", jcr->errmsg);
140 } else if (strcmp(VolHdr.Id, BaculaId) != 0 &&
141 strcmp(VolHdr.Id, OldBaculaId) != 0 &&
142 strcmp(VolHdr.Id, BaculaMetaDataId) != 0 &&
143 strcmp(VolHdr.Id, BaculaAlignedDataId) != 0 &&
144 strcmp(VolHdr.Id, BaculaS3CloudId) != 0) {
145 Mmsg(jcr->errmsg, _("Volume Header Id bad: %s\n"), VolHdr.Id);
146 Dmsg1(dbglvl, "%s", jcr->errmsg);
149 Dmsg1(dbglvl, "VolHdr.Id OK: %s\n", VolHdr.Id);
151 dcr->reading_label = false;
152 free_record(record); /* finished reading Volume record */
154 if (!is_volume_to_unload()) {
159 if (jcr->ignore_label_errors) {
160 set_labeled(); /* set has Bacula label */
161 if (jcr->errmsg[0]) {
162 Jmsg(jcr, M_ERROR, 0, "%s", jcr->errmsg);
168 Dmsg0(dbglvl, "No volume label - bailing out\n");
173 /* At this point, we have read the first Bacula block, and
174 * then read the Bacula Volume label. Now we need to
175 * make sure we have the right Volume.
177 if (VolHdr.VerNum != BaculaTapeVersion &&
178 VolHdr.VerNum != BaculaMetaDataVersion &&
179 VolHdr.VerNum != BaculaS3CloudVersion &&
180 VolHdr.VerNum != OldCompatibleBaculaTapeVersion1 &&
181 VolHdr.VerNum != OldCompatibleBaculaTapeVersion2) {
182 Mmsg(jcr->errmsg, _("Volume on %s device %s has wrong Bacula version. Wanted %d got %d\n"),
183 print_type(), print_name(), BaculaTapeVersion, VolHdr.VerNum);
184 Dmsg1(dbglvl, "VOL_VERSION_ERROR: %s", jcr->errmsg);
185 stat = VOL_VERSION_ERROR;
188 Dmsg1(dbglvl, "VolHdr.VerNum=%ld OK.\n", VolHdr.VerNum);
190 /* We are looking for either an unused Bacula tape (PRE_LABEL) or
191 * a Bacula volume label (VOL_LABEL)
193 if (VolHdr.LabelType != PRE_LABEL && VolHdr.LabelType != VOL_LABEL) {
194 Mmsg(jcr->errmsg, _("Volume on %s device %s has bad Bacula label type: %ld\n"),
195 print_type(), print_name(), VolHdr.LabelType);
196 Dmsg1(dbglvl, "%s", jcr->errmsg);
197 if (!poll && jcr->label_errors++ > 100) {
198 Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
200 Dmsg0(dbglvl, "return VOL_LABEL_ERROR\n");
201 stat = VOL_LABEL_ERROR;
205 set_labeled(); /* set has Bacula label */
207 /* Compare Volume Names */
208 Dmsg2(130, "Compare Vol names: VolName=%s hdr=%s\n", VolName?VolName:"*", VolHdr.VolumeName);
209 if (VolName && *VolName && *VolName != '*' && strcmp(VolHdr.VolumeName, VolName) != 0) {
210 Mmsg(jcr->errmsg, _("Wrong Volume mounted on %s device %s: Wanted %s have %s\n"),
211 print_type(), print_name(), VolName, VolHdr.VolumeName);
212 Dmsg1(dbglvl, "%s", jcr->errmsg);
214 * Cancel Job if too many label errors
215 * => we are in a loop
217 if (!poll && jcr->label_errors++ > 100) {
218 Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
220 Dmsg0(dbglvl, "return VOL_NAME_ERROR\n");
221 stat = VOL_NAME_ERROR;
225 /* Compare VolType to Device Type */
228 if (strcmp(VolHdr.Id, BaculaId) != 0) {
229 Mmsg(jcr->errmsg, _("Wrong Volume Type. Wanted a File or Tape Volume %s on device %s, but got: %s\n"),
230 VolHdr.VolumeName, print_name(), VolHdr.Id);
231 stat = VOL_TYPE_ERROR;
237 if (strcmp(VolHdr.Id, BaculaMetaDataId) != 0) {
238 Mmsg(jcr->errmsg, _("Wrong Volume Type. Wanted an Aligned Volume %s on device %s, but got: %s\n"),
239 VolHdr.VolumeName, print_name(), VolHdr.Id);
240 stat = VOL_TYPE_ERROR;
245 if (strcmp(VolHdr.Id, BaculaS3CloudId) != 0) {
246 Mmsg(jcr->errmsg, _("Wrong Volume Type. Wanted a Cloud Volume %s on device %s, but got: %s\n"),
247 VolHdr.VolumeName, print_name(), VolHdr.Id);
248 stat = VOL_TYPE_ERROR;
255 if (chk_dbglvl(100)) {
258 Dmsg0(dbglvl, "Leave read_volume_label() VOL_OK\n");
259 /* If we are a streaming device, we only get one chance to read */
260 if (!has_cap(CAP_STREAM)) {
262 if (have_ansi_label) {
263 stat = read_ansi_ibm_label(dcr);
264 /* If we want a label and didn't find it, return error */
265 if (stat != VOL_OK) {
271 Dmsg1(100, "Call reserve_volume=%s\n", VolHdr.VolumeName);
272 if (reserve_volume(dcr, VolHdr.VolumeName) == NULL) {
273 if (!jcr->errmsg[0]) {
274 Mmsg3(jcr->errmsg, _("Could not reserve volume %s on %s device %s\n"),
275 VolHdr.VolumeName, print_type(), print_name());
277 Dmsg2(dbglvl, "Could not reserve volume %s on %s\n", VolHdr.VolumeName, print_name());
278 stat = VOL_NAME_ERROR;
290 Dmsg2(dbglvl, "return stat=%d %s", stat, jcr->errmsg);
297 * Create and put a volume label into the block
299 * Returns: false on failure
302 * Handle both the ameta and adata volumes.
304 bool DEVICE::write_volume_label_to_block(DCR *dcr)
315 memset(&rec, 0, sizeof(rec));
316 rec.data = get_memory(SER_LENGTH_Volume_Label);
317 memset(rec.data, 0, SER_LENGTH_Volume_Label);
318 empty_block(block); /* Volume label always at beginning */
320 create_volume_label_record(dcr, dcr->dev, &rec, dcr->block->adata);
322 block->BlockNumber = 0;
323 /* Note for adata this also writes to disk */
324 Dmsg1(100, "write_record_to_block adata=%d\n", dcr->dev->adata);
325 if (!write_record_to_block(dcr, &rec)) {
326 free_pool_memory(rec.data);
327 Jmsg2(jcr, M_FATAL, 0, _("Cannot write Volume label to block for %s device %s\n"),
328 dev->print_type(), dev->print_name());
332 Dmsg4(100, "Wrote fd=%d adata=%d label of %d bytes to block. Vol=%s\n",
333 dev->fd(), block->adata, rec.data_len, dcr->VolumeName);
335 free_pool_memory(rec.data);
343 * Write a Volume Label
344 * !!! Note, this is ONLY used for writing
345 * a fresh volume label. Any data
346 * after the label will be destroyed,
347 * in fact, we write the label 5 times !!!!
349 * This routine should be used only when labeling a blank tape or
350 * when recylcing a volume.
352 * Handle both the ameta and adata volumes.
354 bool DEVICE::write_volume_label(DCR *dcr, const char *VolName,
355 const char *PoolName, bool relabel, bool no_prelabel)
360 Dmsg4(230, "Write: block=%p ameta=%p dev=%p ameta_dev=%p\n",
361 dcr->block, dcr->ameta_block, dcr->dev, dcr->ameta_dev);
365 Dmsg0(150, "write_volume_label()\n");
368 Mmsg(dcr->jcr->errmsg, "ERROR: new_volume_label_to_dev called with NULL VolName\n");
370 Pmsg0(0, "=== ERROR: write_volume_label called with NULL VolName\n");
375 volume_unused(dcr); /* mark current volume unused */
376 /* Truncate device */
377 if (!dev->truncate(dcr)) {
380 dev->close_part(dcr); /* make sure closed for rename */
383 /* Set the new filename for open, ... */
384 dev->setVolCatName(VolName);
385 dcr->setVolCatName(VolName);
386 dev->clearVolCatBytes();
388 Dmsg1(100, "New VolName=%s\n", VolName);
389 if (!dev->open_device(dcr, OPEN_READ_WRITE)) {
390 /* If device is not tape, attempt to create it */
391 if (dev->is_tape() || !dev->open_device(dcr, CREATE_READ_WRITE)) {
392 Jmsg4(dcr->jcr, M_WARNING, 0, _("Open %s device %s Volume \"%s\" failed: ERR=%s"),
393 dev->print_type(), dev->print_name(), dcr->VolumeName, dev->bstrerror());
397 Dmsg1(150, "Label type=%d\n", dev->label_type);
399 if (!write_volume_label_to_dev(dcr, VolName, PoolName, relabel, no_prelabel)) {
403 /* Not aligned data */
404 if (dev->weof(dcr, 1)) {
408 if (chk_dbglvl(100)) {
409 dev->dump_volume_label();
411 Dmsg0(50, "Call reserve_volume\n");
412 /**** ***FIXME*** if dev changes, dcr must be updated */
413 if (reserve_volume(dcr, VolName) == NULL) {
414 if (!dcr->jcr->errmsg[0]) {
415 Mmsg3(dcr->jcr->errmsg, _("Could not reserve volume %s on %s device %s\n"),
416 dev->VolHdr.VolumeName, dev->print_type(), dev->print_name());
418 Dmsg1(50, "%s", dcr->jcr->errmsg);
421 dev = dcr->dev; /* may have changed in reserve_volume */
422 dev->clear_append(); /* remove append since this is PRE_LABEL */
427 dcr->adata_label = false;
430 dcr->dev->clear_append(); /* remove append since this is PRE_LABEL */
435 bool DEVICE::write_volume_label_to_dev(DCR *dcr, const char *VolName,
436 const char *PoolName, bool relabel, bool no_prelabel)
438 DEVICE *dev, *ameta_dev;
440 DEV_RECORD *rec = new_record();
445 ameta_dev = dcr->ameta_dev;
449 if (!dev->rewind(dcr)) {
450 Dmsg2(130, "Bad status on %s from rewind: ERR=%s\n", dev->print_name(), dev->print_errmsg());
454 /* Temporarily mark in append state to enable writing */
457 /* Create PRE_LABEL or VOL_LABEL */
458 create_volume_header(dev, VolName, PoolName, no_prelabel);
461 * If we have already detected an ANSI label, re-read it
462 * to skip past it. Otherwise, we write a new one if
466 if (dev->label_type != B_BACULA_LABEL) {
467 if (read_ansi_ibm_label(dcr) != VOL_OK) {
471 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, VolName)) {
476 create_volume_label_record(dcr, dev, rec, block->adata);
478 rec->maskedStream = 0;
480 Dmsg2(100, "write_record_to_block adata=%d FI=%d\n", dcr->dev->adata,
483 /* For adata label this also writes to disk */
484 if (!write_record_to_block(dcr, rec)) {
485 Dmsg2(40, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
488 Dmsg3(100, "Wrote label=%d bytes adata=%d block: %s\n", rec->data_len, block->adata, dev->print_name());
490 Dmsg3(100, "New label adata=%d VolCatBytes=%lld VolCatStatus=%s\n",
491 dev->adata, ameta_dev->VolCatInfo.VolCatBytes, ameta_dev->VolCatInfo.VolCatStatus);
494 /* Empty block and set data start address */
495 empty_block(dcr->adata_block);
497 Dmsg4(130, "Call write_block_to_dev() fd=%d adata=%d block=%p Addr=%lld\n",
498 dcr->dev->fd(), dcr->block->adata, dcr->block, block->dev->lseek(dcr, 0, SEEK_CUR));
499 Dmsg1(100, "write_record_to_dev adata=%d\n", dcr->dev->adata);
500 /* Write ameta block to device */
501 if (!dcr->write_block_to_dev()) {
502 Dmsg2(40, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
506 Dmsg3(100, "Wrote new Vol label adata=%d VolCatBytes=%lld VolCatStatus=%s\n",
507 dev->adata, ameta_dev->VolCatInfo.VolCatBytes, ameta_dev->VolCatInfo.VolCatStatus);
517 * Write a volume label. This is ONLY called if we have a valid Bacula
518 * label of type PRE_LABEL or we are recyling an existing Volume.
520 * By calling write_volume_label_to_block, both ameta and adata
523 * Returns: true if OK
524 * false if unable to write it
526 bool DEVICE::rewrite_volume_label(DCR *dcr, bool recycle)
532 ASSERT2(dcr->VolumeName[0], "Empty Volume name");
533 ASSERT(!dcr->block->adata);
534 if (!open_device(dcr, OPEN_READ_WRITE)) {
535 Jmsg4(jcr, M_WARNING, 0, _("Open %s device %s Volume \"%s\" failed: ERR=%s\n"),
536 print_type(), print_name(), dcr->VolumeName, bstrerror());
540 Dmsg2(190, "set append found freshly labeled volume. fd=%d dev=%x\n", fd(), this);
541 VolHdr.LabelType = VOL_LABEL; /* set Volume label */
543 Dmsg0(100, "Rewrite_volume_label set volcatbytes=0\n");
544 clearVolCatBytes(); /* resets both ameta and adata byte counts */
545 setVolCatStatus("Append"); /* set append status */
547 if (!has_cap(CAP_STREAM)) {
549 Jmsg3(jcr, M_FATAL, 0, _("Rewind error on %s device %s: ERR=%s\n"),
550 print_type(), print_name(), print_errmsg());
555 Dmsg1(150, "Doing recycle. Vol=%s\n", dcr->VolumeName);
556 if (!truncate(dcr)) {
557 Jmsg3(jcr, M_FATAL, 0, _("Truncate error on %s device %s: ERR=%s\n"),
558 print_type(), print_name(), print_errmsg());
562 if (!open_device(dcr, OPEN_READ_WRITE)) {
563 Jmsg3(jcr, M_FATAL, 0,
564 _("Failed to re-open device after truncate on %s device %s: ERR=%s"),
565 print_type(), print_name(), print_errmsg());
572 if (!write_volume_label_to_block(dcr)) {
573 Dmsg0(150, "Error from write volume label.\n");
577 Dmsg2(100, "wrote vol label to block. adata=%d Vol=%s\n", dcr->block->adata, dcr->VolumeName);
579 ASSERT2(dcr->VolumeName[0], "Empty Volume name");
580 setVolCatInfo(false);
583 * If we are not dealing with a streaming device,
584 * write the block now to ensure we have write permission.
585 * It is better to find out now rather than later.
586 * We do not write the block now if this is an ANSI label. This
587 * avoids re-writing the ANSI label, which we do not want to do.
589 if (!has_cap(CAP_STREAM)) {
591 * If we have already detected an ANSI label, re-read it
592 * to skip past it. Otherwise, we write a new one if
595 if (label_type != B_BACULA_LABEL) {
596 if (read_ansi_ibm_label(dcr) != VOL_OK) {
601 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, VolHdr.VolumeName)) {
606 /* Attempt write to check write permission */
607 Dmsg1(200, "Attempt to write to device fd=%d.\n", fd());
608 if (!dcr->write_block_to_dev()) {
609 Jmsg3(jcr, M_ERROR, 0, _("Unable to write %s device %s: ERR=%s\n"),
610 print_type(), print_name(), print_errmsg());
611 Dmsg0(200, "===ERROR write block to dev\n");
616 ASSERT2(dcr->VolumeName[0], "Empty Volume name");
617 setVolCatName(dcr->VolumeName);
618 if (!dir_get_volume_info(dcr, dcr->VolumeName, GET_VOL_INFO_FOR_WRITE)) {
623 /* Set or reset Volume statistics */
624 VolCatInfo.VolCatJobs = 0;
625 VolCatInfo.VolCatFiles = 0;
626 VolCatInfo.VolCatErrors = 0;
627 VolCatInfo.VolCatBlocks = 0;
628 VolCatInfo.VolCatRBytes = 0;
629 VolCatInfo.VolCatCloudParts = 0;
630 VolCatInfo.VolLastPartBytes = 0;
631 VolCatInfo.VolCatType = 0; /* Will be set by dir_update_volume_info() */
633 VolCatInfo.VolCatMounts++;
634 VolCatInfo.VolCatRecycles++;
636 VolCatInfo.VolCatMounts = 1;
637 VolCatInfo.VolCatRecycles = 0;
638 VolCatInfo.VolCatWrites = 1;
639 VolCatInfo.VolCatReads = 1;
641 dcr->VolMediaId = dcr->VolCatInfo.VolMediaId; /* make create_jobmedia work */
642 dir_create_jobmedia_record(dcr, true);
643 Dmsg1(100, "dir_update_vol_info. Set Append vol=%s\n", dcr->VolumeName);
644 VolCatInfo.VolFirstWritten = time(NULL);
645 setVolCatStatus("Append");
646 if (!dir_update_volume_info(dcr, true, true)) { /* indicate relabel */
651 Jmsg(jcr, M_INFO, 0, _("Recycled volume \"%s\" on %s device %s, all previous data lost.\n"),
652 dcr->VolumeName, print_type(), print_name());
654 Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume \"%s\" on %s device %s\n"),
655 dcr->VolumeName, print_type(), print_name());
658 * End writing real Volume label (from pre-labeled tape), or recycling
661 Dmsg4(100, "OK rewrite vol label. Addr=%s adata=%d slot=%d Vol=%s\n",
662 print_addr(ed1, sizeof(ed1)), dcr->block->adata, VolCatInfo.Slot, dcr->VolumeName);
669 * create_volume_label_record
670 * Note: it is assumed that you have created the volume_header
671 * (label) prior to calling this subroutine.
672 * Serialize label (from dev->VolHdr structure) into device record.
673 * Assumes that the dev->VolHdr structure is properly
676 static void create_volume_label_record(DCR *dcr, DEVICE *dev,
677 DEV_RECORD *rec, bool adata)
684 /* Serialize the label into the device record. */
687 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
688 memset(rec->data, 0, SER_LENGTH_Volume_Label);
689 ser_begin(rec->data, SER_LENGTH_Volume_Label);
690 ser_string(dev->VolHdr.Id);
692 ser_uint32(dev->VolHdr.VerNum);
694 if (dev->VolHdr.VerNum >= 11) {
695 ser_btime(dev->VolHdr.label_btime);
696 dev->VolHdr.write_btime = get_current_btime();
697 ser_btime(dev->VolHdr.write_btime);
698 dev->VolHdr.write_date = 0;
699 dev->VolHdr.write_time = 0;
701 /* OLD WAY DEPRECATED */
702 ser_float64(dev->VolHdr.label_date);
703 ser_float64(dev->VolHdr.label_time);
704 get_current_time(&dt);
705 dev->VolHdr.write_date = dt.julian_day_number;
706 dev->VolHdr.write_time = dt.julian_day_fraction;
708 ser_float64(dev->VolHdr.write_date); /* 0 if VerNum >= 11 */
709 ser_float64(dev->VolHdr.write_time); /* 0 if VerNum >= 11 */
711 ser_string(dev->VolHdr.VolumeName);
712 ser_string(dev->VolHdr.PrevVolumeName);
713 ser_string(dev->VolHdr.PoolName);
714 ser_string(dev->VolHdr.PoolType);
715 ser_string(dev->VolHdr.MediaType);
717 ser_string(dev->VolHdr.HostName);
718 ser_string(dev->VolHdr.LabelProg);
719 ser_string(dev->VolHdr.ProgVersion);
720 ser_string(dev->VolHdr.ProgDate);
722 dev->VolHdr.AlignedVolumeName[0] = 0;
723 ser_string(dev->VolHdr.AlignedVolumeName);
725 /* This is adata Volume information */
726 ser_uint64(dev->VolHdr.FirstData);
727 ser_uint32(dev->VolHdr.FileAlignment);
728 ser_uint32(dev->VolHdr.PaddingSize);
729 /* adata and dedup volumes */
730 ser_uint32(dev->VolHdr.BlockSize);
732 ser_end(rec->data, SER_LENGTH_Volume_Label);
734 bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName));
736 ASSERT2(dcr->VolumeName[0], "Empty Volume name");
737 rec->data_len = ser_length(rec->data);
738 rec->FileIndex = dev->VolHdr.LabelType;
739 Dmsg2(100, "LabelType=%d adata=%d\n", dev->VolHdr.LabelType, dev->adata);
740 rec->VolSessionId = jcr->VolSessionId;
741 rec->VolSessionTime = jcr->VolSessionTime;
742 rec->Stream = jcr->NumWriteVolumes;
743 rec->maskedStream = jcr->NumWriteVolumes;
744 Dmsg3(100, "Created adata=%d Vol label rec: FI=%s len=%d\n", adata, FI_to_ascii(buf, rec->FileIndex),
746 Dmsg2(100, "reclen=%d recdata=%s", rec->data_len, rec->data);
752 * Create a volume header (label) in memory
753 * The volume record is created after this header (label)
756 void create_volume_header(DEVICE *dev, const char *VolName,
757 const char *PoolName, bool no_prelabel)
759 DEVRES *device = (DEVRES *)dev->device;
763 ASSERT2(dev != NULL, "dev ptr is NULL");
765 if (dev->is_aligned()) {
766 bstrncpy(dev->VolHdr.Id, BaculaMetaDataId, sizeof(dev->VolHdr.Id));
767 dev->VolHdr.VerNum = BaculaMetaDataVersion;
768 dev->VolHdr.FirstData = dev->file_alignment;
769 dev->VolHdr.FileAlignment = dev->file_alignment;
770 dev->VolHdr.PaddingSize = dev->padding_size;
771 dev->VolHdr.BlockSize = dev->adata_size;
772 } else if (dev->is_adata()) {
773 bstrncpy(dev->VolHdr.Id, BaculaAlignedDataId, sizeof(dev->VolHdr.Id));
774 dev->VolHdr.VerNum = BaculaAlignedDataVersion;
775 dev->VolHdr.FirstData = dev->file_alignment;
776 dev->VolHdr.FileAlignment = dev->file_alignment;
777 dev->VolHdr.PaddingSize = dev->padding_size;
778 dev->VolHdr.BlockSize = dev->adata_size;
779 } else if (dev->is_cloud()) {
780 bstrncpy(dev->VolHdr.Id, BaculaS3CloudId, sizeof(dev->VolHdr.Id));
781 dev->VolHdr.VerNum = BaculaS3CloudVersion;
782 dev->VolHdr.BlockSize = dev->max_block_size;
784 bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
785 dev->VolHdr.VerNum = BaculaTapeVersion;
786 dev->VolHdr.BlockSize = dev->max_block_size;
789 if (dev->has_cap(CAP_STREAM) && no_prelabel) {
790 /* We do not want to re-label so write VOL_LABEL now */
791 dev->VolHdr.LabelType = VOL_LABEL;
793 dev->VolHdr.LabelType = PRE_LABEL; /* Mark Volume as unused */
795 bstrncpy(dev->VolHdr.VolumeName, VolName, sizeof(dev->VolHdr.VolumeName));
796 bstrncpy(dev->VolHdr.PoolName, PoolName, sizeof(dev->VolHdr.PoolName));
797 bstrncpy(dev->VolHdr.MediaType, device->media_type, sizeof(dev->VolHdr.MediaType));
799 bstrncpy(dev->VolHdr.PoolType, "Backup", sizeof(dev->VolHdr.PoolType));
801 dev->VolHdr.label_btime = get_current_btime();
802 dev->VolHdr.label_date = 0;
803 dev->VolHdr.label_time = 0;
805 if (gethostname(dev->VolHdr.HostName, sizeof(dev->VolHdr.HostName)) != 0) {
806 dev->VolHdr.HostName[0] = 0;
808 bstrncpy(dev->VolHdr.LabelProg, my_name, sizeof(dev->VolHdr.LabelProg));
809 sprintf(dev->VolHdr.ProgVersion, "Ver. %s %s ", VERSION, BDATE);
810 sprintf(dev->VolHdr.ProgDate, "Build %s %s ", __DATE__, __TIME__);
811 dev->set_labeled(); /* set has Bacula label */
812 if (chk_dbglvl(100)) {
813 dev->dump_volume_label();
818 * Create session (Job) label
819 * The pool memory must be released by the calling program
821 void create_session_label(DCR *dcr, DEV_RECORD *rec, int label)
827 rec->VolSessionId = jcr->VolSessionId;
828 rec->VolSessionTime = jcr->VolSessionTime;
829 rec->Stream = jcr->JobId;
830 rec->maskedStream = jcr->JobId;
832 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
833 ser_begin(rec->data, SER_LENGTH_Session_Label);
834 ser_string(BaculaId);
835 ser_uint32(BaculaTapeVersion);
837 ser_uint32(jcr->JobId);
839 /* Changed in VerNum 11 */
840 ser_btime(get_current_btime());
843 ser_string(dcr->pool_name);
844 ser_string(dcr->pool_type);
845 ser_string(jcr->job_name); /* base Job name */
846 ser_string(jcr->client_name);
848 /* Added in VerNum 10 */
849 ser_string(jcr->Job); /* Unique name of this Job */
850 ser_string(jcr->fileset_name);
851 ser_uint32(jcr->getJobType());
852 ser_uint32(jcr->getJobLevel());
853 /* Added in VerNum 11 */
854 ser_string(jcr->fileset_md5);
856 if (label == EOS_LABEL) {
857 ser_uint32(jcr->JobFiles);
858 ser_uint64(jcr->JobBytes);
859 ser_uint32((uint32_t)dcr->StartAddr); /* Start Block */
860 ser_uint32((uint32_t)dcr->EndAddr); /* End Block */
861 ser_uint32((uint32_t)(dcr->StartAddr>>32)); /* Start File */
862 ser_uint32((uint32_t)(dcr->EndAddr>>32)); /* End File */
863 ser_uint32(jcr->JobErrors);
865 /* Added in VerNum 11 */
866 ser_uint32(jcr->JobStatus);
868 ser_end(rec->data, SER_LENGTH_Session_Label);
869 rec->data_len = ser_length(rec->data);
873 /* Write session (Job) label
874 * Returns: false on failure
877 bool write_session_label(DCR *dcr, int label)
880 DEVICE *dev = dcr->dev;
882 DEV_BLOCK *block = dcr->block;
883 char buf1[100], buf2[100];
887 Dmsg2(140, "=== write_session_label label=%d Vol=%s.\n", label, dev->getVolCatName());
888 if (!check_for_newvol_or_newfile(dcr)) {
889 Pmsg0(000, "ERR: !check_for_new_vol_or_newfile\n");
895 Dmsg1(130, "session_label record=%x\n", rec);
898 set_start_vol_position(dcr);
901 dcr->EndAddr = dev->get_full_addr();
904 Jmsg1(jcr, M_ABORT, 0, _("Bad Volume session label request=%d\n"), label);
908 create_session_label(dcr, rec, label);
909 rec->FileIndex = label;
913 * We guarantee that the session record can totally fit
914 * into a block. If not, write the block, and put it in
915 * the next block. Having the sesssion record totally in
916 * one block makes reading them much easier (no need to
917 * read the next block).
919 if (!can_write_record_to_block(block, rec)) {
920 Dmsg0(150, "Cannot write session label to block.\n");
921 if (!dcr->write_block_to_device()) {
922 Dmsg0(130, "Got session label write_block_to_dev error.\n");
929 * We use write_record() because it handles the case that
930 * the maximum user size has been reached.
932 if (!dcr->write_record(rec)) {
933 Dmsg0(150, "Bad return from write_record\n");
939 Dmsg6(150, "Write sesson_label record JobId=%d FI=%s SessId=%d Strm=%s len=%d "
940 "remainder=%d\n", jcr->JobId,
941 FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
942 stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
946 Dmsg2(150, "Leave write_session_label Block=%u File=%u\n",
947 dev->get_block_num(), dev->get_file());
952 /* unser_volume_label
954 * Unserialize the Bacula Volume label into the device Volume_Label
957 * Assumes that the record is already read.
959 * Returns: false on error
963 bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec)
966 char buf1[100], buf2[100];
969 if (rec->FileIndex != VOL_LABEL && rec->FileIndex != PRE_LABEL) {
970 Mmsg3(dev->errmsg, _("Expecting Volume Label, got FI=%s Stream=%s len=%d\n"),
971 FI_to_ascii(buf1, rec->FileIndex),
972 stream_to_ascii(buf2, rec->Stream, rec->FileIndex),
980 dev->VolHdr.LabelType = rec->FileIndex;
981 dev->VolHdr.LabelSize = rec->data_len;
984 /* Unserialize the record into the Volume Header */
985 Dmsg2(100, "reclen=%d recdata=%s", rec->data_len, rec->data);
986 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
987 Dmsg2(100, "reclen=%d recdata=%s", rec->data_len, rec->data);
988 ser_begin(rec->data, SER_LENGTH_Volume_Label);
989 unser_string(dev->VolHdr.Id);
990 unser_uint32(dev->VolHdr.VerNum);
992 if (dev->VolHdr.VerNum >= 11) {
993 unser_btime(dev->VolHdr.label_btime);
994 unser_btime(dev->VolHdr.write_btime);
995 } else { /* old way */
996 unser_float64(dev->VolHdr.label_date);
997 unser_float64(dev->VolHdr.label_time);
999 unser_float64(dev->VolHdr.write_date); /* Unused with VerNum >= 11 */
1000 unser_float64(dev->VolHdr.write_time); /* Unused with VerNum >= 11 */
1002 unser_string(dev->VolHdr.VolumeName);
1003 unser_string(dev->VolHdr.PrevVolumeName);
1004 unser_string(dev->VolHdr.PoolName);
1005 unser_string(dev->VolHdr.PoolType);
1006 unser_string(dev->VolHdr.MediaType);
1008 unser_string(dev->VolHdr.HostName);
1009 unser_string(dev->VolHdr.LabelProg);
1010 unser_string(dev->VolHdr.ProgVersion);
1011 unser_string(dev->VolHdr.ProgDate);
1013 // unser_string(dev->VolHdr.AlignedVolumeName);
1014 dev->VolHdr.AlignedVolumeName[0] = 0;
1015 unser_uint64(dev->VolHdr.FirstData);
1016 unser_uint32(dev->VolHdr.FileAlignment);
1017 unser_uint32(dev->VolHdr.PaddingSize);
1018 unser_uint32(dev->VolHdr.BlockSize);
1020 ser_end(rec->data, SER_LENGTH_Volume_Label);
1021 Dmsg0(190, "unser_vol_label\n");
1022 if (chk_dbglvl(100)) {
1023 dev->dump_volume_label();
1030 bool unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec)
1035 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
1036 unser_begin(rec->data, SER_LENGTH_Session_Label);
1037 unser_string(label->Id);
1038 unser_uint32(label->VerNum);
1039 unser_uint32(label->JobId);
1040 if (label->VerNum >= 11) {
1041 unser_btime(label->write_btime);
1043 unser_float64(label->write_date);
1045 unser_float64(label->write_time);
1046 unser_string(label->PoolName);
1047 unser_string(label->PoolType);
1048 unser_string(label->JobName);
1049 unser_string(label->ClientName);
1050 if (label->VerNum >= 10) {
1051 unser_string(label->Job); /* Unique name of this Job */
1052 unser_string(label->FileSetName);
1053 unser_uint32(label->JobType);
1054 unser_uint32(label->JobLevel);
1056 if (label->VerNum >= 11) {
1057 unser_string(label->FileSetMD5);
1059 label->FileSetMD5[0] = 0;
1061 if (rec->FileIndex == EOS_LABEL) {
1062 unser_uint32(label->JobFiles);
1063 unser_uint64(label->JobBytes);
1064 unser_uint32(label->StartBlock);
1065 unser_uint32(label->EndBlock);
1066 unser_uint32(label->StartFile);
1067 unser_uint32(label->EndFile);
1068 unser_uint32(label->JobErrors);
1069 if (label->VerNum >= 11) {
1070 unser_uint32(label->JobStatus);
1072 label->JobStatus = JS_Terminated; /* kludge */
1079 void DEVICE::dump_volume_label()
1081 int64_t dbl = debug_level;
1083 const char *LabelType;
1086 struct date_time dt;
1090 switch (VolHdr.LabelType) {
1092 LabelType = "PRE_LABEL";
1095 LabelType = "VOL_LABEL";
1098 LabelType = "EOM_LABEL";
1101 LabelType = "SOS_LABEL";
1104 LabelType = "EOS_LABEL";
1110 sprintf(buf, _("Unknown %d"), VolHdr.LabelType);
1114 Pmsg12(-1, _("\nVolume Label:\n"
1119 "PrevVolName : %s\n"
1129 VolHdr.Id, VolHdr.VerNum,
1130 VolHdr.VolumeName, VolHdr.PrevVolumeName,
1131 File, LabelType, VolHdr.LabelSize,
1132 VolHdr.PoolName, VolHdr.MediaType,
1133 VolHdr.PoolType, VolHdr.HostName);
1135 if (VolHdr.VerNum >= 11) {
1137 bstrftime(dt, sizeof(dt), btime_to_utime(VolHdr.label_btime));
1138 Pmsg1(-1, _("Date label written: %s\n"), dt);
1140 dt.julian_day_number = VolHdr.label_date;
1141 dt.julian_day_fraction = VolHdr.label_time;
1142 tm_decode(&dt, &tm);
1144 _("Date label written: %04d-%02d-%02d at %02d:%02d\n"),
1145 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
1153 static void dump_session_label(DEV_RECORD *rec, const char *type)
1156 struct date_time dt;
1158 SESSION_LABEL label;
1159 char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], ec6[30], ec7[30];
1161 unser_session_label(&label, rec);
1164 Pmsg7(-1, _("\n%s Record:\n"
1171 ""), type, label.JobId, label.VerNum,
1172 label.PoolName, label.PoolType,
1173 label.JobName, label.ClientName);
1175 if (label.VerNum >= 10) {
1177 "Job (unique name) : %s\n"
1181 ""), label.Job, label.FileSetName, label.JobType, label.JobLevel);
1184 if (rec->FileIndex == EOS_LABEL) {
1195 edit_uint64_with_commas(label.JobFiles, ec1),
1196 edit_uint64_with_commas(label.JobBytes, ec2),
1197 edit_uint64_with_commas(label.StartBlock, ec3),
1198 edit_uint64_with_commas(label.EndBlock, ec4),
1199 edit_uint64_with_commas(label.StartFile, ec5),
1200 edit_uint64_with_commas(label.EndFile, ec6),
1201 edit_uint64_with_commas(label.JobErrors, ec7),
1204 if (label.VerNum >= 11) {
1206 bstrftime(dt, sizeof(dt), btime_to_utime(label.write_btime));
1207 Pmsg1(-1, _("Date written : %s\n"), dt);
1209 dt.julian_day_number = label.write_date;
1210 dt.julian_day_fraction = label.write_time;
1211 tm_decode(&dt, &tm);
1212 Pmsg5(-1, _("Date written : %04d-%02d-%02d at %02d:%02d\n"),
1213 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
1219 static int check_label(SESSION_LABEL *label)
1223 if (label->JobId > 10000000 || label->JobId < 0) {
1224 Pmsg0(-1, _("***** ERROR ****** : Found error with the JobId\n"));
1229 switch (label->JobLevel) {
1232 case L_DIFFERENTIAL:
1234 case L_VERIFY_CATALOG:
1236 case L_VERIFY_VOLUME_TO_CATALOG:
1237 case L_VERIFY_DISK_TO_CATALOG:
1241 case L_VIRTUAL_FULL:
1244 Pmsg0(-1, _("***** ERROR ****** : Found error with the JobLevel\n"));
1249 switch (label->JobType) {
1251 case JT_MIGRATED_JOB:
1264 Pmsg0(-1, _("***** ERROR ****** : Found error with the JobType\n"));
1269 POOLMEM *err = get_pool_memory(PM_EMSG);
1270 if (!is_name_valid(label->Job, &err)) {
1271 Pmsg1(-1, _("***** ERROR ****** : Found error with the Job name %s\n"), err);
1274 free_pool_memory(err);
1279 int dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose, bool check_err)
1285 if (rec->FileIndex == 0 && rec->VolSessionId == 0 && rec->VolSessionTime == 0) {
1290 switch (rec->FileIndex) {
1292 type = _("Fresh Volume");
1298 type = _("Begin Job Session");
1301 type = _("End Job Session");
1304 type = _("End of Media");
1307 type = _("End of Tape");
1310 type = _("Unknown");
1314 switch (rec->FileIndex) {
1317 unser_volume_label(dev, rec);
1318 dev->dump_volume_label();
1323 dump_session_label(rec, type);
1326 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1327 type, dev->file, dev->block_num, rec->VolSessionId,
1328 rec->VolSessionTime, rec->Stream, rec->data_len);
1331 Pmsg0(-1, _("Bacula \"End of Tape\" label found.\n"));
1334 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1335 type, dev->file, dev->block_num, rec->VolSessionId,
1336 rec->VolSessionTime, rec->Stream, rec->data_len);
1340 SESSION_LABEL label;
1342 switch (rec->FileIndex) {
1344 unser_session_label(&label, rec);
1345 bstrftimes(dt, sizeof(dt), btime_to_utime(label.write_btime));
1346 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1347 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1348 Pmsg4(-1, _(" Job=%s Date=%s Level=%c Type=%c\n"),
1349 label.Job, dt, label.JobLevel, label.JobType);
1351 errors += check_label(&label);
1355 char ed1[30], ed2[30];
1356 unser_session_label(&label, rec);
1357 bstrftimes(dt, sizeof(dt), btime_to_utime(label.write_btime));
1358 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1359 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1360 Pmsg7(-1, _(" Date=%s Level=%c Type=%c Files=%s Bytes=%s Errors=%d Status=%c\n"),
1361 dt, label.JobLevel, label.JobType,
1362 edit_uint64_with_commas(label.JobFiles, ed1),
1363 edit_uint64_with_commas(label.JobBytes, ed2),
1364 label.JobErrors, (char)label.JobStatus);
1366 errors += check_label(&label);
1373 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1374 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime,
1375 rec->Stream, rec->data_len);