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 stat = VOL_NAME_ERROR;
250 Dmsg1(150, "return %d\n", stat);
255 * Put a volume label into the block
257 * Returns: false on failure
260 bool write_volume_label_to_block(DCR *dcr)
263 DEVICE *dev = dcr->dev;
265 DEV_BLOCK *block = dcr->block;
267 Dmsg0(130, "write Label in write_volume_label_to_block()\n");
268 memset(&rec, 0, sizeof(rec));
269 rec.data = get_memory(SER_LENGTH_Volume_Label);
270 empty_block(block); /* Volume label always at beginning */
272 create_volume_label_record(dcr, &rec);
274 block->BlockNumber = 0;
275 if (!write_record_to_block(block, &rec)) {
276 free_pool_memory(rec.data);
277 Jmsg1(jcr, M_FATAL, 0, _("Cannot write Volume label to block for device %s\n"),
281 Dmsg2(130, "Wrote label of %d bytes to block. Vol=%s\n", rec.data_len,
284 free_pool_memory(rec.data);
290 * Write a Volume Label
291 * !!! Note, this is ONLY used for writing
292 * a fresh volume label. Any data
293 * after the label will be destroyed,
294 * in fact, we write the label 5 times !!!!
296 * This routine should be used only when labeling a blank tape.
298 bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName,
299 const char *PoolName, bool relabel, bool dvdnow)
301 DEVICE * volatile dev = dcr->dev;
304 Dmsg0(150, "write_volume_label()\n");
305 empty_block(dcr->block);
307 Pmsg0(0, "=== ERROR: write_new_volume_label_to_dev called with NULL VolName\n");
312 volume_unused(dcr); /* mark current volume unused */
313 /* Truncate device */
314 if (!dev->truncate(dcr)) {
317 if (!dev->is_tape()) {
318 dev->close_part(dcr); /* make sure DVD/file closed for rename */
322 /* Set the new filename for open, ... */
323 bstrncpy(dev->VolCatInfo.VolCatName, VolName, sizeof(dev->VolCatInfo.VolCatName));
324 bstrncpy(dcr->VolCatInfo.VolCatName, VolName, sizeof(dcr->VolCatInfo.VolCatName));
325 Dmsg1(150, "New VolName=%s\n", VolName);
326 if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
327 /* If device is not tape, attempt to create it */
328 if (dev->is_tape() || dev->open(dcr, CREATE_READ_WRITE) < 0) {
329 Jmsg3(dcr->jcr, M_WARNING, 0, _("Open device %s Volume \"%s\" failed: ERR=%s\n"),
330 dev->print_name(), dcr->VolumeName, dev->bstrerror());
334 Dmsg1(150, "Label type=%d\n", dev->label_type);
335 if (!dev->rewind(dcr)) {
336 Dmsg2(130, "Bad status on %s from rewind: ERR=%s\n", dev->print_name(), dev->print_errmsg());
342 /* Temporarily mark in append state to enable writing */
345 /* Create PRE_LABEL or VOL_LABEL if DVD */
346 create_volume_label(dev, VolName, PoolName, dvdnow);
349 * If we have already detected an ANSI label, re-read it
350 * to skip past it. Otherwise, we write a new one if
353 if (dev->label_type != B_BACULA_LABEL) {
354 if (read_ansi_ibm_label(dcr) != VOL_OK) {
358 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, VolName)) {
362 create_volume_label_record(dcr, dcr->rec);
363 dcr->rec->Stream = 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->VolCatInfo.VolCatBytes = 0; /* reset byte count */
445 * If we are not dealing with a streaming device,
446 * write the block now to ensure we have write permission.
447 * It is better to find out now rather than later.
448 * We do not write the block now if this is an ANSI label. This
449 * avoids re-writing the ANSI label, which we do not want to do.
451 if (!dev->has_cap(CAP_STREAM)) {
452 if (!dev->rewind(dcr)) {
453 Jmsg2(jcr, M_FATAL, 0, _("Rewind error on device %s: ERR=%s\n"),
454 dev->print_name(), dev->print_errmsg());
458 Dmsg1(150, "Doing recycle. Vol=%s\n", dcr->VolumeName);
459 // volume_unused(dcr); /* mark volume unused */
460 if (!dev->truncate(dcr)) {
461 Jmsg2(jcr, M_FATAL, 0, _("Truncate error on device %s: ERR=%s\n"),
462 dev->print_name(), dev->print_errmsg());
465 if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
466 Jmsg2(jcr, M_FATAL, 0,
467 _("Failed to re-open DVD after truncate on device %s: ERR=%s\n"),
468 dev->print_name(), dev->print_errmsg());
474 * If we have already detected an ANSI label, re-read it
475 * to skip past it. Otherwise, we write a new one if
478 if (dev->label_type != B_BACULA_LABEL) {
479 if (read_ansi_ibm_label(dcr) != VOL_OK) {
483 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, dev->VolHdr.VolumeName)) {
487 /* Attempt write to check write permission */
488 Dmsg1(200, "Attempt to write to device fd=%d.\n", dev->fd());
489 if (!write_block_to_dev(dcr)) {
490 Jmsg2(jcr, M_ERROR, 0, _("Unable to write device %s: ERR=%s\n"),
491 dev->print_name(), dev->print_errmsg());
492 Dmsg0(200, "===ERROR write block to dev\n");
497 /* Set or reset Volume statistics */
498 dev->VolCatInfo.VolCatJobs = 0;
499 dev->VolCatInfo.VolCatFiles = 0;
500 dev->VolCatInfo.VolCatErrors = 0;
501 dev->VolCatInfo.VolCatBlocks = 0;
502 dev->VolCatInfo.VolCatRBytes = 0;
504 dev->VolCatInfo.VolCatMounts++;
505 dev->VolCatInfo.VolCatRecycles++;
506 dir_create_jobmedia_record(dcr, true);
508 dev->VolCatInfo.VolCatMounts = 1;
509 dev->VolCatInfo.VolCatRecycles = 0;
510 dev->VolCatInfo.VolCatWrites = 1;
511 dev->VolCatInfo.VolCatReads = 1;
513 Dmsg1(150, "dir_update_vol_info. Set Append vol=%s\n", dcr->VolumeName);
514 bstrncpy(dev->VolCatInfo.VolCatStatus, "Append", sizeof(dev->VolCatInfo.VolCatStatus));
515 bstrncpy(dev->VolCatInfo.VolCatName, dcr->VolumeName, sizeof(dev->VolCatInfo.VolCatName));
516 if (!dir_update_volume_info(dcr, true, true)) { /* indicate doing relabel */
520 Jmsg(jcr, M_INFO, 0, _("Recycled volume \"%s\" on device %s, all previous data lost.\n"),
521 dcr->VolumeName, dev->print_name());
523 Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume \"%s\" on device %s\n"),
524 dcr->VolumeName, dev->print_name());
527 * End writing real Volume label (from pre-labeled tape), or recycling
530 Dmsg1(150, "OK from rewrite vol label. Vol=%s\n", dcr->VolumeName);
536 * create_volume_label_record
537 * Serialize label (from dev->VolHdr structure) into device record.
538 * Assumes that the dev->VolHdr structure is properly
541 static void create_volume_label_record(DCR *dcr, DEV_RECORD *rec)
545 DEVICE *dev = dcr->dev;
549 /* Serialize the label into the device record. */
551 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
552 ser_begin(rec->data, SER_LENGTH_Volume_Label);
553 ser_string(dev->VolHdr.Id);
555 ser_uint32(dev->VolHdr.VerNum);
557 if (dev->VolHdr.VerNum >= 11) {
558 ser_btime(dev->VolHdr.label_btime);
559 dev->VolHdr.write_btime = get_current_btime();
560 ser_btime(dev->VolHdr.write_btime);
561 dev->VolHdr.write_date = 0;
562 dev->VolHdr.write_time = 0;
564 /* OLD WAY DEPRECATED */
565 ser_float64(dev->VolHdr.label_date);
566 ser_float64(dev->VolHdr.label_time);
567 get_current_time(&dt);
568 dev->VolHdr.write_date = dt.julian_day_number;
569 dev->VolHdr.write_time = dt.julian_day_fraction;
571 ser_float64(dev->VolHdr.write_date); /* 0 if VerNum >= 11 */
572 ser_float64(dev->VolHdr.write_time); /* 0 if VerNum >= 11 */
574 ser_string(dev->VolHdr.VolumeName);
575 ser_string(dev->VolHdr.PrevVolumeName);
576 ser_string(dev->VolHdr.PoolName);
577 ser_string(dev->VolHdr.PoolType);
578 ser_string(dev->VolHdr.MediaType);
580 ser_string(dev->VolHdr.HostName);
581 ser_string(dev->VolHdr.LabelProg);
582 ser_string(dev->VolHdr.ProgVersion);
583 ser_string(dev->VolHdr.ProgDate);
585 ser_end(rec->data, SER_LENGTH_Volume_Label);
586 bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName));
587 rec->data_len = ser_length(rec->data);
588 rec->FileIndex = dev->VolHdr.LabelType;
589 rec->VolSessionId = jcr->VolSessionId;
590 rec->VolSessionTime = jcr->VolSessionTime;
591 rec->Stream = jcr->NumWriteVolumes;
592 Dmsg2(150, "Created Vol label rec: FI=%s len=%d\n", FI_to_ascii(buf, rec->FileIndex),
598 * Create a volume label in memory
600 void create_volume_label(DEVICE *dev, const char *VolName,
601 const char *PoolName, bool dvdnow)
603 DEVRES *device = (DEVRES *)dev->device;
605 Dmsg0(130, "Start create_volume_label()\n");
609 dev->clear_volhdr(); /* clear any old volume info */
611 bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
612 dev->VolHdr.VerNum = BaculaTapeVersion;
613 if (dev->is_dvd() && dvdnow) {
614 /* We do not want to re-label a DVD so write VOL_LABEL now */
615 dev->VolHdr.LabelType = VOL_LABEL;
617 dev->VolHdr.LabelType = PRE_LABEL; /* Mark tape as unused */
619 bstrncpy(dev->VolHdr.VolumeName, VolName, sizeof(dev->VolHdr.VolumeName));
620 bstrncpy(dev->VolHdr.PoolName, PoolName, sizeof(dev->VolHdr.PoolName));
621 bstrncpy(dev->VolHdr.MediaType, device->media_type, sizeof(dev->VolHdr.MediaType));
623 bstrncpy(dev->VolHdr.PoolType, "Backup", sizeof(dev->VolHdr.PoolType));
625 dev->VolHdr.label_btime = get_current_btime();
626 dev->VolHdr.label_date = 0;
627 dev->VolHdr.label_time = 0;
629 if (gethostname(dev->VolHdr.HostName, sizeof(dev->VolHdr.HostName)) != 0) {
630 dev->VolHdr.HostName[0] = 0;
632 bstrncpy(dev->VolHdr.LabelProg, my_name, sizeof(dev->VolHdr.LabelProg));
633 sprintf(dev->VolHdr.ProgVersion, "Ver. %s %s", VERSION, BDATE);
634 sprintf(dev->VolHdr.ProgDate, "Build %s %s", __DATE__, __TIME__);
635 dev->set_labeled(); /* set has Bacula label */
636 if (debug_level >= 90) {
637 dump_volume_label(dev);
642 * Create session label
643 * The pool memory must be released by the calling program
645 void create_session_label(DCR *dcr, DEV_RECORD *rec, int label)
650 rec->VolSessionId = jcr->VolSessionId;
651 rec->VolSessionTime = jcr->VolSessionTime;
652 rec->Stream = jcr->JobId;
654 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
655 ser_begin(rec->data, SER_LENGTH_Session_Label);
656 ser_string(BaculaId);
657 ser_uint32(BaculaTapeVersion);
659 ser_uint32(jcr->JobId);
661 /* Changed in VerNum 11 */
662 ser_btime(get_current_btime());
665 ser_string(dcr->pool_name);
666 ser_string(dcr->pool_type);
667 ser_string(jcr->job_name); /* base Job name */
668 ser_string(jcr->client_name);
670 /* Added in VerNum 10 */
671 ser_string(jcr->Job); /* Unique name of this Job */
672 ser_string(jcr->fileset_name);
673 ser_uint32(jcr->get_JobType());
674 ser_uint32(jcr->get_JobLevel());
675 /* Added in VerNum 11 */
676 ser_string(jcr->fileset_md5);
678 if (label == EOS_LABEL) {
679 ser_uint32(jcr->JobFiles);
680 ser_uint64(jcr->JobBytes);
681 ser_uint32(dcr->StartBlock);
682 ser_uint32(dcr->EndBlock);
683 ser_uint32(dcr->StartFile);
684 ser_uint32(dcr->EndFile);
685 ser_uint32(jcr->JobErrors);
687 /* Added in VerNum 11 */
688 ser_uint32(jcr->JobStatus);
690 ser_end(rec->data, SER_LENGTH_Session_Label);
691 rec->data_len = ser_length(rec->data);
694 /* Write session label
695 * Returns: false on failure
698 bool write_session_label(DCR *dcr, int label)
701 DEVICE *dev = dcr->dev;
703 DEV_BLOCK *block = dcr->block;
704 char buf1[100], buf2[100];
707 Dmsg1(130, "session_label record=%x\n", rec);
710 set_start_vol_position(dcr);
713 if (dev->is_tape()) {
714 dcr->EndBlock = dev->EndBlock;
715 dcr->EndFile = dev->EndFile;
717 dcr->EndBlock = (uint32_t)dev->file_addr;
718 dcr->EndFile = (uint32_t)(dev->file_addr >> 32);
722 Jmsg1(jcr, M_ABORT, 0, _("Bad Volume session label = %d\n"), label);
725 create_session_label(dcr, rec, label);
726 rec->FileIndex = label;
729 * We guarantee that the session record can totally fit
730 * into a block. If not, write the block, and put it in
731 * the next block. Having the sesssion record totally in
732 * one block makes reading them much easier (no need to
733 * read the next block).
735 if (!can_write_record_to_block(block, rec)) {
736 Dmsg0(150, "Cannot write session label to block.\n");
737 if (!write_block_to_device(dcr)) {
738 Dmsg0(130, "Got session label write_block_to_dev error.\n");
743 if (!write_record_to_block(block, rec)) {
748 Dmsg6(150, "Write sesson_label record JobId=%d FI=%s SessId=%d Strm=%s len=%d "
749 "remainder=%d\n", jcr->JobId,
750 FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
751 stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
755 Dmsg2(150, "Leave write_session_label Block=%ud File=%ud\n",
756 dev->get_block_num(), dev->get_file());
760 /* unser_volume_label
762 * Unserialize the Bacula Volume label into the device Volume_Label
765 * Assumes that the record is already read.
767 * Returns: false on error
771 bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec)
774 char buf1[100], buf2[100];
776 if (rec->FileIndex != VOL_LABEL && rec->FileIndex != PRE_LABEL) {
777 Mmsg3(dev->errmsg, _("Expecting Volume Label, got FI=%s Stream=%s len=%d\n"),
778 FI_to_ascii(buf1, rec->FileIndex),
779 stream_to_ascii(buf2, rec->Stream, rec->FileIndex),
786 dev->VolHdr.LabelType = rec->FileIndex;
787 dev->VolHdr.LabelSize = rec->data_len;
790 /* Unserialize the record into the Volume Header */
791 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
792 ser_begin(rec->data, SER_LENGTH_Volume_Label);
793 unser_string(dev->VolHdr.Id);
794 unser_uint32(dev->VolHdr.VerNum);
796 if (dev->VolHdr.VerNum >= 11) {
797 unser_btime(dev->VolHdr.label_btime);
798 unser_btime(dev->VolHdr.write_btime);
799 } else { /* old way */
800 unser_float64(dev->VolHdr.label_date);
801 unser_float64(dev->VolHdr.label_time);
803 unser_float64(dev->VolHdr.write_date); /* Unused with VerNum >= 11 */
804 unser_float64(dev->VolHdr.write_time); /* Unused with VerNum >= 11 */
806 unser_string(dev->VolHdr.VolumeName);
807 unser_string(dev->VolHdr.PrevVolumeName);
808 unser_string(dev->VolHdr.PoolName);
809 unser_string(dev->VolHdr.PoolType);
810 unser_string(dev->VolHdr.MediaType);
812 unser_string(dev->VolHdr.HostName);
813 unser_string(dev->VolHdr.LabelProg);
814 unser_string(dev->VolHdr.ProgVersion);
815 unser_string(dev->VolHdr.ProgDate);
817 ser_end(rec->data, SER_LENGTH_Volume_Label);
818 Dmsg0(190, "unser_vol_label\n");
819 if (debug_level >= 190) {
820 dump_volume_label(dev);
826 bool unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec)
830 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
831 unser_begin(rec->data, SER_LENGTH_Session_Label);
832 unser_string(label->Id);
833 unser_uint32(label->VerNum);
834 unser_uint32(label->JobId);
835 if (label->VerNum >= 11) {
836 unser_btime(label->write_btime);
838 unser_float64(label->write_date);
840 unser_float64(label->write_time);
841 unser_string(label->PoolName);
842 unser_string(label->PoolType);
843 unser_string(label->JobName);
844 unser_string(label->ClientName);
845 if (label->VerNum >= 10) {
846 unser_string(label->Job); /* Unique name of this Job */
847 unser_string(label->FileSetName);
848 unser_uint32(label->JobType);
849 unser_uint32(label->JobLevel);
851 if (label->VerNum >= 11) {
852 unser_string(label->FileSetMD5);
854 label->FileSetMD5[0] = 0;
856 if (rec->FileIndex == EOS_LABEL) {
857 unser_uint32(label->JobFiles);
858 unser_uint64(label->JobBytes);
859 unser_uint32(label->StartBlock);
860 unser_uint32(label->EndBlock);
861 unser_uint32(label->StartFile);
862 unser_uint32(label->EndFile);
863 unser_uint32(label->JobErrors);
864 if (label->VerNum >= 11) {
865 unser_uint32(label->JobStatus);
867 label->JobStatus = JS_Terminated; /* kludge */
873 void dump_volume_label(DEVICE *dev)
875 int dbl = debug_level;
877 const char *LabelType;
884 switch (dev->VolHdr.LabelType) {
886 LabelType = "PRE_LABEL";
889 LabelType = "VOL_LABEL";
892 LabelType = "EOM_LABEL";
895 LabelType = "SOS_LABEL";
898 LabelType = "EOS_LABEL";
904 sprintf(buf, _("Unknown %d"), dev->VolHdr.LabelType);
908 Pmsg11(-1, _("\nVolume Label:\n"
921 dev->VolHdr.Id, dev->VolHdr.VerNum,
922 dev->VolHdr.VolumeName, dev->VolHdr.PrevVolumeName,
923 File, LabelType, dev->VolHdr.LabelSize,
924 dev->VolHdr.PoolName, dev->VolHdr.MediaType,
925 dev->VolHdr.PoolType, dev->VolHdr.HostName);
927 if (dev->VolHdr.VerNum >= 11) {
929 bstrftime(dt, sizeof(dt), btime_to_utime(dev->VolHdr.label_btime));
930 Pmsg1(-1, _("Date label written: %s\n"), dt);
932 dt.julian_day_number = dev->VolHdr.label_date;
933 dt.julian_day_fraction = dev->VolHdr.label_time;
936 _("Date label written: %04d-%02d-%02d at %02d:%02d\n"),
937 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
945 static void dump_session_label(DEV_RECORD *rec, const char *type)
951 char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], ec6[30], ec7[30];
953 unser_session_label(&label, rec);
956 Pmsg7(-1, _("\n%s Record:\n"
963 ""), type, label.JobId, label.VerNum,
964 label.PoolName, label.PoolType,
965 label.JobName, label.ClientName);
967 if (label.VerNum >= 10) {
969 "Job (unique name) : %s\n"
973 ""), label.Job, label.FileSetName, label.JobType, label.JobLevel);
976 if (rec->FileIndex == EOS_LABEL) {
987 edit_uint64_with_commas(label.JobFiles, ec1),
988 edit_uint64_with_commas(label.JobBytes, ec2),
989 edit_uint64_with_commas(label.StartBlock, ec3),
990 edit_uint64_with_commas(label.EndBlock, ec4),
991 edit_uint64_with_commas(label.StartFile, ec5),
992 edit_uint64_with_commas(label.EndFile, ec6),
993 edit_uint64_with_commas(label.JobErrors, ec7),
996 if (label.VerNum >= 11) {
998 bstrftime(dt, sizeof(dt), btime_to_utime(label.write_btime));
999 Pmsg1(-1, _("Date written : %s\n"), dt);
1001 dt.julian_day_number = label.write_date;
1002 dt.julian_day_fraction = label.write_time;
1003 tm_decode(&dt, &tm);
1004 Pmsg5(-1, _("Date written : %04d-%02d-%02d at %02d:%02d\n"),
1005 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
1011 void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose)
1016 if (rec->FileIndex == 0 && rec->VolSessionId == 0 && rec->VolSessionTime == 0) {
1021 switch (rec->FileIndex) {
1023 type = _("Fresh Volume");
1029 type = _("Begin Job Session");
1032 type = _("End Job Session");
1035 type = _("End of Media");
1038 type = _("End of Tape");
1041 type = _("Unknown");
1045 switch (rec->FileIndex) {
1048 unser_volume_label(dev, rec);
1049 dump_volume_label(dev);
1052 dump_session_label(rec, type);
1055 dump_session_label(rec, type);
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);
1063 Pmsg0(-1, _("End of physical tape.\n"));
1066 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1067 type, dev->file, dev->block_num, rec->VolSessionId,
1068 rec->VolSessionTime, rec->Stream, rec->data_len);
1072 SESSION_LABEL label;
1074 switch (rec->FileIndex) {
1076 unser_session_label(&label, rec);
1077 bstrftimes(dt, sizeof(dt), btime_to_utime(label.write_btime));
1078 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1079 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1080 Pmsg4(-1, _(" Job=%s Date=%s Level=%c Type=%c\n"),
1081 label.Job, dt, label.JobLevel, label.JobType);
1084 char ed1[30], ed2[30];
1085 unser_session_label(&label, rec);
1086 bstrftimes(dt, sizeof(dt), btime_to_utime(label.write_btime));
1087 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1088 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1089 Pmsg7(-1, _(" Date=%s Level=%c Type=%c Files=%s Bytes=%s Errors=%d Status=%c\n"),
1090 dt, label.JobLevel, label.JobType,
1091 edit_uint64_with_commas(label.JobFiles, ed1),
1092 edit_uint64_with_commas(label.JobBytes, ed2),
1093 label.JobErrors, (char)label.JobStatus);
1099 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1100 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime,
1101 rec->Stream, rec->data_len);