2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2009 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 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
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) {
92 dev->label_type = B_BACULA_LABEL;
94 if (!dev->rewind(dcr)) {
95 Mmsg(jcr->errmsg, _("Couldn't rewind device %s: ERR=%s\n"),
96 dev->print_name(), dev->print_errmsg());
97 Dmsg1(130, "return VOL_NO_MEDIA: %s", jcr->errmsg);
100 bstrncpy(dev->VolHdr.Id, "**error**", sizeof(dev->VolHdr.Id));
102 /* Read ANSI/IBM label if so requested */
103 want_ansi_label = dcr->VolCatInfo.LabelType != B_BACULA_LABEL ||
104 dcr->device->label_type != B_BACULA_LABEL;
105 if (want_ansi_label || dev->has_cap(CAP_CHECKLABELS)) {
106 stat = read_ansi_ibm_label(dcr);
107 /* If we want a label and didn't find it, return error */
108 if (want_ansi_label && stat != VOL_OK) {
111 if (stat == VOL_NAME_ERROR || stat == VOL_LABEL_ERROR) {
112 Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
113 dev->print_name(), VolName, dev->VolHdr.VolumeName);
114 if (!dev->poll && jcr->label_errors++ > 100) {
115 Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
119 if (stat != VOL_OK) { /* Not an ANSI/IBM label, so re-read */
122 have_ansi_label = true;
126 /* Read the Bacula Volume label block */
127 record = new_record();
130 Dmsg0(130, "Big if statement in read_volume_label\n");
131 if (!read_block_from_dev(dcr, NO_BLOCK_NUMBER_CHECK)) {
132 Mmsg(jcr->errmsg, _("Requested Volume \"%s\" on %s is not a Bacula "
133 "labeled Volume, because: ERR=%s"), NPRT(VolName),
134 dev->print_name(), dev->print_errmsg());
135 Dmsg1(130, "%s", jcr->errmsg);
136 } else if (!read_record_from_block(dcr, block, record)) {
137 Mmsg(jcr->errmsg, _("Could not read Volume label from block.\n"));
138 Dmsg1(130, "%s", jcr->errmsg);
139 } else if (!unser_volume_label(dev, record)) {
140 Mmsg(jcr->errmsg, _("Could not unserialize Volume label: ERR=%s\n"),
141 dev->print_errmsg());
142 Dmsg1(130, "%s", jcr->errmsg);
143 } else if (strcmp(dev->VolHdr.Id, BaculaId) != 0 &&
144 strcmp(dev->VolHdr.Id, OldBaculaId) != 0) {
145 Mmsg(jcr->errmsg, _("Volume Header Id bad: %s\n"), dev->VolHdr.Id);
146 Dmsg1(130, "%s", jcr->errmsg);
150 free_record(record); /* finished reading Volume record */
152 if (!dev->is_volume_to_unload()) {
157 if (forge_on || jcr->ignore_label_errors) {
158 dev->set_labeled(); /* set has Bacula label */
159 Jmsg(jcr, M_ERROR, 0, "%s", jcr->errmsg);
163 Dmsg0(100, "No volume label - bailing out\n");
168 /* At this point, we have read the first Bacula block, and
169 * then read the Bacula Volume label. Now we need to
170 * make sure we have the right Volume.
174 if (dev->VolHdr.VerNum != BaculaTapeVersion &&
175 dev->VolHdr.VerNum != OldCompatibleBaculaTapeVersion1 &&
176 dev->VolHdr.VerNum != OldCompatibleBaculaTapeVersion2) {
177 Mmsg(jcr->errmsg, _("Volume on %s has wrong Bacula version. Wanted %d got %d\n"),
178 dev->print_name(), BaculaTapeVersion, dev->VolHdr.VerNum);
179 Dmsg1(130, "VOL_VERSION_ERROR: %s", jcr->errmsg);
180 stat = VOL_VERSION_ERROR;
184 /* We are looking for either an unused Bacula tape (PRE_LABEL) or
185 * a Bacula volume label (VOL_LABEL)
187 if (dev->VolHdr.LabelType != PRE_LABEL && dev->VolHdr.LabelType != VOL_LABEL) {
188 Mmsg(jcr->errmsg, _("Volume on %s has bad Bacula label type: %x\n"),
189 dev->print_name(), dev->VolHdr.LabelType);
190 Dmsg1(130, "%s", jcr->errmsg);
191 if (!dev->poll && jcr->label_errors++ > 100) {
192 Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
194 Dmsg0(150, "return VOL_LABEL_ERROR\n");
195 stat = VOL_LABEL_ERROR;
199 dev->set_labeled(); /* set has Bacula label */
201 /* Compare Volume Names */
202 Dmsg2(130, "Compare Vol names: VolName=%s hdr=%s\n", VolName?VolName:"*", dev->VolHdr.VolumeName);
203 if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolumeName, VolName) != 0) {
204 Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
205 dev->print_name(), VolName, dev->VolHdr.VolumeName);
206 Dmsg1(130, "%s", jcr->errmsg);
208 * Cancel Job if too many label errors
209 * => we are in a loop
211 if (!dev->poll && jcr->label_errors++ > 100) {
212 Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
214 Dmsg0(150, "return VOL_NAME_ERROR\n");
215 stat = VOL_NAME_ERROR;
220 if (debug_level >= 10) {
221 dump_volume_label(dev);
223 Dmsg0(130, "Leave read_volume_label() VOL_OK\n");
224 /* If we are a streaming device, we only get one chance to read */
225 if (!dev->has_cap(CAP_STREAM)) {
227 if (have_ansi_label) {
228 stat = read_ansi_ibm_label(dcr);
229 /* If we want a label and didn't find it, return error */
230 if (stat != VOL_OK) {
236 Dmsg1(100, "Call reserve_volume=%s\n", dev->VolHdr.VolumeName);
237 if (reserve_volume(dcr, dev->VolHdr.VolumeName) == NULL) {
238 Mmsg2(jcr->errmsg, _("Could not reserve volume %s on %s\n"),
239 dev->VolHdr.VolumeName, dev->print_name());
240 Dmsg2(150, "Could not reserve volume %s on %s\n", dev->VolHdr.VolumeName, dev->print_name());
241 stat = VOL_NAME_ERROR;
251 Dmsg1(150, "return %d\n", stat);
256 * Put a volume label into the block
258 * Returns: false on failure
261 bool write_volume_label_to_block(DCR *dcr)
264 DEVICE *dev = dcr->dev;
266 DEV_BLOCK *block = dcr->block;
268 Dmsg0(130, "write Label in write_volume_label_to_block()\n");
269 memset(&rec, 0, sizeof(rec));
270 rec.data = get_memory(SER_LENGTH_Volume_Label);
271 empty_block(block); /* Volume label always at beginning */
273 create_volume_label_record(dcr, &rec);
275 block->BlockNumber = 0;
276 if (!write_record_to_block(block, &rec)) {
277 free_pool_memory(rec.data);
278 Jmsg1(jcr, M_FATAL, 0, _("Cannot write Volume label to block for device %s\n"),
282 Dmsg2(130, "Wrote label of %d bytes to block. Vol=%s\n", rec.data_len,
285 free_pool_memory(rec.data);
291 * Write a Volume Label
292 * !!! Note, this is ONLY used for writing
293 * a fresh volume label. Any data
294 * after the label will be destroyed,
295 * in fact, we write the label 5 times !!!!
297 * This routine should be used only when labeling a blank tape.
299 bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName,
300 const char *PoolName, bool relabel, bool dvdnow)
302 DEVICE * volatile dev = dcr->dev;
305 Dmsg0(150, "write_volume_label()\n");
306 empty_block(dcr->block);
308 Pmsg0(0, "=== ERROR: write_new_volume_label_to_dev called with NULL VolName\n");
313 volume_unused(dcr); /* mark current volume unused */
314 /* Truncate device */
315 if (!dev->truncate(dcr)) {
318 if (!dev->is_tape()) {
319 dev->close_part(dcr); /* make sure DVD/file 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) {
330 Jmsg3(dcr->jcr, M_WARNING, 0, _("Open device %s Volume \"%s\" failed: ERR=%s\n"),
331 dev->print_name(), dcr->VolumeName, dev->bstrerror());
335 Dmsg1(150, "Label type=%d\n", dev->label_type);
336 if (!dev->rewind(dcr)) {
337 Dmsg2(130, "Bad status on %s from rewind: ERR=%s\n", dev->print_name(), dev->print_errmsg());
343 /* Temporarily mark in append state to enable writing */
346 /* Create PRE_LABEL or VOL_LABEL if DVD */
347 create_volume_label(dev, VolName, PoolName, dvdnow);
350 * If we have already detected an ANSI label, re-read it
351 * to skip past it. Otherwise, we write a new one if
354 if (dev->label_type != B_BACULA_LABEL) {
355 if (read_ansi_ibm_label(dcr) != VOL_OK) {
359 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, VolName)) {
363 create_volume_label_record(dcr, dcr->rec);
364 dcr->rec->Stream = 0;
366 if (!write_record_to_block(dcr->block, dcr->rec)) {
367 Dmsg2(130, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
370 Dmsg2(130, "Wrote label of %d bytes to %s\n", dcr->rec->data_len, dev->print_name());
373 Dmsg0(130, "Call write_block_to_dev()\n");
374 if (!write_block_to_dev(dcr)) {
375 Dmsg2(130, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
379 /* Now commit block to DVD if we should write now */
380 if (dev->is_dvd() && dvdnow) {
381 Dmsg1(150, "New VolName=%s\n", dev->VolCatInfo.VolCatName);
382 if (!dvd_write_part(dcr)) {
383 Dmsg2(130, "Bad DVD write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
388 Dmsg0(130, " Wrote block to device\n");
392 write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
395 if (debug_level >= 20) {
396 dump_volume_label(dev);
398 Dmsg0(100, "Call reserve_volume\n");
399 if (reserve_volume(dcr, VolName) == NULL) {
400 Mmsg2(dcr->jcr->errmsg, _("Could not reserve volume %s on %s\n"),
401 dev->VolHdr.VolumeName, dev->print_name());
402 Dmsg1(100, "%s", dcr->jcr->errmsg);
405 dev = dcr->dev; /* may have changed in reserve_volume */
407 dev->clear_append(); /* remove append since this is PRE_LABEL */
413 dev->clear_append(); /* remove append since this is PRE_LABEL */
418 * Write a volume label. This is ONLY called if we have a valid Bacula
419 * label of type PRE_LABEL or we are recyling an existing Volume.
421 * Returns: true if OK
422 * false if unable to write it
424 bool rewrite_volume_label(DCR *dcr, bool recycle)
426 DEVICE *dev = dcr->dev;
429 if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
430 Jmsg3(jcr, M_WARNING, 0, _("Open device %s Volume \"%s\" failed: ERR=%s\n"),
431 dev->print_name(), dcr->VolumeName, dev->bstrerror());
434 Dmsg2(190, "set append found freshly labeled volume. fd=%d dev=%x\n", dev->fd(), dev);
435 dev->VolHdr.LabelType = VOL_LABEL; /* set Volume label */
437 if (!write_volume_label_to_block(dcr)) {
438 Dmsg0(200, "Error from write volume label.\n");
441 Dmsg1(150, "wrote vol label to block. Vol=%s\n", dcr->VolumeName);
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 bstrncpy(dev->VolCatInfo.VolCatStatus, "Append", sizeof(dev->VolCatInfo.VolCatStatus));
516 bstrncpy(dev->VolCatInfo.VolCatName, dcr->VolumeName, sizeof(dev->VolCatInfo.VolCatName));
517 if (!dir_update_volume_info(dcr, true, true)) { /* indicate doing relabel */
521 Jmsg(jcr, M_INFO, 0, _("Recycled volume \"%s\" on device %s, all previous data lost.\n"),
522 dcr->VolumeName, dev->print_name());
524 Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume \"%s\" on device %s\n"),
525 dcr->VolumeName, dev->print_name());
528 * End writing real Volume label (from pre-labeled tape), or recycling
531 Dmsg1(150, "OK from rewrite vol label. Vol=%s\n", dcr->VolumeName);
537 * create_volume_label_record
538 * Serialize label (from dev->VolHdr structure) into device record.
539 * Assumes that the dev->VolHdr structure is properly
542 static void create_volume_label_record(DCR *dcr, DEV_RECORD *rec)
546 DEVICE *dev = dcr->dev;
550 /* Serialize the label into the device record. */
552 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
553 ser_begin(rec->data, SER_LENGTH_Volume_Label);
554 ser_string(dev->VolHdr.Id);
556 ser_uint32(dev->VolHdr.VerNum);
558 if (dev->VolHdr.VerNum >= 11) {
559 ser_btime(dev->VolHdr.label_btime);
560 dev->VolHdr.write_btime = get_current_btime();
561 ser_btime(dev->VolHdr.write_btime);
562 dev->VolHdr.write_date = 0;
563 dev->VolHdr.write_time = 0;
565 /* OLD WAY DEPRECATED */
566 ser_float64(dev->VolHdr.label_date);
567 ser_float64(dev->VolHdr.label_time);
568 get_current_time(&dt);
569 dev->VolHdr.write_date = dt.julian_day_number;
570 dev->VolHdr.write_time = dt.julian_day_fraction;
572 ser_float64(dev->VolHdr.write_date); /* 0 if VerNum >= 11 */
573 ser_float64(dev->VolHdr.write_time); /* 0 if VerNum >= 11 */
575 ser_string(dev->VolHdr.VolumeName);
576 ser_string(dev->VolHdr.PrevVolumeName);
577 ser_string(dev->VolHdr.PoolName);
578 ser_string(dev->VolHdr.PoolType);
579 ser_string(dev->VolHdr.MediaType);
581 ser_string(dev->VolHdr.HostName);
582 ser_string(dev->VolHdr.LabelProg);
583 ser_string(dev->VolHdr.ProgVersion);
584 ser_string(dev->VolHdr.ProgDate);
586 ser_end(rec->data, SER_LENGTH_Volume_Label);
587 bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName));
588 rec->data_len = ser_length(rec->data);
589 rec->FileIndex = dev->VolHdr.LabelType;
590 rec->VolSessionId = jcr->VolSessionId;
591 rec->VolSessionTime = jcr->VolSessionTime;
592 rec->Stream = jcr->NumWriteVolumes;
593 Dmsg2(150, "Created Vol label rec: FI=%s len=%d\n", FI_to_ascii(buf, rec->FileIndex),
599 * Create a volume label in memory
601 void create_volume_label(DEVICE *dev, const char *VolName,
602 const char *PoolName, bool dvdnow)
604 DEVRES *device = (DEVRES *)dev->device;
606 Dmsg0(130, "Start create_volume_label()\n");
610 dev->clear_volhdr(); /* clear any old volume info */
612 bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
613 dev->VolHdr.VerNum = BaculaTapeVersion;
614 if (dev->is_dvd() && dvdnow) {
615 /* We do not want to re-label a DVD so write VOL_LABEL now */
616 dev->VolHdr.LabelType = VOL_LABEL;
618 dev->VolHdr.LabelType = PRE_LABEL; /* Mark tape as unused */
620 bstrncpy(dev->VolHdr.VolumeName, VolName, sizeof(dev->VolHdr.VolumeName));
621 bstrncpy(dev->VolHdr.PoolName, PoolName, sizeof(dev->VolHdr.PoolName));
622 bstrncpy(dev->VolHdr.MediaType, device->media_type, sizeof(dev->VolHdr.MediaType));
624 bstrncpy(dev->VolHdr.PoolType, "Backup", sizeof(dev->VolHdr.PoolType));
626 dev->VolHdr.label_btime = get_current_btime();
627 dev->VolHdr.label_date = 0;
628 dev->VolHdr.label_time = 0;
630 if (gethostname(dev->VolHdr.HostName, sizeof(dev->VolHdr.HostName)) != 0) {
631 dev->VolHdr.HostName[0] = 0;
633 bstrncpy(dev->VolHdr.LabelProg, my_name, sizeof(dev->VolHdr.LabelProg));
634 sprintf(dev->VolHdr.ProgVersion, "Ver. %s %s", VERSION, BDATE);
635 sprintf(dev->VolHdr.ProgDate, "Build %s %s", __DATE__, __TIME__);
636 dev->set_labeled(); /* set has Bacula label */
637 if (debug_level >= 90) {
638 dump_volume_label(dev);
643 * Create session label
644 * The pool memory must be released by the calling program
646 void create_session_label(DCR *dcr, DEV_RECORD *rec, int label)
651 rec->VolSessionId = jcr->VolSessionId;
652 rec->VolSessionTime = jcr->VolSessionTime;
653 rec->Stream = jcr->JobId;
655 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
656 ser_begin(rec->data, SER_LENGTH_Session_Label);
657 ser_string(BaculaId);
658 ser_uint32(BaculaTapeVersion);
660 ser_uint32(jcr->JobId);
662 /* Changed in VerNum 11 */
663 ser_btime(get_current_btime());
666 ser_string(dcr->pool_name);
667 ser_string(dcr->pool_type);
668 ser_string(jcr->job_name); /* base Job name */
669 ser_string(jcr->client_name);
671 /* Added in VerNum 10 */
672 ser_string(jcr->Job); /* Unique name of this Job */
673 ser_string(jcr->fileset_name);
674 ser_uint32(jcr->getJobType());
675 ser_uint32(jcr->getJobLevel());
676 /* Added in VerNum 11 */
677 ser_string(jcr->fileset_md5);
679 if (label == EOS_LABEL) {
680 ser_uint32(jcr->JobFiles);
681 ser_uint64(jcr->JobBytes);
682 ser_uint32(dcr->StartBlock);
683 ser_uint32(dcr->EndBlock);
684 ser_uint32(dcr->StartFile);
685 ser_uint32(dcr->EndFile);
686 ser_uint32(jcr->JobErrors);
688 /* Added in VerNum 11 */
689 ser_uint32(jcr->JobStatus);
691 ser_end(rec->data, SER_LENGTH_Session_Label);
692 rec->data_len = ser_length(rec->data);
695 /* Write session label
696 * Returns: false on failure
699 bool write_session_label(DCR *dcr, int label)
702 DEVICE *dev = dcr->dev;
704 DEV_BLOCK *block = dcr->block;
705 char buf1[100], buf2[100];
708 Dmsg1(130, "session_label record=%x\n", rec);
711 set_start_vol_position(dcr);
714 if (dev->is_tape()) {
715 dcr->EndBlock = dev->EndBlock;
716 dcr->EndFile = dev->EndFile;
718 dcr->EndBlock = (uint32_t)dev->file_addr;
719 dcr->EndFile = (uint32_t)(dev->file_addr >> 32);
723 Jmsg1(jcr, M_ABORT, 0, _("Bad Volume session label = %d\n"), label);
726 create_session_label(dcr, rec, label);
727 rec->FileIndex = label;
730 * We guarantee that the session record can totally fit
731 * into a block. If not, write the block, and put it in
732 * the next block. Having the sesssion record totally in
733 * one block makes reading them much easier (no need to
734 * read the next block).
736 if (!can_write_record_to_block(block, rec)) {
737 Dmsg0(150, "Cannot write session label to block.\n");
738 if (!write_block_to_device(dcr)) {
739 Dmsg0(130, "Got session label write_block_to_dev error.\n");
744 if (!write_record_to_block(block, rec)) {
749 Dmsg6(150, "Write sesson_label record JobId=%d FI=%s SessId=%d Strm=%s len=%d "
750 "remainder=%d\n", jcr->JobId,
751 FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
752 stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
756 Dmsg2(150, "Leave write_session_label Block=%ud File=%ud\n",
757 dev->get_block_num(), dev->get_file());
761 /* unser_volume_label
763 * Unserialize the Bacula Volume label into the device Volume_Label
766 * Assumes that the record is already read.
768 * Returns: false on error
772 bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec)
775 char buf1[100], buf2[100];
777 if (rec->FileIndex != VOL_LABEL && rec->FileIndex != PRE_LABEL) {
778 Mmsg3(dev->errmsg, _("Expecting Volume Label, got FI=%s Stream=%s len=%d\n"),
779 FI_to_ascii(buf1, rec->FileIndex),
780 stream_to_ascii(buf2, rec->Stream, rec->FileIndex),
787 dev->VolHdr.LabelType = rec->FileIndex;
788 dev->VolHdr.LabelSize = rec->data_len;
791 /* Unserialize the record into the Volume Header */
792 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
793 ser_begin(rec->data, SER_LENGTH_Volume_Label);
794 unser_string(dev->VolHdr.Id);
795 unser_uint32(dev->VolHdr.VerNum);
797 if (dev->VolHdr.VerNum >= 11) {
798 unser_btime(dev->VolHdr.label_btime);
799 unser_btime(dev->VolHdr.write_btime);
800 } else { /* old way */
801 unser_float64(dev->VolHdr.label_date);
802 unser_float64(dev->VolHdr.label_time);
804 unser_float64(dev->VolHdr.write_date); /* Unused with VerNum >= 11 */
805 unser_float64(dev->VolHdr.write_time); /* Unused with VerNum >= 11 */
807 unser_string(dev->VolHdr.VolumeName);
808 unser_string(dev->VolHdr.PrevVolumeName);
809 unser_string(dev->VolHdr.PoolName);
810 unser_string(dev->VolHdr.PoolType);
811 unser_string(dev->VolHdr.MediaType);
813 unser_string(dev->VolHdr.HostName);
814 unser_string(dev->VolHdr.LabelProg);
815 unser_string(dev->VolHdr.ProgVersion);
816 unser_string(dev->VolHdr.ProgDate);
818 ser_end(rec->data, SER_LENGTH_Volume_Label);
819 Dmsg0(190, "unser_vol_label\n");
820 if (debug_level >= 190) {
821 dump_volume_label(dev);
827 bool unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec)
831 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
832 unser_begin(rec->data, SER_LENGTH_Session_Label);
833 unser_string(label->Id);
834 unser_uint32(label->VerNum);
835 unser_uint32(label->JobId);
836 if (label->VerNum >= 11) {
837 unser_btime(label->write_btime);
839 unser_float64(label->write_date);
841 unser_float64(label->write_time);
842 unser_string(label->PoolName);
843 unser_string(label->PoolType);
844 unser_string(label->JobName);
845 unser_string(label->ClientName);
846 if (label->VerNum >= 10) {
847 unser_string(label->Job); /* Unique name of this Job */
848 unser_string(label->FileSetName);
849 unser_uint32(label->JobType);
850 unser_uint32(label->JobLevel);
852 if (label->VerNum >= 11) {
853 unser_string(label->FileSetMD5);
855 label->FileSetMD5[0] = 0;
857 if (rec->FileIndex == EOS_LABEL) {
858 unser_uint32(label->JobFiles);
859 unser_uint64(label->JobBytes);
860 unser_uint32(label->StartBlock);
861 unser_uint32(label->EndBlock);
862 unser_uint32(label->StartFile);
863 unser_uint32(label->EndFile);
864 unser_uint32(label->JobErrors);
865 if (label->VerNum >= 11) {
866 unser_uint32(label->JobStatus);
868 label->JobStatus = JS_Terminated; /* kludge */
874 void dump_volume_label(DEVICE *dev)
876 int dbl = debug_level;
878 const char *LabelType;
885 switch (dev->VolHdr.LabelType) {
887 LabelType = "PRE_LABEL";
890 LabelType = "VOL_LABEL";
893 LabelType = "EOM_LABEL";
896 LabelType = "SOS_LABEL";
899 LabelType = "EOS_LABEL";
905 sprintf(buf, _("Unknown %d"), dev->VolHdr.LabelType);
909 Pmsg11(-1, _("\nVolume Label:\n"
922 dev->VolHdr.Id, dev->VolHdr.VerNum,
923 dev->VolHdr.VolumeName, dev->VolHdr.PrevVolumeName,
924 File, LabelType, dev->VolHdr.LabelSize,
925 dev->VolHdr.PoolName, dev->VolHdr.MediaType,
926 dev->VolHdr.PoolType, dev->VolHdr.HostName);
928 if (dev->VolHdr.VerNum >= 11) {
930 bstrftime(dt, sizeof(dt), btime_to_utime(dev->VolHdr.label_btime));
931 Pmsg1(-1, _("Date label written: %s\n"), dt);
933 dt.julian_day_number = dev->VolHdr.label_date;
934 dt.julian_day_fraction = dev->VolHdr.label_time;
937 _("Date label written: %04d-%02d-%02d at %02d:%02d\n"),
938 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
946 static void dump_session_label(DEV_RECORD *rec, const char *type)
952 char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], ec6[30], ec7[30];
954 unser_session_label(&label, rec);
957 Pmsg7(-1, _("\n%s Record:\n"
964 ""), type, label.JobId, label.VerNum,
965 label.PoolName, label.PoolType,
966 label.JobName, label.ClientName);
968 if (label.VerNum >= 10) {
970 "Job (unique name) : %s\n"
974 ""), label.Job, label.FileSetName, label.JobType, label.JobLevel);
977 if (rec->FileIndex == EOS_LABEL) {
988 edit_uint64_with_commas(label.JobFiles, ec1),
989 edit_uint64_with_commas(label.JobBytes, ec2),
990 edit_uint64_with_commas(label.StartBlock, ec3),
991 edit_uint64_with_commas(label.EndBlock, ec4),
992 edit_uint64_with_commas(label.StartFile, ec5),
993 edit_uint64_with_commas(label.EndFile, ec6),
994 edit_uint64_with_commas(label.JobErrors, ec7),
997 if (label.VerNum >= 11) {
999 bstrftime(dt, sizeof(dt), btime_to_utime(label.write_btime));
1000 Pmsg1(-1, _("Date written : %s\n"), dt);
1002 dt.julian_day_number = label.write_date;
1003 dt.julian_day_fraction = label.write_time;
1004 tm_decode(&dt, &tm);
1005 Pmsg5(-1, _("Date written : %04d-%02d-%02d at %02d:%02d\n"),
1006 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
1012 void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose)
1017 if (rec->FileIndex == 0 && rec->VolSessionId == 0 && rec->VolSessionTime == 0) {
1022 switch (rec->FileIndex) {
1024 type = _("Fresh Volume");
1030 type = _("Begin Job Session");
1033 type = _("End Job Session");
1036 type = _("End of Media");
1039 type = _("End of Tape");
1042 type = _("Unknown");
1046 switch (rec->FileIndex) {
1049 unser_volume_label(dev, rec);
1050 dump_volume_label(dev);
1053 dump_session_label(rec, type);
1056 dump_session_label(rec, type);
1059 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1060 type, dev->file, dev->block_num, rec->VolSessionId,
1061 rec->VolSessionTime, rec->Stream, rec->data_len);
1064 Pmsg0(-1, _("End of physical tape.\n"));
1067 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1068 type, dev->file, dev->block_num, rec->VolSessionId,
1069 rec->VolSessionTime, rec->Stream, rec->data_len);
1073 SESSION_LABEL label;
1075 switch (rec->FileIndex) {
1077 unser_session_label(&label, rec);
1078 bstrftimes(dt, sizeof(dt), btime_to_utime(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 Pmsg4(-1, _(" Job=%s Date=%s Level=%c Type=%c\n"),
1082 label.Job, dt, label.JobLevel, label.JobType);
1085 char ed1[30], ed2[30];
1086 unser_session_label(&label, rec);
1087 bstrftimes(dt, sizeof(dt), btime_to_utime(label.write_btime));
1088 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1089 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1090 Pmsg7(-1, _(" Date=%s Level=%c Type=%c Files=%s Bytes=%s Errors=%d Status=%c\n"),
1091 dt, label.JobLevel, label.JobType,
1092 edit_uint64_with_commas(label.JobFiles, ed1),
1093 edit_uint64_with_commas(label.JobBytes, ed2),
1094 label.JobErrors, (char)label.JobStatus);
1100 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1101 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime,
1102 rec->Stream, rec->data_len);