2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2007 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 plus additions
11 that are listed in the file LICENSE.
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 *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->reserved_device, 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) {
88 if (dev->is_labeled()) { /* did we already read label? */
89 /* Compare Volume Names allow special wild card */
90 if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolumeName, VolName) != 0) {
91 Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
92 dev->print_name(), VolName, dev->VolHdr.VolumeName);
94 * Cancel Job if too many label errors
97 if (!dev->poll && jcr->label_errors++ > 100) {
98 Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
100 Dmsg0(150, "return VOL_NAME_ERROR\n");
101 stat = VOL_NAME_ERROR;
104 Dmsg0(30, "Leave read_volume_label() VOL_OK\n");
105 return VOL_OK; /* label already read */
108 dev->clear_labeled();
111 dev->label_type = B_BACULA_LABEL;
113 if (!dev->rewind(dcr)) {
114 Mmsg(jcr->errmsg, _("Couldn't rewind device %s: ERR=%s\n"),
115 dev->print_name(), dev->print_errmsg());
116 Dmsg1(30, "return VOL_NO_MEDIA: %s", jcr->errmsg);
119 bstrncpy(dev->VolHdr.Id, "**error**", sizeof(dev->VolHdr.Id));
121 /* Read ANSI/IBM label if so requested */
123 want_ansi_label = dcr->VolCatInfo.LabelType != B_BACULA_LABEL ||
124 dcr->device->label_type != B_BACULA_LABEL;
125 if (want_ansi_label || dev->has_cap(CAP_CHECKLABELS)) {
126 stat = read_ansi_ibm_label(dcr);
127 /* If we want a label and didn't find it, return error */
128 if (want_ansi_label && stat != VOL_OK) {
131 if (stat == VOL_NAME_ERROR || stat == VOL_LABEL_ERROR) {
132 Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
133 dev->print_name(), VolName, dev->VolHdr.VolumeName);
134 if (!dev->poll && jcr->label_errors++ > 100) {
135 Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
139 if (stat != VOL_OK) { /* Not an ANSI/IBM label, so re-read */
142 have_ansi_label = true;
146 /* Read the Bacula Volume label block */
147 record = new_record();
150 Dmsg0(90, "Big if statement in read_volume_label\n");
151 if (!read_block_from_dev(dcr, NO_BLOCK_NUMBER_CHECK)) {
152 Mmsg(jcr->errmsg, _("Requested Volume \"%s\" on %s is not a Bacula "
153 "labeled Volume, because: ERR=%s"), NPRT(VolName),
154 dev->print_name(), dev->print_errmsg());
155 Dmsg1(30, "%s", jcr->errmsg);
156 } else if (!read_record_from_block(dcr, block, record)) {
157 Mmsg(jcr->errmsg, _("Could not read Volume label from block.\n"));
158 Dmsg1(30, "%s", jcr->errmsg);
159 } else if (!unser_volume_label(dev, record)) {
160 Mmsg(jcr->errmsg, _("Could not unserialize Volume label: ERR=%s\n"),
161 dev->print_errmsg());
162 Dmsg1(30, "%s", jcr->errmsg);
163 } else if (strcmp(dev->VolHdr.Id, BaculaId) != 0 &&
164 strcmp(dev->VolHdr.Id, OldBaculaId) != 0) {
165 Mmsg(jcr->errmsg, _("Volume Header Id bad: %s\n"), dev->VolHdr.Id);
166 Dmsg1(30, "%s", jcr->errmsg);
170 free_record(record); /* finished reading Volume record */
173 if (forge_on || jcr->ignore_label_errors) {
174 dev->set_labeled(); /* set has Bacula label */
175 Jmsg(jcr, M_ERROR, 0, "%s", jcr->errmsg);
179 Dmsg0(100, "No volume label - bailing out\n");
184 /* At this point, we have read the first Bacula block, and
185 * then read the Bacula Volume label. Now we need to
186 * make sure we have the right Volume.
190 if (dev->VolHdr.VerNum != BaculaTapeVersion &&
191 dev->VolHdr.VerNum != OldCompatibleBaculaTapeVersion1 &&
192 dev->VolHdr.VerNum != OldCompatibleBaculaTapeVersion2) {
193 Mmsg(jcr->errmsg, _("Volume on %s has wrong Bacula version. Wanted %d got %d\n"),
194 dev->print_name(), BaculaTapeVersion, dev->VolHdr.VerNum);
195 Dmsg1(30, "VOL_VERSION_ERROR: %s", jcr->errmsg);
196 stat = VOL_VERSION_ERROR;
200 /* We are looking for either an unused Bacula tape (PRE_LABEL) or
201 * a Bacula volume label (VOL_LABEL)
203 if (dev->VolHdr.LabelType != PRE_LABEL && dev->VolHdr.LabelType != VOL_LABEL) {
204 Mmsg(jcr->errmsg, _("Volume on %s has bad Bacula label type: %x\n"),
205 dev->print_name(), dev->VolHdr.LabelType);
206 Dmsg1(30, "%s", jcr->errmsg);
207 if (!dev->poll && jcr->label_errors++ > 100) {
208 Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
210 Dmsg0(150, "return VOL_LABEL_ERROR\n");
211 stat = VOL_LABEL_ERROR;
215 dev->set_labeled(); /* set has Bacula label */
216 reserve_volume(dcr, dev->VolHdr.VolumeName);
218 /* Compare Volume Names */
219 Dmsg2(30, "Compare Vol names: VolName=%s hdr=%s\n", VolName?VolName:"*", dev->VolHdr.VolumeName);
220 if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolumeName, VolName) != 0) {
221 Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
222 dev->print_name(), VolName, dev->VolHdr.VolumeName);
223 Dmsg1(30, "%s", jcr->errmsg);
225 * Cancel Job if too many label errors
226 * => we are in a loop
228 if (!dev->poll && jcr->label_errors++ > 100) {
229 Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
231 Dmsg0(150, "return VOL_NAME_ERROR\n");
232 stat = VOL_NAME_ERROR;
235 Dmsg1(30, "Copy vol_name=%s\n", dev->VolHdr.VolumeName);
237 if (debug_level >= 10) {
238 dump_volume_label(dev);
240 Dmsg0(30, "Leave read_volume_label() VOL_OK\n");
241 /* If we are a streaming device, we only get one chance to read */
242 if (!dev->has_cap(CAP_STREAM)) {
244 if (have_ansi_label) {
245 stat = read_ansi_ibm_label(dcr);
246 /* If we want a label and didn't find it, return error */
247 if (stat != VOL_OK) {
258 Dmsg1(150, "return %d\n", stat);
263 * Put a volume label into the block
265 * Returns: false on failure
268 bool write_volume_label_to_block(DCR *dcr)
271 DEVICE *dev = dcr->dev;
273 DEV_BLOCK *block = dcr->block;
275 Dmsg0(20, "write Label in write_volume_label_to_block()\n");
276 memset(&rec, 0, sizeof(rec));
277 rec.data = get_memory(SER_LENGTH_Volume_Label);
278 empty_block(block); /* Volume label always at beginning */
280 create_volume_label_record(dcr, &rec);
282 block->BlockNumber = 0;
283 if (!write_record_to_block(block, &rec)) {
284 free_pool_memory(rec.data);
285 Jmsg1(jcr, M_FATAL, 0, _("Cannot write Volume label to block for device %s\n"),
289 Dmsg1(90, "Wrote label of %d bytes to block\n", rec.data_len);
291 free_pool_memory(rec.data);
297 * Write a Volume Label
298 * !!! Note, this is ONLY used for writing
299 * a fresh volume label. Any data
300 * after the label will be destroyed,
301 * in fact, we write the label 5 times !!!!
303 * This routine should be used only when labeling a blank tape.
305 bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName,
306 const char *PoolName, bool relabel, bool dvdnow)
308 DEVICE *dev = dcr->dev;
311 Dmsg0(99, "write_volume_label()\n");
312 empty_block(dcr->block);
314 /* If relabeling, truncate the device */
315 if (relabel && !dev->truncate(dcr)) {
320 dev->close_part(dcr); /* make sure closed for rename */
323 /* Set the new filename for open, ... */
324 bstrncpy(dev->VolCatInfo.VolCatName, VolName, sizeof(dev->VolCatInfo.VolCatName));
325 bstrncpy(dcr->VolCatInfo.VolCatName, VolName, sizeof(dcr->VolCatInfo.VolCatName));
326 Dmsg1(150, "New VolName=%s\n", VolName);
327 if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
328 /* If device is not tape, attempt to create it */
329 if (dev->is_tape() || dev->open(dcr, CREATE_READ_WRITE) < 0) {
333 Dmsg1(150, "Label type=%d\n", dev->label_type);
334 if (!dev->rewind(dcr)) {
336 Dmsg2(30, "Bad status on %s from rewind: ERR=%s\n", dev->print_name(), dev->print_errmsg());
342 /* Create PRE_LABEL or VOL_LABEL if DVD */
343 create_volume_label(dev, VolName, PoolName, dvdnow);
346 * If we have already detected an ANSI label, re-read it
347 * to skip past it. Otherwise, we write a new one if
350 if (dev->label_type != B_BACULA_LABEL) {
351 if (read_ansi_ibm_label(dcr) != VOL_OK) {
355 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, VolName)) {
359 create_volume_label_record(dcr, dcr->rec);
360 dcr->rec->Stream = 0;
362 /* Temporarily mark in append state to enable writing */
364 if (!write_record_to_block(dcr->block, dcr->rec)) {
365 Dmsg2(30, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
368 Dmsg2(30, "Wrote label of %d bytes to %s\n", dcr->rec->data_len, dev->print_name());
371 Dmsg0(99, "Call write_block_to_dev()\n");
372 if (!write_block_to_dev(dcr)) {
373 Dmsg2(30, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
377 /* Now commit block to DVD if we should write now */
378 if (dev->is_dvd() && dvdnow) {
379 Dmsg1(150, "New VolName=%s\n", dev->VolCatInfo.VolCatName);
380 if (!dvd_write_part(dcr)) {
381 Dmsg2(30, "Bad DVD write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
386 Dmsg0(99, " Wrote block to device\n");
390 write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
393 if (debug_level >= 20) {
394 dump_volume_label(dev);
396 reserve_volume(dcr, VolName);
397 dev->clear_append(); /* remove append since this is PRE_LABEL */
402 dev->clear_append(); /* remove append since this is PRE_LABEL */
407 * Write a volume label. This is ONLY called if we have a valid Bacula
408 * label of type PRE_LABEL;
409 * Returns: true if OK
410 * false if unable to write it
412 bool rewrite_volume_label(DCR *dcr, bool recycle)
414 DEVICE *dev = dcr->dev;
417 if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
420 Dmsg2(190, "set append found freshly labeled volume. fd=%d dev=%x\n", dev->fd(), dev);
421 dev->VolHdr.LabelType = VOL_LABEL; /* set Volume label */
423 if (!write_volume_label_to_block(dcr)) {
424 Dmsg0(200, "Error from write volume label.\n");
428 dev->VolCatInfo.VolCatBytes = 0; /* reset byte count */
431 * If we are not dealing with a streaming device,
432 * write the block now to ensure we have write permission.
433 * It is better to find out now rather than later.
434 * We do not write the block now if this is an ANSI label. This
435 * avoids re-writing the ANSI label, which we do not want to do.
437 if (!dev->has_cap(CAP_STREAM)) {
438 if (!dev->rewind(dcr)) {
439 Jmsg2(jcr, M_FATAL, 0, _("Rewind error on device %s: ERR=%s\n"),
440 dev->print_name(), dev->print_errmsg());
444 if (!dev->truncate(dcr)) {
445 Jmsg2(jcr, M_FATAL, 0, _("Truncate error on device %s: ERR=%s\n"),
446 dev->print_name(), dev->print_errmsg());
449 if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
450 Jmsg2(jcr, M_FATAL, 0,
451 _("Failed to re-open DVD after truncate on device %s: ERR=%s\n"),
452 dev->print_name(), dev->print_errmsg());
458 * If we have already detected an ANSI label, re-read it
459 * to skip past it. Otherwise, we write a new one if
462 if (dev->label_type != B_BACULA_LABEL) {
463 if (read_ansi_ibm_label(dcr) != VOL_OK) {
467 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, dev->VolHdr.VolumeName)) {
471 /* Attempt write to check write permission */
472 Dmsg1(200, "Attempt to write to device fd=%d.\n", dev->fd());
473 if (!write_block_to_dev(dcr)) {
474 Jmsg2(jcr, M_ERROR, 0, _("Unable to write device %s: ERR=%s\n"),
475 dev->print_name(), dev->print_errmsg());
476 Dmsg0(200, "===ERROR write block to dev\n");
481 /* Set or reset Volume statistics */
482 dev->VolCatInfo.VolCatJobs = 0;
483 dev->VolCatInfo.VolCatFiles = 0;
484 dev->VolCatInfo.VolCatErrors = 0;
485 dev->VolCatInfo.VolCatBlocks = 0;
486 dev->VolCatInfo.VolCatRBytes = 0;
488 dev->VolCatInfo.VolCatMounts++;
489 dev->VolCatInfo.VolCatRecycles++;
491 dev->VolCatInfo.VolCatMounts = 1;
492 dev->VolCatInfo.VolCatRecycles = 0;
493 dev->VolCatInfo.VolCatWrites = 1;
494 dev->VolCatInfo.VolCatReads = 1;
496 Dmsg0(150, "dir_update_vol_info. Set Append\n");
497 bstrncpy(dev->VolCatInfo.VolCatStatus, "Append", sizeof(dev->VolCatInfo.VolCatStatus));
498 if (!dir_update_volume_info(dcr, true)) { /* indicate doing relabel */
502 Jmsg(jcr, M_INFO, 0, _("Recycled volume \"%s\" on device %s, all previous data lost.\n"),
503 dcr->VolumeName, dev->print_name());
505 Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume \"%s\" on device %s\n"),
506 dcr->VolumeName, dev->print_name());
509 * End writing real Volume label (from pre-labeled tape), or recycling
512 Dmsg0(200, "OK from rewrite vol label.\n");
518 * create_volume_label_record
519 * Serialize label (from dev->VolHdr structure) into device record.
520 * Assumes that the dev->VolHdr structure is properly
523 static void create_volume_label_record(DCR *dcr, DEV_RECORD *rec)
527 DEVICE *dev = dcr->dev;
531 /* Serialize the label into the device record. */
533 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
534 ser_begin(rec->data, SER_LENGTH_Volume_Label);
535 ser_string(dev->VolHdr.Id);
537 ser_uint32(dev->VolHdr.VerNum);
539 if (dev->VolHdr.VerNum >= 11) {
540 ser_btime(dev->VolHdr.label_btime);
541 dev->VolHdr.write_btime = get_current_btime();
542 ser_btime(dev->VolHdr.write_btime);
543 dev->VolHdr.write_date = 0;
544 dev->VolHdr.write_time = 0;
546 /* OLD WAY DEPRECATED */
547 ser_float64(dev->VolHdr.label_date);
548 ser_float64(dev->VolHdr.label_time);
549 get_current_time(&dt);
550 dev->VolHdr.write_date = dt.julian_day_number;
551 dev->VolHdr.write_time = dt.julian_day_fraction;
553 ser_float64(dev->VolHdr.write_date); /* 0 if VerNum >= 11 */
554 ser_float64(dev->VolHdr.write_time); /* 0 if VerNum >= 11 */
556 ser_string(dev->VolHdr.VolumeName);
557 ser_string(dev->VolHdr.PrevVolumeName);
558 ser_string(dev->VolHdr.PoolName);
559 ser_string(dev->VolHdr.PoolType);
560 ser_string(dev->VolHdr.MediaType);
562 ser_string(dev->VolHdr.HostName);
563 ser_string(dev->VolHdr.LabelProg);
564 ser_string(dev->VolHdr.ProgVersion);
565 ser_string(dev->VolHdr.ProgDate);
567 ser_end(rec->data, SER_LENGTH_Volume_Label);
568 rec->data_len = ser_length(rec->data);
569 rec->FileIndex = dev->VolHdr.LabelType;
570 rec->VolSessionId = jcr->VolSessionId;
571 rec->VolSessionTime = jcr->VolSessionTime;
572 rec->Stream = jcr->NumWriteVolumes;
573 Dmsg2(150, "Created Vol label rec: FI=%s len=%d\n", FI_to_ascii(buf, rec->FileIndex),
579 * Create a volume label in memory
581 void create_volume_label(DEVICE *dev, const char *VolName,
582 const char *PoolName, bool dvdnow)
584 DEVRES *device = (DEVRES *)dev->device;
586 Dmsg0(90, "Start create_volume_label()\n");
590 dev->clear_volhdr(); /* release any old volume */
592 bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
593 dev->VolHdr.VerNum = BaculaTapeVersion;
594 if (dev->is_dvd() && dvdnow) {
595 /* We do not want to re-label a DVD so write VOL_LABEL now */
596 dev->VolHdr.LabelType = VOL_LABEL;
598 dev->VolHdr.LabelType = PRE_LABEL; /* Mark tape as unused */
600 bstrncpy(dev->VolHdr.VolumeName, VolName, sizeof(dev->VolHdr.VolumeName));
601 bstrncpy(dev->VolHdr.PoolName, PoolName, sizeof(dev->VolHdr.PoolName));
602 bstrncpy(dev->VolHdr.MediaType, device->media_type, sizeof(dev->VolHdr.MediaType));
604 bstrncpy(dev->VolHdr.PoolType, "Backup", sizeof(dev->VolHdr.PoolType));
606 dev->VolHdr.label_btime = get_current_btime();
607 dev->VolHdr.label_date = 0;
608 dev->VolHdr.label_time = 0;
610 if (gethostname(dev->VolHdr.HostName, sizeof(dev->VolHdr.HostName)) != 0) {
611 dev->VolHdr.HostName[0] = 0;
613 bstrncpy(dev->VolHdr.LabelProg, my_name, sizeof(dev->VolHdr.LabelProg));
614 sprintf(dev->VolHdr.ProgVersion, "Ver. %s %s", VERSION, BDATE);
615 sprintf(dev->VolHdr.ProgDate, "Build %s %s", __DATE__, __TIME__);
616 dev->set_labeled(); /* set has Bacula label */
617 if (debug_level >= 90) {
618 dump_volume_label(dev);
623 * Create session label
624 * The pool memory must be released by the calling program
626 void create_session_label(DCR *dcr, DEV_RECORD *rec, int label)
631 rec->VolSessionId = jcr->VolSessionId;
632 rec->VolSessionTime = jcr->VolSessionTime;
633 rec->Stream = jcr->JobId;
635 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
636 ser_begin(rec->data, SER_LENGTH_Session_Label);
637 ser_string(BaculaId);
638 ser_uint32(BaculaTapeVersion);
640 ser_uint32(jcr->JobId);
642 /* Changed in VerNum 11 */
643 ser_btime(get_current_btime());
646 ser_string(dcr->pool_name);
647 ser_string(dcr->pool_type);
648 ser_string(jcr->job_name); /* base Job name */
649 ser_string(jcr->client_name);
651 /* Added in VerNum 10 */
652 ser_string(jcr->Job); /* Unique name of this Job */
653 ser_string(jcr->fileset_name);
654 ser_uint32(jcr->JobType);
655 ser_uint32(jcr->JobLevel);
656 /* Added in VerNum 11 */
657 ser_string(jcr->fileset_md5);
659 if (label == EOS_LABEL) {
660 ser_uint32(jcr->JobFiles);
661 ser_uint64(jcr->JobBytes);
662 ser_uint32(dcr->StartBlock);
663 ser_uint32(dcr->EndBlock);
664 ser_uint32(dcr->StartFile);
665 ser_uint32(dcr->EndFile);
666 ser_uint32(jcr->JobErrors);
668 /* Added in VerNum 11 */
669 ser_uint32(jcr->JobStatus);
671 ser_end(rec->data, SER_LENGTH_Session_Label);
672 rec->data_len = ser_length(rec->data);
675 /* Write session label
676 * Returns: false on failure
679 bool write_session_label(DCR *dcr, int label)
682 DEVICE *dev = dcr->dev;
684 DEV_BLOCK *block = dcr->block;
685 char buf1[100], buf2[100];
688 Dmsg1(90, "session_label record=%x\n", rec);
691 if (dev->is_tape()) {
692 dcr->StartBlock = dev->block_num;
693 dcr->StartFile = dev->file;
695 dcr->StartBlock = (uint32_t)dev->file_addr;
696 dcr->StartFile = (uint32_t)(dev->file_addr >> 32);
700 if (dev->is_tape()) {
701 dcr->EndBlock = dev->EndBlock;
702 dcr->EndFile = dev->EndFile;
704 dcr->EndBlock = (uint32_t)dev->file_addr;
705 dcr->EndFile = (uint32_t)(dev->file_addr >> 32);
709 Jmsg1(jcr, M_ABORT, 0, _("Bad session label = %d\n"), label);
712 create_session_label(dcr, rec, label);
713 rec->FileIndex = label;
716 * We guarantee that the session record can totally fit
717 * into a block. If not, write the block, and put it in
718 * the next block. Having the sesssion record totally in
719 * one block makes reading them much easier (no need to
720 * read the next block).
722 if (!can_write_record_to_block(block, rec)) {
723 Dmsg0(150, "Cannot write session label to block.\n");
724 if (!write_block_to_device(dcr)) {
725 Dmsg0(90, "Got session label write_block_to_dev error.\n");
726 /* ****FIXME***** errno is not set here */
727 Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"),
728 dev_vol_name(dev), strerror(errno));
733 if (!write_record_to_block(block, rec)) {
734 Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"),
735 dev_vol_name(dev), strerror(errno));
740 Dmsg6(50, "Write sesson_label record JobId=%d FI=%s SessId=%d Strm=%s len=%d "
741 "remainder=%d\n", jcr->JobId,
742 FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
743 stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
747 Dmsg2(50, "Leave write_session_label Block=%ud File=%ud\n",
748 dev->get_block(), dev->get_file());
752 /* unser_volume_label
754 * Unserialize the Bacula Volume label into the device Volume_Label
757 * Assumes that the record is already read.
759 * Returns: false on error
763 bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec)
766 char buf1[100], buf2[100];
768 if (rec->FileIndex != VOL_LABEL && rec->FileIndex != PRE_LABEL) {
769 Mmsg3(dev->errmsg, _("Expecting Volume Label, got FI=%s Stream=%s len=%d\n"),
770 FI_to_ascii(buf1, rec->FileIndex),
771 stream_to_ascii(buf2, rec->Stream, rec->FileIndex),
778 dev->VolHdr.LabelType = rec->FileIndex;
779 dev->VolHdr.LabelSize = rec->data_len;
782 /* Unserialize the record into the Volume Header */
783 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
784 ser_begin(rec->data, SER_LENGTH_Volume_Label);
785 unser_string(dev->VolHdr.Id);
786 unser_uint32(dev->VolHdr.VerNum);
788 if (dev->VolHdr.VerNum >= 11) {
789 unser_btime(dev->VolHdr.label_btime);
790 unser_btime(dev->VolHdr.write_btime);
791 } else { /* old way */
792 unser_float64(dev->VolHdr.label_date);
793 unser_float64(dev->VolHdr.label_time);
795 unser_float64(dev->VolHdr.write_date); /* Unused with VerNum >= 11 */
796 unser_float64(dev->VolHdr.write_time); /* Unused with VerNum >= 11 */
798 unser_string(dev->VolHdr.VolumeName);
799 unser_string(dev->VolHdr.PrevVolumeName);
800 unser_string(dev->VolHdr.PoolName);
801 unser_string(dev->VolHdr.PoolType);
802 unser_string(dev->VolHdr.MediaType);
804 unser_string(dev->VolHdr.HostName);
805 unser_string(dev->VolHdr.LabelProg);
806 unser_string(dev->VolHdr.ProgVersion);
807 unser_string(dev->VolHdr.ProgDate);
809 ser_end(rec->data, SER_LENGTH_Volume_Label);
810 Dmsg0(190, "unser_vol_label\n");
811 if (debug_level >= 190) {
812 dump_volume_label(dev);
818 bool unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec)
822 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
823 unser_begin(rec->data, SER_LENGTH_Session_Label);
824 unser_string(label->Id);
825 unser_uint32(label->VerNum);
826 unser_uint32(label->JobId);
827 if (label->VerNum >= 11) {
828 unser_btime(label->write_btime);
830 unser_float64(label->write_date);
832 unser_float64(label->write_time);
833 unser_string(label->PoolName);
834 unser_string(label->PoolType);
835 unser_string(label->JobName);
836 unser_string(label->ClientName);
837 if (label->VerNum >= 10) {
838 unser_string(label->Job); /* Unique name of this Job */
839 unser_string(label->FileSetName);
840 unser_uint32(label->JobType);
841 unser_uint32(label->JobLevel);
843 if (label->VerNum >= 11) {
844 unser_string(label->FileSetMD5);
846 label->FileSetMD5[0] = 0;
848 if (rec->FileIndex == EOS_LABEL) {
849 unser_uint32(label->JobFiles);
850 unser_uint64(label->JobBytes);
851 unser_uint32(label->StartBlock);
852 unser_uint32(label->EndBlock);
853 unser_uint32(label->StartFile);
854 unser_uint32(label->EndFile);
855 unser_uint32(label->JobErrors);
856 if (label->VerNum >= 11) {
857 unser_uint32(label->JobStatus);
859 label->JobStatus = JS_Terminated; /* kludge */
865 void dump_volume_label(DEVICE *dev)
867 int dbl = debug_level;
869 const char *LabelType;
876 switch (dev->VolHdr.LabelType) {
878 LabelType = "PRE_LABEL";
881 LabelType = "VOL_LABEL";
884 LabelType = "EOM_LABEL";
887 LabelType = "SOS_LABEL";
890 LabelType = "EOS_LABEL";
896 sprintf(buf, _("Unknown %d"), dev->VolHdr.LabelType);
900 Pmsg11(-1, _("\nVolume Label:\n"
913 dev->VolHdr.Id, dev->VolHdr.VerNum,
914 dev->VolHdr.VolumeName, dev->VolHdr.PrevVolumeName,
915 File, LabelType, dev->VolHdr.LabelSize,
916 dev->VolHdr.PoolName, dev->VolHdr.MediaType,
917 dev->VolHdr.PoolType, dev->VolHdr.HostName);
919 if (dev->VolHdr.VerNum >= 11) {
921 bstrftime(dt, sizeof(dt), btime_to_unix(dev->VolHdr.label_btime));
922 Pmsg1(-1, _("Date label written: %s\n"), dt);
924 dt.julian_day_number = dev->VolHdr.label_date;
925 dt.julian_day_fraction = dev->VolHdr.label_time;
928 _("Date label written: %04d-%02d-%02d at %02d:%02d\n"),
929 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
937 static void dump_session_label(DEV_RECORD *rec, const char *type)
943 char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], ec6[30], ec7[30];
945 unser_session_label(&label, rec);
948 Pmsg7(-1, _("\n%s Record:\n"
955 ""), type, label.JobId, label.VerNum,
956 label.PoolName, label.PoolType,
957 label.JobName, label.ClientName);
959 if (label.VerNum >= 10) {
961 "Job (unique name) : %s\n"
965 ""), label.Job, label.FileSetName, label.JobType, label.JobLevel);
968 if (rec->FileIndex == EOS_LABEL) {
979 edit_uint64_with_commas(label.JobFiles, ec1),
980 edit_uint64_with_commas(label.JobBytes, ec2),
981 edit_uint64_with_commas(label.StartBlock, ec3),
982 edit_uint64_with_commas(label.EndBlock, ec4),
983 edit_uint64_with_commas(label.StartFile, ec5),
984 edit_uint64_with_commas(label.EndFile, ec6),
985 edit_uint64_with_commas(label.JobErrors, ec7),
988 if (label.VerNum >= 11) {
990 bstrftime(dt, sizeof(dt), btime_to_unix(label.write_btime));
991 Pmsg1(-1, _("Date written : %s\n"), dt);
993 dt.julian_day_number = label.write_date;
994 dt.julian_day_fraction = label.write_time;
996 Pmsg5(-1, _("Date written : %04d-%02d-%02d at %02d:%02d\n"),
997 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
1003 void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose)
1008 if (rec->FileIndex == 0 && rec->VolSessionId == 0 && rec->VolSessionTime == 0) {
1013 switch (rec->FileIndex) {
1015 type = _("Fresh Volume");
1021 type = _("Begin Job Session");
1024 type = _("End Job Session");
1027 type = _("End of Media");
1030 type = _("End of Tape");
1033 type = _("Unknown");
1037 switch (rec->FileIndex) {
1040 unser_volume_label(dev, rec);
1041 dump_volume_label(dev);
1044 dump_session_label(rec, type);
1047 dump_session_label(rec, type);
1050 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1051 type, dev->file, dev->block_num, rec->VolSessionId,
1052 rec->VolSessionTime, rec->Stream, rec->data_len);
1055 Pmsg0(-1, _("End of physical tape.\n"));
1058 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1059 type, dev->file, dev->block_num, rec->VolSessionId,
1060 rec->VolSessionTime, rec->Stream, rec->data_len);
1064 SESSION_LABEL label;
1066 switch (rec->FileIndex) {
1068 unser_session_label(&label, rec);
1069 bstrftimes(dt, sizeof(dt), btime_to_unix(label.write_btime));
1070 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1071 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1072 Pmsg4(-1, _(" Job=%s Date=%s Level=%c Type=%c\n"),
1073 label.Job, dt, label.JobLevel, label.JobType);
1076 char ed1[30], ed2[30];
1077 unser_session_label(&label, rec);
1078 bstrftimes(dt, sizeof(dt), btime_to_unix(label.write_btime));
1079 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1080 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1081 Pmsg7(-1, _(" Date=%s Level=%c Type=%c Files=%s Bytes=%s Errors=%d Status=%c\n"),
1082 dt, label.JobLevel, label.JobType,
1083 edit_uint64_with_commas(label.JobFiles, ed1),
1084 edit_uint64_with_commas(label.JobBytes, ed2),
1085 label.JobErrors, (char)label.JobStatus);
1091 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1092 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime,
1093 rec->Stream, rec->data_len);