2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2008 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 two of the GNU 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 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 John Walker.
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
38 #include "bacula.h" /* pull in global headers */
39 #include "stored.h" /* pull in Storage Deamon headers */
41 /* Forward referenced functions */
42 static void create_volume_label_record(DCR *dcr, DEV_RECORD *rec);
45 * Read the volume label
47 * If dcr->VolumeName == NULL, we accept any Bacula Volume
48 * If dcr->VolumeName[0] == 0, we accept any Bacula Volume
49 * otherwise dcr->VolumeName must match the Volume.
51 * If VolName given, ensure that it matches
53 * Returns VOL_ code as defined in record.h
55 * VOL_OK good label found
56 * VOL_NO_LABEL volume not labeled
57 * VOL_IO_ERROR I/O error reading tape
58 * VOL_NAME_ERROR label has wrong name
59 * VOL_CREATE_ERROR Error creating label
60 * VOL_VERSION_ERROR label has wrong version
61 * VOL_LABEL_ERROR bad label type
62 * VOL_NO_MEDIA no media in drive
64 * The dcr block is emptied on return, and the Volume is
67 int read_dev_volume_label(DCR *dcr)
70 DEVICE * volatile dev = dcr->dev;
71 char *VolName = dcr->VolumeName;
74 DEV_BLOCK *block = dcr->block;
77 bool have_ansi_label = false;
79 Dmsg4(100, "Enter read_volume_label res=%d device=%s vol=%s dev_Vol=%s\n",
80 dev->num_reserved(), dev->print_name(), VolName,
81 dev->VolHdr.VolumeName[0]?dev->VolHdr.VolumeName:"*NULL*");
83 if (!dev->is_open()) {
84 if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
89 if (dev->is_labeled()) { /* did we already read label? */
90 /* Compare Volume Names allow special wild card */
91 if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolumeName, VolName) != 0) {
92 Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
93 dev->print_name(), VolName, dev->VolHdr.VolumeName);
95 * Cancel Job if too many label errors
98 if (!dev->poll && jcr->label_errors++ > 100) {
99 Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
101 Dmsg0(150, "return VOL_NAME_ERROR\n");
102 stat = VOL_NAME_ERROR;
105 Dmsg0(130, "Leave read_volume_label() VOL_OK\n");
106 return VOL_OK; /* label already read */
110 dev->clear_labeled();
113 dev->label_type = B_BACULA_LABEL;
115 if (!dev->rewind(dcr)) {
116 Mmsg(jcr->errmsg, _("Couldn't rewind device %s: ERR=%s\n"),
117 dev->print_name(), dev->print_errmsg());
118 Dmsg1(130, "return VOL_NO_MEDIA: %s", jcr->errmsg);
121 bstrncpy(dev->VolHdr.Id, "**error**", sizeof(dev->VolHdr.Id));
123 /* Read ANSI/IBM label if so requested */
124 want_ansi_label = dcr->VolCatInfo.LabelType != B_BACULA_LABEL ||
125 dcr->device->label_type != B_BACULA_LABEL;
126 if (want_ansi_label || dev->has_cap(CAP_CHECKLABELS)) {
127 stat = read_ansi_ibm_label(dcr);
128 /* If we want a label and didn't find it, return error */
129 if (want_ansi_label && stat != VOL_OK) {
132 if (stat == VOL_NAME_ERROR || stat == VOL_LABEL_ERROR) {
133 Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
134 dev->print_name(), VolName, dev->VolHdr.VolumeName);
135 if (!dev->poll && jcr->label_errors++ > 100) {
136 Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
140 if (stat != VOL_OK) { /* Not an ANSI/IBM label, so re-read */
143 have_ansi_label = true;
147 /* Read the Bacula Volume label block */
148 record = new_record();
151 Dmsg0(130, "Big if statement in read_volume_label\n");
152 if (!read_block_from_dev(dcr, NO_BLOCK_NUMBER_CHECK)) {
153 Mmsg(jcr->errmsg, _("Requested Volume \"%s\" on %s is not a Bacula "
154 "labeled Volume, because: ERR=%s"), NPRT(VolName),
155 dev->print_name(), dev->print_errmsg());
156 Dmsg1(130, "%s", jcr->errmsg);
157 } else if (!read_record_from_block(dcr, block, record)) {
158 Mmsg(jcr->errmsg, _("Could not read Volume label from block.\n"));
159 Dmsg1(130, "%s", jcr->errmsg);
160 } else if (!unser_volume_label(dev, record)) {
161 Mmsg(jcr->errmsg, _("Could not unserialize Volume label: ERR=%s\n"),
162 dev->print_errmsg());
163 Dmsg1(130, "%s", jcr->errmsg);
164 } else if (strcmp(dev->VolHdr.Id, BaculaId) != 0 &&
165 strcmp(dev->VolHdr.Id, OldBaculaId) != 0) {
166 Mmsg(jcr->errmsg, _("Volume Header Id bad: %s\n"), dev->VolHdr.Id);
167 Dmsg1(130, "%s", jcr->errmsg);
171 free_record(record); /* finished reading Volume record */
173 if (!dev->is_volume_to_unload()) {
178 if (forge_on || jcr->ignore_label_errors) {
179 dev->set_labeled(); /* set has Bacula label */
180 Jmsg(jcr, M_ERROR, 0, "%s", jcr->errmsg);
184 Dmsg0(100, "No volume label - bailing out\n");
189 /* At this point, we have read the first Bacula block, and
190 * then read the Bacula Volume label. Now we need to
191 * make sure we have the right Volume.
195 if (dev->VolHdr.VerNum != BaculaTapeVersion &&
196 dev->VolHdr.VerNum != OldCompatibleBaculaTapeVersion1 &&
197 dev->VolHdr.VerNum != OldCompatibleBaculaTapeVersion2) {
198 Mmsg(jcr->errmsg, _("Volume on %s has wrong Bacula version. Wanted %d got %d\n"),
199 dev->print_name(), BaculaTapeVersion, dev->VolHdr.VerNum);
200 Dmsg1(130, "VOL_VERSION_ERROR: %s", jcr->errmsg);
201 stat = VOL_VERSION_ERROR;
205 /* We are looking for either an unused Bacula tape (PRE_LABEL) or
206 * a Bacula volume label (VOL_LABEL)
208 if (dev->VolHdr.LabelType != PRE_LABEL && dev->VolHdr.LabelType != VOL_LABEL) {
209 Mmsg(jcr->errmsg, _("Volume on %s has bad Bacula label type: %x\n"),
210 dev->print_name(), dev->VolHdr.LabelType);
211 Dmsg1(130, "%s", jcr->errmsg);
212 if (!dev->poll && jcr->label_errors++ > 100) {
213 Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
215 Dmsg0(150, "return VOL_LABEL_ERROR\n");
216 stat = VOL_LABEL_ERROR;
220 dev->set_labeled(); /* set has Bacula label */
222 /* Compare Volume Names */
223 Dmsg2(130, "Compare Vol names: VolName=%s hdr=%s\n", VolName?VolName:"*", dev->VolHdr.VolumeName);
224 if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolumeName, VolName) != 0) {
225 Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
226 dev->print_name(), VolName, dev->VolHdr.VolumeName);
227 Dmsg1(130, "%s", jcr->errmsg);
229 * Cancel Job if too many label errors
230 * => we are in a loop
232 if (!dev->poll && jcr->label_errors++ > 100) {
233 Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
235 Dmsg0(150, "return VOL_NAME_ERROR\n");
236 stat = VOL_NAME_ERROR;
241 if (debug_level >= 10) {
242 dump_volume_label(dev);
244 Dmsg0(130, "Leave read_volume_label() VOL_OK\n");
245 /* If we are a streaming device, we only get one chance to read */
246 if (!dev->has_cap(CAP_STREAM)) {
248 if (have_ansi_label) {
249 stat = read_ansi_ibm_label(dcr);
250 /* If we want a label and didn't find it, return error */
251 if (stat != VOL_OK) {
257 Dmsg1(100, "Call reserve_volume=%s\n", dev->VolHdr.VolumeName);
258 if (reserve_volume(dcr, dev->VolHdr.VolumeName) == NULL) {
259 Mmsg2(jcr->errmsg, _("Could not reserve volume %s on %s\n"),
260 dev->VolHdr.VolumeName, dev->print_name());
261 stat = VOL_NAME_ERROR;
271 Dmsg1(150, "return %d\n", stat);
276 * Put a volume label into the block
278 * Returns: false on failure
281 bool write_volume_label_to_block(DCR *dcr)
284 DEVICE *dev = dcr->dev;
286 DEV_BLOCK *block = dcr->block;
288 Dmsg0(130, "write Label in write_volume_label_to_block()\n");
289 memset(&rec, 0, sizeof(rec));
290 rec.data = get_memory(SER_LENGTH_Volume_Label);
291 empty_block(block); /* Volume label always at beginning */
293 create_volume_label_record(dcr, &rec);
295 block->BlockNumber = 0;
296 if (!write_record_to_block(block, &rec)) {
297 free_pool_memory(rec.data);
298 Jmsg1(jcr, M_FATAL, 0, _("Cannot write Volume label to block for device %s\n"),
302 Dmsg2(130, "Wrote label of %d bytes to block. Vol=%s\n", rec.data_len,
305 free_pool_memory(rec.data);
311 * Write a Volume Label
312 * !!! Note, this is ONLY used for writing
313 * a fresh volume label. Any data
314 * after the label will be destroyed,
315 * in fact, we write the label 5 times !!!!
317 * This routine should be used only when labeling a blank tape.
319 bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName,
320 const char *PoolName, bool relabel, bool dvdnow)
322 DEVICE * volatile dev = dcr->dev;
325 Dmsg0(150, "write_volume_label()\n");
326 empty_block(dcr->block);
328 Pmsg0(0, "=== ERROR: write_new_volume_label_to_dev called with NULL VolName\n");
333 volume_unused(dcr); /* mark current volume unused */
334 /* Truncate device */
335 if (!dev->truncate(dcr)) {
338 if (!dev->is_tape()) {
339 dev->close_part(dcr); /* make sure DVD/file closed for rename */
343 /* Set the new filename for open, ... */
344 bstrncpy(dev->VolCatInfo.VolCatName, VolName, sizeof(dev->VolCatInfo.VolCatName));
345 bstrncpy(dcr->VolCatInfo.VolCatName, VolName, sizeof(dcr->VolCatInfo.VolCatName));
346 Dmsg1(150, "New VolName=%s\n", VolName);
347 if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
348 /* If device is not tape, attempt to create it */
349 if (dev->is_tape() || dev->open(dcr, CREATE_READ_WRITE) < 0) {
350 Jmsg3(dcr->jcr, M_WARNING, 0, _("Open device %s Volume \"%s\" failed: ERR=%s\n"),
351 dev->print_name(), dcr->VolumeName, dev->bstrerror());
355 Dmsg1(150, "Label type=%d\n", dev->label_type);
356 if (!dev->rewind(dcr)) {
357 Dmsg2(130, "Bad status on %s from rewind: ERR=%s\n", dev->print_name(), dev->print_errmsg());
363 /* Temporarily mark in append state to enable writing */
366 /* Create PRE_LABEL or VOL_LABEL if DVD */
367 create_volume_label(dev, VolName, PoolName, dvdnow);
370 * If we have already detected an ANSI label, re-read it
371 * to skip past it. Otherwise, we write a new one if
374 if (dev->label_type != B_BACULA_LABEL) {
375 if (read_ansi_ibm_label(dcr) != VOL_OK) {
379 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, VolName)) {
383 create_volume_label_record(dcr, dcr->rec);
384 dcr->rec->Stream = 0;
386 if (!write_record_to_block(dcr->block, dcr->rec)) {
387 Dmsg2(130, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
390 Dmsg2(130, "Wrote label of %d bytes to %s\n", dcr->rec->data_len, dev->print_name());
393 Dmsg0(130, "Call write_block_to_dev()\n");
394 if (!write_block_to_dev(dcr)) {
395 Dmsg2(130, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
399 /* Now commit block to DVD if we should write now */
400 if (dev->is_dvd() && dvdnow) {
401 Dmsg1(150, "New VolName=%s\n", dev->VolCatInfo.VolCatName);
402 if (!dvd_write_part(dcr)) {
403 Dmsg2(130, "Bad DVD write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
408 Dmsg0(130, " Wrote block to device\n");
412 write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
415 if (debug_level >= 20) {
416 dump_volume_label(dev);
418 Dmsg0(100, "Call reserve_volume\n");
419 if (reserve_volume(dcr, VolName) == NULL) {
420 Mmsg2(dcr->jcr->errmsg, _("Could not reserve volume %s on %s\n"),
421 dev->VolHdr.VolumeName, dev->print_name());
424 dev = dcr->dev; /* may have changed in reserve_volume */
426 dev->clear_append(); /* remove append since this is PRE_LABEL */
432 dev->clear_append(); /* remove append since this is PRE_LABEL */
437 * Write a volume label. This is ONLY called if we have a valid Bacula
438 * label of type PRE_LABEL;
439 * Returns: true if OK
440 * false if unable to write it
442 bool rewrite_volume_label(DCR *dcr, bool recycle)
444 DEVICE *dev = dcr->dev;
447 if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
448 Jmsg3(jcr, M_WARNING, 0, _("Open device %s Volume \"%s\" failed: ERR=%s\n"),
449 dev->print_name(), dcr->VolumeName, dev->bstrerror());
452 Dmsg2(190, "set append found freshly labeled volume. fd=%d dev=%x\n", dev->fd(), dev);
453 dev->VolHdr.LabelType = VOL_LABEL; /* set Volume label */
455 if (!write_volume_label_to_block(dcr)) {
456 Dmsg0(200, "Error from write volume label.\n");
459 Dmsg1(150, "wrote vol label to block. Vol=%s\n", dcr->VolumeName);
461 dev->VolCatInfo.VolCatBytes = 0; /* reset byte count */
464 * If we are not dealing with a streaming device,
465 * write the block now to ensure we have write permission.
466 * It is better to find out now rather than later.
467 * We do not write the block now if this is an ANSI label. This
468 * avoids re-writing the ANSI label, which we do not want to do.
470 if (!dev->has_cap(CAP_STREAM)) {
471 if (!dev->rewind(dcr)) {
472 Jmsg2(jcr, M_FATAL, 0, _("Rewind error on device %s: ERR=%s\n"),
473 dev->print_name(), dev->print_errmsg());
477 Dmsg1(150, "Doing recycle. Vol=%s\n", dcr->VolumeName);
478 // volume_unused(dcr); /* mark volume unused */
479 if (!dev->truncate(dcr)) {
480 Jmsg2(jcr, M_FATAL, 0, _("Truncate error on device %s: ERR=%s\n"),
481 dev->print_name(), dev->print_errmsg());
484 if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
485 Jmsg2(jcr, M_FATAL, 0,
486 _("Failed to re-open DVD after truncate on device %s: ERR=%s\n"),
487 dev->print_name(), dev->print_errmsg());
493 * If we have already detected an ANSI label, re-read it
494 * to skip past it. Otherwise, we write a new one if
497 if (dev->label_type != B_BACULA_LABEL) {
498 if (read_ansi_ibm_label(dcr) != VOL_OK) {
502 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, dev->VolHdr.VolumeName)) {
506 /* Attempt write to check write permission */
507 Dmsg1(200, "Attempt to write to device fd=%d.\n", dev->fd());
508 if (!write_block_to_dev(dcr)) {
509 Jmsg2(jcr, M_ERROR, 0, _("Unable to write device %s: ERR=%s\n"),
510 dev->print_name(), dev->print_errmsg());
511 Dmsg0(200, "===ERROR write block to dev\n");
516 /* Set or reset Volume statistics */
517 dev->VolCatInfo.VolCatJobs = 0;
518 dev->VolCatInfo.VolCatFiles = 0;
519 dev->VolCatInfo.VolCatErrors = 0;
520 dev->VolCatInfo.VolCatBlocks = 0;
521 dev->VolCatInfo.VolCatRBytes = 0;
523 dev->VolCatInfo.VolCatMounts++;
524 dev->VolCatInfo.VolCatRecycles++;
526 dev->VolCatInfo.VolCatMounts = 1;
527 dev->VolCatInfo.VolCatRecycles = 0;
528 dev->VolCatInfo.VolCatWrites = 1;
529 dev->VolCatInfo.VolCatReads = 1;
531 Dmsg1(150, "dir_update_vol_info. Set Append vol=%s\n", dcr->VolumeName);
532 bstrncpy(dev->VolCatInfo.VolCatStatus, "Append", sizeof(dev->VolCatInfo.VolCatStatus));
533 bstrncpy(dev->VolCatInfo.VolCatName, dcr->VolumeName, sizeof(dev->VolCatInfo.VolCatName));
534 if (!dir_update_volume_info(dcr, true, true)) { /* indicate doing relabel */
538 Jmsg(jcr, M_INFO, 0, _("Recycled volume \"%s\" on device %s, all previous data lost.\n"),
539 dcr->VolumeName, dev->print_name());
541 Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume \"%s\" on device %s\n"),
542 dcr->VolumeName, dev->print_name());
545 * End writing real Volume label (from pre-labeled tape), or recycling
548 Dmsg1(150, "OK from rewrite vol label. Vol=%s\n", dcr->VolumeName);
554 * create_volume_label_record
555 * Serialize label (from dev->VolHdr structure) into device record.
556 * Assumes that the dev->VolHdr structure is properly
559 static void create_volume_label_record(DCR *dcr, DEV_RECORD *rec)
563 DEVICE *dev = dcr->dev;
567 /* Serialize the label into the device record. */
569 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
570 ser_begin(rec->data, SER_LENGTH_Volume_Label);
571 ser_string(dev->VolHdr.Id);
573 ser_uint32(dev->VolHdr.VerNum);
575 if (dev->VolHdr.VerNum >= 11) {
576 ser_btime(dev->VolHdr.label_btime);
577 dev->VolHdr.write_btime = get_current_btime();
578 ser_btime(dev->VolHdr.write_btime);
579 dev->VolHdr.write_date = 0;
580 dev->VolHdr.write_time = 0;
582 /* OLD WAY DEPRECATED */
583 ser_float64(dev->VolHdr.label_date);
584 ser_float64(dev->VolHdr.label_time);
585 get_current_time(&dt);
586 dev->VolHdr.write_date = dt.julian_day_number;
587 dev->VolHdr.write_time = dt.julian_day_fraction;
589 ser_float64(dev->VolHdr.write_date); /* 0 if VerNum >= 11 */
590 ser_float64(dev->VolHdr.write_time); /* 0 if VerNum >= 11 */
592 ser_string(dev->VolHdr.VolumeName);
593 ser_string(dev->VolHdr.PrevVolumeName);
594 ser_string(dev->VolHdr.PoolName);
595 ser_string(dev->VolHdr.PoolType);
596 ser_string(dev->VolHdr.MediaType);
598 ser_string(dev->VolHdr.HostName);
599 ser_string(dev->VolHdr.LabelProg);
600 ser_string(dev->VolHdr.ProgVersion);
601 ser_string(dev->VolHdr.ProgDate);
603 ser_end(rec->data, SER_LENGTH_Volume_Label);
604 bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName));
605 rec->data_len = ser_length(rec->data);
606 rec->FileIndex = dev->VolHdr.LabelType;
607 rec->VolSessionId = jcr->VolSessionId;
608 rec->VolSessionTime = jcr->VolSessionTime;
609 rec->Stream = jcr->NumWriteVolumes;
610 Dmsg2(150, "Created Vol label rec: FI=%s len=%d\n", FI_to_ascii(buf, rec->FileIndex),
616 * Create a volume label in memory
618 void create_volume_label(DEVICE *dev, const char *VolName,
619 const char *PoolName, bool dvdnow)
621 DEVRES *device = (DEVRES *)dev->device;
623 Dmsg0(130, "Start create_volume_label()\n");
627 dev->clear_volhdr(); /* clear any old volume info */
629 bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
630 dev->VolHdr.VerNum = BaculaTapeVersion;
631 if (dev->is_dvd() && dvdnow) {
632 /* We do not want to re-label a DVD so write VOL_LABEL now */
633 dev->VolHdr.LabelType = VOL_LABEL;
635 dev->VolHdr.LabelType = PRE_LABEL; /* Mark tape as unused */
637 bstrncpy(dev->VolHdr.VolumeName, VolName, sizeof(dev->VolHdr.VolumeName));
638 bstrncpy(dev->VolHdr.PoolName, PoolName, sizeof(dev->VolHdr.PoolName));
639 bstrncpy(dev->VolHdr.MediaType, device->media_type, sizeof(dev->VolHdr.MediaType));
641 bstrncpy(dev->VolHdr.PoolType, "Backup", sizeof(dev->VolHdr.PoolType));
643 dev->VolHdr.label_btime = get_current_btime();
644 dev->VolHdr.label_date = 0;
645 dev->VolHdr.label_time = 0;
647 if (gethostname(dev->VolHdr.HostName, sizeof(dev->VolHdr.HostName)) != 0) {
648 dev->VolHdr.HostName[0] = 0;
650 bstrncpy(dev->VolHdr.LabelProg, my_name, sizeof(dev->VolHdr.LabelProg));
651 sprintf(dev->VolHdr.ProgVersion, "Ver. %s %s", VERSION, BDATE);
652 sprintf(dev->VolHdr.ProgDate, "Build %s %s", __DATE__, __TIME__);
653 dev->set_labeled(); /* set has Bacula label */
654 if (debug_level >= 90) {
655 dump_volume_label(dev);
660 * Create session label
661 * The pool memory must be released by the calling program
663 void create_session_label(DCR *dcr, DEV_RECORD *rec, int label)
668 rec->VolSessionId = jcr->VolSessionId;
669 rec->VolSessionTime = jcr->VolSessionTime;
670 rec->Stream = jcr->JobId;
672 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
673 ser_begin(rec->data, SER_LENGTH_Session_Label);
674 ser_string(BaculaId);
675 ser_uint32(BaculaTapeVersion);
677 ser_uint32(jcr->JobId);
679 /* Changed in VerNum 11 */
680 ser_btime(get_current_btime());
683 ser_string(dcr->pool_name);
684 ser_string(dcr->pool_type);
685 ser_string(jcr->job_name); /* base Job name */
686 ser_string(jcr->client_name);
688 /* Added in VerNum 10 */
689 ser_string(jcr->Job); /* Unique name of this Job */
690 ser_string(jcr->fileset_name);
691 ser_uint32(jcr->JobType);
692 ser_uint32(jcr->JobLevel);
693 /* Added in VerNum 11 */
694 ser_string(jcr->fileset_md5);
696 if (label == EOS_LABEL) {
697 ser_uint32(jcr->JobFiles);
698 ser_uint64(jcr->JobBytes);
699 ser_uint32(dcr->StartBlock);
700 ser_uint32(dcr->EndBlock);
701 ser_uint32(dcr->StartFile);
702 ser_uint32(dcr->EndFile);
703 ser_uint32(jcr->JobErrors);
705 /* Added in VerNum 11 */
706 ser_uint32(jcr->JobStatus);
708 ser_end(rec->data, SER_LENGTH_Session_Label);
709 rec->data_len = ser_length(rec->data);
712 /* Write session label
713 * Returns: false on failure
716 bool write_session_label(DCR *dcr, int label)
719 DEVICE *dev = dcr->dev;
721 DEV_BLOCK *block = dcr->block;
722 char buf1[100], buf2[100];
725 Dmsg1(130, "session_label record=%x\n", rec);
728 set_start_vol_position(dcr);
731 if (dev->is_tape()) {
732 dcr->EndBlock = dev->EndBlock;
733 dcr->EndFile = dev->EndFile;
735 dcr->EndBlock = (uint32_t)dev->file_addr;
736 dcr->EndFile = (uint32_t)(dev->file_addr >> 32);
740 Jmsg1(jcr, M_ABORT, 0, _("Bad Volume session label = %d\n"), label);
743 create_session_label(dcr, rec, label);
744 rec->FileIndex = label;
747 * We guarantee that the session record can totally fit
748 * into a block. If not, write the block, and put it in
749 * the next block. Having the sesssion record totally in
750 * one block makes reading them much easier (no need to
751 * read the next block).
753 if (!can_write_record_to_block(block, rec)) {
754 Dmsg0(150, "Cannot write session label to block.\n");
755 if (!write_block_to_device(dcr)) {
756 Dmsg0(130, "Got session label write_block_to_dev error.\n");
761 if (!write_record_to_block(block, rec)) {
766 Dmsg6(150, "Write sesson_label record JobId=%d FI=%s SessId=%d Strm=%s len=%d "
767 "remainder=%d\n", jcr->JobId,
768 FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
769 stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
773 Dmsg2(150, "Leave write_session_label Block=%ud File=%ud\n",
774 dev->get_block_num(), dev->get_file());
778 /* unser_volume_label
780 * Unserialize the Bacula Volume label into the device Volume_Label
783 * Assumes that the record is already read.
785 * Returns: false on error
789 bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec)
792 char buf1[100], buf2[100];
794 if (rec->FileIndex != VOL_LABEL && rec->FileIndex != PRE_LABEL) {
795 Mmsg3(dev->errmsg, _("Expecting Volume Label, got FI=%s Stream=%s len=%d\n"),
796 FI_to_ascii(buf1, rec->FileIndex),
797 stream_to_ascii(buf2, rec->Stream, rec->FileIndex),
804 dev->VolHdr.LabelType = rec->FileIndex;
805 dev->VolHdr.LabelSize = rec->data_len;
808 /* Unserialize the record into the Volume Header */
809 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
810 ser_begin(rec->data, SER_LENGTH_Volume_Label);
811 unser_string(dev->VolHdr.Id);
812 unser_uint32(dev->VolHdr.VerNum);
814 if (dev->VolHdr.VerNum >= 11) {
815 unser_btime(dev->VolHdr.label_btime);
816 unser_btime(dev->VolHdr.write_btime);
817 } else { /* old way */
818 unser_float64(dev->VolHdr.label_date);
819 unser_float64(dev->VolHdr.label_time);
821 unser_float64(dev->VolHdr.write_date); /* Unused with VerNum >= 11 */
822 unser_float64(dev->VolHdr.write_time); /* Unused with VerNum >= 11 */
824 unser_string(dev->VolHdr.VolumeName);
825 unser_string(dev->VolHdr.PrevVolumeName);
826 unser_string(dev->VolHdr.PoolName);
827 unser_string(dev->VolHdr.PoolType);
828 unser_string(dev->VolHdr.MediaType);
830 unser_string(dev->VolHdr.HostName);
831 unser_string(dev->VolHdr.LabelProg);
832 unser_string(dev->VolHdr.ProgVersion);
833 unser_string(dev->VolHdr.ProgDate);
835 ser_end(rec->data, SER_LENGTH_Volume_Label);
836 Dmsg0(190, "unser_vol_label\n");
837 if (debug_level >= 190) {
838 dump_volume_label(dev);
844 bool unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec)
848 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
849 unser_begin(rec->data, SER_LENGTH_Session_Label);
850 unser_string(label->Id);
851 unser_uint32(label->VerNum);
852 unser_uint32(label->JobId);
853 if (label->VerNum >= 11) {
854 unser_btime(label->write_btime);
856 unser_float64(label->write_date);
858 unser_float64(label->write_time);
859 unser_string(label->PoolName);
860 unser_string(label->PoolType);
861 unser_string(label->JobName);
862 unser_string(label->ClientName);
863 if (label->VerNum >= 10) {
864 unser_string(label->Job); /* Unique name of this Job */
865 unser_string(label->FileSetName);
866 unser_uint32(label->JobType);
867 unser_uint32(label->JobLevel);
869 if (label->VerNum >= 11) {
870 unser_string(label->FileSetMD5);
872 label->FileSetMD5[0] = 0;
874 if (rec->FileIndex == EOS_LABEL) {
875 unser_uint32(label->JobFiles);
876 unser_uint64(label->JobBytes);
877 unser_uint32(label->StartBlock);
878 unser_uint32(label->EndBlock);
879 unser_uint32(label->StartFile);
880 unser_uint32(label->EndFile);
881 unser_uint32(label->JobErrors);
882 if (label->VerNum >= 11) {
883 unser_uint32(label->JobStatus);
885 label->JobStatus = JS_Terminated; /* kludge */
891 void dump_volume_label(DEVICE *dev)
893 int dbl = debug_level;
895 const char *LabelType;
902 switch (dev->VolHdr.LabelType) {
904 LabelType = "PRE_LABEL";
907 LabelType = "VOL_LABEL";
910 LabelType = "EOM_LABEL";
913 LabelType = "SOS_LABEL";
916 LabelType = "EOS_LABEL";
922 sprintf(buf, _("Unknown %d"), dev->VolHdr.LabelType);
926 Pmsg11(-1, _("\nVolume Label:\n"
939 dev->VolHdr.Id, dev->VolHdr.VerNum,
940 dev->VolHdr.VolumeName, dev->VolHdr.PrevVolumeName,
941 File, LabelType, dev->VolHdr.LabelSize,
942 dev->VolHdr.PoolName, dev->VolHdr.MediaType,
943 dev->VolHdr.PoolType, dev->VolHdr.HostName);
945 if (dev->VolHdr.VerNum >= 11) {
947 bstrftime(dt, sizeof(dt), btime_to_unix(dev->VolHdr.label_btime));
948 Pmsg1(-1, _("Date label written: %s\n"), dt);
950 dt.julian_day_number = dev->VolHdr.label_date;
951 dt.julian_day_fraction = dev->VolHdr.label_time;
954 _("Date label written: %04d-%02d-%02d at %02d:%02d\n"),
955 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
963 static void dump_session_label(DEV_RECORD *rec, const char *type)
969 char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], ec6[30], ec7[30];
971 unser_session_label(&label, rec);
974 Pmsg7(-1, _("\n%s Record:\n"
981 ""), type, label.JobId, label.VerNum,
982 label.PoolName, label.PoolType,
983 label.JobName, label.ClientName);
985 if (label.VerNum >= 10) {
987 "Job (unique name) : %s\n"
991 ""), label.Job, label.FileSetName, label.JobType, label.JobLevel);
994 if (rec->FileIndex == EOS_LABEL) {
1005 edit_uint64_with_commas(label.JobFiles, ec1),
1006 edit_uint64_with_commas(label.JobBytes, ec2),
1007 edit_uint64_with_commas(label.StartBlock, ec3),
1008 edit_uint64_with_commas(label.EndBlock, ec4),
1009 edit_uint64_with_commas(label.StartFile, ec5),
1010 edit_uint64_with_commas(label.EndFile, ec6),
1011 edit_uint64_with_commas(label.JobErrors, ec7),
1014 if (label.VerNum >= 11) {
1016 bstrftime(dt, sizeof(dt), btime_to_unix(label.write_btime));
1017 Pmsg1(-1, _("Date written : %s\n"), dt);
1019 dt.julian_day_number = label.write_date;
1020 dt.julian_day_fraction = label.write_time;
1021 tm_decode(&dt, &tm);
1022 Pmsg5(-1, _("Date written : %04d-%02d-%02d at %02d:%02d\n"),
1023 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
1029 void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose)
1034 if (rec->FileIndex == 0 && rec->VolSessionId == 0 && rec->VolSessionTime == 0) {
1039 switch (rec->FileIndex) {
1041 type = _("Fresh Volume");
1047 type = _("Begin Job Session");
1050 type = _("End Job Session");
1053 type = _("End of Media");
1056 type = _("End of Tape");
1059 type = _("Unknown");
1063 switch (rec->FileIndex) {
1066 unser_volume_label(dev, rec);
1067 dump_volume_label(dev);
1070 dump_session_label(rec, type);
1073 dump_session_label(rec, type);
1076 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1077 type, dev->file, dev->block_num, rec->VolSessionId,
1078 rec->VolSessionTime, rec->Stream, rec->data_len);
1081 Pmsg0(-1, _("End of physical tape.\n"));
1084 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1085 type, dev->file, dev->block_num, rec->VolSessionId,
1086 rec->VolSessionTime, rec->Stream, rec->data_len);
1090 SESSION_LABEL label;
1092 switch (rec->FileIndex) {
1094 unser_session_label(&label, rec);
1095 bstrftimes(dt, sizeof(dt), btime_to_unix(label.write_btime));
1096 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1097 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1098 Pmsg4(-1, _(" Job=%s Date=%s Level=%c Type=%c\n"),
1099 label.Job, dt, label.JobLevel, label.JobType);
1102 char ed1[30], ed2[30];
1103 unser_session_label(&label, rec);
1104 bstrftimes(dt, sizeof(dt), btime_to_unix(label.write_btime));
1105 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1106 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1107 Pmsg7(-1, _(" Date=%s Level=%c Type=%c Files=%s Bytes=%s Errors=%d Status=%c\n"),
1108 dt, label.JobLevel, label.JobType,
1109 edit_uint64_with_commas(label.JobFiles, ed1),
1110 edit_uint64_with_commas(label.JobBytes, ed2),
1111 label.JobErrors, (char)label.JobStatus);
1117 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1118 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime,
1119 rec->Stream, rec->data_len);