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->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) {
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 Dmsg1(100, "Call reserve_volume=%s\n", dev->VolHdr.VolumeName);
216 Dmsg2(100, "=== dcr->dev=%p dev=%p\n", dcr->dev, dev);
217 if (reserve_volume(dcr, dev->VolHdr.VolumeName) == NULL) {
218 Mmsg2(jcr->errmsg, _("Could not reserve volume %s on %s\n"),
219 dev->VolHdr.VolumeName, dev->print_name());
220 stat = VOL_NAME_ERROR;
223 Dmsg2(100, "=== dcr->dev=%p dev=%p\n", dcr->dev, dev);
225 /* Compare Volume Names */
226 Dmsg2(130, "Compare Vol names: VolName=%s hdr=%s\n", VolName?VolName:"*", dev->VolHdr.VolumeName);
227 if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolumeName, VolName) != 0) {
228 Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
229 dev->print_name(), VolName, dev->VolHdr.VolumeName);
230 Dmsg1(130, "%s", jcr->errmsg);
232 * Cancel Job if too many label errors
233 * => we are in a loop
235 if (!dev->poll && jcr->label_errors++ > 100) {
236 Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
238 Dmsg0(150, "return VOL_NAME_ERROR\n");
239 stat = VOL_NAME_ERROR;
240 volume_unused(dcr); /* mark volume "released" */
243 Dmsg1(130, "Copy vol_name=%s\n", dev->VolHdr.VolumeName);
245 if (debug_level >= 10) {
246 dump_volume_label(dev);
248 Dmsg0(130, "Leave read_volume_label() VOL_OK\n");
249 /* If we are a streaming device, we only get one chance to read */
250 if (!dev->has_cap(CAP_STREAM)) {
252 if (have_ansi_label) {
253 stat = read_ansi_ibm_label(dcr);
254 /* If we want a label and didn't find it, return error */
255 if (stat != VOL_OK) {
256 volume_unused(dcr); /* mark volume "released" */
267 Dmsg1(150, "return %d\n", stat);
272 * Put a volume label into the block
274 * Returns: false on failure
277 bool write_volume_label_to_block(DCR *dcr)
280 DEVICE *dev = dcr->dev;
282 DEV_BLOCK *block = dcr->block;
284 Dmsg0(130, "write Label in write_volume_label_to_block()\n");
285 memset(&rec, 0, sizeof(rec));
286 rec.data = get_memory(SER_LENGTH_Volume_Label);
287 empty_block(block); /* Volume label always at beginning */
289 create_volume_label_record(dcr, &rec);
291 block->BlockNumber = 0;
292 if (!write_record_to_block(block, &rec)) {
293 free_pool_memory(rec.data);
294 Jmsg1(jcr, M_FATAL, 0, _("Cannot write Volume label to block for device %s\n"),
298 Dmsg1(130, "Wrote label of %d bytes to block\n", rec.data_len);
300 free_pool_memory(rec.data);
306 * Write a Volume Label
307 * !!! Note, this is ONLY used for writing
308 * a fresh volume label. Any data
309 * after the label will be destroyed,
310 * in fact, we write the label 5 times !!!!
312 * This routine should be used only when labeling a blank tape.
314 bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName,
315 const char *PoolName, bool relabel, bool dvdnow)
317 DEVICE * volatile dev = dcr->dev;
320 Dmsg0(150, "write_volume_label()\n");
321 empty_block(dcr->block);
324 volume_unused(dcr); /* mark current volume unused */
325 /* Truncate device */
326 if (!dev->truncate(dcr)) {
329 if (!dev->is_tape()) {
330 dev->close_part(dcr); /* make sure DVD/file closed for rename */
334 /* Set the new filename for open, ... */
335 bstrncpy(dev->VolCatInfo.VolCatName, VolName, sizeof(dev->VolCatInfo.VolCatName));
336 bstrncpy(dcr->VolCatInfo.VolCatName, VolName, sizeof(dcr->VolCatInfo.VolCatName));
337 Dmsg1(150, "New VolName=%s\n", VolName);
338 if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
339 /* If device is not tape, attempt to create it */
340 if (dev->is_tape() || dev->open(dcr, CREATE_READ_WRITE) < 0) {
341 Jmsg3(dcr->jcr, M_WARNING, 0, _("Open device %s Volume \"%s\" failed: ERR=%s\n"),
342 dev->print_name(), dcr->VolumeName, dev->bstrerror());
346 Dmsg1(150, "Label type=%d\n", dev->label_type);
347 if (!dev->rewind(dcr)) {
348 Dmsg2(130, "Bad status on %s from rewind: ERR=%s\n", dev->print_name(), dev->print_errmsg());
354 /* Temporarily mark in append state to enable writing */
357 /* Create PRE_LABEL or VOL_LABEL if DVD */
358 create_volume_label(dev, VolName, PoolName, dvdnow);
361 * If we have already detected an ANSI label, re-read it
362 * to skip past it. Otherwise, we write a new one if
365 if (dev->label_type != B_BACULA_LABEL) {
366 if (read_ansi_ibm_label(dcr) != VOL_OK) {
370 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, VolName)) {
374 create_volume_label_record(dcr, dcr->rec);
375 dcr->rec->Stream = 0;
377 if (!write_record_to_block(dcr->block, dcr->rec)) {
378 Dmsg2(130, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
381 Dmsg2(130, "Wrote label of %d bytes to %s\n", dcr->rec->data_len, dev->print_name());
384 Dmsg0(130, "Call write_block_to_dev()\n");
385 if (!write_block_to_dev(dcr)) {
386 Dmsg2(130, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
390 /* Now commit block to DVD if we should write now */
391 if (dev->is_dvd() && dvdnow) {
392 Dmsg1(150, "New VolName=%s\n", dev->VolCatInfo.VolCatName);
393 if (!dvd_write_part(dcr)) {
394 Dmsg2(130, "Bad DVD write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
399 Dmsg0(130, " Wrote block to device\n");
403 write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
406 if (debug_level >= 20) {
407 dump_volume_label(dev);
409 Dmsg0(100, "Call reserve_volume\n");
410 if (reserve_volume(dcr, VolName) == NULL) {
411 Mmsg2(dcr->jcr->errmsg, _("Could not reserve volume %s on %s\n"),
412 dev->VolHdr.VolumeName, dev->print_name());
415 dev = dcr->dev; /* may have changed in reserve_volume */
417 dev->clear_append(); /* remove append since this is PRE_LABEL */
423 dev->clear_append(); /* remove append since this is PRE_LABEL */
428 * Write a volume label. This is ONLY called if we have a valid Bacula
429 * label of type PRE_LABEL;
430 * Returns: true if OK
431 * false if unable to write it
433 bool rewrite_volume_label(DCR *dcr, bool recycle)
435 DEVICE *dev = dcr->dev;
438 if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
439 Jmsg3(jcr, M_WARNING, 0, _("Open device %s Volume \"%s\" failed: ERR=%s\n"),
440 dev->print_name(), dcr->VolumeName, dev->bstrerror());
443 Dmsg2(190, "set append found freshly labeled volume. fd=%d dev=%x\n", dev->fd(), dev);
444 dev->VolHdr.LabelType = VOL_LABEL; /* set Volume label */
446 if (!write_volume_label_to_block(dcr)) {
447 Dmsg0(200, "Error from write volume label.\n");
451 dev->VolCatInfo.VolCatBytes = 0; /* reset byte count */
454 * If we are not dealing with a streaming device,
455 * write the block now to ensure we have write permission.
456 * It is better to find out now rather than later.
457 * We do not write the block now if this is an ANSI label. This
458 * avoids re-writing the ANSI label, which we do not want to do.
460 if (!dev->has_cap(CAP_STREAM)) {
461 if (!dev->rewind(dcr)) {
462 Jmsg2(jcr, M_FATAL, 0, _("Rewind error on device %s: ERR=%s\n"),
463 dev->print_name(), dev->print_errmsg());
467 // volume_unused(dcr); /* mark volume unused */
468 if (!dev->truncate(dcr)) {
469 Jmsg2(jcr, M_FATAL, 0, _("Truncate error on device %s: ERR=%s\n"),
470 dev->print_name(), dev->print_errmsg());
473 if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
474 Jmsg2(jcr, M_FATAL, 0,
475 _("Failed to re-open DVD after truncate on device %s: ERR=%s\n"),
476 dev->print_name(), dev->print_errmsg());
482 * If we have already detected an ANSI label, re-read it
483 * to skip past it. Otherwise, we write a new one if
486 if (dev->label_type != B_BACULA_LABEL) {
487 if (read_ansi_ibm_label(dcr) != VOL_OK) {
491 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, dev->VolHdr.VolumeName)) {
495 /* Attempt write to check write permission */
496 Dmsg1(200, "Attempt to write to device fd=%d.\n", dev->fd());
497 if (!write_block_to_dev(dcr)) {
498 Jmsg2(jcr, M_ERROR, 0, _("Unable to write device %s: ERR=%s\n"),
499 dev->print_name(), dev->print_errmsg());
500 Dmsg0(200, "===ERROR write block to dev\n");
505 /* Set or reset Volume statistics */
506 dev->VolCatInfo.VolCatJobs = 0;
507 dev->VolCatInfo.VolCatFiles = 0;
508 dev->VolCatInfo.VolCatErrors = 0;
509 dev->VolCatInfo.VolCatBlocks = 0;
510 dev->VolCatInfo.VolCatRBytes = 0;
512 dev->VolCatInfo.VolCatMounts++;
513 dev->VolCatInfo.VolCatRecycles++;
515 dev->VolCatInfo.VolCatMounts = 1;
516 dev->VolCatInfo.VolCatRecycles = 0;
517 dev->VolCatInfo.VolCatWrites = 1;
518 dev->VolCatInfo.VolCatReads = 1;
520 Dmsg0(150, "dir_update_vol_info. Set Append\n");
521 bstrncpy(dev->VolCatInfo.VolCatStatus, "Append", sizeof(dev->VolCatInfo.VolCatStatus));
522 if (!dir_update_volume_info(dcr, true, true)) { /* indicate doing relabel */
526 Jmsg(jcr, M_INFO, 0, _("Recycled volume \"%s\" on device %s, all previous data lost.\n"),
527 dcr->VolumeName, dev->print_name());
529 Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume \"%s\" on device %s\n"),
530 dcr->VolumeName, dev->print_name());
533 * End writing real Volume label (from pre-labeled tape), or recycling
536 Dmsg0(200, "OK from rewrite vol label.\n");
542 * create_volume_label_record
543 * Serialize label (from dev->VolHdr structure) into device record.
544 * Assumes that the dev->VolHdr structure is properly
547 static void create_volume_label_record(DCR *dcr, DEV_RECORD *rec)
551 DEVICE *dev = dcr->dev;
555 /* Serialize the label into the device record. */
557 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
558 ser_begin(rec->data, SER_LENGTH_Volume_Label);
559 ser_string(dev->VolHdr.Id);
561 ser_uint32(dev->VolHdr.VerNum);
563 if (dev->VolHdr.VerNum >= 11) {
564 ser_btime(dev->VolHdr.label_btime);
565 dev->VolHdr.write_btime = get_current_btime();
566 ser_btime(dev->VolHdr.write_btime);
567 dev->VolHdr.write_date = 0;
568 dev->VolHdr.write_time = 0;
570 /* OLD WAY DEPRECATED */
571 ser_float64(dev->VolHdr.label_date);
572 ser_float64(dev->VolHdr.label_time);
573 get_current_time(&dt);
574 dev->VolHdr.write_date = dt.julian_day_number;
575 dev->VolHdr.write_time = dt.julian_day_fraction;
577 ser_float64(dev->VolHdr.write_date); /* 0 if VerNum >= 11 */
578 ser_float64(dev->VolHdr.write_time); /* 0 if VerNum >= 11 */
580 ser_string(dev->VolHdr.VolumeName);
581 ser_string(dev->VolHdr.PrevVolumeName);
582 ser_string(dev->VolHdr.PoolName);
583 ser_string(dev->VolHdr.PoolType);
584 ser_string(dev->VolHdr.MediaType);
586 ser_string(dev->VolHdr.HostName);
587 ser_string(dev->VolHdr.LabelProg);
588 ser_string(dev->VolHdr.ProgVersion);
589 ser_string(dev->VolHdr.ProgDate);
591 ser_end(rec->data, SER_LENGTH_Volume_Label);
592 rec->data_len = ser_length(rec->data);
593 rec->FileIndex = dev->VolHdr.LabelType;
594 rec->VolSessionId = jcr->VolSessionId;
595 rec->VolSessionTime = jcr->VolSessionTime;
596 rec->Stream = jcr->NumWriteVolumes;
597 Dmsg2(150, "Created Vol label rec: FI=%s len=%d\n", FI_to_ascii(buf, rec->FileIndex),
603 * Create a volume label in memory
605 void create_volume_label(DEVICE *dev, const char *VolName,
606 const char *PoolName, bool dvdnow)
608 DEVRES *device = (DEVRES *)dev->device;
610 Dmsg0(130, "Start create_volume_label()\n");
614 dev->clear_volhdr(); /* clear any old volume info */
616 bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
617 dev->VolHdr.VerNum = BaculaTapeVersion;
618 if (dev->is_dvd() && dvdnow) {
619 /* We do not want to re-label a DVD so write VOL_LABEL now */
620 dev->VolHdr.LabelType = VOL_LABEL;
622 dev->VolHdr.LabelType = PRE_LABEL; /* Mark tape as unused */
624 bstrncpy(dev->VolHdr.VolumeName, VolName, sizeof(dev->VolHdr.VolumeName));
625 bstrncpy(dev->VolHdr.PoolName, PoolName, sizeof(dev->VolHdr.PoolName));
626 bstrncpy(dev->VolHdr.MediaType, device->media_type, sizeof(dev->VolHdr.MediaType));
628 bstrncpy(dev->VolHdr.PoolType, "Backup", sizeof(dev->VolHdr.PoolType));
630 dev->VolHdr.label_btime = get_current_btime();
631 dev->VolHdr.label_date = 0;
632 dev->VolHdr.label_time = 0;
634 if (gethostname(dev->VolHdr.HostName, sizeof(dev->VolHdr.HostName)) != 0) {
635 dev->VolHdr.HostName[0] = 0;
637 bstrncpy(dev->VolHdr.LabelProg, my_name, sizeof(dev->VolHdr.LabelProg));
638 sprintf(dev->VolHdr.ProgVersion, "Ver. %s %s", VERSION, BDATE);
639 sprintf(dev->VolHdr.ProgDate, "Build %s %s", __DATE__, __TIME__);
640 dev->set_labeled(); /* set has Bacula label */
641 if (debug_level >= 90) {
642 dump_volume_label(dev);
647 * Create session label
648 * The pool memory must be released by the calling program
650 void create_session_label(DCR *dcr, DEV_RECORD *rec, int label)
655 rec->VolSessionId = jcr->VolSessionId;
656 rec->VolSessionTime = jcr->VolSessionTime;
657 rec->Stream = jcr->JobId;
659 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
660 ser_begin(rec->data, SER_LENGTH_Session_Label);
661 ser_string(BaculaId);
662 ser_uint32(BaculaTapeVersion);
664 ser_uint32(jcr->JobId);
666 /* Changed in VerNum 11 */
667 ser_btime(get_current_btime());
670 ser_string(dcr->pool_name);
671 ser_string(dcr->pool_type);
672 ser_string(jcr->job_name); /* base Job name */
673 ser_string(jcr->client_name);
675 /* Added in VerNum 10 */
676 ser_string(jcr->Job); /* Unique name of this Job */
677 ser_string(jcr->fileset_name);
678 ser_uint32(jcr->JobType);
679 ser_uint32(jcr->JobLevel);
680 /* Added in VerNum 11 */
681 ser_string(jcr->fileset_md5);
683 if (label == EOS_LABEL) {
684 ser_uint32(jcr->JobFiles);
685 ser_uint64(jcr->JobBytes);
686 ser_uint32(dcr->StartBlock);
687 ser_uint32(dcr->EndBlock);
688 ser_uint32(dcr->StartFile);
689 ser_uint32(dcr->EndFile);
690 ser_uint32(jcr->JobErrors);
692 /* Added in VerNum 11 */
693 ser_uint32(jcr->JobStatus);
695 ser_end(rec->data, SER_LENGTH_Session_Label);
696 rec->data_len = ser_length(rec->data);
699 /* Write session label
700 * Returns: false on failure
703 bool write_session_label(DCR *dcr, int label)
706 DEVICE *dev = dcr->dev;
708 DEV_BLOCK *block = dcr->block;
709 char buf1[100], buf2[100];
712 Dmsg1(130, "session_label record=%x\n", rec);
715 set_start_vol_position(dcr);
718 if (dev->is_tape()) {
719 dcr->EndBlock = dev->EndBlock;
720 dcr->EndFile = dev->EndFile;
722 dcr->EndBlock = (uint32_t)dev->file_addr;
723 dcr->EndFile = (uint32_t)(dev->file_addr >> 32);
727 Jmsg1(jcr, M_ABORT, 0, _("Bad Volume session label = %d\n"), label);
730 create_session_label(dcr, rec, label);
731 rec->FileIndex = label;
734 * We guarantee that the session record can totally fit
735 * into a block. If not, write the block, and put it in
736 * the next block. Having the sesssion record totally in
737 * one block makes reading them much easier (no need to
738 * read the next block).
740 if (!can_write_record_to_block(block, rec)) {
741 Dmsg0(150, "Cannot write session label to block.\n");
742 if (!write_block_to_device(dcr)) {
743 Dmsg0(130, "Got session label write_block_to_dev error.\n");
748 if (!write_record_to_block(block, rec)) {
753 Dmsg6(150, "Write sesson_label record JobId=%d FI=%s SessId=%d Strm=%s len=%d "
754 "remainder=%d\n", jcr->JobId,
755 FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
756 stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
760 Dmsg2(150, "Leave write_session_label Block=%ud File=%ud\n",
761 dev->get_block_num(), dev->get_file());
765 /* unser_volume_label
767 * Unserialize the Bacula Volume label into the device Volume_Label
770 * Assumes that the record is already read.
772 * Returns: false on error
776 bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec)
779 char buf1[100], buf2[100];
781 if (rec->FileIndex != VOL_LABEL && rec->FileIndex != PRE_LABEL) {
782 Mmsg3(dev->errmsg, _("Expecting Volume Label, got FI=%s Stream=%s len=%d\n"),
783 FI_to_ascii(buf1, rec->FileIndex),
784 stream_to_ascii(buf2, rec->Stream, rec->FileIndex),
791 dev->VolHdr.LabelType = rec->FileIndex;
792 dev->VolHdr.LabelSize = rec->data_len;
795 /* Unserialize the record into the Volume Header */
796 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
797 ser_begin(rec->data, SER_LENGTH_Volume_Label);
798 unser_string(dev->VolHdr.Id);
799 unser_uint32(dev->VolHdr.VerNum);
801 if (dev->VolHdr.VerNum >= 11) {
802 unser_btime(dev->VolHdr.label_btime);
803 unser_btime(dev->VolHdr.write_btime);
804 } else { /* old way */
805 unser_float64(dev->VolHdr.label_date);
806 unser_float64(dev->VolHdr.label_time);
808 unser_float64(dev->VolHdr.write_date); /* Unused with VerNum >= 11 */
809 unser_float64(dev->VolHdr.write_time); /* Unused with VerNum >= 11 */
811 unser_string(dev->VolHdr.VolumeName);
812 unser_string(dev->VolHdr.PrevVolumeName);
813 unser_string(dev->VolHdr.PoolName);
814 unser_string(dev->VolHdr.PoolType);
815 unser_string(dev->VolHdr.MediaType);
817 unser_string(dev->VolHdr.HostName);
818 unser_string(dev->VolHdr.LabelProg);
819 unser_string(dev->VolHdr.ProgVersion);
820 unser_string(dev->VolHdr.ProgDate);
822 ser_end(rec->data, SER_LENGTH_Volume_Label);
823 Dmsg0(190, "unser_vol_label\n");
824 if (debug_level >= 190) {
825 dump_volume_label(dev);
831 bool unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec)
835 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
836 unser_begin(rec->data, SER_LENGTH_Session_Label);
837 unser_string(label->Id);
838 unser_uint32(label->VerNum);
839 unser_uint32(label->JobId);
840 if (label->VerNum >= 11) {
841 unser_btime(label->write_btime);
843 unser_float64(label->write_date);
845 unser_float64(label->write_time);
846 unser_string(label->PoolName);
847 unser_string(label->PoolType);
848 unser_string(label->JobName);
849 unser_string(label->ClientName);
850 if (label->VerNum >= 10) {
851 unser_string(label->Job); /* Unique name of this Job */
852 unser_string(label->FileSetName);
853 unser_uint32(label->JobType);
854 unser_uint32(label->JobLevel);
856 if (label->VerNum >= 11) {
857 unser_string(label->FileSetMD5);
859 label->FileSetMD5[0] = 0;
861 if (rec->FileIndex == EOS_LABEL) {
862 unser_uint32(label->JobFiles);
863 unser_uint64(label->JobBytes);
864 unser_uint32(label->StartBlock);
865 unser_uint32(label->EndBlock);
866 unser_uint32(label->StartFile);
867 unser_uint32(label->EndFile);
868 unser_uint32(label->JobErrors);
869 if (label->VerNum >= 11) {
870 unser_uint32(label->JobStatus);
872 label->JobStatus = JS_Terminated; /* kludge */
878 void dump_volume_label(DEVICE *dev)
880 int dbl = debug_level;
882 const char *LabelType;
889 switch (dev->VolHdr.LabelType) {
891 LabelType = "PRE_LABEL";
894 LabelType = "VOL_LABEL";
897 LabelType = "EOM_LABEL";
900 LabelType = "SOS_LABEL";
903 LabelType = "EOS_LABEL";
909 sprintf(buf, _("Unknown %d"), dev->VolHdr.LabelType);
913 Pmsg11(-1, _("\nVolume Label:\n"
926 dev->VolHdr.Id, dev->VolHdr.VerNum,
927 dev->VolHdr.VolumeName, dev->VolHdr.PrevVolumeName,
928 File, LabelType, dev->VolHdr.LabelSize,
929 dev->VolHdr.PoolName, dev->VolHdr.MediaType,
930 dev->VolHdr.PoolType, dev->VolHdr.HostName);
932 if (dev->VolHdr.VerNum >= 11) {
934 bstrftime(dt, sizeof(dt), btime_to_unix(dev->VolHdr.label_btime));
935 Pmsg1(-1, _("Date label written: %s\n"), dt);
937 dt.julian_day_number = dev->VolHdr.label_date;
938 dt.julian_day_fraction = dev->VolHdr.label_time;
941 _("Date label written: %04d-%02d-%02d at %02d:%02d\n"),
942 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
950 static void dump_session_label(DEV_RECORD *rec, const char *type)
956 char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], ec6[30], ec7[30];
958 unser_session_label(&label, rec);
961 Pmsg7(-1, _("\n%s Record:\n"
968 ""), type, label.JobId, label.VerNum,
969 label.PoolName, label.PoolType,
970 label.JobName, label.ClientName);
972 if (label.VerNum >= 10) {
974 "Job (unique name) : %s\n"
978 ""), label.Job, label.FileSetName, label.JobType, label.JobLevel);
981 if (rec->FileIndex == EOS_LABEL) {
992 edit_uint64_with_commas(label.JobFiles, ec1),
993 edit_uint64_with_commas(label.JobBytes, ec2),
994 edit_uint64_with_commas(label.StartBlock, ec3),
995 edit_uint64_with_commas(label.EndBlock, ec4),
996 edit_uint64_with_commas(label.StartFile, ec5),
997 edit_uint64_with_commas(label.EndFile, ec6),
998 edit_uint64_with_commas(label.JobErrors, ec7),
1001 if (label.VerNum >= 11) {
1003 bstrftime(dt, sizeof(dt), btime_to_unix(label.write_btime));
1004 Pmsg1(-1, _("Date written : %s\n"), dt);
1006 dt.julian_day_number = label.write_date;
1007 dt.julian_day_fraction = label.write_time;
1008 tm_decode(&dt, &tm);
1009 Pmsg5(-1, _("Date written : %04d-%02d-%02d at %02d:%02d\n"),
1010 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
1016 void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose)
1021 if (rec->FileIndex == 0 && rec->VolSessionId == 0 && rec->VolSessionTime == 0) {
1026 switch (rec->FileIndex) {
1028 type = _("Fresh Volume");
1034 type = _("Begin Job Session");
1037 type = _("End Job Session");
1040 type = _("End of Media");
1043 type = _("End of Tape");
1046 type = _("Unknown");
1050 switch (rec->FileIndex) {
1053 unser_volume_label(dev, rec);
1054 dump_volume_label(dev);
1057 dump_session_label(rec, type);
1060 dump_session_label(rec, type);
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);
1068 Pmsg0(-1, _("End of physical tape.\n"));
1071 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1072 type, dev->file, dev->block_num, rec->VolSessionId,
1073 rec->VolSessionTime, rec->Stream, rec->data_len);
1077 SESSION_LABEL label;
1079 switch (rec->FileIndex) {
1081 unser_session_label(&label, rec);
1082 bstrftimes(dt, sizeof(dt), btime_to_unix(label.write_btime));
1083 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1084 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1085 Pmsg4(-1, _(" Job=%s Date=%s Level=%c Type=%c\n"),
1086 label.Job, dt, label.JobLevel, label.JobType);
1089 char ed1[30], ed2[30];
1090 unser_session_label(&label, rec);
1091 bstrftimes(dt, sizeof(dt), btime_to_unix(label.write_btime));
1092 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1093 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1094 Pmsg7(-1, _(" Date=%s Level=%c Type=%c Files=%s Bytes=%s Errors=%d Status=%c\n"),
1095 dt, label.JobLevel, label.JobType,
1096 edit_uint64_with_commas(label.JobFiles, ed1),
1097 edit_uint64_with_commas(label.JobBytes, ed2),
1098 label.JobErrors, (char)label.JobStatus);
1104 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1105 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime,
1106 rec->Stream, rec->data_len);