2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2012 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version three of the GNU Affero General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU Affero General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
30 * label.c Bacula routines to handle labels
36 #include "bacula.h" /* pull in global headers */
37 #include "stored.h" /* pull in Storage Deamon headers */
39 /* Forward referenced functions */
40 static void create_volume_label_record(DCR *dcr, DEVICE *dev, DEV_RECORD *rec);
43 * Read the volume label
45 * If dcr->VolumeName == NULL, we accept any Bacula Volume
46 * If dcr->VolumeName[0] == 0, we accept any Bacula Volume
47 * otherwise dcr->VolumeName must match the Volume.
49 * If VolName given, ensure that it matches
51 * Returns VOL_ code as defined in record.h
53 * VOL_OK good label found
54 * VOL_NO_LABEL volume not labeled
55 * VOL_IO_ERROR I/O error reading tape
56 * VOL_NAME_ERROR label has wrong name
57 * VOL_CREATE_ERROR Error creating label
58 * VOL_VERSION_ERROR label has wrong version
59 * VOL_LABEL_ERROR bad label type
60 * VOL_NO_MEDIA no media in drive
62 * The dcr block is emptied on return, and the Volume is
65 int read_dev_volume_label(DCR *dcr)
68 DEVICE * volatile dev = dcr->dev;
69 char *VolName = dcr->VolumeName;
72 DEV_BLOCK *block = dcr->block;
75 bool have_ansi_label = false;
77 Dmsg4(100, "Enter read_volume_label res=%d device=%s vol=%s dev_Vol=%s\n",
78 dev->num_reserved(), dev->print_name(), VolName,
79 dev->VolHdr.VolumeName[0]?dev->VolHdr.VolumeName:"*NULL*");
81 if (!dev->is_open()) {
82 if (!dev->open(dcr, OPEN_READ_ONLY)) {
90 dev->label_type = B_BACULA_LABEL;
92 if (!dev->rewind(dcr)) {
93 Mmsg(jcr->errmsg, _("Couldn't rewind device %s: ERR=%s\n"),
94 dev->print_name(), dev->print_errmsg());
95 Dmsg1(130, "return VOL_NO_MEDIA: %s", jcr->errmsg);
98 bstrncpy(dev->VolHdr.Id, "**error**", sizeof(dev->VolHdr.Id));
100 /* Read ANSI/IBM label if so requested */
101 want_ansi_label = dcr->VolCatInfo.LabelType != B_BACULA_LABEL ||
102 dcr->device->label_type != B_BACULA_LABEL;
103 if (want_ansi_label || dev->has_cap(CAP_CHECKLABELS)) {
104 stat = read_ansi_ibm_label(dcr);
105 /* If we want a label and didn't find it, return error */
106 if (want_ansi_label && stat != VOL_OK) {
109 if (stat == VOL_NAME_ERROR || stat == VOL_LABEL_ERROR) {
110 Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
111 dev->print_name(), VolName, dev->VolHdr.VolumeName);
112 if (!dev->poll && jcr->label_errors++ > 100) {
113 Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
117 if (stat != VOL_OK) { /* Not an ANSI/IBM label, so re-read */
120 have_ansi_label = true;
124 /* Read the Bacula Volume label block */
125 record = new_record();
128 Dmsg0(130, "Big if statement in read_volume_label\n");
129 if (!dcr->read_block_from_dev(NO_BLOCK_NUMBER_CHECK)) {
130 Mmsg(jcr->errmsg, _("Requested Volume \"%s\" on %s is not a Bacula "
131 "labeled Volume, because: ERR=%s"), NPRT(VolName),
132 dev->print_name(), dev->print_errmsg());
133 Dmsg1(130, "%s", jcr->errmsg);
134 } else if (!read_record_from_block(dcr, block, record)) {
135 Mmsg(jcr->errmsg, _("Could not read Volume label from block.\n"));
136 Dmsg1(130, "%s", jcr->errmsg);
137 } else if (!unser_volume_label(dev, record)) {
138 Mmsg(jcr->errmsg, _("Could not unserialize Volume label: ERR=%s\n"),
139 dev->print_errmsg());
140 Dmsg1(130, "%s", jcr->errmsg);
141 } else if (strcmp(dev->VolHdr.Id, BaculaId) != 0 &&
142 strcmp(dev->VolHdr.Id, OldBaculaId) != 0) {
143 Mmsg(jcr->errmsg, _("Volume Header Id bad: %s\n"), dev->VolHdr.Id);
144 Dmsg1(130, "%s", jcr->errmsg);
148 free_record(record); /* finished reading Volume record */
150 if (!dev->is_volume_to_unload()) {
155 if (forge_on || jcr->ignore_label_errors) {
156 dev->set_labeled(); /* set has Bacula label */
157 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 has wrong Bacula version. Wanted %d got %d\n"),
176 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 has bad Bacula label type: %x\n"),
187 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 device %s: Wanted %s have %s\n"),
203 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;
218 if (debug_level >= 10) {
219 dump_volume_label(dev);
221 Dmsg0(130, "Leave read_volume_label() VOL_OK\n");
222 /* If we are a streaming device, we only get one chance to read */
223 if (!dev->has_cap(CAP_STREAM)) {
225 if (have_ansi_label) {
226 stat = read_ansi_ibm_label(dcr);
227 /* If we want a label and didn't find it, return error */
228 if (stat != VOL_OK) {
234 Dmsg1(100, "Call reserve_volume=%s\n", dev->VolHdr.VolumeName);
235 if (reserve_volume(dcr, dev->VolHdr.VolumeName) == NULL) {
236 Mmsg2(jcr->errmsg, _("Could not reserve volume %s on %s\n"),
237 dev->VolHdr.VolumeName, dev->print_name());
238 Dmsg2(150, "Could not reserve volume %s on %s\n", dev->VolHdr.VolumeName, dev->print_name());
239 stat = VOL_NAME_ERROR;
249 Dmsg1(150, "return %d\n", stat);
254 * Put a volume label into the block
256 * Returns: false on failure
259 static bool write_volume_label_to_block(DCR *dcr)
261 DEVICE *dev = dcr->dev;
262 DEV_BLOCK *block = dcr->block;
266 Dmsg0(130, "write Label in write_volume_label_to_block()\n");
268 memset(&rec, 0, sizeof(rec));
269 rec.data = get_memory(SER_LENGTH_Volume_Label);
270 empty_block(block); /* Volume label always at beginning */
272 create_volume_label_record(dcr, dev, &rec);
274 block->BlockNumber = 0;
275 if (!write_record_to_block(dcr, &rec)) {
276 free_pool_memory(rec.data);
277 Jmsg1(jcr, M_FATAL, 0, _("Cannot write Volume label to block for device %s\n"),
281 Dmsg2(130, "Wrote label of %d bytes to block. Vol=%s\n", rec.data_len,
284 free_pool_memory(rec.data);
290 * Write a Volume Label
291 * !!! Note, this is ONLY used for writing
292 * a fresh volume label. Any data
293 * after the label will be destroyed,
294 * in fact, we write the label 5 times !!!!
296 * This routine should be used only when labeling a blank tape.
298 bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName,
299 const char *PoolName, bool relabel, bool dvdnow)
301 DEVICE *dev = dcr->dev;
302 DEV_BLOCK *block = dcr->block;
304 Dmsg0(150, "write_volume_label()\n");
306 Pmsg0(0, "=== ERROR: write_new_volume_label_to_dev called with NULL VolName\n");
311 volume_unused(dcr); /* mark current volume unused */
312 /* Truncate device */
313 if (!dev->truncate(dcr)) {
316 if (!dev->is_tape()) {
317 dev->close_part(dcr); /* make sure DVD/file closed for rename */
321 /* Set the new filename for open, ... */
322 dev->setVolCatName(VolName);
323 dcr->setVolCatName(VolName);
324 Dmsg1(150, "New VolName=%s\n", VolName);
325 if (!dev->open(dcr, OPEN_READ_WRITE)) {
326 /* If device is not tape, attempt to create it */
327 if (dev->is_tape() || !dev->open(dcr, CREATE_READ_WRITE)) {
328 Jmsg3(dcr->jcr, M_WARNING, 0, _("Open device %s Volume \"%s\" failed: ERR=%s\n"),
329 dev->print_name(), dcr->VolumeName, dev->bstrerror());
333 Dmsg1(150, "Label type=%d\n", dev->label_type);
337 if (!dev->rewind(dcr)) {
338 Dmsg2(130, "Bad status on %s from rewind: ERR=%s\n", dev->print_name(), dev->print_errmsg());
344 /* Temporarily mark in append state to enable writing */
347 /* Create PRE_LABEL or VOL_LABEL if DVD */
348 create_volume_label(dev, VolName, PoolName, dvdnow);
351 * If we have already detected an ANSI label, re-read it
352 * to skip past it. Otherwise, we write a new one if
355 if (dev->label_type != B_BACULA_LABEL) {
356 if (read_ansi_ibm_label(dcr) != VOL_OK) {
360 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, VolName)) {
364 create_volume_label_record(dcr, dev, dcr->rec);
365 dcr->rec->Stream = 0;
366 dcr->rec->maskedStream = 0;
368 if (!write_record_to_block(dcr, dcr->rec)) {
369 Dmsg2(130, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
372 Dmsg2(130, "Wrote label of %d bytes to %s\n", dcr->rec->data_len, dev->print_name());
375 Dmsg0(130, "Call write_block_to_dev()\n");
376 if (!dcr->write_block_to_dev()) {
377 Dmsg2(130, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
385 Dmsg0(130, " Wrote block to device\n");
389 write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
392 if (debug_level >= 20) {
393 dump_volume_label(dev);
395 Dmsg0(100, "Call reserve_volume\n");
396 if (reserve_volume(dcr, VolName) == NULL) {
397 Mmsg2(dcr->jcr->errmsg, _("Could not reserve volume %s on %s\n"),
398 dev->VolHdr.VolumeName, dev->print_name());
399 Dmsg1(100, "%s", dcr->jcr->errmsg);
402 dev = dcr->dev; /* may have changed in reserve_volume */
404 dev->clear_append(); /* remove append since this is PRE_LABEL */
410 dev->clear_append(); /* remove append since this is PRE_LABEL */
415 * Write a volume label. This is ONLY called if we have a valid Bacula
416 * label of type PRE_LABEL or we are recyling an existing Volume.
418 * Returns: true if OK
419 * false if unable to write it
421 bool DCR::rewrite_volume_label(bool recycle)
425 if (!dev->open(dcr, OPEN_READ_WRITE)) {
426 Jmsg3(jcr, M_WARNING, 0, _("Open device %s Volume \"%s\" failed: ERR=%s\n"),
427 dev->print_name(), dcr->VolumeName, dev->bstrerror());
430 Dmsg2(190, "set append found freshly labeled volume. fd=%d dev=%x\n", dev->fd(), dev);
431 dev->VolHdr.LabelType = VOL_LABEL; /* set Volume label */
433 if (!write_volume_label_to_block(dcr)) {
434 Dmsg0(200, "Error from write volume label.\n");
437 Dmsg1(150, "wrote vol label to block. Vol=%s\n", dcr->VolumeName);
439 dev->setVolCatInfo(false);
440 dev->VolCatInfo.VolCatBytes = 0; /* reset byte count */
443 * If we are not dealing with a streaming device,
444 * write the block now to ensure we have write permission.
445 * It is better to find out now rather than later.
446 * We do not write the block now if this is an ANSI label. This
447 * avoids re-writing the ANSI label, which we do not want to do.
449 if (!dev->has_cap(CAP_STREAM)) {
450 if (!dev->rewind(dcr)) {
451 Jmsg2(jcr, M_FATAL, 0, _("Rewind error on device %s: ERR=%s\n"),
452 dev->print_name(), dev->print_errmsg());
456 Dmsg1(150, "Doing recycle. Vol=%s\n", dcr->VolumeName);
457 if (!dev->truncate(dcr)) {
458 Jmsg2(jcr, M_FATAL, 0, _("Truncate error on device %s: ERR=%s\n"),
459 dev->print_name(), dev->print_errmsg());
462 if (!dev->open(dcr, OPEN_READ_WRITE)) {
463 Jmsg2(jcr, M_FATAL, 0,
464 _("Failed to re-open DVD after truncate on device %s: ERR=%s\n"),
465 dev->print_name(), dev->print_errmsg());
471 * If we have already detected an ANSI label, re-read it
472 * to skip past it. Otherwise, we write a new one if
475 if (dev->label_type != B_BACULA_LABEL) {
476 if (read_ansi_ibm_label(dcr) != VOL_OK) {
480 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, dev->VolHdr.VolumeName)) {
484 /* Attempt write to check write permission */
485 Dmsg1(200, "Attempt to write to device fd=%d.\n", dev->fd());
486 if (!dcr->write_block_to_dev()) {
487 Jmsg2(jcr, M_ERROR, 0, _("Unable to write device %s: ERR=%s\n"),
488 dev->print_name(), dev->print_errmsg());
489 Dmsg0(200, "===ERROR write block to dev\n");
494 /* Set or reset Volume statistics */
495 dev->VolCatInfo.VolCatJobs = 0;
496 dev->VolCatInfo.VolCatFiles = 0;
497 dev->VolCatInfo.VolCatErrors = 0;
498 dev->VolCatInfo.VolCatBlocks = 0;
499 dev->VolCatInfo.VolCatRBytes = 0;
501 dev->VolCatInfo.VolCatMounts++;
502 dev->VolCatInfo.VolCatRecycles++;
503 dir_create_jobmedia_record(dcr, true);
505 dev->VolCatInfo.VolCatMounts = 1;
506 dev->VolCatInfo.VolCatRecycles = 0;
507 dev->VolCatInfo.VolCatWrites = 1;
508 dev->VolCatInfo.VolCatReads = 1;
510 Dmsg1(150, "dir_update_vol_info. Set Append vol=%s\n", dcr->VolumeName);
511 dev->VolCatInfo.VolFirstWritten = time(NULL);
512 bstrncpy(dev->VolCatInfo.VolCatStatus, "Append", sizeof(dev->VolCatInfo.VolCatStatus));
513 dev->setVolCatName(dcr->VolumeName);
514 if (!dir_update_volume_info(dcr, true, true)) { /* indicate doing relabel */
518 Jmsg(jcr, M_INFO, 0, _("Recycled volume \"%s\" on device %s, all previous data lost.\n"),
519 dcr->VolumeName, dev->print_name());
521 Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume \"%s\" on device %s\n"),
522 dcr->VolumeName, dev->print_name());
525 * End writing real Volume label (from pre-labeled tape), or recycling
528 Dmsg1(150, "OK from rewrite vol label. Vol=%s\n", dcr->VolumeName);
534 * create_volume_label_record
535 * Serialize label (from dev->VolHdr structure) into device record.
536 * Assumes that the dev->VolHdr structure is properly
539 static void create_volume_label_record(DCR *dcr, DEVICE *dev, DEV_RECORD *rec)
546 /* Serialize the label into the device record. */
548 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
549 ser_begin(rec->data, SER_LENGTH_Volume_Label);
550 ser_string(dev->VolHdr.Id);
552 ser_uint32(dev->VolHdr.VerNum);
554 if (dev->VolHdr.VerNum >= 11) {
555 ser_btime(dev->VolHdr.label_btime);
556 dev->VolHdr.write_btime = get_current_btime();
557 ser_btime(dev->VolHdr.write_btime);
558 dev->VolHdr.write_date = 0;
559 dev->VolHdr.write_time = 0;
561 /* OLD WAY DEPRECATED */
562 ser_float64(dev->VolHdr.label_date);
563 ser_float64(dev->VolHdr.label_time);
564 get_current_time(&dt);
565 dev->VolHdr.write_date = dt.julian_day_number;
566 dev->VolHdr.write_time = dt.julian_day_fraction;
568 ser_float64(dev->VolHdr.write_date); /* 0 if VerNum >= 11 */
569 ser_float64(dev->VolHdr.write_time); /* 0 if VerNum >= 11 */
571 ser_string(dev->VolHdr.VolumeName);
572 ser_string(dev->VolHdr.PrevVolumeName);
573 ser_string(dev->VolHdr.PoolName);
574 ser_string(dev->VolHdr.PoolType);
575 ser_string(dev->VolHdr.MediaType);
577 ser_string(dev->VolHdr.HostName);
578 ser_string(dev->VolHdr.LabelProg);
579 ser_string(dev->VolHdr.ProgVersion);
580 ser_string(dev->VolHdr.ProgDate);
582 ser_end(rec->data, SER_LENGTH_Volume_Label);
583 bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName));
584 rec->data_len = ser_length(rec->data);
585 rec->FileIndex = dev->VolHdr.LabelType;
586 rec->VolSessionId = jcr->VolSessionId;
587 rec->VolSessionTime = jcr->VolSessionTime;
588 rec->Stream = jcr->NumWriteVolumes;
589 rec->maskedStream = jcr->NumWriteVolumes;
590 Dmsg2(150, "Created Vol label rec: FI=%s len=%d\n", FI_to_ascii(buf, rec->FileIndex),
596 * Create a volume label in memory
598 void create_volume_label(DEVICE *dev, const char *VolName,
599 const char *PoolName, bool dvdnow)
601 DEVRES *device = (DEVRES *)dev->device;
603 Dmsg0(130, "Start create_volume_label()\n");
607 dev->clear_volhdr(); /* clear any old volume info */
609 bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
610 dev->VolHdr.VerNum = BaculaTapeVersion;
611 if (dev->is_dvd() && dvdnow) {
612 /* We do not want to re-label a DVD so write VOL_LABEL now */
613 dev->VolHdr.LabelType = VOL_LABEL;
615 dev->VolHdr.LabelType = PRE_LABEL; /* Mark tape as unused */
617 bstrncpy(dev->VolHdr.VolumeName, VolName, sizeof(dev->VolHdr.VolumeName));
618 bstrncpy(dev->VolHdr.PoolName, PoolName, sizeof(dev->VolHdr.PoolName));
619 bstrncpy(dev->VolHdr.MediaType, device->media_type, sizeof(dev->VolHdr.MediaType));
621 bstrncpy(dev->VolHdr.PoolType, "Backup", sizeof(dev->VolHdr.PoolType));
623 dev->VolHdr.label_btime = get_current_btime();
624 dev->VolHdr.label_date = 0;
625 dev->VolHdr.label_time = 0;
627 if (gethostname(dev->VolHdr.HostName, sizeof(dev->VolHdr.HostName)) != 0) {
628 dev->VolHdr.HostName[0] = 0;
630 bstrncpy(dev->VolHdr.LabelProg, my_name, sizeof(dev->VolHdr.LabelProg));
631 sprintf(dev->VolHdr.ProgVersion, "Ver. %s %s", VERSION, BDATE);
632 sprintf(dev->VolHdr.ProgDate, "Build %s %s", __DATE__, __TIME__);
633 dev->set_labeled(); /* set has Bacula label */
634 if (debug_level >= 90) {
635 dump_volume_label(dev);
640 * Create session label
641 * The pool memory must be released by the calling program
643 void create_session_label(DCR *dcr, DEV_RECORD *rec, int label)
648 rec->VolSessionId = jcr->VolSessionId;
649 rec->VolSessionTime = jcr->VolSessionTime;
650 rec->Stream = jcr->JobId;
651 rec->maskedStream = jcr->JobId;
653 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
654 ser_begin(rec->data, SER_LENGTH_Session_Label);
655 ser_string(BaculaId);
656 ser_uint32(BaculaTapeVersion);
658 ser_uint32(jcr->JobId);
660 /* Changed in VerNum 11 */
661 ser_btime(get_current_btime());
664 ser_string(dcr->pool_name);
665 ser_string(dcr->pool_type);
666 ser_string(jcr->job_name); /* base Job name */
667 ser_string(jcr->client_name);
669 /* Added in VerNum 10 */
670 ser_string(jcr->Job); /* Unique name of this Job */
671 ser_string(jcr->fileset_name);
672 ser_uint32(jcr->getJobType());
673 ser_uint32(jcr->getJobLevel());
674 /* Added in VerNum 11 */
675 ser_string(jcr->fileset_md5);
677 if (label == EOS_LABEL) {
678 ser_uint32(jcr->JobFiles);
679 ser_uint64(jcr->JobBytes);
680 ser_uint32(dcr->StartBlock);
681 ser_uint32(dcr->EndBlock);
682 ser_uint32(dcr->StartFile);
683 ser_uint32(dcr->EndFile);
684 ser_uint32(jcr->JobErrors);
686 /* Added in VerNum 11 */
687 ser_uint32(jcr->JobStatus);
689 ser_end(rec->data, SER_LENGTH_Session_Label);
690 rec->data_len = ser_length(rec->data);
693 /* Write session label
694 * Returns: false on failure
697 bool write_session_label(DCR *dcr, int label)
700 DEVICE *dev = dcr->dev;
702 DEV_BLOCK *block = dcr->block;
703 char buf1[100], buf2[100];
706 Dmsg1(130, "session_label record=%x\n", rec);
709 set_start_vol_position(dcr);
712 if (dev->is_tape()) {
713 dcr->EndBlock = dev->EndBlock;
714 dcr->EndFile = dev->EndFile;
716 dcr->EndBlock = (uint32_t)dev->file_addr;
717 dcr->EndFile = (uint32_t)(dev->file_addr >> 32);
721 Jmsg1(jcr, M_ABORT, 0, _("Bad Volume session label = %d\n"), label);
724 create_session_label(dcr, rec, label);
725 rec->FileIndex = label;
728 * We guarantee that the session record can totally fit
729 * into a block. If not, write the block, and put it in
730 * the next block. Having the sesssion record totally in
731 * one block makes reading them much easier (no need to
732 * read the next block).
734 if (!can_write_record_to_block(block, rec)) {
735 Dmsg0(150, "Cannot write session label to block.\n");
736 if (!dcr->write_block_to_device()) {
737 Dmsg0(130, "Got session label write_block_to_dev error.\n");
742 if (!write_record_to_block(dcr, rec)) {
747 Dmsg6(150, "Write sesson_label record JobId=%d FI=%s SessId=%d Strm=%s len=%d "
748 "remainder=%d\n", jcr->JobId,
749 FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
750 stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
754 Dmsg2(150, "Leave write_session_label Block=%ud File=%ud\n",
755 dev->get_block_num(), dev->get_file());
759 /* unser_volume_label
761 * Unserialize the Bacula Volume label into the device Volume_Label
764 * Assumes that the record is already read.
766 * Returns: false on error
770 bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec)
773 char buf1[100], buf2[100];
775 if (rec->FileIndex != VOL_LABEL && rec->FileIndex != PRE_LABEL) {
776 Mmsg3(dev->errmsg, _("Expecting Volume Label, got FI=%s Stream=%s len=%d\n"),
777 FI_to_ascii(buf1, rec->FileIndex),
778 stream_to_ascii(buf2, rec->Stream, rec->FileIndex),
785 dev->VolHdr.LabelType = rec->FileIndex;
786 dev->VolHdr.LabelSize = rec->data_len;
789 /* Unserialize the record into the Volume Header */
790 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
791 ser_begin(rec->data, SER_LENGTH_Volume_Label);
792 unser_string(dev->VolHdr.Id);
793 unser_uint32(dev->VolHdr.VerNum);
795 if (dev->VolHdr.VerNum >= 11) {
796 unser_btime(dev->VolHdr.label_btime);
797 unser_btime(dev->VolHdr.write_btime);
798 } else { /* old way */
799 unser_float64(dev->VolHdr.label_date);
800 unser_float64(dev->VolHdr.label_time);
802 unser_float64(dev->VolHdr.write_date); /* Unused with VerNum >= 11 */
803 unser_float64(dev->VolHdr.write_time); /* Unused with VerNum >= 11 */
805 unser_string(dev->VolHdr.VolumeName);
806 unser_string(dev->VolHdr.PrevVolumeName);
807 unser_string(dev->VolHdr.PoolName);
808 unser_string(dev->VolHdr.PoolType);
809 unser_string(dev->VolHdr.MediaType);
811 unser_string(dev->VolHdr.HostName);
812 unser_string(dev->VolHdr.LabelProg);
813 unser_string(dev->VolHdr.ProgVersion);
814 unser_string(dev->VolHdr.ProgDate);
816 ser_end(rec->data, SER_LENGTH_Volume_Label);
817 Dmsg0(190, "unser_vol_label\n");
818 if (debug_level >= 190) {
819 dump_volume_label(dev);
825 bool unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec)
829 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
830 unser_begin(rec->data, SER_LENGTH_Session_Label);
831 unser_string(label->Id);
832 unser_uint32(label->VerNum);
833 unser_uint32(label->JobId);
834 if (label->VerNum >= 11) {
835 unser_btime(label->write_btime);
837 unser_float64(label->write_date);
839 unser_float64(label->write_time);
840 unser_string(label->PoolName);
841 unser_string(label->PoolType);
842 unser_string(label->JobName);
843 unser_string(label->ClientName);
844 if (label->VerNum >= 10) {
845 unser_string(label->Job); /* Unique name of this Job */
846 unser_string(label->FileSetName);
847 unser_uint32(label->JobType);
848 unser_uint32(label->JobLevel);
850 if (label->VerNum >= 11) {
851 unser_string(label->FileSetMD5);
853 label->FileSetMD5[0] = 0;
855 if (rec->FileIndex == EOS_LABEL) {
856 unser_uint32(label->JobFiles);
857 unser_uint64(label->JobBytes);
858 unser_uint32(label->StartBlock);
859 unser_uint32(label->EndBlock);
860 unser_uint32(label->StartFile);
861 unser_uint32(label->EndFile);
862 unser_uint32(label->JobErrors);
863 if (label->VerNum >= 11) {
864 unser_uint32(label->JobStatus);
866 label->JobStatus = JS_Terminated; /* kludge */
872 void dump_volume_label(DEVICE *dev)
874 int dbl = debug_level;
876 const char *LabelType;
883 switch (dev->VolHdr.LabelType) {
885 LabelType = "PRE_LABEL";
888 LabelType = "VOL_LABEL";
891 LabelType = "EOM_LABEL";
894 LabelType = "SOS_LABEL";
897 LabelType = "EOS_LABEL";
903 sprintf(buf, _("Unknown %d"), dev->VolHdr.LabelType);
907 Pmsg11(-1, _("\nVolume Label:\n"
920 dev->VolHdr.Id, dev->VolHdr.VerNum,
921 dev->VolHdr.VolumeName, dev->VolHdr.PrevVolumeName,
922 File, LabelType, dev->VolHdr.LabelSize,
923 dev->VolHdr.PoolName, dev->VolHdr.MediaType,
924 dev->VolHdr.PoolType, dev->VolHdr.HostName);
926 if (dev->VolHdr.VerNum >= 11) {
928 bstrftime(dt, sizeof(dt), btime_to_utime(dev->VolHdr.label_btime));
929 Pmsg1(-1, _("Date label written: %s\n"), dt);
931 dt.julian_day_number = dev->VolHdr.label_date;
932 dt.julian_day_fraction = dev->VolHdr.label_time;
935 _("Date label written: %04d-%02d-%02d at %02d:%02d\n"),
936 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
944 static void dump_session_label(DEV_RECORD *rec, const char *type)
950 char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], ec6[30], ec7[30];
952 unser_session_label(&label, rec);
955 Pmsg7(-1, _("\n%s Record:\n"
962 ""), type, label.JobId, label.VerNum,
963 label.PoolName, label.PoolType,
964 label.JobName, label.ClientName);
966 if (label.VerNum >= 10) {
968 "Job (unique name) : %s\n"
972 ""), label.Job, label.FileSetName, label.JobType, label.JobLevel);
975 if (rec->FileIndex == EOS_LABEL) {
986 edit_uint64_with_commas(label.JobFiles, ec1),
987 edit_uint64_with_commas(label.JobBytes, ec2),
988 edit_uint64_with_commas(label.StartBlock, ec3),
989 edit_uint64_with_commas(label.EndBlock, ec4),
990 edit_uint64_with_commas(label.StartFile, ec5),
991 edit_uint64_with_commas(label.EndFile, ec6),
992 edit_uint64_with_commas(label.JobErrors, ec7),
995 if (label.VerNum >= 11) {
997 bstrftime(dt, sizeof(dt), btime_to_utime(label.write_btime));
998 Pmsg1(-1, _("Date written : %s\n"), dt);
1000 dt.julian_day_number = label.write_date;
1001 dt.julian_day_fraction = label.write_time;
1002 tm_decode(&dt, &tm);
1003 Pmsg5(-1, _("Date written : %04d-%02d-%02d at %02d:%02d\n"),
1004 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
1010 void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose)
1015 if (rec->FileIndex == 0 && rec->VolSessionId == 0 && rec->VolSessionTime == 0) {
1020 switch (rec->FileIndex) {
1022 type = _("Fresh Volume");
1028 type = _("Begin Job Session");
1031 type = _("End Job Session");
1034 type = _("End of Media");
1037 type = _("End of Tape");
1040 type = _("Unknown");
1044 switch (rec->FileIndex) {
1047 unser_volume_label(dev, rec);
1048 dump_volume_label(dev);
1051 dump_session_label(rec, type);
1054 dump_session_label(rec, type);
1057 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1058 type, dev->file, dev->block_num, rec->VolSessionId,
1059 rec->VolSessionTime, rec->Stream, rec->data_len);
1062 Pmsg0(-1, _("End of physical tape.\n"));
1065 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1066 type, dev->file, dev->block_num, rec->VolSessionId,
1067 rec->VolSessionTime, rec->Stream, rec->data_len);
1071 SESSION_LABEL label;
1073 switch (rec->FileIndex) {
1075 unser_session_label(&label, rec);
1076 bstrftimes(dt, sizeof(dt), btime_to_utime(label.write_btime));
1077 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1078 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1079 Pmsg4(-1, _(" Job=%s Date=%s Level=%c Type=%c\n"),
1080 label.Job, dt, label.JobLevel, label.JobType);
1083 char ed1[30], ed2[30];
1084 unser_session_label(&label, rec);
1085 bstrftimes(dt, sizeof(dt), btime_to_utime(label.write_btime));
1086 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1087 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1088 Pmsg7(-1, _(" Date=%s Level=%c Type=%c Files=%s Bytes=%s Errors=%d Status=%c\n"),
1089 dt, label.JobLevel, label.JobType,
1090 edit_uint64_with_commas(label.JobFiles, ed1),
1091 edit_uint64_with_commas(label.JobBytes, ed2),
1092 label.JobErrors, (char)label.JobStatus);
1098 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1099 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime,
1100 rec->Stream, rec->data_len);