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;
282 if (dcr->is_writing()) {
292 Dmsg2(dbglvl, "return stat=%d %s", stat, jcr->errmsg);
299 * Create and put a volume label into the block
301 * Returns: false on failure
304 * Handle both the ameta and adata volumes.
306 bool DEVICE::write_volume_label_to_block(DCR *dcr)
317 memset(&rec, 0, sizeof(rec));
318 rec.data = get_memory(SER_LENGTH_Volume_Label);
319 memset(rec.data, 0, SER_LENGTH_Volume_Label);
320 empty_block(block); /* Volume label always at beginning */
322 create_volume_label_record(dcr, dcr->dev, &rec, dcr->block->adata);
324 block->BlockNumber = 0;
325 /* Note for adata this also writes to disk */
326 Dmsg1(100, "write_record_to_block adata=%d\n", dcr->dev->adata);
327 if (!write_record_to_block(dcr, &rec)) {
328 free_pool_memory(rec.data);
329 Jmsg2(jcr, M_FATAL, 0, _("Cannot write Volume label to block for %s device %s\n"),
330 dev->print_type(), dev->print_name());
334 Dmsg4(100, "Wrote fd=%d adata=%d label of %d bytes to block. Vol=%s\n",
335 dev->fd(), block->adata, rec.data_len, dcr->VolumeName);
337 free_pool_memory(rec.data);
345 * Write a Volume Label
346 * !!! Note, this is ONLY used for writing
347 * a fresh volume label. Any data
348 * after the label will be destroyed,
349 * in fact, we write the label 5 times !!!!
351 * This routine should be used only when labeling a blank tape or
352 * when recylcing a volume.
354 * Handle both the ameta and adata volumes.
356 bool DEVICE::write_volume_label(DCR *dcr, const char *VolName,
357 const char *PoolName, bool relabel, bool no_prelabel)
362 Dmsg4(230, "Write: block=%p ameta=%p dev=%p ameta_dev=%p\n",
363 dcr->block, dcr->ameta_block, dcr->dev, dcr->ameta_dev);
367 Dmsg0(150, "write_volume_label()\n");
370 Mmsg(dcr->jcr->errmsg, "ERROR: new_volume_label_to_dev called with NULL VolName\n");
372 Pmsg0(0, "=== ERROR: write_volume_label called with NULL VolName\n");
377 volume_unused(dcr); /* mark current volume unused */
378 /* Truncate device */
379 if (!dev->truncate(dcr)) {
382 dev->close_part(dcr); /* make sure closed for rename */
385 /* Set the new filename for open, ... */
386 dev->setVolCatName(VolName);
387 dcr->setVolCatName(VolName);
388 dev->clearVolCatBytes();
390 Dmsg1(100, "New VolName=%s\n", VolName);
391 if (!dev->open_device(dcr, OPEN_READ_WRITE)) {
392 /* If device is not tape, attempt to create it */
393 if (dev->is_tape() || !dev->open_device(dcr, CREATE_READ_WRITE)) {
394 Jmsg4(dcr->jcr, M_WARNING, 0, _("Open %s device %s Volume \"%s\" failed: ERR=%s"),
395 dev->print_type(), dev->print_name(), dcr->VolumeName, dev->bstrerror());
399 Dmsg1(150, "Label type=%d\n", dev->label_type);
401 if (!write_volume_label_to_dev(dcr, VolName, PoolName, relabel, no_prelabel)) {
405 if (!dev->is_aligned()) {
406 /* Not aligned data */
407 if (dev->weof(dcr, 1)) {
411 if (chk_dbglvl(100)) {
412 dev->dump_volume_label();
414 Dmsg0(50, "Call reserve_volume\n");
415 /**** ***FIXME*** if dev changes, dcr must be updated */
416 if (reserve_volume(dcr, VolName) == NULL) {
417 if (!dcr->jcr->errmsg[0]) {
418 Mmsg3(dcr->jcr->errmsg, _("Could not reserve volume %s on %s device %s\n"),
419 dev->VolHdr.VolumeName, dev->print_type(), dev->print_name());
421 Dmsg1(50, "%s", dcr->jcr->errmsg);
424 dev = dcr->dev; /* may have changed in reserve_volume */
426 dev->clear_append(); /* remove append since this is PRE_LABEL */
431 dcr->adata_label = false;
434 dcr->dev->clear_append(); /* remove append since this is PRE_LABEL */
439 bool DEVICE::write_volume_label_to_dev(DCR *dcr, const char *VolName,
440 const char *PoolName, bool relabel, bool no_prelabel)
442 DEVICE *dev, *ameta_dev;
444 DEV_RECORD *rec = new_record();
449 ameta_dev = dcr->ameta_dev;
453 if (!dev->rewind(dcr)) {
454 Dmsg2(130, "Bad status on %s from rewind: ERR=%s\n", dev->print_name(), dev->print_errmsg());
458 /* Temporarily mark in append state to enable writing */
461 /* Create PRE_LABEL or VOL_LABEL */
462 create_volume_header(dev, VolName, PoolName, no_prelabel);
465 * If we have already detected an ANSI label, re-read it
466 * to skip past it. Otherwise, we write a new one if
470 if (dev->label_type != B_BACULA_LABEL) {
471 if (read_ansi_ibm_label(dcr) != VOL_OK) {
475 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, VolName)) {
480 create_volume_label_record(dcr, dev, rec, block->adata);
482 rec->maskedStream = 0;
484 Dmsg2(100, "write_record_to_block adata=%d FI=%d\n", dcr->dev->adata,
487 /* For adata label this also writes to disk */
488 if (!write_record_to_block(dcr, rec)) {
489 Dmsg2(40, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
492 Dmsg3(100, "Wrote label=%d bytes adata=%d block: %s\n", rec->data_len, block->adata, dev->print_name());
494 Dmsg3(100, "New label adata=%d VolCatBytes=%lld VolCatStatus=%s\n",
495 dev->adata, ameta_dev->VolCatInfo.VolCatBytes, ameta_dev->VolCatInfo.VolCatStatus);
498 /* Empty block and set data start address */
499 empty_block(dcr->adata_block);
501 Dmsg4(130, "Call write_block_to_dev() fd=%d adata=%d block=%p Addr=%lld\n",
502 dcr->dev->fd(), dcr->block->adata, dcr->block, block->dev->lseek(dcr, 0, SEEK_CUR));
503 Dmsg1(100, "write_record_to_dev adata=%d\n", dcr->dev->adata);
504 /* Write ameta block to device */
505 if (!dcr->write_block_to_dev()) {
506 Dmsg2(40, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
510 Dmsg3(100, "Wrote new Vol label adata=%d VolCatBytes=%lld VolCatStatus=%s\n",
511 dev->adata, ameta_dev->VolCatInfo.VolCatBytes, ameta_dev->VolCatInfo.VolCatStatus);
521 * Write a volume label. This is ONLY called if we have a valid Bacula
522 * label of type PRE_LABEL or we are recyling an existing Volume.
524 * By calling write_volume_label_to_block, both ameta and adata
527 * Returns: true if OK
528 * false if unable to write it
530 bool DEVICE::rewrite_volume_label(DCR *dcr, bool recycle)
536 ASSERT2(dcr->VolumeName[0], "Empty Volume name");
537 ASSERT(!dcr->block->adata);
538 if (!open_device(dcr, OPEN_READ_WRITE)) {
539 Jmsg4(jcr, M_WARNING, 0, _("Open %s device %s Volume \"%s\" failed: ERR=%s\n"),
540 print_type(), print_name(), dcr->VolumeName, bstrerror());
544 Dmsg2(190, "set append found freshly labeled volume. fd=%d dev=%x\n", fd(), this);
545 VolHdr.LabelType = VOL_LABEL; /* set Volume label */
547 Dmsg0(100, "Rewrite_volume_label set volcatbytes=0\n");
548 clearVolCatBytes(); /* resets both ameta and adata byte counts */
549 setVolCatStatus("Append"); /* set append status */
551 if (!has_cap(CAP_STREAM)) {
553 Jmsg3(jcr, M_FATAL, 0, _("Rewind error on %s device %s: ERR=%s\n"),
554 print_type(), print_name(), print_errmsg());
559 Dmsg1(150, "Doing recycle. Vol=%s\n", dcr->VolumeName);
560 if (!truncate(dcr)) {
561 Jmsg3(jcr, M_FATAL, 0, _("Truncate error on %s device %s: ERR=%s\n"),
562 print_type(), print_name(), print_errmsg());
566 if (!open_device(dcr, OPEN_READ_WRITE)) {
567 Jmsg3(jcr, M_FATAL, 0,
568 _("Failed to re-open device after truncate on %s device %s: ERR=%s"),
569 print_type(), print_name(), print_errmsg());
576 if (!write_volume_label_to_block(dcr)) {
577 Dmsg0(150, "Error from write volume label.\n");
581 Dmsg2(100, "wrote vol label to block. adata=%d Vol=%s\n", dcr->block->adata, dcr->VolumeName);
583 ASSERT2(dcr->VolumeName[0], "Empty Volume name");
584 setVolCatInfo(false);
587 * If we are not dealing with a streaming device,
588 * write the block now to ensure we have write permission.
589 * It is better to find out now rather than later.
590 * We do not write the block now if this is an ANSI label. This
591 * avoids re-writing the ANSI label, which we do not want to do.
593 if (!has_cap(CAP_STREAM)) {
595 * If we have already detected an ANSI label, re-read it
596 * to skip past it. Otherwise, we write a new one if
599 if (label_type != B_BACULA_LABEL) {
600 if (read_ansi_ibm_label(dcr) != VOL_OK) {
605 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, VolHdr.VolumeName)) {
610 /* Attempt write to check write permission */
611 Dmsg1(200, "Attempt to write to device fd=%d.\n", fd());
612 if (!dcr->write_block_to_dev()) {
613 Jmsg3(jcr, M_ERROR, 0, _("Unable to write %s device %s: ERR=%s\n"),
614 print_type(), print_name(), print_errmsg());
615 Dmsg0(200, "===ERROR write block to dev\n");
620 ASSERT2(dcr->VolumeName[0], "Empty Volume name");
621 setVolCatName(dcr->VolumeName);
622 if (!dir_get_volume_info(dcr, dcr->VolumeName, GET_VOL_INFO_FOR_WRITE)) {
627 /* Set or reset Volume statistics */
628 VolCatInfo.VolCatJobs = 0;
629 VolCatInfo.VolCatFiles = 0;
630 VolCatInfo.VolCatErrors = 0;
631 VolCatInfo.VolCatBlocks = 0;
632 VolCatInfo.VolCatRBytes = 0;
633 VolCatInfo.VolCatCloudParts = 0;
634 VolCatInfo.VolLastPartBytes = 0;
635 VolCatInfo.VolCatType = 0; /* Will be set by dir_update_volume_info() */
637 VolCatInfo.VolCatMounts++;
638 VolCatInfo.VolCatRecycles++;
640 VolCatInfo.VolCatMounts = 1;
641 VolCatInfo.VolCatRecycles = 0;
642 VolCatInfo.VolCatWrites = 1;
643 VolCatInfo.VolCatReads = 1;
645 dcr->VolMediaId = dcr->VolCatInfo.VolMediaId; /* make create_jobmedia work */
646 dir_create_jobmedia_record(dcr, true);
647 Dmsg1(100, "dir_update_vol_info. Set Append vol=%s\n", dcr->VolumeName);
648 VolCatInfo.VolFirstWritten = time(NULL);
649 setVolCatStatus("Append");
650 if (!dir_update_volume_info(dcr, true, true)) { /* indicate relabel */
655 Jmsg(jcr, M_INFO, 0, _("Recycled volume \"%s\" on %s device %s, all previous data lost.\n"),
656 dcr->VolumeName, print_type(), print_name());
658 Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume \"%s\" on %s device %s\n"),
659 dcr->VolumeName, print_type(), print_name());
662 * End writing real Volume label (from pre-labeled tape), or recycling
665 Dmsg4(100, "OK rewrite vol label. Addr=%s adata=%d slot=%d Vol=%s\n",
666 print_addr(ed1, sizeof(ed1)), dcr->block->adata, VolCatInfo.Slot, dcr->VolumeName);
673 * create_volume_label_record
674 * Note: it is assumed that you have created the volume_header
675 * (label) prior to calling this subroutine.
676 * Serialize label (from dev->VolHdr structure) into device record.
677 * Assumes that the dev->VolHdr structure is properly
680 static void create_volume_label_record(DCR *dcr, DEVICE *dev,
681 DEV_RECORD *rec, bool adata)
688 /* Serialize the label into the device record. */
691 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
692 memset(rec->data, 0, SER_LENGTH_Volume_Label);
693 ser_begin(rec->data, SER_LENGTH_Volume_Label);
694 ser_string(dev->VolHdr.Id);
696 ser_uint32(dev->VolHdr.VerNum);
698 if (dev->VolHdr.VerNum >= 11) {
699 ser_btime(dev->VolHdr.label_btime);
700 dev->VolHdr.write_btime = get_current_btime();
701 ser_btime(dev->VolHdr.write_btime);
702 dev->VolHdr.write_date = 0;
703 dev->VolHdr.write_time = 0;
705 /* OLD WAY DEPRECATED */
706 ser_float64(dev->VolHdr.label_date);
707 ser_float64(dev->VolHdr.label_time);
708 get_current_time(&dt);
709 dev->VolHdr.write_date = dt.julian_day_number;
710 dev->VolHdr.write_time = dt.julian_day_fraction;
712 ser_float64(dev->VolHdr.write_date); /* 0 if VerNum >= 11 */
713 ser_float64(dev->VolHdr.write_time); /* 0 if VerNum >= 11 */
715 ser_string(dev->VolHdr.VolumeName);
716 ser_string(dev->VolHdr.PrevVolumeName);
717 ser_string(dev->VolHdr.PoolName);
718 ser_string(dev->VolHdr.PoolType);
719 ser_string(dev->VolHdr.MediaType);
721 ser_string(dev->VolHdr.HostName);
722 ser_string(dev->VolHdr.LabelProg);
723 ser_string(dev->VolHdr.ProgVersion);
724 ser_string(dev->VolHdr.ProgDate);
726 dev->VolHdr.AlignedVolumeName[0] = 0;
727 ser_string(dev->VolHdr.AlignedVolumeName);
729 /* This is adata Volume information */
730 ser_uint64(dev->VolHdr.FirstData);
731 ser_uint32(dev->VolHdr.FileAlignment);
732 ser_uint32(dev->VolHdr.PaddingSize);
733 /* adata and dedup volumes */
734 ser_uint32(dev->VolHdr.BlockSize);
736 ser_end(rec->data, SER_LENGTH_Volume_Label);
738 bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName));
740 ASSERT2(dcr->VolumeName[0], "Empty Volume name");
741 rec->data_len = ser_length(rec->data);
742 rec->FileIndex = dev->VolHdr.LabelType;
743 Dmsg2(100, "LabelType=%d adata=%d\n", dev->VolHdr.LabelType, dev->adata);
744 rec->VolSessionId = jcr->VolSessionId;
745 rec->VolSessionTime = jcr->VolSessionTime;
746 rec->Stream = jcr->NumWriteVolumes;
747 rec->maskedStream = jcr->NumWriteVolumes;
748 Dmsg3(100, "Created adata=%d Vol label rec: FI=%s len=%d\n", adata, FI_to_ascii(buf, rec->FileIndex),
750 Dmsg2(100, "reclen=%d recdata=%s", rec->data_len, rec->data);
756 * Create a volume header (label) in memory
757 * The volume record is created after this header (label)
760 void create_volume_header(DEVICE *dev, const char *VolName,
761 const char *PoolName, bool no_prelabel)
763 DEVRES *device = (DEVRES *)dev->device;
767 ASSERT2(dev != NULL, "dev ptr is NULL");
769 if (dev->is_aligned()) {
770 bstrncpy(dev->VolHdr.Id, BaculaMetaDataId, sizeof(dev->VolHdr.Id));
771 dev->VolHdr.VerNum = BaculaMetaDataVersion;
772 dev->VolHdr.FirstData = dev->file_alignment;
773 dev->VolHdr.FileAlignment = dev->file_alignment;
774 dev->VolHdr.PaddingSize = dev->padding_size;
775 dev->VolHdr.BlockSize = dev->adata_size;
776 } else if (dev->is_adata()) {
777 bstrncpy(dev->VolHdr.Id, BaculaAlignedDataId, sizeof(dev->VolHdr.Id));
778 dev->VolHdr.VerNum = BaculaAlignedDataVersion;
779 dev->VolHdr.FirstData = dev->file_alignment;
780 dev->VolHdr.FileAlignment = dev->file_alignment;
781 dev->VolHdr.PaddingSize = dev->padding_size;
782 dev->VolHdr.BlockSize = dev->adata_size;
783 } else if (dev->is_cloud()) {
784 bstrncpy(dev->VolHdr.Id, BaculaS3CloudId, sizeof(dev->VolHdr.Id));
785 dev->VolHdr.VerNum = BaculaS3CloudVersion;
786 dev->VolHdr.BlockSize = dev->max_block_size;
788 bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
789 dev->VolHdr.VerNum = BaculaTapeVersion;
790 dev->VolHdr.BlockSize = dev->max_block_size;
793 if (dev->has_cap(CAP_STREAM) && no_prelabel) {
794 /* We do not want to re-label so write VOL_LABEL now */
795 dev->VolHdr.LabelType = VOL_LABEL;
797 dev->VolHdr.LabelType = PRE_LABEL; /* Mark Volume as unused */
799 bstrncpy(dev->VolHdr.VolumeName, VolName, sizeof(dev->VolHdr.VolumeName));
800 bstrncpy(dev->VolHdr.PoolName, PoolName, sizeof(dev->VolHdr.PoolName));
801 bstrncpy(dev->VolHdr.MediaType, device->media_type, sizeof(dev->VolHdr.MediaType));
803 bstrncpy(dev->VolHdr.PoolType, "Backup", sizeof(dev->VolHdr.PoolType));
805 dev->VolHdr.label_btime = get_current_btime();
806 dev->VolHdr.label_date = 0;
807 dev->VolHdr.label_time = 0;
809 if (gethostname(dev->VolHdr.HostName, sizeof(dev->VolHdr.HostName)) != 0) {
810 dev->VolHdr.HostName[0] = 0;
812 bstrncpy(dev->VolHdr.LabelProg, my_name, sizeof(dev->VolHdr.LabelProg));
813 sprintf(dev->VolHdr.ProgVersion, "Ver. %s %s ", VERSION, BDATE);
814 sprintf(dev->VolHdr.ProgDate, "Build %s %s ", __DATE__, __TIME__);
815 dev->set_labeled(); /* set has Bacula label */
816 if (chk_dbglvl(100)) {
817 dev->dump_volume_label();
822 * Create session (Job) label
823 * The pool memory must be released by the calling program
825 void create_session_label(DCR *dcr, DEV_RECORD *rec, int label)
831 rec->VolSessionId = jcr->VolSessionId;
832 rec->VolSessionTime = jcr->VolSessionTime;
833 rec->Stream = jcr->JobId;
834 rec->maskedStream = jcr->JobId;
836 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
837 ser_begin(rec->data, SER_LENGTH_Session_Label);
838 ser_string(BaculaId);
839 ser_uint32(BaculaTapeVersion);
841 ser_uint32(jcr->JobId);
843 /* Changed in VerNum 11 */
844 ser_btime(get_current_btime());
847 ser_string(dcr->pool_name);
848 ser_string(dcr->pool_type);
849 ser_string(jcr->job_name); /* base Job name */
850 ser_string(jcr->client_name);
852 /* Added in VerNum 10 */
853 ser_string(jcr->Job); /* Unique name of this Job */
854 ser_string(jcr->fileset_name);
855 ser_uint32(jcr->getJobType());
856 ser_uint32(jcr->getJobLevel());
857 /* Added in VerNum 11 */
858 ser_string(jcr->fileset_md5);
860 if (label == EOS_LABEL) {
861 ser_uint32(jcr->JobFiles);
862 ser_uint64(jcr->JobBytes);
863 ser_uint32((uint32_t)dcr->StartAddr); /* Start Block */
864 ser_uint32((uint32_t)dcr->EndAddr); /* End Block */
865 ser_uint32((uint32_t)(dcr->StartAddr>>32)); /* Start File */
866 ser_uint32((uint32_t)(dcr->EndAddr>>32)); /* End File */
867 ser_uint32(jcr->JobErrors);
869 /* Added in VerNum 11 */
870 ser_uint32(jcr->JobStatus);
872 ser_end(rec->data, SER_LENGTH_Session_Label);
873 rec->data_len = ser_length(rec->data);
877 /* Write session (Job) label
878 * Returns: false on failure
881 bool write_session_label(DCR *dcr, int label)
884 DEVICE *dev = dcr->dev;
886 DEV_BLOCK *block = dcr->block;
887 char buf1[100], buf2[100];
891 Dmsg2(140, "=== write_session_label label=%d Vol=%s.\n", label, dev->getVolCatName());
892 if (!check_for_newvol_or_newfile(dcr)) {
893 Pmsg0(000, "ERR: !check_for_new_vol_or_newfile\n");
899 Dmsg1(130, "session_label record=%x\n", rec);
902 set_start_vol_position(dcr);
905 dcr->EndAddr = dev->get_full_addr();
908 Jmsg1(jcr, M_ABORT, 0, _("Bad Volume session label request=%d\n"), label);
912 create_session_label(dcr, rec, label);
913 rec->FileIndex = label;
917 * We guarantee that the session record can totally fit
918 * into a block. If not, write the block, and put it in
919 * the next block. Having the sesssion record totally in
920 * one block makes reading them much easier (no need to
921 * read the next block).
923 if (!can_write_record_to_block(block, rec)) {
924 Dmsg0(150, "Cannot write session label to block.\n");
925 if (!dcr->write_block_to_device()) {
926 Dmsg0(130, "Got session label write_block_to_dev error.\n");
933 * We use write_record() because it handles the case that
934 * the maximum user size has been reached.
936 if (!dcr->write_record(rec)) {
937 Dmsg0(150, "Bad return from write_record\n");
943 Dmsg6(150, "Write sesson_label record JobId=%d FI=%s SessId=%d Strm=%s len=%d "
944 "remainder=%d\n", jcr->JobId,
945 FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
946 stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
950 Dmsg2(150, "Leave write_session_label Block=%u File=%u\n",
951 dev->get_block_num(), dev->get_file());
956 /* unser_volume_label
958 * Unserialize the Bacula Volume label into the device Volume_Label
961 * Assumes that the record is already read.
963 * Returns: false on error
967 bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec)
970 char buf1[100], buf2[100];
973 if (rec->FileIndex != VOL_LABEL && rec->FileIndex != PRE_LABEL) {
974 Mmsg3(dev->errmsg, _("Expecting Volume Label, got FI=%s Stream=%s len=%d\n"),
975 FI_to_ascii(buf1, rec->FileIndex),
976 stream_to_ascii(buf2, rec->Stream, rec->FileIndex),
984 dev->VolHdr.LabelType = rec->FileIndex;
985 dev->VolHdr.LabelSize = rec->data_len;
988 /* Unserialize the record into the Volume Header */
989 Dmsg2(100, "reclen=%d recdata=%s", rec->data_len, rec->data);
990 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
991 Dmsg2(100, "reclen=%d recdata=%s", rec->data_len, rec->data);
992 ser_begin(rec->data, SER_LENGTH_Volume_Label);
993 unser_string(dev->VolHdr.Id);
994 unser_uint32(dev->VolHdr.VerNum);
996 if (dev->VolHdr.VerNum >= 11) {
997 unser_btime(dev->VolHdr.label_btime);
998 unser_btime(dev->VolHdr.write_btime);
999 } else { /* old way */
1000 unser_float64(dev->VolHdr.label_date);
1001 unser_float64(dev->VolHdr.label_time);
1003 unser_float64(dev->VolHdr.write_date); /* Unused with VerNum >= 11 */
1004 unser_float64(dev->VolHdr.write_time); /* Unused with VerNum >= 11 */
1006 unser_string(dev->VolHdr.VolumeName);
1007 unser_string(dev->VolHdr.PrevVolumeName);
1008 unser_string(dev->VolHdr.PoolName);
1009 unser_string(dev->VolHdr.PoolType);
1010 unser_string(dev->VolHdr.MediaType);
1012 unser_string(dev->VolHdr.HostName);
1013 unser_string(dev->VolHdr.LabelProg);
1014 unser_string(dev->VolHdr.ProgVersion);
1015 unser_string(dev->VolHdr.ProgDate);
1017 // unser_string(dev->VolHdr.AlignedVolumeName);
1018 dev->VolHdr.AlignedVolumeName[0] = 0;
1019 unser_uint64(dev->VolHdr.FirstData);
1020 unser_uint32(dev->VolHdr.FileAlignment);
1021 unser_uint32(dev->VolHdr.PaddingSize);
1022 unser_uint32(dev->VolHdr.BlockSize);
1024 ser_end(rec->data, SER_LENGTH_Volume_Label);
1025 Dmsg0(190, "unser_vol_label\n");
1026 if (chk_dbglvl(100)) {
1027 dev->dump_volume_label();
1034 bool unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec)
1039 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
1040 unser_begin(rec->data, SER_LENGTH_Session_Label);
1041 unser_string(label->Id);
1042 unser_uint32(label->VerNum);
1043 unser_uint32(label->JobId);
1044 if (label->VerNum >= 11) {
1045 unser_btime(label->write_btime);
1047 unser_float64(label->write_date);
1049 unser_float64(label->write_time);
1050 unser_string(label->PoolName);
1051 unser_string(label->PoolType);
1052 unser_string(label->JobName);
1053 unser_string(label->ClientName);
1054 if (label->VerNum >= 10) {
1055 unser_string(label->Job); /* Unique name of this Job */
1056 unser_string(label->FileSetName);
1057 unser_uint32(label->JobType);
1058 unser_uint32(label->JobLevel);
1060 if (label->VerNum >= 11) {
1061 unser_string(label->FileSetMD5);
1063 label->FileSetMD5[0] = 0;
1065 if (rec->FileIndex == EOS_LABEL) {
1066 unser_uint32(label->JobFiles);
1067 unser_uint64(label->JobBytes);
1068 unser_uint32(label->StartBlock);
1069 unser_uint32(label->EndBlock);
1070 unser_uint32(label->StartFile);
1071 unser_uint32(label->EndFile);
1072 unser_uint32(label->JobErrors);
1073 if (label->VerNum >= 11) {
1074 unser_uint32(label->JobStatus);
1076 label->JobStatus = JS_Terminated; /* kludge */
1083 void DEVICE::dump_volume_label()
1085 int64_t dbl = debug_level;
1087 const char *LabelType;
1090 struct date_time dt;
1094 switch (VolHdr.LabelType) {
1096 LabelType = "PRE_LABEL";
1099 LabelType = "VOL_LABEL";
1102 LabelType = "EOM_LABEL";
1105 LabelType = "SOS_LABEL";
1108 LabelType = "EOS_LABEL";
1114 sprintf(buf, _("Unknown %d"), VolHdr.LabelType);
1118 Pmsg12(-1, _("\nVolume Label:\n"
1123 "PrevVolName : %s\n"
1133 VolHdr.Id, VolHdr.VerNum,
1134 VolHdr.VolumeName, VolHdr.PrevVolumeName,
1135 File, LabelType, VolHdr.LabelSize,
1136 VolHdr.PoolName, VolHdr.MediaType,
1137 VolHdr.PoolType, VolHdr.HostName);
1139 if (VolHdr.VerNum >= 11) {
1141 bstrftime(dt, sizeof(dt), btime_to_utime(VolHdr.label_btime));
1142 Pmsg1(-1, _("Date label written: %s\n"), dt);
1144 dt.julian_day_number = VolHdr.label_date;
1145 dt.julian_day_fraction = VolHdr.label_time;
1146 tm_decode(&dt, &tm);
1148 _("Date label written: %04d-%02d-%02d at %02d:%02d\n"),
1149 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
1157 static void dump_session_label(DEV_RECORD *rec, const char *type)
1160 struct date_time dt;
1162 SESSION_LABEL label;
1163 char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], ec6[30], ec7[30];
1165 unser_session_label(&label, rec);
1168 Pmsg7(-1, _("\n%s Record:\n"
1175 ""), type, label.JobId, label.VerNum,
1176 label.PoolName, label.PoolType,
1177 label.JobName, label.ClientName);
1179 if (label.VerNum >= 10) {
1181 "Job (unique name) : %s\n"
1185 ""), label.Job, label.FileSetName, label.JobType, label.JobLevel);
1188 if (rec->FileIndex == EOS_LABEL) {
1199 edit_uint64_with_commas(label.JobFiles, ec1),
1200 edit_uint64_with_commas(label.JobBytes, ec2),
1201 edit_uint64_with_commas(label.StartBlock, ec3),
1202 edit_uint64_with_commas(label.EndBlock, ec4),
1203 edit_uint64_with_commas(label.StartFile, ec5),
1204 edit_uint64_with_commas(label.EndFile, ec6),
1205 edit_uint64_with_commas(label.JobErrors, ec7),
1208 if (label.VerNum >= 11) {
1210 bstrftime(dt, sizeof(dt), btime_to_utime(label.write_btime));
1211 Pmsg1(-1, _("Date written : %s\n"), dt);
1213 dt.julian_day_number = label.write_date;
1214 dt.julian_day_fraction = label.write_time;
1215 tm_decode(&dt, &tm);
1216 Pmsg5(-1, _("Date written : %04d-%02d-%02d at %02d:%02d\n"),
1217 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
1223 static int check_label(SESSION_LABEL *label)
1227 if (label->JobId > 10000000 || label->JobId < 0) {
1228 Pmsg0(-1, _("***** ERROR ****** : Found error with the JobId\n"));
1233 switch (label->JobLevel) {
1236 case L_DIFFERENTIAL:
1238 case L_VERIFY_CATALOG:
1240 case L_VERIFY_VOLUME_TO_CATALOG:
1241 case L_VERIFY_DISK_TO_CATALOG:
1245 case L_VIRTUAL_FULL:
1248 Pmsg0(-1, _("***** ERROR ****** : Found error with the JobLevel\n"));
1253 switch (label->JobType) {
1255 case JT_MIGRATED_JOB:
1268 Pmsg0(-1, _("***** ERROR ****** : Found error with the JobType\n"));
1273 POOLMEM *err = get_pool_memory(PM_EMSG);
1274 if (!is_name_valid(label->Job, &err)) {
1275 Pmsg1(-1, _("***** ERROR ****** : Found error with the Job name %s\n"), err);
1278 free_pool_memory(err);
1283 int dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose, bool check_err)
1289 if (rec->FileIndex == 0 && rec->VolSessionId == 0 && rec->VolSessionTime == 0) {
1294 switch (rec->FileIndex) {
1296 type = _("Fresh Volume");
1302 type = _("Begin Job Session");
1305 type = _("End Job Session");
1308 type = _("End of Media");
1311 type = _("End of Tape");
1314 type = _("Unknown");
1318 switch (rec->FileIndex) {
1321 unser_volume_label(dev, rec);
1322 dev->dump_volume_label();
1327 dump_session_label(rec, type);
1330 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1331 type, dev->file, dev->block_num, rec->VolSessionId,
1332 rec->VolSessionTime, rec->Stream, rec->data_len);
1335 Pmsg0(-1, _("Bacula \"End of Tape\" label found.\n"));
1338 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1339 type, dev->file, dev->block_num, rec->VolSessionId,
1340 rec->VolSessionTime, rec->Stream, rec->data_len);
1344 SESSION_LABEL label;
1346 switch (rec->FileIndex) {
1348 unser_session_label(&label, rec);
1349 bstrftimes(dt, sizeof(dt), btime_to_utime(label.write_btime));
1350 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1351 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1352 Pmsg4(-1, _(" Job=%s Date=%s Level=%c Type=%c\n"),
1353 label.Job, dt, label.JobLevel, label.JobType);
1355 errors += check_label(&label);
1359 char ed1[30], ed2[30];
1360 unser_session_label(&label, rec);
1361 bstrftimes(dt, sizeof(dt), btime_to_utime(label.write_btime));
1362 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1363 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1364 Pmsg7(-1, _(" Date=%s Level=%c Type=%c Files=%s Bytes=%s Errors=%d Status=%c\n"),
1365 dt, label.JobLevel, label.JobType,
1366 edit_uint64_with_commas(label.JobFiles, ed1),
1367 edit_uint64_with_commas(label.JobBytes, ed2),
1368 label.JobErrors, (char)label.JobStatus);
1370 errors += check_label(&label);
1377 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1378 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime,
1379 rec->Stream, rec->data_len);