2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version two of the GNU General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of John Walker.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
30 * label.c Bacula routines to handle labels
38 #include "bacula.h" /* pull in global headers */
39 #include "stored.h" /* pull in Storage Deamon headers */
41 /* Forward referenced functions */
42 static void create_volume_label_record(DCR *dcr, DEV_RECORD *rec);
45 * Read the volume label
47 * If dcr->VolumeName == NULL, we accept any Bacula Volume
48 * If dcr->VolumeName[0] == 0, we accept any Bacula Volume
49 * otherwise dcr->VolumeName must match the Volume.
51 * If VolName given, ensure that it matches
53 * Returns VOL_ code as defined in record.h
55 * VOL_OK good label found
56 * VOL_NO_LABEL volume not labeled
57 * VOL_IO_ERROR I/O error reading tape
58 * VOL_NAME_ERROR label has wrong name
59 * VOL_CREATE_ERROR Error creating label
60 * VOL_VERSION_ERROR label has wrong version
61 * VOL_LABEL_ERROR bad label type
62 * VOL_NO_MEDIA no media in drive
64 * The dcr block is emptied on return, and the Volume is
67 int read_dev_volume_label(DCR *dcr)
70 DEVICE * volatile dev = dcr->dev;
71 char *VolName = dcr->VolumeName;
74 DEV_BLOCK *block = dcr->block;
77 bool have_ansi_label = false;
79 Dmsg4(100, "Enter read_volume_label res=%d device=%s vol=%s dev_Vol=%s\n",
80 dev->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(130, "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(130, "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 */
122 want_ansi_label = dcr->VolCatInfo.LabelType != B_BACULA_LABEL ||
123 dcr->device->label_type != B_BACULA_LABEL;
124 if (want_ansi_label || dev->has_cap(CAP_CHECKLABELS)) {
125 stat = read_ansi_ibm_label(dcr);
126 /* If we want a label and didn't find it, return error */
127 if (want_ansi_label && stat != VOL_OK) {
130 if (stat == VOL_NAME_ERROR || stat == VOL_LABEL_ERROR) {
131 Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
132 dev->print_name(), VolName, dev->VolHdr.VolumeName);
133 if (!dev->poll && jcr->label_errors++ > 100) {
134 Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
138 if (stat != VOL_OK) { /* Not an ANSI/IBM label, so re-read */
141 have_ansi_label = true;
145 /* Read the Bacula Volume label block */
146 record = new_record();
149 Dmsg0(130, "Big if statement in read_volume_label\n");
150 if (!read_block_from_dev(dcr, NO_BLOCK_NUMBER_CHECK)) {
151 Mmsg(jcr->errmsg, _("Requested Volume \"%s\" on %s is not a Bacula "
152 "labeled Volume, because: ERR=%s"), NPRT(VolName),
153 dev->print_name(), dev->print_errmsg());
154 Dmsg1(130, "%s", jcr->errmsg);
155 } else if (!read_record_from_block(dcr, block, record)) {
156 Mmsg(jcr->errmsg, _("Could not read Volume label from block.\n"));
157 Dmsg1(130, "%s", jcr->errmsg);
158 } else if (!unser_volume_label(dev, record)) {
159 Mmsg(jcr->errmsg, _("Could not unserialize Volume label: ERR=%s\n"),
160 dev->print_errmsg());
161 Dmsg1(130, "%s", jcr->errmsg);
162 } else if (strcmp(dev->VolHdr.Id, BaculaId) != 0 &&
163 strcmp(dev->VolHdr.Id, OldBaculaId) != 0) {
164 Mmsg(jcr->errmsg, _("Volume Header Id bad: %s\n"), dev->VolHdr.Id);
165 Dmsg1(130, "%s", jcr->errmsg);
169 free_record(record); /* finished reading Volume record */
172 if (forge_on || jcr->ignore_label_errors) {
173 dev->set_labeled(); /* set has Bacula label */
174 Jmsg(jcr, M_ERROR, 0, "%s", jcr->errmsg);
178 Dmsg0(100, "No volume label - bailing out\n");
183 /* At this point, we have read the first Bacula block, and
184 * then read the Bacula Volume label. Now we need to
185 * make sure we have the right Volume.
189 if (dev->VolHdr.VerNum != BaculaTapeVersion &&
190 dev->VolHdr.VerNum != OldCompatibleBaculaTapeVersion1 &&
191 dev->VolHdr.VerNum != OldCompatibleBaculaTapeVersion2) {
192 Mmsg(jcr->errmsg, _("Volume on %s has wrong Bacula version. Wanted %d got %d\n"),
193 dev->print_name(), BaculaTapeVersion, dev->VolHdr.VerNum);
194 Dmsg1(130, "VOL_VERSION_ERROR: %s", jcr->errmsg);
195 stat = VOL_VERSION_ERROR;
199 /* We are looking for either an unused Bacula tape (PRE_LABEL) or
200 * a Bacula volume label (VOL_LABEL)
202 if (dev->VolHdr.LabelType != PRE_LABEL && dev->VolHdr.LabelType != VOL_LABEL) {
203 Mmsg(jcr->errmsg, _("Volume on %s has bad Bacula label type: %x\n"),
204 dev->print_name(), dev->VolHdr.LabelType);
205 Dmsg1(130, "%s", jcr->errmsg);
206 if (!dev->poll && jcr->label_errors++ > 100) {
207 Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
209 Dmsg0(150, "return VOL_LABEL_ERROR\n");
210 stat = VOL_LABEL_ERROR;
214 dev->set_labeled(); /* set has Bacula label */
215 if (reserve_volume(dcr, dev->VolHdr.VolumeName) == NULL) {
216 Mmsg2(jcr->errmsg, _("Could not reserve volume %s on %s\n"),
217 dev->VolHdr.VolumeName, dev->print_name());
218 stat = VOL_NAME_ERROR;
221 dev = dcr->dev; /* may have changed in reserve volume */
223 /* Compare Volume Names */
224 Dmsg2(130, "Compare Vol names: VolName=%s hdr=%s\n", VolName?VolName:"*", dev->VolHdr.VolumeName);
225 if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolumeName, VolName) != 0) {
226 Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
227 dev->print_name(), VolName, dev->VolHdr.VolumeName);
228 Dmsg1(130, "%s", jcr->errmsg);
230 * Cancel Job if too many label errors
231 * => we are in a loop
233 if (!dev->poll && jcr->label_errors++ > 100) {
234 Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
236 Dmsg0(150, "return VOL_NAME_ERROR\n");
237 stat = VOL_NAME_ERROR;
240 Dmsg1(130, "Copy vol_name=%s\n", dev->VolHdr.VolumeName);
242 if (debug_level >= 10) {
243 dump_volume_label(dev);
245 Dmsg0(130, "Leave read_volume_label() VOL_OK\n");
246 /* If we are a streaming device, we only get one chance to read */
247 if (!dev->has_cap(CAP_STREAM)) {
249 if (have_ansi_label) {
250 stat = read_ansi_ibm_label(dcr);
251 /* If we want a label and didn't find it, return error */
252 if (stat != VOL_OK) {
261 volume_unused(dcr); /* mark volume "released" */
264 Dmsg1(150, "return %d\n", stat);
269 * Put a volume label into the block
271 * Returns: false on failure
274 bool write_volume_label_to_block(DCR *dcr)
277 DEVICE *dev = dcr->dev;
279 DEV_BLOCK *block = dcr->block;
281 Dmsg0(130, "write Label in write_volume_label_to_block()\n");
282 memset(&rec, 0, sizeof(rec));
283 rec.data = get_memory(SER_LENGTH_Volume_Label);
284 empty_block(block); /* Volume label always at beginning */
286 create_volume_label_record(dcr, &rec);
288 block->BlockNumber = 0;
289 if (!write_record_to_block(block, &rec)) {
290 free_pool_memory(rec.data);
291 Jmsg1(jcr, M_FATAL, 0, _("Cannot write Volume label to block for device %s\n"),
295 Dmsg1(130, "Wrote label of %d bytes to block\n", rec.data_len);
297 free_pool_memory(rec.data);
303 * Write a Volume Label
304 * !!! Note, this is ONLY used for writing
305 * a fresh volume label. Any data
306 * after the label will be destroyed,
307 * in fact, we write the label 5 times !!!!
309 * This routine should be used only when labeling a blank tape.
311 bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName,
312 const char *PoolName, bool relabel, bool dvdnow)
314 DEVICE * volatile dev = dcr->dev;
317 Dmsg0(150, "write_volume_label()\n");
318 empty_block(dcr->block);
321 volume_unused(dcr); /* mark current volume unused */
322 /* Truncate device */
323 if (!dev->truncate(dcr)) {
326 if (!dev->is_tape()) {
327 dev->close_part(dcr); /* make sure DVD/file closed for rename */
331 /* Set the new filename for open, ... */
332 bstrncpy(dev->VolCatInfo.VolCatName, VolName, sizeof(dev->VolCatInfo.VolCatName));
333 bstrncpy(dcr->VolCatInfo.VolCatName, VolName, sizeof(dcr->VolCatInfo.VolCatName));
334 Dmsg1(150, "New VolName=%s\n", VolName);
335 if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
336 /* If device is not tape, attempt to create it */
337 if (dev->is_tape() || dev->open(dcr, CREATE_READ_WRITE) < 0) {
341 Dmsg1(150, "Label type=%d\n", dev->label_type);
342 if (!dev->rewind(dcr)) {
343 Dmsg2(130, "Bad status on %s from rewind: ERR=%s\n", dev->print_name(), dev->print_errmsg());
349 /* Temporarily mark in append state to enable writing */
352 /* Create PRE_LABEL or VOL_LABEL if DVD */
353 create_volume_label(dev, VolName, PoolName, dvdnow);
356 * If we have already detected an ANSI label, re-read it
357 * to skip past it. Otherwise, we write a new one if
360 if (dev->label_type != B_BACULA_LABEL) {
361 if (read_ansi_ibm_label(dcr) != VOL_OK) {
365 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, VolName)) {
369 create_volume_label_record(dcr, dcr->rec);
370 dcr->rec->Stream = 0;
372 if (!write_record_to_block(dcr->block, dcr->rec)) {
373 Dmsg2(130, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
376 Dmsg2(130, "Wrote label of %d bytes to %s\n", dcr->rec->data_len, dev->print_name());
379 Dmsg0(130, "Call write_block_to_dev()\n");
380 if (!write_block_to_dev(dcr)) {
381 Dmsg2(130, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
385 /* Now commit block to DVD if we should write now */
386 if (dev->is_dvd() && dvdnow) {
387 Dmsg1(150, "New VolName=%s\n", dev->VolCatInfo.VolCatName);
388 if (!dvd_write_part(dcr)) {
389 Dmsg2(130, "Bad DVD write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
394 Dmsg0(130, " Wrote block to device\n");
398 write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
401 if (debug_level >= 20) {
402 dump_volume_label(dev);
404 if (reserve_volume(dcr, VolName) == NULL) {
405 Mmsg2(dcr->jcr->errmsg, _("Could not reserve volume %s on %s\n"),
406 dev->VolHdr.VolumeName, dev->print_name());
409 dev = dcr->dev; /* may have changed in reserve_volume */
411 dev->clear_append(); /* remove append since this is PRE_LABEL */
417 dev->clear_append(); /* remove append since this is PRE_LABEL */
422 * Write a volume label. This is ONLY called if we have a valid Bacula
423 * label of type PRE_LABEL;
424 * Returns: true if OK
425 * false if unable to write it
427 bool rewrite_volume_label(DCR *dcr, bool recycle)
429 DEVICE *dev = dcr->dev;
432 if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
435 Dmsg2(190, "set append found freshly labeled volume. fd=%d dev=%x\n", dev->fd(), dev);
436 dev->VolHdr.LabelType = VOL_LABEL; /* set Volume label */
438 if (!write_volume_label_to_block(dcr)) {
439 Dmsg0(200, "Error from write volume label.\n");
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 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++;
507 dev->VolCatInfo.VolCatMounts = 1;
508 dev->VolCatInfo.VolCatRecycles = 0;
509 dev->VolCatInfo.VolCatWrites = 1;
510 dev->VolCatInfo.VolCatReads = 1;
512 Dmsg0(150, "dir_update_vol_info. Set Append\n");
513 bstrncpy(dev->VolCatInfo.VolCatStatus, "Append", sizeof(dev->VolCatInfo.VolCatStatus));
514 if (!dir_update_volume_info(dcr, true, true)) { /* indicate doing relabel */
518 Jmsg(jcr, M_INFO, 0, _("Recycled volume \"%s\" on device %s, all previous data lost.\n"),
519 dcr->VolumeName, dev->print_name());
521 Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume \"%s\" on device %s\n"),
522 dcr->VolumeName, dev->print_name());
525 * End writing real Volume label (from pre-labeled tape), or recycling
528 Dmsg0(200, "OK from rewrite vol label.\n");
534 * create_volume_label_record
535 * Serialize label (from dev->VolHdr structure) into device record.
536 * Assumes that the dev->VolHdr structure is properly
539 static void create_volume_label_record(DCR *dcr, DEV_RECORD *rec)
543 DEVICE *dev = dcr->dev;
547 /* Serialize the label into the device record. */
549 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
550 ser_begin(rec->data, SER_LENGTH_Volume_Label);
551 ser_string(dev->VolHdr.Id);
553 ser_uint32(dev->VolHdr.VerNum);
555 if (dev->VolHdr.VerNum >= 11) {
556 ser_btime(dev->VolHdr.label_btime);
557 dev->VolHdr.write_btime = get_current_btime();
558 ser_btime(dev->VolHdr.write_btime);
559 dev->VolHdr.write_date = 0;
560 dev->VolHdr.write_time = 0;
562 /* OLD WAY DEPRECATED */
563 ser_float64(dev->VolHdr.label_date);
564 ser_float64(dev->VolHdr.label_time);
565 get_current_time(&dt);
566 dev->VolHdr.write_date = dt.julian_day_number;
567 dev->VolHdr.write_time = dt.julian_day_fraction;
569 ser_float64(dev->VolHdr.write_date); /* 0 if VerNum >= 11 */
570 ser_float64(dev->VolHdr.write_time); /* 0 if VerNum >= 11 */
572 ser_string(dev->VolHdr.VolumeName);
573 ser_string(dev->VolHdr.PrevVolumeName);
574 ser_string(dev->VolHdr.PoolName);
575 ser_string(dev->VolHdr.PoolType);
576 ser_string(dev->VolHdr.MediaType);
578 ser_string(dev->VolHdr.HostName);
579 ser_string(dev->VolHdr.LabelProg);
580 ser_string(dev->VolHdr.ProgVersion);
581 ser_string(dev->VolHdr.ProgDate);
583 ser_end(rec->data, SER_LENGTH_Volume_Label);
584 rec->data_len = ser_length(rec->data);
585 rec->FileIndex = dev->VolHdr.LabelType;
586 rec->VolSessionId = jcr->VolSessionId;
587 rec->VolSessionTime = jcr->VolSessionTime;
588 rec->Stream = jcr->NumWriteVolumes;
589 Dmsg2(150, "Created Vol label rec: FI=%s len=%d\n", FI_to_ascii(buf, rec->FileIndex),
595 * Create a volume label in memory
597 void create_volume_label(DEVICE *dev, const char *VolName,
598 const char *PoolName, bool dvdnow)
600 DEVRES *device = (DEVRES *)dev->device;
602 Dmsg0(130, "Start create_volume_label()\n");
606 dev->clear_volhdr(); /* clear any old volume info */
608 bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
609 dev->VolHdr.VerNum = BaculaTapeVersion;
610 if (dev->is_dvd() && dvdnow) {
611 /* We do not want to re-label a DVD so write VOL_LABEL now */
612 dev->VolHdr.LabelType = VOL_LABEL;
614 dev->VolHdr.LabelType = PRE_LABEL; /* Mark tape as unused */
616 bstrncpy(dev->VolHdr.VolumeName, VolName, sizeof(dev->VolHdr.VolumeName));
617 bstrncpy(dev->VolHdr.PoolName, PoolName, sizeof(dev->VolHdr.PoolName));
618 bstrncpy(dev->VolHdr.MediaType, device->media_type, sizeof(dev->VolHdr.MediaType));
620 bstrncpy(dev->VolHdr.PoolType, "Backup", sizeof(dev->VolHdr.PoolType));
622 dev->VolHdr.label_btime = get_current_btime();
623 dev->VolHdr.label_date = 0;
624 dev->VolHdr.label_time = 0;
626 if (gethostname(dev->VolHdr.HostName, sizeof(dev->VolHdr.HostName)) != 0) {
627 dev->VolHdr.HostName[0] = 0;
629 bstrncpy(dev->VolHdr.LabelProg, my_name, sizeof(dev->VolHdr.LabelProg));
630 sprintf(dev->VolHdr.ProgVersion, "Ver. %s %s", VERSION, BDATE);
631 sprintf(dev->VolHdr.ProgDate, "Build %s %s", __DATE__, __TIME__);
632 dev->set_labeled(); /* set has Bacula label */
633 if (debug_level >= 90) {
634 dump_volume_label(dev);
639 * Create session label
640 * The pool memory must be released by the calling program
642 void create_session_label(DCR *dcr, DEV_RECORD *rec, int label)
647 rec->VolSessionId = jcr->VolSessionId;
648 rec->VolSessionTime = jcr->VolSessionTime;
649 rec->Stream = jcr->JobId;
651 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
652 ser_begin(rec->data, SER_LENGTH_Session_Label);
653 ser_string(BaculaId);
654 ser_uint32(BaculaTapeVersion);
656 ser_uint32(jcr->JobId);
658 /* Changed in VerNum 11 */
659 ser_btime(get_current_btime());
662 ser_string(dcr->pool_name);
663 ser_string(dcr->pool_type);
664 ser_string(jcr->job_name); /* base Job name */
665 ser_string(jcr->client_name);
667 /* Added in VerNum 10 */
668 ser_string(jcr->Job); /* Unique name of this Job */
669 ser_string(jcr->fileset_name);
670 ser_uint32(jcr->JobType);
671 ser_uint32(jcr->JobLevel);
672 /* Added in VerNum 11 */
673 ser_string(jcr->fileset_md5);
675 if (label == EOS_LABEL) {
676 ser_uint32(jcr->JobFiles);
677 ser_uint64(jcr->JobBytes);
678 ser_uint32(dcr->StartBlock);
679 ser_uint32(dcr->EndBlock);
680 ser_uint32(dcr->StartFile);
681 ser_uint32(dcr->EndFile);
682 ser_uint32(jcr->JobErrors);
684 /* Added in VerNum 11 */
685 ser_uint32(jcr->JobStatus);
687 ser_end(rec->data, SER_LENGTH_Session_Label);
688 rec->data_len = ser_length(rec->data);
691 /* Write session label
692 * Returns: false on failure
695 bool write_session_label(DCR *dcr, int label)
698 DEVICE *dev = dcr->dev;
700 DEV_BLOCK *block = dcr->block;
701 char buf1[100], buf2[100];
704 Dmsg1(130, "session_label record=%x\n", rec);
707 set_start_vol_position(dcr);
710 if (dev->is_tape()) {
711 dcr->EndBlock = dev->EndBlock;
712 dcr->EndFile = dev->EndFile;
714 dcr->EndBlock = (uint32_t)dev->file_addr;
715 dcr->EndFile = (uint32_t)(dev->file_addr >> 32);
719 Jmsg1(jcr, M_ABORT, 0, _("Bad Volume session label = %d\n"), label);
722 create_session_label(dcr, rec, label);
723 rec->FileIndex = label;
726 * We guarantee that the session record can totally fit
727 * into a block. If not, write the block, and put it in
728 * the next block. Having the sesssion record totally in
729 * one block makes reading them much easier (no need to
730 * read the next block).
732 if (!can_write_record_to_block(block, rec)) {
733 Dmsg0(150, "Cannot write session label to block.\n");
734 if (!write_block_to_device(dcr)) {
735 Dmsg0(130, "Got session label write_block_to_dev error.\n");
740 if (!write_record_to_block(block, rec)) {
745 Dmsg6(150, "Write sesson_label record JobId=%d FI=%s SessId=%d Strm=%s len=%d "
746 "remainder=%d\n", jcr->JobId,
747 FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
748 stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
752 Dmsg2(150, "Leave write_session_label Block=%ud File=%ud\n",
753 dev->get_block_num(), dev->get_file());
757 /* unser_volume_label
759 * Unserialize the Bacula Volume label into the device Volume_Label
762 * Assumes that the record is already read.
764 * Returns: false on error
768 bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec)
771 char buf1[100], buf2[100];
773 if (rec->FileIndex != VOL_LABEL && rec->FileIndex != PRE_LABEL) {
774 Mmsg3(dev->errmsg, _("Expecting Volume Label, got FI=%s Stream=%s len=%d\n"),
775 FI_to_ascii(buf1, rec->FileIndex),
776 stream_to_ascii(buf2, rec->Stream, rec->FileIndex),
783 dev->VolHdr.LabelType = rec->FileIndex;
784 dev->VolHdr.LabelSize = rec->data_len;
787 /* Unserialize the record into the Volume Header */
788 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
789 ser_begin(rec->data, SER_LENGTH_Volume_Label);
790 unser_string(dev->VolHdr.Id);
791 unser_uint32(dev->VolHdr.VerNum);
793 if (dev->VolHdr.VerNum >= 11) {
794 unser_btime(dev->VolHdr.label_btime);
795 unser_btime(dev->VolHdr.write_btime);
796 } else { /* old way */
797 unser_float64(dev->VolHdr.label_date);
798 unser_float64(dev->VolHdr.label_time);
800 unser_float64(dev->VolHdr.write_date); /* Unused with VerNum >= 11 */
801 unser_float64(dev->VolHdr.write_time); /* Unused with VerNum >= 11 */
803 unser_string(dev->VolHdr.VolumeName);
804 unser_string(dev->VolHdr.PrevVolumeName);
805 unser_string(dev->VolHdr.PoolName);
806 unser_string(dev->VolHdr.PoolType);
807 unser_string(dev->VolHdr.MediaType);
809 unser_string(dev->VolHdr.HostName);
810 unser_string(dev->VolHdr.LabelProg);
811 unser_string(dev->VolHdr.ProgVersion);
812 unser_string(dev->VolHdr.ProgDate);
814 ser_end(rec->data, SER_LENGTH_Volume_Label);
815 Dmsg0(190, "unser_vol_label\n");
816 if (debug_level >= 190) {
817 dump_volume_label(dev);
823 bool unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec)
827 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
828 unser_begin(rec->data, SER_LENGTH_Session_Label);
829 unser_string(label->Id);
830 unser_uint32(label->VerNum);
831 unser_uint32(label->JobId);
832 if (label->VerNum >= 11) {
833 unser_btime(label->write_btime);
835 unser_float64(label->write_date);
837 unser_float64(label->write_time);
838 unser_string(label->PoolName);
839 unser_string(label->PoolType);
840 unser_string(label->JobName);
841 unser_string(label->ClientName);
842 if (label->VerNum >= 10) {
843 unser_string(label->Job); /* Unique name of this Job */
844 unser_string(label->FileSetName);
845 unser_uint32(label->JobType);
846 unser_uint32(label->JobLevel);
848 if (label->VerNum >= 11) {
849 unser_string(label->FileSetMD5);
851 label->FileSetMD5[0] = 0;
853 if (rec->FileIndex == EOS_LABEL) {
854 unser_uint32(label->JobFiles);
855 unser_uint64(label->JobBytes);
856 unser_uint32(label->StartBlock);
857 unser_uint32(label->EndBlock);
858 unser_uint32(label->StartFile);
859 unser_uint32(label->EndFile);
860 unser_uint32(label->JobErrors);
861 if (label->VerNum >= 11) {
862 unser_uint32(label->JobStatus);
864 label->JobStatus = JS_Terminated; /* kludge */
870 void dump_volume_label(DEVICE *dev)
872 int dbl = debug_level;
874 const char *LabelType;
881 switch (dev->VolHdr.LabelType) {
883 LabelType = "PRE_LABEL";
886 LabelType = "VOL_LABEL";
889 LabelType = "EOM_LABEL";
892 LabelType = "SOS_LABEL";
895 LabelType = "EOS_LABEL";
901 sprintf(buf, _("Unknown %d"), dev->VolHdr.LabelType);
905 Pmsg11(-1, _("\nVolume Label:\n"
918 dev->VolHdr.Id, dev->VolHdr.VerNum,
919 dev->VolHdr.VolumeName, dev->VolHdr.PrevVolumeName,
920 File, LabelType, dev->VolHdr.LabelSize,
921 dev->VolHdr.PoolName, dev->VolHdr.MediaType,
922 dev->VolHdr.PoolType, dev->VolHdr.HostName);
924 if (dev->VolHdr.VerNum >= 11) {
926 bstrftime(dt, sizeof(dt), btime_to_unix(dev->VolHdr.label_btime));
927 Pmsg1(-1, _("Date label written: %s\n"), dt);
929 dt.julian_day_number = dev->VolHdr.label_date;
930 dt.julian_day_fraction = dev->VolHdr.label_time;
933 _("Date label written: %04d-%02d-%02d at %02d:%02d\n"),
934 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
942 static void dump_session_label(DEV_RECORD *rec, const char *type)
948 char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], ec6[30], ec7[30];
950 unser_session_label(&label, rec);
953 Pmsg7(-1, _("\n%s Record:\n"
960 ""), type, label.JobId, label.VerNum,
961 label.PoolName, label.PoolType,
962 label.JobName, label.ClientName);
964 if (label.VerNum >= 10) {
966 "Job (unique name) : %s\n"
970 ""), label.Job, label.FileSetName, label.JobType, label.JobLevel);
973 if (rec->FileIndex == EOS_LABEL) {
984 edit_uint64_with_commas(label.JobFiles, ec1),
985 edit_uint64_with_commas(label.JobBytes, ec2),
986 edit_uint64_with_commas(label.StartBlock, ec3),
987 edit_uint64_with_commas(label.EndBlock, ec4),
988 edit_uint64_with_commas(label.StartFile, ec5),
989 edit_uint64_with_commas(label.EndFile, ec6),
990 edit_uint64_with_commas(label.JobErrors, ec7),
993 if (label.VerNum >= 11) {
995 bstrftime(dt, sizeof(dt), btime_to_unix(label.write_btime));
996 Pmsg1(-1, _("Date written : %s\n"), dt);
998 dt.julian_day_number = label.write_date;
999 dt.julian_day_fraction = label.write_time;
1000 tm_decode(&dt, &tm);
1001 Pmsg5(-1, _("Date written : %04d-%02d-%02d at %02d:%02d\n"),
1002 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
1008 void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose)
1013 if (rec->FileIndex == 0 && rec->VolSessionId == 0 && rec->VolSessionTime == 0) {
1018 switch (rec->FileIndex) {
1020 type = _("Fresh Volume");
1026 type = _("Begin Job Session");
1029 type = _("End Job Session");
1032 type = _("End of Media");
1035 type = _("End of Tape");
1038 type = _("Unknown");
1042 switch (rec->FileIndex) {
1045 unser_volume_label(dev, rec);
1046 dump_volume_label(dev);
1049 dump_session_label(rec, type);
1052 dump_session_label(rec, type);
1055 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1056 type, dev->file, dev->block_num, rec->VolSessionId,
1057 rec->VolSessionTime, rec->Stream, rec->data_len);
1060 Pmsg0(-1, _("End of physical tape.\n"));
1063 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1064 type, dev->file, dev->block_num, rec->VolSessionId,
1065 rec->VolSessionTime, rec->Stream, rec->data_len);
1069 SESSION_LABEL label;
1071 switch (rec->FileIndex) {
1073 unser_session_label(&label, rec);
1074 bstrftimes(dt, sizeof(dt), btime_to_unix(label.write_btime));
1075 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1076 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1077 Pmsg4(-1, _(" Job=%s Date=%s Level=%c Type=%c\n"),
1078 label.Job, dt, label.JobLevel, label.JobType);
1081 char ed1[30], ed2[30];
1082 unser_session_label(&label, rec);
1083 bstrftimes(dt, sizeof(dt), btime_to_unix(label.write_btime));
1084 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1085 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1086 Pmsg7(-1, _(" Date=%s Level=%c Type=%c Files=%s Bytes=%s Errors=%d Status=%c\n"),
1087 dt, label.JobLevel, label.JobType,
1088 edit_uint64_with_commas(label.JobFiles, ed1),
1089 edit_uint64_with_commas(label.JobBytes, ed2),
1090 label.JobErrors, (char)label.JobStatus);
1096 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1097 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime,
1098 rec->Stream, rec->data_len);