2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2016 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 /* Forward referenced functions */
31 static void create_volume_label_record(DCR *dcr, DEVICE *dev, DEV_RECORD *rec, bool alt);
32 static bool sub_write_volume_label_to_block(DCR *dcr);
33 static bool sub_write_new_volume_label_to_dev(DCR *dcr, const char *VolName,
34 const char *PoolName, bool relabel, bool dvdnow);
37 * Read the volume label
39 * If dcr->VolumeName == NULL, we accept any Bacula Volume
40 * If dcr->VolumeName[0] == 0, we accept any Bacula Volume
41 * otherwise dcr->VolumeName must match the Volume.
43 * If VolName given, ensure that it matches
45 * Returns VOL_ code as defined in record.h
47 * VOL_OK good label found
48 * VOL_NO_LABEL volume not labeled
49 * VOL_IO_ERROR I/O error reading tape
50 * VOL_NAME_ERROR label has wrong name
51 * VOL_CREATE_ERROR Error creating label
52 * VOL_VERSION_ERROR label has wrong version
53 * VOL_LABEL_ERROR bad label type
54 * VOL_NO_MEDIA no media in drive
56 * The dcr block is emptied on return, and the Volume is
60 int read_dev_volume_label(DCR *dcr)
63 DEVICE * volatile dev = dcr->dev;
64 char *VolName = dcr->VolumeName;
67 DEV_BLOCK *block = dcr->block;
70 bool have_ansi_label = false;
73 Dmsg4(100, "Enter read_volume_label res=%d device=%s vol=%s dev_Vol=%s\n",
74 dev->num_reserved(), dev->print_name(), VolName,
75 dev->VolHdr.VolumeName[0]?dev->VolHdr.VolumeName:"*NULL*");
77 if (!dev->is_open()) {
78 if (!dev->open(dcr, OPEN_READ_ONLY)) {
87 dev->label_type = B_BACULA_LABEL;
89 if (!dev->rewind(dcr)) {
90 Mmsg(jcr->errmsg, _("Couldn't rewind %s device %s: ERR=%s\n"),
91 dev->print_type(), dev->print_name(), dev->print_errmsg());
92 Dmsg1(130, "return VOL_NO_MEDIA: %s", jcr->errmsg);
96 bstrncpy(dev->VolHdr.Id, "**error**", sizeof(dev->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 || dev->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 dev->print_type(), dev->print_name(), VolName, dev->VolHdr.VolumeName);
110 if (!dev->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 if (!dcr->read_block_from_dev(NO_BLOCK_NUMBER_CHECK)) {
128 Mmsg(jcr->errmsg, _("Requested Volume \"%s\" on %s device %s is not a Bacula "
129 "labeled Volume, because: ERR=%s"), NPRT(VolName),
130 dev->print_type(), dev->print_name(), dev->print_errmsg());
131 Dmsg1(130, "%s", jcr->errmsg);
132 } else if (!read_record_from_block(dcr, record)) {
133 Mmsg(jcr->errmsg, _("Could not read Volume label from block.\n"));
134 Dmsg1(130, "%s", jcr->errmsg);
135 } else if (!unser_volume_label(dev, record)) {
136 Mmsg(jcr->errmsg, _("Could not unserialize Volume label: ERR=%s\n"),
137 dev->print_errmsg());
138 Dmsg1(130, "%s", jcr->errmsg);
139 } else if (strcmp(dev->VolHdr.Id, BaculaId) != 0 &&
140 strcmp(dev->VolHdr.Id, OldBaculaId) != 0) {
141 Mmsg(jcr->errmsg, _("Volume Header Id bad: %s\n"), dev->VolHdr.Id);
142 Dmsg1(130, "%s", jcr->errmsg);
146 free_record(record); /* finished reading Volume record */
148 if (!dev->is_volume_to_unload()) {
153 if (jcr->ignore_label_errors) {
154 dev->set_labeled(); /* set has Bacula label */
155 Jmsg(jcr, M_ERROR, 0, "%s", jcr->errmsg);
160 Dmsg0(100, "No volume label - bailing out\n");
165 /* At this point, we have read the first Bacula block, and
166 * then read the Bacula Volume label. Now we need to
167 * make sure we have the right Volume.
171 if (dev->VolHdr.VerNum != BaculaTapeVersion &&
172 dev->VolHdr.VerNum != OldCompatibleBaculaTapeVersion1 &&
173 dev->VolHdr.VerNum != OldCompatibleBaculaTapeVersion2) {
174 Mmsg(jcr->errmsg, _("Volume on %s device %s has wrong Bacula version. Wanted %d got %d\n"),
175 dev->print_type(), dev->print_name(), BaculaTapeVersion, dev->VolHdr.VerNum);
176 Dmsg1(130, "VOL_VERSION_ERROR: %s", jcr->errmsg);
177 stat = VOL_VERSION_ERROR;
181 /* We are looking for either an unused Bacula tape (PRE_LABEL) or
182 * a Bacula volume label (VOL_LABEL)
184 if (dev->VolHdr.LabelType != PRE_LABEL && dev->VolHdr.LabelType != VOL_LABEL) {
185 Mmsg(jcr->errmsg, _("Volume on %s device %s has bad Bacula label type: %x\n"),
186 dev->print_type(), dev->print_name(), dev->VolHdr.LabelType);
187 Dmsg1(130, "%s", jcr->errmsg);
188 if (!dev->poll && jcr->label_errors++ > 100) {
189 Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
191 Dmsg0(150, "return VOL_LABEL_ERROR\n");
192 stat = VOL_LABEL_ERROR;
196 dev->set_labeled(); /* set has Bacula label */
198 /* Compare Volume Names */
199 Dmsg2(130, "Compare Vol names: VolName=%s hdr=%s\n", VolName?VolName:"*", dev->VolHdr.VolumeName);
200 if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolumeName, VolName) != 0) {
201 Mmsg(jcr->errmsg, _("Wrong Volume mounted on %s device %s: Wanted %s have %s\n"),
202 dev->print_type(), dev->print_name(), VolName, dev->VolHdr.VolumeName);
203 Dmsg1(130, "%s", jcr->errmsg);
205 * Cancel Job if too many label errors
206 * => we are in a loop
208 if (!dev->poll && jcr->label_errors++ > 100) {
209 Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
211 Dmsg0(150, "return VOL_NAME_ERROR\n");
212 stat = VOL_NAME_ERROR;
216 if (chk_dbglvl(100)) {
217 dump_volume_label(dev);
219 Dmsg0(130, "Leave read_volume_label() VOL_OK\n");
220 /* If we are a streaming device, we only get one chance to read */
221 if (!dev->has_cap(CAP_STREAM)) {
223 if (have_ansi_label) {
224 stat = read_ansi_ibm_label(dcr);
225 /* If we want a label and didn't find it, return error */
226 if (stat != VOL_OK) {
232 Dmsg1(100, "Call reserve_volume=%s\n", dev->VolHdr.VolumeName);
233 if (reserve_volume(dcr, dev->VolHdr.VolumeName) == NULL) {
234 if (!jcr->errmsg[0]) {
235 Mmsg3(jcr->errmsg, _("Could not reserve volume %s on %s device %s\n"),
236 dev->VolHdr.VolumeName, dev->print_type(), dev->print_name());
238 Dmsg2(100, "Could not reserve volume %s on %s\n", dev->VolHdr.VolumeName, dev->print_name());
239 stat = VOL_NAME_ERROR;
251 Dmsg1(150, "return %d\n", stat);
258 * Create and put a volume label into the block
260 * Returns: false on failure
264 static bool write_volume_label_to_block(DCR *dcr)
269 Dmsg0(130, "write Label in write_volume_label_to_block()\n");
271 Dmsg0(100, "Call sub_write_vol_label\n");
272 ok = sub_write_volume_label_to_block(dcr);
282 static bool sub_write_volume_label_to_block(DCR *dcr)
293 memset(&rec, 0, sizeof(rec));
294 rec.data = get_memory(SER_LENGTH_Volume_Label);
295 memset(rec.data, 0, SER_LENGTH_Volume_Label);
296 empty_block(block); /* Volume label always at beginning */
298 create_volume_label_record(dcr, dcr->dev, &rec, false);
300 block->BlockNumber = 0;
301 Dmsg0(100, "write_record_to_block\n");
302 if (!write_record_to_block(dcr, &rec)) {
303 free_pool_memory(rec.data);
304 Jmsg2(jcr, M_FATAL, 0, _("Cannot write Volume label to block for %s device %s\n"),
305 dev->print_type(), dev->print_name());
309 Dmsg3(100, "Wrote fd=%d label of %d bytes to block. Vol=%s\n",
310 dev->fd(), rec.data_len, dcr->VolumeName);
312 free_pool_memory(rec.data);
320 * Write a Volume Label
321 * !!! Note, this is ONLY used for writing
322 * a fresh volume label. Any data
323 * after the label will be destroyed,
324 * in fact, we write the label 5 times !!!!
326 * This routine should be used only when labeling a blank tape or
327 * when recylcing a volume.
330 bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName,
331 const char *PoolName, bool relabel, bool dvdnow)
338 Dmsg0(150, "write_volume_label()\n");
341 Mmsg(dcr->jcr->errmsg, "ERROR: new_volume_label_to_dev called with NULL VolName\n");
343 Pmsg0(0, "=== ERROR: write_new_volume_label_to_dev called with NULL VolName\n");
348 volume_unused(dcr); /* mark current volume unused */
349 /* Truncate device */
350 if (!dev->truncate(dcr)) {
353 if (!dev->is_tape()) {
354 dev->close_part(dcr); /* make sure DVD/file closed for rename */
358 /* Set the new filename for open, ... */
359 dev->setVolCatName(VolName);
360 dcr->setVolCatName(VolName);
361 dev->clearVolCatBytes();
363 Dmsg1(100, "New VolName=%s\n", VolName);
364 if (!dev->open(dcr, OPEN_READ_WRITE)) {
365 /* If device is not tape, attempt to create it */
366 if (dev->is_tape() || !dev->open(dcr, CREATE_READ_WRITE)) {
367 Jmsg4(dcr->jcr, M_WARNING, 0, _("Open %s device %s Volume \"%s\" failed: ERR=%s\n"),
368 dev->print_type(), dev->print_name(), dcr->VolumeName, dev->bstrerror());
372 Dmsg1(150, "Label type=%d\n", dev->label_type);
374 if (!sub_write_new_volume_label_to_dev(dcr, VolName, PoolName, relabel, dvdnow)) {
379 write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
382 if (chk_dbglvl(100)) {
383 dump_volume_label(dev);
385 Dmsg0(50, "Call reserve_volume\n");
386 /**** ***FIXME*** if dev changes, dcr must be updated */
387 if (reserve_volume(dcr, VolName) == NULL) {
388 if (!dcr->jcr->errmsg[0]) {
389 Mmsg3(dcr->jcr->errmsg, _("Could not reserve volume %s on %s device %s\n"),
390 dev->VolHdr.VolumeName, dev->print_type(), dev->print_name());
392 Dmsg1(50, "%s", dcr->jcr->errmsg);
395 dev = dcr->dev; /* may have changed in reserve_volume */
396 dev->clear_append(); /* remove append since this is PRE_LABEL */
402 dcr->dev->clear_append(); /* remove append since this is PRE_LABEL */
407 static bool sub_write_new_volume_label_to_dev(DCR *dcr, const char *VolName,
408 const char *PoolName, bool relabel, bool dvdnow)
418 if (!dev->rewind(dcr)) {
419 Dmsg2(130, "Bad status on %s from rewind: ERR=%s\n", dev->print_name(), dev->print_errmsg());
423 /* Temporarily mark in append state to enable writing */
426 /* Create PRE_LABEL or VOL_LABEL if DVD */
427 create_volume_header(dev, VolName, PoolName, dvdnow);
430 * If we have already detected an ANSI label, re-read it
431 * to skip past it. Otherwise, we write a new one if
434 if (dev->label_type != B_BACULA_LABEL) {
435 if (read_ansi_ibm_label(dcr) != VOL_OK) {
439 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, VolName)) {
443 create_volume_label_record(dcr, dev, dcr->rec, false);
444 dcr->rec->Stream = 0;
445 dcr->rec->maskedStream = 0;
447 Dmsg1(100, "write_record_to_block FI=%d\n", dcr->rec->FileIndex);
449 if (!write_record_to_block(dcr, dcr->rec)) {
450 Dmsg2(40, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
453 Dmsg2(100, "Wrote label=%d bytes block: %s\n", dcr->rec->data_len, dev->print_name());
455 Dmsg2(100, "New label VolCatBytes=%lld VolCatStatus=%s\n",
456 dev->VolCatInfo.VolCatBytes, dev->VolCatInfo.VolCatStatus);
458 Dmsg3(130, "Call write_block_to_dev() fd=%d block=%p Addr=%lld\n",
459 dcr->dev->fd(), dcr->block, block->dev->lseek(dcr, 0, SEEK_CUR));
460 Dmsg0(100, "write_record_to_dev\n");
461 /* Write block to device */
462 if (!dcr->write_block_to_dev()) {
463 Dmsg2(40, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
466 Dmsg2(100, "New label VolCatBytes=%lld VolCatStatus=%s\n",
467 dev->VolCatInfo.VolCatBytes, dev->VolCatInfo.VolCatStatus);
477 * Write a volume label. This is ONLY called if we have a valid Bacula
478 * label of type PRE_LABEL or we are recyling an existing Volume.
480 * By calling write_volume_label_to_block
482 * Returns: true if OK
483 * false if unable to write it
485 bool DCR::rewrite_volume_label(bool recycle)
490 ASSERT2(dcr->VolumeName[0], "Empty Volume name");
491 if (!dev->open(dcr, OPEN_READ_WRITE)) {
492 Jmsg4(jcr, M_WARNING, 0, _("Open %s device %s Volume \"%s\" failed: ERR=%s\n"),
493 dev->print_type(), dev->print_name(), dcr->VolumeName, dev->bstrerror());
497 Dmsg2(190, "set append found freshly labeled volume. fd=%d dev=%x\n", dev->fd(), dev);
498 dev->VolHdr.LabelType = VOL_LABEL; /* set Volume label */
500 Dmsg0(100, "Rewrite_volume_label set volcatbytes=0\n");
501 dev->clearVolCatBytes();
502 dev->setVolCatStatus("Append"); /* set append status */
504 if (!dev->has_cap(CAP_STREAM)) {
505 if (!dev->rewind(dcr)) {
506 Jmsg3(jcr, M_FATAL, 0, _("Rewind error on %s device %s: ERR=%s\n"),
507 dev->print_type(), dev->print_name(), dev->print_errmsg());
512 Dmsg1(150, "Doing recycle. Vol=%s\n", dcr->VolumeName);
513 if (!dev->truncate(dcr)) {
514 Jmsg3(jcr, M_FATAL, 0, _("Truncate error on %s device %s: ERR=%s\n"),
515 dev->print_type(), dev->print_name(), dev->print_errmsg());
519 if (!dev->open(dcr, OPEN_READ_WRITE)) {
520 Jmsg3(jcr, M_FATAL, 0,
521 _("Failed to re-open DVD after truncate on %s device %s: ERR=%s\n"),
522 dev->print_type(), dev->print_name(), dev->print_errmsg());
529 if (!write_volume_label_to_block(dcr)) {
530 Dmsg0(150, "Error from write volume label.\n");
534 Dmsg1(100, "wrote vol label to block. Vol=%s\n", dcr->VolumeName);
536 ASSERT2(dcr->VolumeName[0], "Empty Volume name");
537 dev->setVolCatInfo(false);
540 * If we are not dealing with a streaming device,
541 * write the block now to ensure we have write permission.
542 * It is better to find out now rather than later.
543 * We do not write the block now if this is an ANSI label. This
544 * avoids re-writing the ANSI label, which we do not want to do.
546 if (!dev->has_cap(CAP_STREAM)) {
548 * If we have already detected an ANSI label, re-read it
549 * to skip past it. Otherwise, we write a new one if
552 if (dev->label_type != B_BACULA_LABEL) {
553 if (read_ansi_ibm_label(dcr) != VOL_OK) {
558 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, dev->VolHdr.VolumeName)) {
563 /* Attempt write to check write permission */
564 Dmsg1(200, "Attempt to write to device fd=%d.\n", dev->fd());
565 if (!dcr->write_block_to_dev()) {
566 Jmsg3(jcr, M_ERROR, 0, _("Unable to write %s device %s: ERR=%s\n"),
567 dev->print_type(), dev->print_name(), dev->print_errmsg());
568 Dmsg0(200, "===ERROR write block to dev\n");
573 ASSERT2(dcr->VolumeName[0], "Empty Volume name");
574 dev->setVolCatName(dcr->VolumeName);
575 if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_WRITE)) {
580 /* Set or reset Volume statistics */
581 dev->VolCatInfo.VolCatJobs = 0;
582 dev->VolCatInfo.VolCatFiles = 0;
583 dev->VolCatInfo.VolCatErrors = 0;
584 dev->VolCatInfo.VolCatBlocks = 0;
585 dev->VolCatInfo.VolCatRBytes = 0;
587 dev->VolCatInfo.VolCatMounts++;
588 dev->VolCatInfo.VolCatRecycles++;
589 dir_create_jobmedia_record(dcr, true);
591 dev->VolCatInfo.VolCatMounts = 1;
592 dev->VolCatInfo.VolCatRecycles = 0;
593 dev->VolCatInfo.VolCatWrites = 1;
594 dev->VolCatInfo.VolCatReads = 1;
596 Dmsg1(100, "dir_update_vol_info. Set Append vol=%s\n", dcr->VolumeName);
597 dev->VolCatInfo.VolFirstWritten = time(NULL);
598 dev->setVolCatStatus("Append");
599 if (!dir_update_volume_info(dcr, true, true)) { /* indicate relabel */
604 Jmsg(jcr, M_INFO, 0, _("Recycled volume \"%s\" on %s device %s, all previous data lost.\n"),
605 dcr->VolumeName, dev->print_type(), dev->print_name());
607 Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume \"%s\" on %s device %s\n"),
608 dcr->VolumeName, dev->print_type(), dev->print_name());
611 * End writing real Volume label (from pre-labeled tape), or recycling
614 Dmsg3(100, "OK from rewrite vol label. adata=%d slot=%d Vol=%s\n",
615 dcr->block->adata, dev->VolCatInfo.Slot, dcr->VolumeName);
622 * create_volume_label_record
623 * Serialize label (from dev->VolHdr structure) into device record.
624 * Assumes that the dev->VolHdr structure is properly
627 static void create_volume_label_record(DCR *dcr, DEVICE *dev,
628 DEV_RECORD *rec, bool alt)
635 /* Serialize the label into the device record. */
638 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
639 memset(rec->data, 0, SER_LENGTH_Volume_Label);
640 ser_begin(rec->data, SER_LENGTH_Volume_Label);
641 ser_string(dev->VolHdr.Id);
643 ser_uint32(dev->VolHdr.VerNum);
645 if (dev->VolHdr.VerNum >= 11) {
646 ser_btime(dev->VolHdr.label_btime);
647 dev->VolHdr.write_btime = get_current_btime();
648 ser_btime(dev->VolHdr.write_btime);
649 dev->VolHdr.write_date = 0;
650 dev->VolHdr.write_time = 0;
652 /* OLD WAY DEPRECATED */
653 ser_float64(dev->VolHdr.label_date);
654 ser_float64(dev->VolHdr.label_time);
655 get_current_time(&dt);
656 dev->VolHdr.write_date = dt.julian_day_number;
657 dev->VolHdr.write_time = dt.julian_day_fraction;
659 ser_float64(dev->VolHdr.write_date); /* 0 if VerNum >= 11 */
660 ser_float64(dev->VolHdr.write_time); /* 0 if VerNum >= 11 */
662 ser_string(dev->VolHdr.VolumeName);
663 ser_string(dev->VolHdr.PrevVolumeName);
664 ser_string(dev->VolHdr.PoolName);
665 ser_string(dev->VolHdr.PoolType);
666 ser_string(dev->VolHdr.MediaType);
668 ser_string(dev->VolHdr.HostName);
669 ser_string(dev->VolHdr.LabelProg);
670 ser_string(dev->VolHdr.ProgVersion);
671 ser_string(dev->VolHdr.ProgDate);
673 ser_end(rec->data, SER_LENGTH_Volume_Label);
674 bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName));
675 ASSERT2(dcr->VolumeName[0], "Empty Volume name");
676 rec->data_len = ser_length(rec->data);
677 rec->FileIndex = dev->VolHdr.LabelType;
678 Dmsg1(100, "LabelType=%d\n", dev->VolHdr.LabelType);
679 rec->VolSessionId = jcr->VolSessionId;
680 rec->VolSessionTime = jcr->VolSessionTime;
681 rec->Stream = jcr->NumWriteVolumes;
682 rec->maskedStream = jcr->NumWriteVolumes;
683 Dmsg2(100, "Created Vol label rec: FI=%s len=%d\n", FI_to_ascii(buf, rec->FileIndex),
685 Dmsg2(100, "reclen=%d recdata=%s\n", rec->data_len, rec->data);
691 * Create a volume header in memory
693 void create_volume_header(DEVICE *dev, const char *VolName,
694 const char *PoolName, bool dvdnow)
696 DEVRES *device = (DEVRES *)dev->device;
698 Dmsg0(130, "Start create_volume_header()\n");
702 bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
703 dev->VolHdr.VerNum = BaculaTapeVersion;
704 if (dev->is_dvd() && dvdnow) {
705 /* We do not want to re-label a DVD so write VOL_LABEL now */
706 dev->VolHdr.LabelType = VOL_LABEL;
708 dev->VolHdr.LabelType = PRE_LABEL; /* Mark tape as unused */
710 bstrncpy(dev->VolHdr.VolumeName, VolName, sizeof(dev->VolHdr.VolumeName));
711 bstrncpy(dev->VolHdr.PoolName, PoolName, sizeof(dev->VolHdr.PoolName));
712 bstrncpy(dev->VolHdr.MediaType, device->media_type, sizeof(dev->VolHdr.MediaType));
714 bstrncpy(dev->VolHdr.PoolType, "Backup", sizeof(dev->VolHdr.PoolType));
716 dev->VolHdr.label_btime = get_current_btime();
717 dev->VolHdr.label_date = 0;
718 dev->VolHdr.label_time = 0;
720 if (gethostname(dev->VolHdr.HostName, sizeof(dev->VolHdr.HostName)) != 0) {
721 dev->VolHdr.HostName[0] = 0;
723 bstrncpy(dev->VolHdr.LabelProg, my_name, sizeof(dev->VolHdr.LabelProg));
724 sprintf(dev->VolHdr.ProgVersion, "Ver. %s %s ", VERSION, BDATE);
725 sprintf(dev->VolHdr.ProgDate, "Build %s %s ", __DATE__, __TIME__);
726 dev->set_labeled(); /* set has Bacula label */
727 if (chk_dbglvl(100)) {
728 dump_volume_label(dev);
733 * Create session label
734 * The pool memory must be released by the calling program
736 void create_session_label(DCR *dcr, DEV_RECORD *rec, int label)
742 rec->VolSessionId = jcr->VolSessionId;
743 rec->VolSessionTime = jcr->VolSessionTime;
744 rec->Stream = jcr->JobId;
745 rec->maskedStream = jcr->JobId;
747 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
748 ser_begin(rec->data, SER_LENGTH_Session_Label);
749 ser_string(BaculaId);
750 ser_uint32(BaculaTapeVersion);
752 ser_uint32(jcr->JobId);
754 /* Changed in VerNum 11 */
755 ser_btime(get_current_btime());
758 ser_string(dcr->pool_name);
759 ser_string(dcr->pool_type);
760 ser_string(jcr->job_name); /* base Job name */
761 ser_string(jcr->client_name);
763 /* Added in VerNum 10 */
764 ser_string(jcr->Job); /* Unique name of this Job */
765 ser_string(jcr->fileset_name);
766 ser_uint32(jcr->getJobType());
767 ser_uint32(jcr->getJobLevel());
768 /* Added in VerNum 11 */
769 ser_string(jcr->fileset_md5);
771 if (label == EOS_LABEL) {
772 ser_uint32(jcr->JobFiles);
773 ser_uint64(jcr->JobBytes);
774 ser_uint32(dcr->StartBlock);
775 ser_uint32(dcr->EndBlock);
776 ser_uint32(dcr->StartFile);
777 ser_uint32(dcr->EndFile);
778 ser_uint32(jcr->JobErrors);
780 /* Added in VerNum 11 */
781 ser_uint32(jcr->JobStatus);
783 ser_end(rec->data, SER_LENGTH_Session_Label);
784 rec->data_len = ser_length(rec->data);
788 /* Write session label
789 * Returns: false on failure
792 bool write_session_label(DCR *dcr, int label)
795 DEVICE *dev = dcr->dev;
797 DEV_BLOCK *block = dcr->block;
798 char buf1[100], buf2[100];
802 Dmsg1(130, "session_label record=%x\n", rec);
805 set_start_vol_position(dcr);
808 if (dev->is_tape()) {
809 dcr->EndBlock = dev->EndBlock;
810 dcr->EndFile = dev->EndFile;
812 dcr->EndBlock = (uint32_t)dev->file_addr;
813 dcr->EndFile = (uint32_t)(dev->file_addr >> 32);
817 Jmsg1(jcr, M_ABORT, 0, _("Bad Volume session label request=%d\n"), label);
820 create_session_label(dcr, rec, label);
821 rec->FileIndex = label;
824 * We guarantee that the session record can totally fit
825 * into a block. If not, write the block, and put it in
826 * the next block. Having the sesssion record totally in
827 * one block makes reading them much easier (no need to
828 * read the next block).
830 if (!can_write_record_to_block(block, rec)) {
831 Dmsg0(150, "Cannot write session label to block.\n");
832 if (!dcr->write_block_to_device()) {
833 Dmsg0(130, "Got session label write_block_to_dev error.\n");
840 * We use write_record() because it handles the case that
841 * the maximum user size has been reached.
843 if (!dcr->write_record(rec)) {
844 Dmsg0(150, "Bad return from write_record\n");
850 Dmsg6(150, "Write sesson_label record JobId=%d FI=%s SessId=%d Strm=%s len=%d "
851 "remainder=%d\n", jcr->JobId,
852 FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
853 stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
857 Dmsg2(150, "Leave write_session_label Block=%u File=%u\n",
858 dev->get_block_num(), dev->get_file());
863 /* unser_volume_label
865 * Unserialize the Bacula Volume label into the device Volume_Label
868 * Assumes that the record is already read.
870 * Returns: false on error
874 bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec)
877 char buf1[100], buf2[100];
880 if (rec->FileIndex != VOL_LABEL && rec->FileIndex != PRE_LABEL) {
881 Mmsg3(dev->errmsg, _("Expecting Volume Label, got FI=%s Stream=%s len=%d\n"),
882 FI_to_ascii(buf1, rec->FileIndex),
883 stream_to_ascii(buf2, rec->Stream, rec->FileIndex),
891 dev->VolHdr.LabelType = rec->FileIndex;
892 dev->VolHdr.LabelSize = rec->data_len;
895 /* Unserialize the record into the Volume Header */
896 Dmsg2(100, "reclen=%d recdata=%s\n", rec->data_len, rec->data);
897 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
898 Dmsg2(100, "reclen=%d recdata=%s\n", rec->data_len, rec->data);
899 ser_begin(rec->data, SER_LENGTH_Volume_Label);
900 unser_string(dev->VolHdr.Id);
901 unser_uint32(dev->VolHdr.VerNum);
903 if (dev->VolHdr.VerNum >= 11) {
904 unser_btime(dev->VolHdr.label_btime);
905 unser_btime(dev->VolHdr.write_btime);
906 } else { /* old way */
907 unser_float64(dev->VolHdr.label_date);
908 unser_float64(dev->VolHdr.label_time);
910 unser_float64(dev->VolHdr.write_date); /* Unused with VerNum >= 11 */
911 unser_float64(dev->VolHdr.write_time); /* Unused with VerNum >= 11 */
913 unser_string(dev->VolHdr.VolumeName);
914 unser_string(dev->VolHdr.PrevVolumeName);
915 unser_string(dev->VolHdr.PoolName);
916 unser_string(dev->VolHdr.PoolType);
917 unser_string(dev->VolHdr.MediaType);
919 unser_string(dev->VolHdr.HostName);
920 unser_string(dev->VolHdr.LabelProg);
921 unser_string(dev->VolHdr.ProgVersion);
922 unser_string(dev->VolHdr.ProgDate);
924 ser_end(rec->data, SER_LENGTH_Volume_Label);
925 Dmsg0(190, "unser_vol_label\n");
926 if (chk_dbglvl(100)) {
927 dump_volume_label(dev);
934 bool unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec)
939 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
940 unser_begin(rec->data, SER_LENGTH_Session_Label);
941 unser_string(label->Id);
942 unser_uint32(label->VerNum);
943 unser_uint32(label->JobId);
944 if (label->VerNum >= 11) {
945 unser_btime(label->write_btime);
947 unser_float64(label->write_date);
949 unser_float64(label->write_time);
950 unser_string(label->PoolName);
951 unser_string(label->PoolType);
952 unser_string(label->JobName);
953 unser_string(label->ClientName);
954 if (label->VerNum >= 10) {
955 unser_string(label->Job); /* Unique name of this Job */
956 unser_string(label->FileSetName);
957 unser_uint32(label->JobType);
958 unser_uint32(label->JobLevel);
960 if (label->VerNum >= 11) {
961 unser_string(label->FileSetMD5);
963 label->FileSetMD5[0] = 0;
965 if (rec->FileIndex == EOS_LABEL) {
966 unser_uint32(label->JobFiles);
967 unser_uint64(label->JobBytes);
968 unser_uint32(label->StartBlock);
969 unser_uint32(label->EndBlock);
970 unser_uint32(label->StartFile);
971 unser_uint32(label->EndFile);
972 unser_uint32(label->JobErrors);
973 if (label->VerNum >= 11) {
974 unser_uint32(label->JobStatus);
976 label->JobStatus = JS_Terminated; /* kludge */
983 void dump_volume_label(DEVICE *dev)
985 int64_t dbl = debug_level;
987 const char *LabelType;
994 switch (dev->VolHdr.LabelType) {
996 LabelType = "PRE_LABEL";
999 LabelType = "VOL_LABEL";
1002 LabelType = "EOM_LABEL";
1005 LabelType = "SOS_LABEL";
1008 LabelType = "EOS_LABEL";
1014 sprintf(buf, _("Unknown %d"), dev->VolHdr.LabelType);
1018 Pmsg11(-1, _("\nVolume Label:\n"
1022 "PrevVolName : %s\n"
1031 dev->VolHdr.Id, dev->VolHdr.VerNum,
1032 dev->VolHdr.VolumeName, dev->VolHdr.PrevVolumeName,
1033 File, LabelType, dev->VolHdr.LabelSize,
1034 dev->VolHdr.PoolName, dev->VolHdr.MediaType,
1035 dev->VolHdr.PoolType, dev->VolHdr.HostName);
1037 if (dev->VolHdr.VerNum >= 11) {
1039 bstrftime(dt, sizeof(dt), btime_to_utime(dev->VolHdr.label_btime));
1040 Pmsg1(-1, _("Date label written: %s\n"), dt);
1042 dt.julian_day_number = dev->VolHdr.label_date;
1043 dt.julian_day_fraction = dev->VolHdr.label_time;
1044 tm_decode(&dt, &tm);
1046 _("Date label written: %04d-%02d-%02d at %02d:%02d\n"),
1047 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
1055 static void dump_session_label(DEV_RECORD *rec, const char *type)
1058 struct date_time dt;
1060 SESSION_LABEL label;
1061 char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], ec6[30], ec7[30];
1063 unser_session_label(&label, rec);
1066 Pmsg7(-1, _("\n%s Record:\n"
1073 ""), type, label.JobId, label.VerNum,
1074 label.PoolName, label.PoolType,
1075 label.JobName, label.ClientName);
1077 if (label.VerNum >= 10) {
1079 "Job (unique name) : %s\n"
1083 ""), label.Job, label.FileSetName, label.JobType, label.JobLevel);
1086 if (rec->FileIndex == EOS_LABEL) {
1097 edit_uint64_with_commas(label.JobFiles, ec1),
1098 edit_uint64_with_commas(label.JobBytes, ec2),
1099 edit_uint64_with_commas(label.StartBlock, ec3),
1100 edit_uint64_with_commas(label.EndBlock, ec4),
1101 edit_uint64_with_commas(label.StartFile, ec5),
1102 edit_uint64_with_commas(label.EndFile, ec6),
1103 edit_uint64_with_commas(label.JobErrors, ec7),
1106 if (label.VerNum >= 11) {
1108 bstrftime(dt, sizeof(dt), btime_to_utime(label.write_btime));
1109 Pmsg1(-1, _("Date written : %s\n"), dt);
1111 dt.julian_day_number = label.write_date;
1112 dt.julian_day_fraction = label.write_time;
1113 tm_decode(&dt, &tm);
1114 Pmsg5(-1, _("Date written : %04d-%02d-%02d at %02d:%02d\n"),
1115 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
1121 static int check_label(SESSION_LABEL *label)
1125 if (label->JobId > 10000000 || label->JobId < 0) {
1126 Pmsg0(-1, _("***** ERROR ****** : Found error with the JobId\n"));
1131 switch (label->JobLevel) {
1134 case L_DIFFERENTIAL:
1136 case L_VERIFY_CATALOG:
1138 case L_VERIFY_VOLUME_TO_CATALOG:
1139 case L_VERIFY_DISK_TO_CATALOG:
1143 case L_VIRTUAL_FULL:
1146 Pmsg0(-1, _("***** ERROR ****** : Found error with the JobLevel\n"));
1151 switch (label->JobType) {
1153 case JT_MIGRATED_JOB:
1166 Pmsg0(-1, _("***** ERROR ****** : Found error with the JobType\n"));
1171 POOLMEM *err = get_pool_memory(PM_EMSG);
1172 if (!is_name_valid(label->Job, &err)) {
1173 Pmsg1(-1, _("***** ERROR ****** : Found error with the Job name %s\n"), err);
1176 free_pool_memory(err);
1181 int dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose, bool check_err)
1187 if (rec->FileIndex == 0 && rec->VolSessionId == 0 && rec->VolSessionTime == 0) {
1192 switch (rec->FileIndex) {
1194 type = _("Fresh Volume");
1200 type = _("Begin Job Session");
1203 type = _("End Job Session");
1206 type = _("End of Media");
1209 type = _("End of Tape");
1212 type = _("Unknown");
1216 switch (rec->FileIndex) {
1219 unser_volume_label(dev, rec);
1220 dump_volume_label(dev);
1225 dump_session_label(rec, type);
1228 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1229 type, dev->file, dev->block_num, rec->VolSessionId,
1230 rec->VolSessionTime, rec->Stream, rec->data_len);
1233 Pmsg0(-1, _("Bacula \"End of Tape\" label found.\n"));
1236 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1237 type, dev->file, dev->block_num, rec->VolSessionId,
1238 rec->VolSessionTime, rec->Stream, rec->data_len);
1242 SESSION_LABEL label;
1244 switch (rec->FileIndex) {
1246 unser_session_label(&label, rec);
1247 bstrftimes(dt, sizeof(dt), btime_to_utime(label.write_btime));
1248 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1249 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1250 Pmsg4(-1, _(" Job=%s Date=%s Level=%c Type=%c\n"),
1251 label.Job, dt, label.JobLevel, label.JobType);
1253 errors += check_label(&label);
1257 char ed1[30], ed2[30];
1258 unser_session_label(&label, rec);
1259 bstrftimes(dt, sizeof(dt), btime_to_utime(label.write_btime));
1260 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1261 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1262 Pmsg7(-1, _(" Date=%s Level=%c Type=%c Files=%s Bytes=%s Errors=%d Status=%c\n"),
1263 dt, label.JobLevel, label.JobType,
1264 edit_uint64_with_commas(label.JobFiles, ed1),
1265 edit_uint64_with_commas(label.JobBytes, ed2),
1266 label.JobErrors, (char)label.JobStatus);
1268 errors += check_label(&label);
1275 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1276 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime,
1277 rec->Stream, rec->data_len);