2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2015 Kern Sibbald
5 Copyright (C) 2000-2014 Free Software Foundation Europe e.V.
7 The original author of Bacula is Kern Sibbald, with contributions
8 from many others, a complete list can be found in the file AUTHORS.
10 You may use this file and others of this release according to the
11 license defined in the LICENSE file, which includes the Affero General
12 Public License, v3.0 ("AGPLv3") and some additional permissions and
13 terms pursuant to its AGPLv3 Section 7.
15 This notice must be preserved when any source code is
16 conveyed and/or propagated.
18 Bacula(R) is a registered trademark of Kern Sibbald.
22 * label.c Bacula routines to handle labels
28 #include "bacula.h" /* pull in global headers */
29 #include "stored.h" /* pull in Storage Deamon headers */
31 /* Forward referenced functions */
32 static void create_volume_label_record(DCR *dcr, DEVICE *dev, DEV_RECORD *rec, bool alt);
33 static bool sub_write_volume_label_to_block(DCR *dcr);
34 static bool sub_write_new_volume_label_to_dev(DCR *dcr, const char *VolName,
35 const char *PoolName, bool relabel, bool dvdnow);
38 * Read the volume label
40 * If dcr->VolumeName == NULL, we accept any Bacula Volume
41 * If dcr->VolumeName[0] == 0, we accept any Bacula Volume
42 * otherwise dcr->VolumeName must match the Volume.
44 * If VolName given, ensure that it matches
46 * Returns VOL_ code as defined in record.h
48 * VOL_OK good label found
49 * VOL_NO_LABEL volume not labeled
50 * VOL_IO_ERROR I/O error reading tape
51 * VOL_NAME_ERROR label has wrong name
52 * VOL_CREATE_ERROR Error creating label
53 * VOL_VERSION_ERROR label has wrong version
54 * VOL_LABEL_ERROR bad label type
55 * VOL_NO_MEDIA no media in drive
57 * The dcr block is emptied on return, and the Volume is
61 int read_dev_volume_label(DCR *dcr)
64 DEVICE * volatile dev = dcr->dev;
65 char *VolName = dcr->VolumeName;
68 DEV_BLOCK *block = dcr->block;
71 bool have_ansi_label = false;
74 Dmsg4(100, "Enter read_volume_label res=%d device=%s vol=%s dev_Vol=%s\n",
75 dev->num_reserved(), dev->print_name(), VolName,
76 dev->VolHdr.VolumeName[0]?dev->VolHdr.VolumeName:"*NULL*");
78 if (!dev->is_open()) {
79 if (!dev->open(dcr, OPEN_READ_ONLY)) {
88 dev->label_type = B_BACULA_LABEL;
90 if (!dev->rewind(dcr)) {
91 Mmsg(jcr->errmsg, _("Couldn't rewind %s device %s: ERR=%s\n"),
92 dev->print_type(), dev->print_name(), dev->print_errmsg());
93 Dmsg1(130, "return VOL_NO_MEDIA: %s", jcr->errmsg);
97 bstrncpy(dev->VolHdr.Id, "**error**", sizeof(dev->VolHdr.Id));
99 /* Read ANSI/IBM label if so requested */
100 want_ansi_label = dcr->VolCatInfo.LabelType != B_BACULA_LABEL ||
101 dcr->device->label_type != B_BACULA_LABEL;
102 if (want_ansi_label || dev->has_cap(CAP_CHECKLABELS)) {
103 stat = read_ansi_ibm_label(dcr);
104 /* If we want a label and didn't find it, return error */
105 if (want_ansi_label && stat != VOL_OK) {
108 if (stat == VOL_NAME_ERROR || stat == VOL_LABEL_ERROR) {
109 Mmsg(jcr->errmsg, _("Wrong Volume mounted on %s device %s: Wanted %s have %s\n"),
110 dev->print_type(), dev->print_name(), VolName, dev->VolHdr.VolumeName);
111 if (!dev->poll && jcr->label_errors++ > 100) {
112 Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
116 if (stat != VOL_OK) { /* Not an ANSI/IBM label, so re-read */
119 have_ansi_label = true;
123 /* Read the Bacula Volume label block */
124 record = new_record();
127 Dmsg0(130, "Big if statement in read_volume_label\n");
128 if (!dcr->read_block_from_dev(NO_BLOCK_NUMBER_CHECK)) {
129 Mmsg(jcr->errmsg, _("Requested Volume \"%s\" on %s device %s is not a Bacula "
130 "labeled Volume, because: ERR=%s"), NPRT(VolName),
131 dev->print_type(), dev->print_name(), dev->print_errmsg());
132 Dmsg1(130, "%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(130, "%s", jcr->errmsg);
136 } else if (!unser_volume_label(dev, record)) {
137 Mmsg(jcr->errmsg, _("Could not unserialize Volume label: ERR=%s\n"),
138 dev->print_errmsg());
139 Dmsg1(130, "%s", jcr->errmsg);
140 } else if (strcmp(dev->VolHdr.Id, BaculaId) != 0 &&
141 strcmp(dev->VolHdr.Id, OldBaculaId) != 0) {
142 Mmsg(jcr->errmsg, _("Volume Header Id bad: %s\n"), dev->VolHdr.Id);
143 Dmsg1(130, "%s", jcr->errmsg);
147 free_record(record); /* finished reading Volume record */
149 if (!dev->is_volume_to_unload()) {
154 if (jcr->ignore_label_errors) {
155 dev->set_labeled(); /* set has Bacula label */
156 Jmsg(jcr, M_ERROR, 0, "%s", jcr->errmsg);
161 Dmsg0(100, "No volume label - bailing out\n");
166 /* At this point, we have read the first Bacula block, and
167 * then read the Bacula Volume label. Now we need to
168 * make sure we have the right Volume.
172 if (dev->VolHdr.VerNum != BaculaTapeVersion &&
173 dev->VolHdr.VerNum != OldCompatibleBaculaTapeVersion1 &&
174 dev->VolHdr.VerNum != OldCompatibleBaculaTapeVersion2) {
175 Mmsg(jcr->errmsg, _("Volume on %s device %s has wrong Bacula version. Wanted %d got %d\n"),
176 dev->print_type(), dev->print_name(), BaculaTapeVersion, dev->VolHdr.VerNum);
177 Dmsg1(130, "VOL_VERSION_ERROR: %s", jcr->errmsg);
178 stat = VOL_VERSION_ERROR;
182 /* We are looking for either an unused Bacula tape (PRE_LABEL) or
183 * a Bacula volume label (VOL_LABEL)
185 if (dev->VolHdr.LabelType != PRE_LABEL && dev->VolHdr.LabelType != VOL_LABEL) {
186 Mmsg(jcr->errmsg, _("Volume on %s device %s has bad Bacula label type: %x\n"),
187 dev->print_type(), dev->print_name(), dev->VolHdr.LabelType);
188 Dmsg1(130, "%s", jcr->errmsg);
189 if (!dev->poll && jcr->label_errors++ > 100) {
190 Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
192 Dmsg0(150, "return VOL_LABEL_ERROR\n");
193 stat = VOL_LABEL_ERROR;
197 dev->set_labeled(); /* set has Bacula label */
199 /* Compare Volume Names */
200 Dmsg2(130, "Compare Vol names: VolName=%s hdr=%s\n", VolName?VolName:"*", dev->VolHdr.VolumeName);
201 if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolumeName, VolName) != 0) {
202 Mmsg(jcr->errmsg, _("Wrong Volume mounted on %s device %s: Wanted %s have %s\n"),
203 dev->print_type(), dev->print_name(), VolName, dev->VolHdr.VolumeName);
204 Dmsg1(130, "%s", jcr->errmsg);
206 * Cancel Job if too many label errors
207 * => we are in a loop
209 if (!dev->poll && jcr->label_errors++ > 100) {
210 Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
212 Dmsg0(150, "return VOL_NAME_ERROR\n");
213 stat = VOL_NAME_ERROR;
217 if (chk_dbglvl(100)) {
218 dump_volume_label(dev);
220 Dmsg0(130, "Leave read_volume_label() VOL_OK\n");
221 /* If we are a streaming device, we only get one chance to read */
222 if (!dev->has_cap(CAP_STREAM)) {
224 if (have_ansi_label) {
225 stat = read_ansi_ibm_label(dcr);
226 /* If we want a label and didn't find it, return error */
227 if (stat != VOL_OK) {
233 Dmsg1(100, "Call reserve_volume=%s\n", dev->VolHdr.VolumeName);
234 if (reserve_volume(dcr, dev->VolHdr.VolumeName) == NULL) {
235 if (!jcr->errmsg[0]) {
236 Mmsg3(jcr->errmsg, _("Could not reserve volume %s on %s device %s\n"),
237 dev->VolHdr.VolumeName, dev->print_type(), dev->print_name());
239 Dmsg2(100, "Could not reserve volume %s on %s\n", dev->VolHdr.VolumeName, dev->print_name());
240 stat = VOL_NAME_ERROR;
252 Dmsg1(150, "return %d\n", stat);
259 * Create and put a volume label into the block
261 * Returns: false on failure
265 static bool write_volume_label_to_block(DCR *dcr)
270 Dmsg0(130, "write Label in write_volume_label_to_block()\n");
272 Dmsg0(100, "Call sub_write_vol_label\n");
273 ok = sub_write_volume_label_to_block(dcr);
283 static bool sub_write_volume_label_to_block(DCR *dcr)
294 memset(&rec, 0, sizeof(rec));
295 rec.data = get_memory(SER_LENGTH_Volume_Label);
296 memset(rec.data, 0, SER_LENGTH_Volume_Label);
297 empty_block(block); /* Volume label always at beginning */
299 create_volume_label_record(dcr, dcr->dev, &rec, false);
301 block->BlockNumber = 0;
302 Dmsg0(100, "write_record_to_block\n");
303 if (!write_record_to_block(dcr, &rec)) {
304 free_pool_memory(rec.data);
305 Jmsg2(jcr, M_FATAL, 0, _("Cannot write Volume label to block for %s device %s\n"),
306 dev->print_type(), dev->print_name());
310 Dmsg3(100, "Wrote fd=%d label of %d bytes to block. Vol=%s\n",
311 dev->fd(), rec.data_len, dcr->VolumeName);
313 free_pool_memory(rec.data);
321 * Write a Volume Label
322 * !!! Note, this is ONLY used for writing
323 * a fresh volume label. Any data
324 * after the label will be destroyed,
325 * in fact, we write the label 5 times !!!!
327 * This routine should be used only when labeling a blank tape or
328 * when recylcing a volume.
331 bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName,
332 const char *PoolName, bool relabel, bool dvdnow)
339 Dmsg0(150, "write_volume_label()\n");
342 Mmsg(dcr->jcr->errmsg, "ERROR: new_volume_label_to_dev called with NULL VolName\n");
344 Pmsg0(0, "=== ERROR: write_new_volume_label_to_dev called with NULL VolName\n");
349 volume_unused(dcr); /* mark current volume unused */
350 /* Truncate device */
351 if (!dev->truncate(dcr)) {
354 if (!dev->is_tape()) {
355 dev->close_part(dcr); /* make sure DVD/file closed for rename */
359 /* Set the new filename for open, ... */
360 dev->setVolCatName(VolName);
361 dcr->setVolCatName(VolName);
362 dev->clearVolCatBytes();
364 Dmsg1(100, "New VolName=%s\n", VolName);
365 if (!dev->open(dcr, OPEN_READ_WRITE)) {
366 /* If device is not tape, attempt to create it */
367 if (dev->is_tape() || !dev->open(dcr, CREATE_READ_WRITE)) {
368 Jmsg4(dcr->jcr, M_WARNING, 0, _("Open %s device %s Volume \"%s\" failed: ERR=%s\n"),
369 dev->print_type(), dev->print_name(), dcr->VolumeName, dev->bstrerror());
373 Dmsg1(150, "Label type=%d\n", dev->label_type);
375 if (!sub_write_new_volume_label_to_dev(dcr, VolName, PoolName, relabel, dvdnow)) {
380 write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
383 if (chk_dbglvl(100)) {
384 dump_volume_label(dev);
386 Dmsg0(50, "Call reserve_volume\n");
387 /**** ***FIXME*** if dev changes, dcr must be updated */
388 if (reserve_volume(dcr, VolName) == NULL) {
389 if (!dcr->jcr->errmsg[0]) {
390 Mmsg3(dcr->jcr->errmsg, _("Could not reserve volume %s on %s device %s\n"),
391 dev->VolHdr.VolumeName, dev->print_type(), dev->print_name());
393 Dmsg1(50, "%s", dcr->jcr->errmsg);
396 dev = dcr->dev; /* may have changed in reserve_volume */
397 dev->clear_append(); /* remove append since this is PRE_LABEL */
403 dcr->dev->clear_append(); /* remove append since this is PRE_LABEL */
408 static bool sub_write_new_volume_label_to_dev(DCR *dcr, const char *VolName,
409 const char *PoolName, bool relabel, bool dvdnow)
419 if (!dev->rewind(dcr)) {
420 Dmsg2(130, "Bad status on %s from rewind: ERR=%s\n", dev->print_name(), dev->print_errmsg());
424 /* Temporarily mark in append state to enable writing */
427 /* Create PRE_LABEL or VOL_LABEL if DVD */
428 create_volume_header(dev, VolName, PoolName, dvdnow);
431 * If we have already detected an ANSI label, re-read it
432 * to skip past it. Otherwise, we write a new one if
435 if (dev->label_type != B_BACULA_LABEL) {
436 if (read_ansi_ibm_label(dcr) != VOL_OK) {
440 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, VolName)) {
444 create_volume_label_record(dcr, dev, dcr->rec, false);
445 dcr->rec->Stream = 0;
446 dcr->rec->maskedStream = 0;
448 Dmsg1(100, "write_record_to_block FI=%d\n", dcr->rec->FileIndex);
450 if (!write_record_to_block(dcr, dcr->rec)) {
451 Dmsg2(40, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
454 Dmsg2(100, "Wrote label=%d bytes block: %s\n", dcr->rec->data_len, dev->print_name());
456 Dmsg2(100, "New label VolCatBytes=%lld VolCatStatus=%s\n",
457 dev->VolCatInfo.VolCatBytes, dev->VolCatInfo.VolCatStatus);
459 Dmsg3(130, "Call write_block_to_dev() fd=%d block=%p Addr=%lld\n",
460 dcr->dev->fd(), dcr->block, block->dev->lseek(dcr, 0, SEEK_CUR));
461 Dmsg0(100, "write_record_to_dev\n");
462 /* Write block to device */
463 if (!dcr->write_block_to_dev()) {
464 Dmsg2(40, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
467 Dmsg2(100, "New label VolCatBytes=%lld VolCatStatus=%s\n",
468 dev->VolCatInfo.VolCatBytes, dev->VolCatInfo.VolCatStatus);
478 * Write a volume label. This is ONLY called if we have a valid Bacula
479 * label of type PRE_LABEL or we are recyling an existing Volume.
481 * By calling write_volume_label_to_block
483 * Returns: true if OK
484 * false if unable to write it
486 bool DCR::rewrite_volume_label(bool recycle)
491 ASSERT2(dcr->VolumeName[0], "Empty Volume name");
492 if (!dev->open(dcr, OPEN_READ_WRITE)) {
493 Jmsg4(jcr, M_WARNING, 0, _("Open %s device %s Volume \"%s\" failed: ERR=%s\n"),
494 dev->print_type(), dev->print_name(), dcr->VolumeName, dev->bstrerror());
498 Dmsg2(190, "set append found freshly labeled volume. fd=%d dev=%x\n", dev->fd(), dev);
499 dev->VolHdr.LabelType = VOL_LABEL; /* set Volume label */
501 Dmsg0(100, "Rewrite_volume_label set volcatbytes=0\n");
502 dev->clearVolCatBytes();
503 dev->setVolCatStatus("Append"); /* set append status */
505 if (!dev->has_cap(CAP_STREAM)) {
506 if (!dev->rewind(dcr)) {
507 Jmsg3(jcr, M_FATAL, 0, _("Rewind error on %s device %s: ERR=%s\n"),
508 dev->print_type(), dev->print_name(), dev->print_errmsg());
513 Dmsg1(150, "Doing recycle. Vol=%s\n", dcr->VolumeName);
514 if (!dev->truncate(dcr)) {
515 Jmsg3(jcr, M_FATAL, 0, _("Truncate error on %s device %s: ERR=%s\n"),
516 dev->print_type(), dev->print_name(), dev->print_errmsg());
520 if (!dev->open(dcr, OPEN_READ_WRITE)) {
521 Jmsg3(jcr, M_FATAL, 0,
522 _("Failed to re-open DVD after truncate on %s device %s: ERR=%s\n"),
523 dev->print_type(), dev->print_name(), dev->print_errmsg());
530 if (!write_volume_label_to_block(dcr)) {
531 Dmsg0(150, "Error from write volume label.\n");
535 Dmsg1(100, "wrote vol label to block. Vol=%s\n", dcr->VolumeName);
537 ASSERT2(dcr->VolumeName[0], "Empty Volume name");
538 dev->setVolCatInfo(false);
541 * If we are not dealing with a streaming device,
542 * write the block now to ensure we have write permission.
543 * It is better to find out now rather than later.
544 * We do not write the block now if this is an ANSI label. This
545 * avoids re-writing the ANSI label, which we do not want to do.
547 if (!dev->has_cap(CAP_STREAM)) {
549 * If we have already detected an ANSI label, re-read it
550 * to skip past it. Otherwise, we write a new one if
553 if (dev->label_type != B_BACULA_LABEL) {
554 if (read_ansi_ibm_label(dcr) != VOL_OK) {
559 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, dev->VolHdr.VolumeName)) {
564 /* Attempt write to check write permission */
565 Dmsg1(200, "Attempt to write to device fd=%d.\n", dev->fd());
566 if (!dcr->write_block_to_dev()) {
567 Jmsg3(jcr, M_ERROR, 0, _("Unable to write %s device %s: ERR=%s\n"),
568 dev->print_type(), dev->print_name(), dev->print_errmsg());
569 Dmsg0(200, "===ERROR write block to dev\n");
575 /* Set or reset Volume statistics */
576 dev->VolCatInfo.VolCatJobs = 0;
577 dev->VolCatInfo.VolCatFiles = 0;
578 dev->VolCatInfo.VolCatErrors = 0;
579 dev->VolCatInfo.VolCatBlocks = 0;
580 dev->VolCatInfo.VolCatRBytes = 0;
582 dev->VolCatInfo.VolCatMounts++;
583 dev->VolCatInfo.VolCatRecycles++;
584 dir_create_jobmedia_record(dcr, true);
586 dev->VolCatInfo.VolCatMounts = 1;
587 dev->VolCatInfo.VolCatRecycles = 0;
588 dev->VolCatInfo.VolCatWrites = 1;
589 dev->VolCatInfo.VolCatReads = 1;
591 Dmsg1(100, "dir_update_vol_info. Set Append vol=%s\n", dcr->VolumeName);
592 dev->VolCatInfo.VolFirstWritten = time(NULL);
593 dev->setVolCatStatus("Append");
594 ASSERT2(dcr->VolumeName[0], "Empty Volume name");
595 dev->setVolCatName(dcr->VolumeName);
596 if (!dir_update_volume_info(dcr, true, true)) { /* indicate relabel */
601 Jmsg(jcr, M_INFO, 0, _("Recycled volume \"%s\" on %s device %s, all previous data lost.\n"),
602 dcr->VolumeName, dev->print_type(), dev->print_name());
604 Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume \"%s\" on %s device %s\n"),
605 dcr->VolumeName, dev->print_type(), dev->print_name());
608 * End writing real Volume label (from pre-labeled tape), or recycling
611 Dmsg1(100, "OK from rewrite vol label. Vol=%s\n", dcr->VolumeName);
618 * create_volume_label_record
619 * Serialize label (from dev->VolHdr structure) into device record.
620 * Assumes that the dev->VolHdr structure is properly
623 static void create_volume_label_record(DCR *dcr, DEVICE *dev,
624 DEV_RECORD *rec, bool alt)
631 /* Serialize the label into the device record. */
634 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
635 memset(rec->data, 0, SER_LENGTH_Volume_Label);
636 ser_begin(rec->data, SER_LENGTH_Volume_Label);
637 ser_string(dev->VolHdr.Id);
639 ser_uint32(dev->VolHdr.VerNum);
641 if (dev->VolHdr.VerNum >= 11) {
642 ser_btime(dev->VolHdr.label_btime);
643 dev->VolHdr.write_btime = get_current_btime();
644 ser_btime(dev->VolHdr.write_btime);
645 dev->VolHdr.write_date = 0;
646 dev->VolHdr.write_time = 0;
648 /* OLD WAY DEPRECATED */
649 ser_float64(dev->VolHdr.label_date);
650 ser_float64(dev->VolHdr.label_time);
651 get_current_time(&dt);
652 dev->VolHdr.write_date = dt.julian_day_number;
653 dev->VolHdr.write_time = dt.julian_day_fraction;
655 ser_float64(dev->VolHdr.write_date); /* 0 if VerNum >= 11 */
656 ser_float64(dev->VolHdr.write_time); /* 0 if VerNum >= 11 */
658 ser_string(dev->VolHdr.VolumeName);
659 ser_string(dev->VolHdr.PrevVolumeName);
660 ser_string(dev->VolHdr.PoolName);
661 ser_string(dev->VolHdr.PoolType);
662 ser_string(dev->VolHdr.MediaType);
664 ser_string(dev->VolHdr.HostName);
665 ser_string(dev->VolHdr.LabelProg);
666 ser_string(dev->VolHdr.ProgVersion);
667 ser_string(dev->VolHdr.ProgDate);
669 ser_end(rec->data, SER_LENGTH_Volume_Label);
670 bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName));
671 ASSERT2(dcr->VolumeName[0], "Empty Volume name");
672 rec->data_len = ser_length(rec->data);
673 rec->FileIndex = dev->VolHdr.LabelType;
674 Dmsg1(100, "LabelType=%d\n", dev->VolHdr.LabelType);
675 rec->VolSessionId = jcr->VolSessionId;
676 rec->VolSessionTime = jcr->VolSessionTime;
677 rec->Stream = jcr->NumWriteVolumes;
678 rec->maskedStream = jcr->NumWriteVolumes;
679 Dmsg2(100, "Created Vol label rec: FI=%s len=%d\n", FI_to_ascii(buf, rec->FileIndex),
681 Dmsg2(100, "reclen=%d recdata=%s\n", rec->data_len, rec->data);
687 * Create a volume header in memory
689 void create_volume_header(DEVICE *dev, const char *VolName,
690 const char *PoolName, bool dvdnow)
692 DEVRES *device = (DEVRES *)dev->device;
694 Dmsg0(130, "Start create_volume_header()\n");
698 bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
699 dev->VolHdr.VerNum = BaculaTapeVersion;
700 if (dev->is_dvd() && dvdnow) {
701 /* We do not want to re-label a DVD so write VOL_LABEL now */
702 dev->VolHdr.LabelType = VOL_LABEL;
704 dev->VolHdr.LabelType = PRE_LABEL; /* Mark tape as unused */
706 bstrncpy(dev->VolHdr.VolumeName, VolName, sizeof(dev->VolHdr.VolumeName));
707 bstrncpy(dev->VolHdr.PoolName, PoolName, sizeof(dev->VolHdr.PoolName));
708 bstrncpy(dev->VolHdr.MediaType, device->media_type, sizeof(dev->VolHdr.MediaType));
710 bstrncpy(dev->VolHdr.PoolType, "Backup", sizeof(dev->VolHdr.PoolType));
712 dev->VolHdr.label_btime = get_current_btime();
713 dev->VolHdr.label_date = 0;
714 dev->VolHdr.label_time = 0;
716 if (gethostname(dev->VolHdr.HostName, sizeof(dev->VolHdr.HostName)) != 0) {
717 dev->VolHdr.HostName[0] = 0;
719 bstrncpy(dev->VolHdr.LabelProg, my_name, sizeof(dev->VolHdr.LabelProg));
720 sprintf(dev->VolHdr.ProgVersion, "Ver. %s %s ", VERSION, BDATE);
721 sprintf(dev->VolHdr.ProgDate, "Build %s %s ", __DATE__, __TIME__);
722 dev->set_labeled(); /* set has Bacula label */
723 if (chk_dbglvl(100)) {
724 dump_volume_label(dev);
729 * Create session label
730 * The pool memory must be released by the calling program
732 void create_session_label(DCR *dcr, DEV_RECORD *rec, int label)
738 rec->VolSessionId = jcr->VolSessionId;
739 rec->VolSessionTime = jcr->VolSessionTime;
740 rec->Stream = jcr->JobId;
741 rec->maskedStream = jcr->JobId;
743 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
744 ser_begin(rec->data, SER_LENGTH_Session_Label);
745 ser_string(BaculaId);
746 ser_uint32(BaculaTapeVersion);
748 ser_uint32(jcr->JobId);
750 /* Changed in VerNum 11 */
751 ser_btime(get_current_btime());
754 ser_string(dcr->pool_name);
755 ser_string(dcr->pool_type);
756 ser_string(jcr->job_name); /* base Job name */
757 ser_string(jcr->client_name);
759 /* Added in VerNum 10 */
760 ser_string(jcr->Job); /* Unique name of this Job */
761 ser_string(jcr->fileset_name);
762 ser_uint32(jcr->getJobType());
763 ser_uint32(jcr->getJobLevel());
764 /* Added in VerNum 11 */
765 ser_string(jcr->fileset_md5);
767 if (label == EOS_LABEL) {
768 ser_uint32(jcr->JobFiles);
769 ser_uint64(jcr->JobBytes);
770 ser_uint32(dcr->StartBlock);
771 ser_uint32(dcr->EndBlock);
772 ser_uint32(dcr->StartFile);
773 ser_uint32(dcr->EndFile);
774 ser_uint32(jcr->JobErrors);
776 /* Added in VerNum 11 */
777 ser_uint32(jcr->JobStatus);
779 ser_end(rec->data, SER_LENGTH_Session_Label);
780 rec->data_len = ser_length(rec->data);
784 /* Write session label
785 * Returns: false on failure
788 bool write_session_label(DCR *dcr, int label)
791 DEVICE *dev = dcr->dev;
793 DEV_BLOCK *block = dcr->block;
794 char buf1[100], buf2[100];
798 Dmsg1(130, "session_label record=%x\n", rec);
801 set_start_vol_position(dcr);
804 if (dev->is_tape()) {
805 dcr->EndBlock = dev->EndBlock;
806 dcr->EndFile = dev->EndFile;
808 dcr->EndBlock = (uint32_t)dev->file_addr;
809 dcr->EndFile = (uint32_t)(dev->file_addr >> 32);
813 Jmsg1(jcr, M_ABORT, 0, _("Bad Volume session label request=%d\n"), label);
816 create_session_label(dcr, rec, label);
817 rec->FileIndex = label;
820 * We guarantee that the session record can totally fit
821 * into a block. If not, write the block, and put it in
822 * the next block. Having the sesssion record totally in
823 * one block makes reading them much easier (no need to
824 * read the next block).
826 if (!can_write_record_to_block(block, rec)) {
827 Dmsg0(150, "Cannot write session label to block.\n");
828 if (!dcr->write_block_to_device()) {
829 Dmsg0(130, "Got session label write_block_to_dev error.\n");
836 * We use write_record() because it handles the case that
837 * the maximum user size has been reached.
839 if (!dcr->write_record(rec)) {
840 Dmsg0(150, "Bad return from write_record\n");
846 Dmsg6(150, "Write sesson_label record JobId=%d FI=%s SessId=%d Strm=%s len=%d "
847 "remainder=%d\n", jcr->JobId,
848 FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
849 stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
853 Dmsg2(150, "Leave write_session_label Block=%u File=%u\n",
854 dev->get_block_num(), dev->get_file());
859 /* unser_volume_label
861 * Unserialize the Bacula Volume label into the device Volume_Label
864 * Assumes that the record is already read.
866 * Returns: false on error
870 bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec)
873 char buf1[100], buf2[100];
876 if (rec->FileIndex != VOL_LABEL && rec->FileIndex != PRE_LABEL) {
877 Mmsg3(dev->errmsg, _("Expecting Volume Label, got FI=%s Stream=%s len=%d\n"),
878 FI_to_ascii(buf1, rec->FileIndex),
879 stream_to_ascii(buf2, rec->Stream, rec->FileIndex),
887 dev->VolHdr.LabelType = rec->FileIndex;
888 dev->VolHdr.LabelSize = rec->data_len;
891 /* Unserialize the record into the Volume Header */
892 Dmsg2(100, "reclen=%d recdata=%s\n", rec->data_len, rec->data);
893 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
894 Dmsg2(100, "reclen=%d recdata=%s\n", rec->data_len, rec->data);
895 ser_begin(rec->data, SER_LENGTH_Volume_Label);
896 unser_string(dev->VolHdr.Id);
897 unser_uint32(dev->VolHdr.VerNum);
899 if (dev->VolHdr.VerNum >= 11) {
900 unser_btime(dev->VolHdr.label_btime);
901 unser_btime(dev->VolHdr.write_btime);
902 } else { /* old way */
903 unser_float64(dev->VolHdr.label_date);
904 unser_float64(dev->VolHdr.label_time);
906 unser_float64(dev->VolHdr.write_date); /* Unused with VerNum >= 11 */
907 unser_float64(dev->VolHdr.write_time); /* Unused with VerNum >= 11 */
909 unser_string(dev->VolHdr.VolumeName);
910 unser_string(dev->VolHdr.PrevVolumeName);
911 unser_string(dev->VolHdr.PoolName);
912 unser_string(dev->VolHdr.PoolType);
913 unser_string(dev->VolHdr.MediaType);
915 unser_string(dev->VolHdr.HostName);
916 unser_string(dev->VolHdr.LabelProg);
917 unser_string(dev->VolHdr.ProgVersion);
918 unser_string(dev->VolHdr.ProgDate);
920 ser_end(rec->data, SER_LENGTH_Volume_Label);
921 Dmsg0(190, "unser_vol_label\n");
922 if (chk_dbglvl(100)) {
923 dump_volume_label(dev);
930 bool unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec)
935 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
936 unser_begin(rec->data, SER_LENGTH_Session_Label);
937 unser_string(label->Id);
938 unser_uint32(label->VerNum);
939 unser_uint32(label->JobId);
940 if (label->VerNum >= 11) {
941 unser_btime(label->write_btime);
943 unser_float64(label->write_date);
945 unser_float64(label->write_time);
946 unser_string(label->PoolName);
947 unser_string(label->PoolType);
948 unser_string(label->JobName);
949 unser_string(label->ClientName);
950 if (label->VerNum >= 10) {
951 unser_string(label->Job); /* Unique name of this Job */
952 unser_string(label->FileSetName);
953 unser_uint32(label->JobType);
954 unser_uint32(label->JobLevel);
956 if (label->VerNum >= 11) {
957 unser_string(label->FileSetMD5);
959 label->FileSetMD5[0] = 0;
961 if (rec->FileIndex == EOS_LABEL) {
962 unser_uint32(label->JobFiles);
963 unser_uint64(label->JobBytes);
964 unser_uint32(label->StartBlock);
965 unser_uint32(label->EndBlock);
966 unser_uint32(label->StartFile);
967 unser_uint32(label->EndFile);
968 unser_uint32(label->JobErrors);
969 if (label->VerNum >= 11) {
970 unser_uint32(label->JobStatus);
972 label->JobStatus = JS_Terminated; /* kludge */
979 void dump_volume_label(DEVICE *dev)
981 int64_t dbl = debug_level;
983 const char *LabelType;
990 switch (dev->VolHdr.LabelType) {
992 LabelType = "PRE_LABEL";
995 LabelType = "VOL_LABEL";
998 LabelType = "EOM_LABEL";
1001 LabelType = "SOS_LABEL";
1004 LabelType = "EOS_LABEL";
1010 sprintf(buf, _("Unknown %d"), dev->VolHdr.LabelType);
1014 Pmsg11(-1, _("\nVolume Label:\n"
1018 "PrevVolName : %s\n"
1027 dev->VolHdr.Id, dev->VolHdr.VerNum,
1028 dev->VolHdr.VolumeName, dev->VolHdr.PrevVolumeName,
1029 File, LabelType, dev->VolHdr.LabelSize,
1030 dev->VolHdr.PoolName, dev->VolHdr.MediaType,
1031 dev->VolHdr.PoolType, dev->VolHdr.HostName);
1033 if (dev->VolHdr.VerNum >= 11) {
1035 bstrftime(dt, sizeof(dt), btime_to_utime(dev->VolHdr.label_btime));
1036 Pmsg1(-1, _("Date label written: %s\n"), dt);
1038 dt.julian_day_number = dev->VolHdr.label_date;
1039 dt.julian_day_fraction = dev->VolHdr.label_time;
1040 tm_decode(&dt, &tm);
1042 _("Date label written: %04d-%02d-%02d at %02d:%02d\n"),
1043 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
1051 static void dump_session_label(DEV_RECORD *rec, const char *type)
1054 struct date_time dt;
1056 SESSION_LABEL label;
1057 char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], ec6[30], ec7[30];
1059 unser_session_label(&label, rec);
1062 Pmsg7(-1, _("\n%s Record:\n"
1069 ""), type, label.JobId, label.VerNum,
1070 label.PoolName, label.PoolType,
1071 label.JobName, label.ClientName);
1073 if (label.VerNum >= 10) {
1075 "Job (unique name) : %s\n"
1079 ""), label.Job, label.FileSetName, label.JobType, label.JobLevel);
1082 if (rec->FileIndex == EOS_LABEL) {
1093 edit_uint64_with_commas(label.JobFiles, ec1),
1094 edit_uint64_with_commas(label.JobBytes, ec2),
1095 edit_uint64_with_commas(label.StartBlock, ec3),
1096 edit_uint64_with_commas(label.EndBlock, ec4),
1097 edit_uint64_with_commas(label.StartFile, ec5),
1098 edit_uint64_with_commas(label.EndFile, ec6),
1099 edit_uint64_with_commas(label.JobErrors, ec7),
1102 if (label.VerNum >= 11) {
1104 bstrftime(dt, sizeof(dt), btime_to_utime(label.write_btime));
1105 Pmsg1(-1, _("Date written : %s\n"), dt);
1107 dt.julian_day_number = label.write_date;
1108 dt.julian_day_fraction = label.write_time;
1109 tm_decode(&dt, &tm);
1110 Pmsg5(-1, _("Date written : %04d-%02d-%02d at %02d:%02d\n"),
1111 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
1117 static int check_label(SESSION_LABEL *label)
1121 if (label->JobId > 10000000 || label->JobId < 0) {
1122 Pmsg0(-1, _("***** ERROR ****** : Found error with the JobId\n"));
1127 switch (label->JobLevel) {
1130 case L_DIFFERENTIAL:
1132 case L_VERIFY_CATALOG:
1134 case L_VERIFY_VOLUME_TO_CATALOG:
1135 case L_VERIFY_DISK_TO_CATALOG:
1139 case L_VIRTUAL_FULL:
1142 Pmsg0(-1, _("***** ERROR ****** : Found error with the JobLevel\n"));
1147 switch (label->JobType) {
1149 case JT_MIGRATED_JOB:
1162 Pmsg0(-1, _("***** ERROR ****** : Found error with the JobType\n"));
1167 POOLMEM *err = get_pool_memory(PM_EMSG);
1168 if (!is_name_valid(label->Job, &err)) {
1169 Pmsg1(-1, _("***** ERROR ****** : Found error with the Job name %s\n"), err);
1172 free_pool_memory(err);
1177 int dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose, bool check_err)
1183 if (rec->FileIndex == 0 && rec->VolSessionId == 0 && rec->VolSessionTime == 0) {
1188 switch (rec->FileIndex) {
1190 type = _("Fresh Volume");
1196 type = _("Begin Job Session");
1199 type = _("End Job Session");
1202 type = _("End of Media");
1205 type = _("End of Tape");
1208 type = _("Unknown");
1212 switch (rec->FileIndex) {
1215 unser_volume_label(dev, rec);
1216 dump_volume_label(dev);
1221 dump_session_label(rec, type);
1224 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1225 type, dev->file, dev->block_num, rec->VolSessionId,
1226 rec->VolSessionTime, rec->Stream, rec->data_len);
1229 Pmsg0(-1, _("Bacula \"End of Tape\" label found.\n"));
1232 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1233 type, dev->file, dev->block_num, rec->VolSessionId,
1234 rec->VolSessionTime, rec->Stream, rec->data_len);
1238 SESSION_LABEL label;
1240 switch (rec->FileIndex) {
1242 unser_session_label(&label, rec);
1243 bstrftimes(dt, sizeof(dt), btime_to_utime(label.write_btime));
1244 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1245 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1246 Pmsg4(-1, _(" Job=%s Date=%s Level=%c Type=%c\n"),
1247 label.Job, dt, label.JobLevel, label.JobType);
1249 errors += check_label(&label);
1253 char ed1[30], ed2[30];
1254 unser_session_label(&label, rec);
1255 bstrftimes(dt, sizeof(dt), btime_to_utime(label.write_btime));
1256 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1257 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1258 Pmsg7(-1, _(" Date=%s Level=%c Type=%c Files=%s Bytes=%s Errors=%d Status=%c\n"),
1259 dt, label.JobLevel, label.JobType,
1260 edit_uint64_with_commas(label.JobFiles, ed1),
1261 edit_uint64_with_commas(label.JobBytes, ed2),
1262 label.JobErrors, (char)label.JobStatus);
1264 errors += check_label(&label);
1271 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1272 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime,
1273 rec->Stream, rec->data_len);