2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2010 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, 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) < 0) {
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 (!read_block_from_dev(dcr, 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 bool write_volume_label_to_block(DCR *dcr)
262 DEVICE *dev = dcr->dev;
264 DEV_BLOCK *block = dcr->block;
266 Dmsg0(130, "write Label in write_volume_label_to_block()\n");
267 memset(&rec, 0, sizeof(rec));
268 rec.data = get_memory(SER_LENGTH_Volume_Label);
269 empty_block(block); /* Volume label always at beginning */
271 create_volume_label_record(dcr, &rec);
273 block->BlockNumber = 0;
274 if (!write_record_to_block(block, &rec)) {
275 free_pool_memory(rec.data);
276 Jmsg1(jcr, M_FATAL, 0, _("Cannot write Volume label to block for device %s\n"),
280 Dmsg2(130, "Wrote label of %d bytes to block. Vol=%s\n", rec.data_len,
283 free_pool_memory(rec.data);
289 * Write a Volume Label
290 * !!! Note, this is ONLY used for writing
291 * a fresh volume label. Any data
292 * after the label will be destroyed,
293 * in fact, we write the label 5 times !!!!
295 * This routine should be used only when labeling a blank tape.
297 bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName,
298 const char *PoolName, bool relabel, bool dvdnow)
300 DEVICE * volatile dev = dcr->dev;
303 Dmsg0(150, "write_volume_label()\n");
304 empty_block(dcr->block);
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) < 0) {
326 /* If device is not tape, attempt to create it */
327 if (dev->is_tape() || dev->open(dcr, CREATE_READ_WRITE) < 0) {
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);
334 if (!dev->rewind(dcr)) {
335 Dmsg2(130, "Bad status on %s from rewind: ERR=%s\n", dev->print_name(), dev->print_errmsg());
341 /* Temporarily mark in append state to enable writing */
344 /* Create PRE_LABEL or VOL_LABEL if DVD */
345 create_volume_label(dev, VolName, PoolName, dvdnow);
348 * If we have already detected an ANSI label, re-read it
349 * to skip past it. Otherwise, we write a new one if
352 if (dev->label_type != B_BACULA_LABEL) {
353 if (read_ansi_ibm_label(dcr) != VOL_OK) {
357 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, VolName)) {
361 create_volume_label_record(dcr, dcr->rec);
362 dcr->rec->Stream = 0;
363 dcr->rec->maskedStream = 0;
365 if (!write_record_to_block(dcr->block, dcr->rec)) {
366 Dmsg2(130, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
369 Dmsg2(130, "Wrote label of %d bytes to %s\n", dcr->rec->data_len, dev->print_name());
372 Dmsg0(130, "Call write_block_to_dev()\n");
373 if (!write_block_to_dev(dcr)) {
374 Dmsg2(130, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
378 /* Now commit block to DVD if we should write now */
379 if (dev->is_dvd() && dvdnow) {
380 Dmsg1(150, "New VolName=%s\n", dev->VolCatInfo.VolCatName);
381 if (!dvd_write_part(dcr)) {
382 Dmsg2(130, "Bad DVD write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
387 Dmsg0(130, " Wrote block to device\n");
391 write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
394 if (debug_level >= 20) {
395 dump_volume_label(dev);
397 Dmsg0(100, "Call reserve_volume\n");
398 if (reserve_volume(dcr, VolName) == NULL) {
399 Mmsg2(dcr->jcr->errmsg, _("Could not reserve volume %s on %s\n"),
400 dev->VolHdr.VolumeName, dev->print_name());
401 Dmsg1(100, "%s", dcr->jcr->errmsg);
404 dev = dcr->dev; /* may have changed in reserve_volume */
406 dev->clear_append(); /* remove append since this is PRE_LABEL */
412 dev->clear_append(); /* remove append since this is PRE_LABEL */
417 * Write a volume label. This is ONLY called if we have a valid Bacula
418 * label of type PRE_LABEL or we are recyling an existing Volume.
420 * Returns: true if OK
421 * false if unable to write it
423 bool rewrite_volume_label(DCR *dcr, bool recycle)
425 DEVICE *dev = dcr->dev;
428 if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
429 Jmsg3(jcr, M_WARNING, 0, _("Open device %s Volume \"%s\" failed: ERR=%s\n"),
430 dev->print_name(), dcr->VolumeName, dev->bstrerror());
433 Dmsg2(190, "set append found freshly labeled volume. fd=%d dev=%x\n", dev->fd(), dev);
434 dev->VolHdr.LabelType = VOL_LABEL; /* set Volume label */
436 if (!write_volume_label_to_block(dcr)) {
437 Dmsg0(200, "Error from write volume label.\n");
440 Dmsg1(150, "wrote vol label to block. Vol=%s\n", dcr->VolumeName);
442 dev->setVolCatInfo(false);
443 dev->VolCatInfo.VolCatBytes = 0; /* reset byte count */
446 * If we are not dealing with a streaming device,
447 * write the block now to ensure we have write permission.
448 * It is better to find out now rather than later.
449 * We do not write the block now if this is an ANSI label. This
450 * avoids re-writing the ANSI label, which we do not want to do.
452 if (!dev->has_cap(CAP_STREAM)) {
453 if (!dev->rewind(dcr)) {
454 Jmsg2(jcr, M_FATAL, 0, _("Rewind error on device %s: ERR=%s\n"),
455 dev->print_name(), dev->print_errmsg());
459 Dmsg1(150, "Doing recycle. Vol=%s\n", dcr->VolumeName);
460 // volume_unused(dcr); /* mark volume unused */
461 if (!dev->truncate(dcr)) {
462 Jmsg2(jcr, M_FATAL, 0, _("Truncate error on device %s: ERR=%s\n"),
463 dev->print_name(), dev->print_errmsg());
466 if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
467 Jmsg2(jcr, M_FATAL, 0,
468 _("Failed to re-open DVD after truncate on device %s: ERR=%s\n"),
469 dev->print_name(), dev->print_errmsg());
475 * If we have already detected an ANSI label, re-read it
476 * to skip past it. Otherwise, we write a new one if
479 if (dev->label_type != B_BACULA_LABEL) {
480 if (read_ansi_ibm_label(dcr) != VOL_OK) {
484 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, dev->VolHdr.VolumeName)) {
488 /* Attempt write to check write permission */
489 Dmsg1(200, "Attempt to write to device fd=%d.\n", dev->fd());
490 if (!write_block_to_dev(dcr)) {
491 Jmsg2(jcr, M_ERROR, 0, _("Unable to write device %s: ERR=%s\n"),
492 dev->print_name(), dev->print_errmsg());
493 Dmsg0(200, "===ERROR write block to dev\n");
498 /* Set or reset Volume statistics */
499 dev->VolCatInfo.VolCatJobs = 0;
500 dev->VolCatInfo.VolCatFiles = 0;
501 dev->VolCatInfo.VolCatErrors = 0;
502 dev->VolCatInfo.VolCatBlocks = 0;
503 dev->VolCatInfo.VolCatRBytes = 0;
505 dev->VolCatInfo.VolCatMounts++;
506 dev->VolCatInfo.VolCatRecycles++;
507 dir_create_jobmedia_record(dcr, true);
509 dev->VolCatInfo.VolCatMounts = 1;
510 dev->VolCatInfo.VolCatRecycles = 0;
511 dev->VolCatInfo.VolCatWrites = 1;
512 dev->VolCatInfo.VolCatReads = 1;
514 Dmsg1(150, "dir_update_vol_info. Set Append vol=%s\n", dcr->VolumeName);
515 dev->VolCatInfo.VolFirstWritten = time(NULL);
516 bstrncpy(dev->VolCatInfo.VolCatStatus, "Append", sizeof(dev->VolCatInfo.VolCatStatus));
517 dev->setVolCatName(dcr->VolumeName);
518 if (!dir_update_volume_info(dcr, true, true)) { /* indicate doing relabel */
522 Jmsg(jcr, M_INFO, 0, _("Recycled volume \"%s\" on device %s, all previous data lost.\n"),
523 dcr->VolumeName, dev->print_name());
525 Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume \"%s\" on device %s\n"),
526 dcr->VolumeName, dev->print_name());
529 * End writing real Volume label (from pre-labeled tape), or recycling
532 Dmsg1(150, "OK from rewrite vol label. Vol=%s\n", dcr->VolumeName);
538 * create_volume_label_record
539 * Serialize label (from dev->VolHdr structure) into device record.
540 * Assumes that the dev->VolHdr structure is properly
543 static void create_volume_label_record(DCR *dcr, DEV_RECORD *rec)
547 DEVICE *dev = dcr->dev;
551 /* Serialize the label into the device record. */
553 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
554 ser_begin(rec->data, SER_LENGTH_Volume_Label);
555 ser_string(dev->VolHdr.Id);
557 ser_uint32(dev->VolHdr.VerNum);
559 if (dev->VolHdr.VerNum >= 11) {
560 ser_btime(dev->VolHdr.label_btime);
561 dev->VolHdr.write_btime = get_current_btime();
562 ser_btime(dev->VolHdr.write_btime);
563 dev->VolHdr.write_date = 0;
564 dev->VolHdr.write_time = 0;
566 /* OLD WAY DEPRECATED */
567 ser_float64(dev->VolHdr.label_date);
568 ser_float64(dev->VolHdr.label_time);
569 get_current_time(&dt);
570 dev->VolHdr.write_date = dt.julian_day_number;
571 dev->VolHdr.write_time = dt.julian_day_fraction;
573 ser_float64(dev->VolHdr.write_date); /* 0 if VerNum >= 11 */
574 ser_float64(dev->VolHdr.write_time); /* 0 if VerNum >= 11 */
576 ser_string(dev->VolHdr.VolumeName);
577 ser_string(dev->VolHdr.PrevVolumeName);
578 ser_string(dev->VolHdr.PoolName);
579 ser_string(dev->VolHdr.PoolType);
580 ser_string(dev->VolHdr.MediaType);
582 ser_string(dev->VolHdr.HostName);
583 ser_string(dev->VolHdr.LabelProg);
584 ser_string(dev->VolHdr.ProgVersion);
585 ser_string(dev->VolHdr.ProgDate);
587 ser_end(rec->data, SER_LENGTH_Volume_Label);
588 bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName));
589 rec->data_len = ser_length(rec->data);
590 rec->FileIndex = dev->VolHdr.LabelType;
591 rec->VolSessionId = jcr->VolSessionId;
592 rec->VolSessionTime = jcr->VolSessionTime;
593 rec->Stream = jcr->NumWriteVolumes;
594 rec->maskedStream = jcr->NumWriteVolumes;
595 Dmsg2(150, "Created Vol label rec: FI=%s len=%d\n", FI_to_ascii(buf, rec->FileIndex),
601 * Create a volume label in memory
603 void create_volume_label(DEVICE *dev, const char *VolName,
604 const char *PoolName, bool dvdnow)
606 DEVRES *device = (DEVRES *)dev->device;
608 Dmsg0(130, "Start create_volume_label()\n");
612 dev->clear_volhdr(); /* clear any old volume info */
614 bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
615 dev->VolHdr.VerNum = BaculaTapeVersion;
616 if (dev->is_dvd() && dvdnow) {
617 /* We do not want to re-label a DVD so write VOL_LABEL now */
618 dev->VolHdr.LabelType = VOL_LABEL;
620 dev->VolHdr.LabelType = PRE_LABEL; /* Mark tape as unused */
622 bstrncpy(dev->VolHdr.VolumeName, VolName, sizeof(dev->VolHdr.VolumeName));
623 bstrncpy(dev->VolHdr.PoolName, PoolName, sizeof(dev->VolHdr.PoolName));
624 bstrncpy(dev->VolHdr.MediaType, device->media_type, sizeof(dev->VolHdr.MediaType));
626 bstrncpy(dev->VolHdr.PoolType, "Backup", sizeof(dev->VolHdr.PoolType));
628 dev->VolHdr.label_btime = get_current_btime();
629 dev->VolHdr.label_date = 0;
630 dev->VolHdr.label_time = 0;
632 if (gethostname(dev->VolHdr.HostName, sizeof(dev->VolHdr.HostName)) != 0) {
633 dev->VolHdr.HostName[0] = 0;
635 bstrncpy(dev->VolHdr.LabelProg, my_name, sizeof(dev->VolHdr.LabelProg));
636 sprintf(dev->VolHdr.ProgVersion, "Ver. %s %s", VERSION, BDATE);
637 sprintf(dev->VolHdr.ProgDate, "Build %s %s", __DATE__, __TIME__);
638 dev->set_labeled(); /* set has Bacula label */
639 if (debug_level >= 90) {
640 dump_volume_label(dev);
645 * Create session label
646 * The pool memory must be released by the calling program
648 void create_session_label(DCR *dcr, DEV_RECORD *rec, int label)
653 rec->VolSessionId = jcr->VolSessionId;
654 rec->VolSessionTime = jcr->VolSessionTime;
655 rec->Stream = jcr->JobId;
656 rec->maskedStream = jcr->JobId;
658 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
659 ser_begin(rec->data, SER_LENGTH_Session_Label);
660 ser_string(BaculaId);
661 ser_uint32(BaculaTapeVersion);
663 ser_uint32(jcr->JobId);
665 /* Changed in VerNum 11 */
666 ser_btime(get_current_btime());
669 ser_string(dcr->pool_name);
670 ser_string(dcr->pool_type);
671 ser_string(jcr->job_name); /* base Job name */
672 ser_string(jcr->client_name);
674 /* Added in VerNum 10 */
675 ser_string(jcr->Job); /* Unique name of this Job */
676 ser_string(jcr->fileset_name);
677 ser_uint32(jcr->getJobType());
678 ser_uint32(jcr->getJobLevel());
679 /* Added in VerNum 11 */
680 ser_string(jcr->fileset_md5);
682 if (label == EOS_LABEL) {
683 ser_uint32(jcr->JobFiles);
684 ser_uint64(jcr->JobBytes);
685 ser_uint32(dcr->StartBlock);
686 ser_uint32(dcr->EndBlock);
687 ser_uint32(dcr->StartFile);
688 ser_uint32(dcr->EndFile);
689 ser_uint32(jcr->JobErrors);
691 /* Added in VerNum 11 */
692 ser_uint32(jcr->JobStatus);
694 ser_end(rec->data, SER_LENGTH_Session_Label);
695 rec->data_len = ser_length(rec->data);
698 /* Write session label
699 * Returns: false on failure
702 bool write_session_label(DCR *dcr, int label)
705 DEVICE *dev = dcr->dev;
707 DEV_BLOCK *block = dcr->block;
708 char buf1[100], buf2[100];
711 Dmsg1(130, "session_label record=%x\n", rec);
714 set_start_vol_position(dcr);
717 if (dev->is_tape()) {
718 dcr->EndBlock = dev->EndBlock;
719 dcr->EndFile = dev->EndFile;
721 dcr->EndBlock = (uint32_t)dev->file_addr;
722 dcr->EndFile = (uint32_t)(dev->file_addr >> 32);
726 Jmsg1(jcr, M_ABORT, 0, _("Bad Volume session label = %d\n"), label);
729 create_session_label(dcr, rec, label);
730 rec->FileIndex = label;
733 * We guarantee that the session record can totally fit
734 * into a block. If not, write the block, and put it in
735 * the next block. Having the sesssion record totally in
736 * one block makes reading them much easier (no need to
737 * read the next block).
739 if (!can_write_record_to_block(block, rec)) {
740 Dmsg0(150, "Cannot write session label to block.\n");
741 if (!write_block_to_device(dcr)) {
742 Dmsg0(130, "Got session label write_block_to_dev error.\n");
747 if (!write_record_to_block(block, rec)) {
752 Dmsg6(150, "Write sesson_label record JobId=%d FI=%s SessId=%d Strm=%s len=%d "
753 "remainder=%d\n", jcr->JobId,
754 FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
755 stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
759 Dmsg2(150, "Leave write_session_label Block=%ud File=%ud\n",
760 dev->get_block_num(), dev->get_file());
764 /* unser_volume_label
766 * Unserialize the Bacula Volume label into the device Volume_Label
769 * Assumes that the record is already read.
771 * Returns: false on error
775 bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec)
778 char buf1[100], buf2[100];
780 if (rec->FileIndex != VOL_LABEL && rec->FileIndex != PRE_LABEL) {
781 Mmsg3(dev->errmsg, _("Expecting Volume Label, got FI=%s Stream=%s len=%d\n"),
782 FI_to_ascii(buf1, rec->FileIndex),
783 stream_to_ascii(buf2, rec->Stream, rec->FileIndex),
790 dev->VolHdr.LabelType = rec->FileIndex;
791 dev->VolHdr.LabelSize = rec->data_len;
794 /* Unserialize the record into the Volume Header */
795 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
796 ser_begin(rec->data, SER_LENGTH_Volume_Label);
797 unser_string(dev->VolHdr.Id);
798 unser_uint32(dev->VolHdr.VerNum);
800 if (dev->VolHdr.VerNum >= 11) {
801 unser_btime(dev->VolHdr.label_btime);
802 unser_btime(dev->VolHdr.write_btime);
803 } else { /* old way */
804 unser_float64(dev->VolHdr.label_date);
805 unser_float64(dev->VolHdr.label_time);
807 unser_float64(dev->VolHdr.write_date); /* Unused with VerNum >= 11 */
808 unser_float64(dev->VolHdr.write_time); /* Unused with VerNum >= 11 */
810 unser_string(dev->VolHdr.VolumeName);
811 unser_string(dev->VolHdr.PrevVolumeName);
812 unser_string(dev->VolHdr.PoolName);
813 unser_string(dev->VolHdr.PoolType);
814 unser_string(dev->VolHdr.MediaType);
816 unser_string(dev->VolHdr.HostName);
817 unser_string(dev->VolHdr.LabelProg);
818 unser_string(dev->VolHdr.ProgVersion);
819 unser_string(dev->VolHdr.ProgDate);
821 ser_end(rec->data, SER_LENGTH_Volume_Label);
822 Dmsg0(190, "unser_vol_label\n");
823 if (debug_level >= 190) {
824 dump_volume_label(dev);
830 bool unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec)
834 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
835 unser_begin(rec->data, SER_LENGTH_Session_Label);
836 unser_string(label->Id);
837 unser_uint32(label->VerNum);
838 unser_uint32(label->JobId);
839 if (label->VerNum >= 11) {
840 unser_btime(label->write_btime);
842 unser_float64(label->write_date);
844 unser_float64(label->write_time);
845 unser_string(label->PoolName);
846 unser_string(label->PoolType);
847 unser_string(label->JobName);
848 unser_string(label->ClientName);
849 if (label->VerNum >= 10) {
850 unser_string(label->Job); /* Unique name of this Job */
851 unser_string(label->FileSetName);
852 unser_uint32(label->JobType);
853 unser_uint32(label->JobLevel);
855 if (label->VerNum >= 11) {
856 unser_string(label->FileSetMD5);
858 label->FileSetMD5[0] = 0;
860 if (rec->FileIndex == EOS_LABEL) {
861 unser_uint32(label->JobFiles);
862 unser_uint64(label->JobBytes);
863 unser_uint32(label->StartBlock);
864 unser_uint32(label->EndBlock);
865 unser_uint32(label->StartFile);
866 unser_uint32(label->EndFile);
867 unser_uint32(label->JobErrors);
868 if (label->VerNum >= 11) {
869 unser_uint32(label->JobStatus);
871 label->JobStatus = JS_Terminated; /* kludge */
877 void dump_volume_label(DEVICE *dev)
879 int dbl = debug_level;
881 const char *LabelType;
888 switch (dev->VolHdr.LabelType) {
890 LabelType = "PRE_LABEL";
893 LabelType = "VOL_LABEL";
896 LabelType = "EOM_LABEL";
899 LabelType = "SOS_LABEL";
902 LabelType = "EOS_LABEL";
908 sprintf(buf, _("Unknown %d"), dev->VolHdr.LabelType);
912 Pmsg11(-1, _("\nVolume Label:\n"
925 dev->VolHdr.Id, dev->VolHdr.VerNum,
926 dev->VolHdr.VolumeName, dev->VolHdr.PrevVolumeName,
927 File, LabelType, dev->VolHdr.LabelSize,
928 dev->VolHdr.PoolName, dev->VolHdr.MediaType,
929 dev->VolHdr.PoolType, dev->VolHdr.HostName);
931 if (dev->VolHdr.VerNum >= 11) {
933 bstrftime(dt, sizeof(dt), btime_to_utime(dev->VolHdr.label_btime));
934 Pmsg1(-1, _("Date label written: %s\n"), dt);
936 dt.julian_day_number = dev->VolHdr.label_date;
937 dt.julian_day_fraction = dev->VolHdr.label_time;
940 _("Date label written: %04d-%02d-%02d at %02d:%02d\n"),
941 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
949 static void dump_session_label(DEV_RECORD *rec, const char *type)
955 char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], ec6[30], ec7[30];
957 unser_session_label(&label, rec);
960 Pmsg7(-1, _("\n%s Record:\n"
967 ""), type, label.JobId, label.VerNum,
968 label.PoolName, label.PoolType,
969 label.JobName, label.ClientName);
971 if (label.VerNum >= 10) {
973 "Job (unique name) : %s\n"
977 ""), label.Job, label.FileSetName, label.JobType, label.JobLevel);
980 if (rec->FileIndex == EOS_LABEL) {
991 edit_uint64_with_commas(label.JobFiles, ec1),
992 edit_uint64_with_commas(label.JobBytes, ec2),
993 edit_uint64_with_commas(label.StartBlock, ec3),
994 edit_uint64_with_commas(label.EndBlock, ec4),
995 edit_uint64_with_commas(label.StartFile, ec5),
996 edit_uint64_with_commas(label.EndFile, ec6),
997 edit_uint64_with_commas(label.JobErrors, ec7),
1000 if (label.VerNum >= 11) {
1002 bstrftime(dt, sizeof(dt), btime_to_utime(label.write_btime));
1003 Pmsg1(-1, _("Date written : %s\n"), dt);
1005 dt.julian_day_number = label.write_date;
1006 dt.julian_day_fraction = label.write_time;
1007 tm_decode(&dt, &tm);
1008 Pmsg5(-1, _("Date written : %04d-%02d-%02d at %02d:%02d\n"),
1009 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
1015 void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose)
1020 if (rec->FileIndex == 0 && rec->VolSessionId == 0 && rec->VolSessionTime == 0) {
1025 switch (rec->FileIndex) {
1027 type = _("Fresh Volume");
1033 type = _("Begin Job Session");
1036 type = _("End Job Session");
1039 type = _("End of Media");
1042 type = _("End of Tape");
1045 type = _("Unknown");
1049 switch (rec->FileIndex) {
1052 unser_volume_label(dev, rec);
1053 dump_volume_label(dev);
1056 dump_session_label(rec, type);
1059 dump_session_label(rec, type);
1062 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1063 type, dev->file, dev->block_num, rec->VolSessionId,
1064 rec->VolSessionTime, rec->Stream, rec->data_len);
1067 Pmsg0(-1, _("End of physical tape.\n"));
1070 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1071 type, dev->file, dev->block_num, rec->VolSessionId,
1072 rec->VolSessionTime, rec->Stream, rec->data_len);
1076 SESSION_LABEL label;
1078 switch (rec->FileIndex) {
1080 unser_session_label(&label, rec);
1081 bstrftimes(dt, sizeof(dt), btime_to_utime(label.write_btime));
1082 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1083 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1084 Pmsg4(-1, _(" Job=%s Date=%s Level=%c Type=%c\n"),
1085 label.Job, dt, label.JobLevel, label.JobType);
1088 char ed1[30], ed2[30];
1089 unser_session_label(&label, rec);
1090 bstrftimes(dt, sizeof(dt), btime_to_utime(label.write_btime));
1091 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1092 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1093 Pmsg7(-1, _(" Date=%s Level=%c Type=%c Files=%s Bytes=%s Errors=%d Status=%c\n"),
1094 dt, label.JobLevel, label.JobType,
1095 edit_uint64_with_commas(label.JobFiles, ed1),
1096 edit_uint64_with_commas(label.JobBytes, ed2),
1097 label.JobErrors, (char)label.JobStatus);
1103 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1104 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime,
1105 rec->Stream, rec->data_len);