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);
224 // dev = dcr->dev; /* may have changed in reserve volume */
226 /* Compare Volume Names */
227 Dmsg2(130, "Compare Vol names: VolName=%s hdr=%s\n", VolName?VolName:"*", dev->VolHdr.VolumeName);
228 if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolumeName, VolName) != 0) {
229 Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
230 dev->print_name(), VolName, dev->VolHdr.VolumeName);
231 Dmsg1(130, "%s", jcr->errmsg);
233 * Cancel Job if too many label errors
234 * => we are in a loop
236 if (!dev->poll && jcr->label_errors++ > 100) {
237 Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
239 Dmsg0(150, "return VOL_NAME_ERROR\n");
240 stat = VOL_NAME_ERROR;
241 volume_unused(dcr); /* mark volume "released" */
244 Dmsg1(130, "Copy vol_name=%s\n", dev->VolHdr.VolumeName);
246 if (debug_level >= 10) {
247 dump_volume_label(dev);
249 Dmsg0(130, "Leave read_volume_label() VOL_OK\n");
250 /* If we are a streaming device, we only get one chance to read */
251 if (!dev->has_cap(CAP_STREAM)) {
253 if (have_ansi_label) {
254 stat = read_ansi_ibm_label(dcr);
255 /* If we want a label and didn't find it, return error */
256 if (stat != VOL_OK) {
257 volume_unused(dcr); /* mark volume "released" */
268 Dmsg1(150, "return %d\n", stat);
273 * Put a volume label into the block
275 * Returns: false on failure
278 bool write_volume_label_to_block(DCR *dcr)
281 DEVICE *dev = dcr->dev;
283 DEV_BLOCK *block = dcr->block;
285 Dmsg0(130, "write Label in write_volume_label_to_block()\n");
286 memset(&rec, 0, sizeof(rec));
287 rec.data = get_memory(SER_LENGTH_Volume_Label);
288 empty_block(block); /* Volume label always at beginning */
290 create_volume_label_record(dcr, &rec);
292 block->BlockNumber = 0;
293 if (!write_record_to_block(block, &rec)) {
294 free_pool_memory(rec.data);
295 Jmsg1(jcr, M_FATAL, 0, _("Cannot write Volume label to block for device %s\n"),
299 Dmsg1(130, "Wrote label of %d bytes to block\n", rec.data_len);
301 free_pool_memory(rec.data);
307 * Write a Volume Label
308 * !!! Note, this is ONLY used for writing
309 * a fresh volume label. Any data
310 * after the label will be destroyed,
311 * in fact, we write the label 5 times !!!!
313 * This routine should be used only when labeling a blank tape.
315 bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName,
316 const char *PoolName, bool relabel, bool dvdnow)
318 DEVICE * volatile dev = dcr->dev;
321 Dmsg0(150, "write_volume_label()\n");
322 empty_block(dcr->block);
325 volume_unused(dcr); /* mark current volume unused */
326 /* Truncate device */
327 if (!dev->truncate(dcr)) {
330 if (!dev->is_tape()) {
331 dev->close_part(dcr); /* make sure DVD/file closed for rename */
335 /* Set the new filename for open, ... */
336 bstrncpy(dev->VolCatInfo.VolCatName, VolName, sizeof(dev->VolCatInfo.VolCatName));
337 bstrncpy(dcr->VolCatInfo.VolCatName, VolName, sizeof(dcr->VolCatInfo.VolCatName));
338 Dmsg1(150, "New VolName=%s\n", VolName);
339 if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
340 /* If device is not tape, attempt to create it */
341 if (dev->is_tape() || dev->open(dcr, CREATE_READ_WRITE) < 0) {
345 Dmsg1(150, "Label type=%d\n", dev->label_type);
346 if (!dev->rewind(dcr)) {
347 Dmsg2(130, "Bad status on %s from rewind: ERR=%s\n", dev->print_name(), dev->print_errmsg());
353 /* Temporarily mark in append state to enable writing */
356 /* Create PRE_LABEL or VOL_LABEL if DVD */
357 create_volume_label(dev, VolName, PoolName, dvdnow);
360 * If we have already detected an ANSI label, re-read it
361 * to skip past it. Otherwise, we write a new one if
364 if (dev->label_type != B_BACULA_LABEL) {
365 if (read_ansi_ibm_label(dcr) != VOL_OK) {
369 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, VolName)) {
373 create_volume_label_record(dcr, dcr->rec);
374 dcr->rec->Stream = 0;
376 if (!write_record_to_block(dcr->block, dcr->rec)) {
377 Dmsg2(130, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
380 Dmsg2(130, "Wrote label of %d bytes to %s\n", dcr->rec->data_len, dev->print_name());
383 Dmsg0(130, "Call write_block_to_dev()\n");
384 if (!write_block_to_dev(dcr)) {
385 Dmsg2(130, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
389 /* Now commit block to DVD if we should write now */
390 if (dev->is_dvd() && dvdnow) {
391 Dmsg1(150, "New VolName=%s\n", dev->VolCatInfo.VolCatName);
392 if (!dvd_write_part(dcr)) {
393 Dmsg2(130, "Bad DVD write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
398 Dmsg0(130, " Wrote block to device\n");
402 write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
405 if (debug_level >= 20) {
406 dump_volume_label(dev);
408 Dmsg0(100, "Call reserve_volume\n");
409 if (reserve_volume(dcr, VolName) == NULL) {
410 Mmsg2(dcr->jcr->errmsg, _("Could not reserve volume %s on %s\n"),
411 dev->VolHdr.VolumeName, dev->print_name());
414 dev = dcr->dev; /* may have changed in reserve_volume */
416 dev->clear_append(); /* remove append since this is PRE_LABEL */
422 dev->clear_append(); /* remove append since this is PRE_LABEL */
427 * Write a volume label. This is ONLY called if we have a valid Bacula
428 * label of type PRE_LABEL;
429 * Returns: true if OK
430 * false if unable to write it
432 bool rewrite_volume_label(DCR *dcr, bool recycle)
434 DEVICE *dev = dcr->dev;
437 if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
440 Dmsg2(190, "set append found freshly labeled volume. fd=%d dev=%x\n", dev->fd(), dev);
441 dev->VolHdr.LabelType = VOL_LABEL; /* set Volume label */
443 if (!write_volume_label_to_block(dcr)) {
444 Dmsg0(200, "Error from write volume label.\n");
448 dev->VolCatInfo.VolCatBytes = 0; /* reset byte count */
451 * If we are not dealing with a streaming device,
452 * write the block now to ensure we have write permission.
453 * It is better to find out now rather than later.
454 * We do not write the block now if this is an ANSI label. This
455 * avoids re-writing the ANSI label, which we do not want to do.
457 if (!dev->has_cap(CAP_STREAM)) {
458 if (!dev->rewind(dcr)) {
459 Jmsg2(jcr, M_FATAL, 0, _("Rewind error on device %s: ERR=%s\n"),
460 dev->print_name(), dev->print_errmsg());
464 volume_unused(dcr); /* mark volume unused */
465 if (!dev->truncate(dcr)) {
466 Jmsg2(jcr, M_FATAL, 0, _("Truncate error on device %s: ERR=%s\n"),
467 dev->print_name(), dev->print_errmsg());
470 if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
471 Jmsg2(jcr, M_FATAL, 0,
472 _("Failed to re-open DVD after truncate on device %s: ERR=%s\n"),
473 dev->print_name(), dev->print_errmsg());
479 * If we have already detected an ANSI label, re-read it
480 * to skip past it. Otherwise, we write a new one if
483 if (dev->label_type != B_BACULA_LABEL) {
484 if (read_ansi_ibm_label(dcr) != VOL_OK) {
488 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, dev->VolHdr.VolumeName)) {
492 /* Attempt write to check write permission */
493 Dmsg1(200, "Attempt to write to device fd=%d.\n", dev->fd());
494 if (!write_block_to_dev(dcr)) {
495 Jmsg2(jcr, M_ERROR, 0, _("Unable to write device %s: ERR=%s\n"),
496 dev->print_name(), dev->print_errmsg());
497 Dmsg0(200, "===ERROR write block to dev\n");
502 /* Set or reset Volume statistics */
503 dev->VolCatInfo.VolCatJobs = 0;
504 dev->VolCatInfo.VolCatFiles = 0;
505 dev->VolCatInfo.VolCatErrors = 0;
506 dev->VolCatInfo.VolCatBlocks = 0;
507 dev->VolCatInfo.VolCatRBytes = 0;
509 dev->VolCatInfo.VolCatMounts++;
510 dev->VolCatInfo.VolCatRecycles++;
512 dev->VolCatInfo.VolCatMounts = 1;
513 dev->VolCatInfo.VolCatRecycles = 0;
514 dev->VolCatInfo.VolCatWrites = 1;
515 dev->VolCatInfo.VolCatReads = 1;
517 Dmsg0(150, "dir_update_vol_info. Set Append\n");
518 bstrncpy(dev->VolCatInfo.VolCatStatus, "Append", sizeof(dev->VolCatInfo.VolCatStatus));
519 if (!dir_update_volume_info(dcr, true, true)) { /* indicate doing relabel */
523 Jmsg(jcr, M_INFO, 0, _("Recycled volume \"%s\" on device %s, all previous data lost.\n"),
524 dcr->VolumeName, dev->print_name());
526 Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume \"%s\" on device %s\n"),
527 dcr->VolumeName, dev->print_name());
530 * End writing real Volume label (from pre-labeled tape), or recycling
533 Dmsg0(200, "OK from rewrite vol label.\n");
539 * create_volume_label_record
540 * Serialize label (from dev->VolHdr structure) into device record.
541 * Assumes that the dev->VolHdr structure is properly
544 static void create_volume_label_record(DCR *dcr, DEV_RECORD *rec)
548 DEVICE *dev = dcr->dev;
552 /* Serialize the label into the device record. */
554 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
555 ser_begin(rec->data, SER_LENGTH_Volume_Label);
556 ser_string(dev->VolHdr.Id);
558 ser_uint32(dev->VolHdr.VerNum);
560 if (dev->VolHdr.VerNum >= 11) {
561 ser_btime(dev->VolHdr.label_btime);
562 dev->VolHdr.write_btime = get_current_btime();
563 ser_btime(dev->VolHdr.write_btime);
564 dev->VolHdr.write_date = 0;
565 dev->VolHdr.write_time = 0;
567 /* OLD WAY DEPRECATED */
568 ser_float64(dev->VolHdr.label_date);
569 ser_float64(dev->VolHdr.label_time);
570 get_current_time(&dt);
571 dev->VolHdr.write_date = dt.julian_day_number;
572 dev->VolHdr.write_time = dt.julian_day_fraction;
574 ser_float64(dev->VolHdr.write_date); /* 0 if VerNum >= 11 */
575 ser_float64(dev->VolHdr.write_time); /* 0 if VerNum >= 11 */
577 ser_string(dev->VolHdr.VolumeName);
578 ser_string(dev->VolHdr.PrevVolumeName);
579 ser_string(dev->VolHdr.PoolName);
580 ser_string(dev->VolHdr.PoolType);
581 ser_string(dev->VolHdr.MediaType);
583 ser_string(dev->VolHdr.HostName);
584 ser_string(dev->VolHdr.LabelProg);
585 ser_string(dev->VolHdr.ProgVersion);
586 ser_string(dev->VolHdr.ProgDate);
588 ser_end(rec->data, SER_LENGTH_Volume_Label);
589 rec->data_len = ser_length(rec->data);
590 rec->FileIndex = dev->VolHdr.LabelType;
591 rec->VolSessionId = jcr->VolSessionId;
592 rec->VolSessionTime = jcr->VolSessionTime;
593 rec->Stream = jcr->NumWriteVolumes;
594 Dmsg2(150, "Created Vol label rec: FI=%s len=%d\n", FI_to_ascii(buf, rec->FileIndex),
600 * Create a volume label in memory
602 void create_volume_label(DEVICE *dev, const char *VolName,
603 const char *PoolName, bool dvdnow)
605 DEVRES *device = (DEVRES *)dev->device;
607 Dmsg0(130, "Start create_volume_label()\n");
611 dev->clear_volhdr(); /* clear any old volume info */
613 bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
614 dev->VolHdr.VerNum = BaculaTapeVersion;
615 if (dev->is_dvd() && dvdnow) {
616 /* We do not want to re-label a DVD so write VOL_LABEL now */
617 dev->VolHdr.LabelType = VOL_LABEL;
619 dev->VolHdr.LabelType = PRE_LABEL; /* Mark tape as unused */
621 bstrncpy(dev->VolHdr.VolumeName, VolName, sizeof(dev->VolHdr.VolumeName));
622 bstrncpy(dev->VolHdr.PoolName, PoolName, sizeof(dev->VolHdr.PoolName));
623 bstrncpy(dev->VolHdr.MediaType, device->media_type, sizeof(dev->VolHdr.MediaType));
625 bstrncpy(dev->VolHdr.PoolType, "Backup", sizeof(dev->VolHdr.PoolType));
627 dev->VolHdr.label_btime = get_current_btime();
628 dev->VolHdr.label_date = 0;
629 dev->VolHdr.label_time = 0;
631 if (gethostname(dev->VolHdr.HostName, sizeof(dev->VolHdr.HostName)) != 0) {
632 dev->VolHdr.HostName[0] = 0;
634 bstrncpy(dev->VolHdr.LabelProg, my_name, sizeof(dev->VolHdr.LabelProg));
635 sprintf(dev->VolHdr.ProgVersion, "Ver. %s %s", VERSION, BDATE);
636 sprintf(dev->VolHdr.ProgDate, "Build %s %s", __DATE__, __TIME__);
637 dev->set_labeled(); /* set has Bacula label */
638 if (debug_level >= 90) {
639 dump_volume_label(dev);
644 * Create session label
645 * The pool memory must be released by the calling program
647 void create_session_label(DCR *dcr, DEV_RECORD *rec, int label)
652 rec->VolSessionId = jcr->VolSessionId;
653 rec->VolSessionTime = jcr->VolSessionTime;
654 rec->Stream = jcr->JobId;
656 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
657 ser_begin(rec->data, SER_LENGTH_Session_Label);
658 ser_string(BaculaId);
659 ser_uint32(BaculaTapeVersion);
661 ser_uint32(jcr->JobId);
663 /* Changed in VerNum 11 */
664 ser_btime(get_current_btime());
667 ser_string(dcr->pool_name);
668 ser_string(dcr->pool_type);
669 ser_string(jcr->job_name); /* base Job name */
670 ser_string(jcr->client_name);
672 /* Added in VerNum 10 */
673 ser_string(jcr->Job); /* Unique name of this Job */
674 ser_string(jcr->fileset_name);
675 ser_uint32(jcr->JobType);
676 ser_uint32(jcr->JobLevel);
677 /* Added in VerNum 11 */
678 ser_string(jcr->fileset_md5);
680 if (label == EOS_LABEL) {
681 ser_uint32(jcr->JobFiles);
682 ser_uint64(jcr->JobBytes);
683 ser_uint32(dcr->StartBlock);
684 ser_uint32(dcr->EndBlock);
685 ser_uint32(dcr->StartFile);
686 ser_uint32(dcr->EndFile);
687 ser_uint32(jcr->JobErrors);
689 /* Added in VerNum 11 */
690 ser_uint32(jcr->JobStatus);
692 ser_end(rec->data, SER_LENGTH_Session_Label);
693 rec->data_len = ser_length(rec->data);
696 /* Write session label
697 * Returns: false on failure
700 bool write_session_label(DCR *dcr, int label)
703 DEVICE *dev = dcr->dev;
705 DEV_BLOCK *block = dcr->block;
706 char buf1[100], buf2[100];
709 Dmsg1(130, "session_label record=%x\n", rec);
712 set_start_vol_position(dcr);
715 if (dev->is_tape()) {
716 dcr->EndBlock = dev->EndBlock;
717 dcr->EndFile = dev->EndFile;
719 dcr->EndBlock = (uint32_t)dev->file_addr;
720 dcr->EndFile = (uint32_t)(dev->file_addr >> 32);
724 Jmsg1(jcr, M_ABORT, 0, _("Bad Volume session label = %d\n"), label);
727 create_session_label(dcr, rec, label);
728 rec->FileIndex = label;
731 * We guarantee that the session record can totally fit
732 * into a block. If not, write the block, and put it in
733 * the next block. Having the sesssion record totally in
734 * one block makes reading them much easier (no need to
735 * read the next block).
737 if (!can_write_record_to_block(block, rec)) {
738 Dmsg0(150, "Cannot write session label to block.\n");
739 if (!write_block_to_device(dcr)) {
740 Dmsg0(130, "Got session label write_block_to_dev error.\n");
745 if (!write_record_to_block(block, rec)) {
750 Dmsg6(150, "Write sesson_label record JobId=%d FI=%s SessId=%d Strm=%s len=%d "
751 "remainder=%d\n", jcr->JobId,
752 FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
753 stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
757 Dmsg2(150, "Leave write_session_label Block=%ud File=%ud\n",
758 dev->get_block_num(), dev->get_file());
762 /* unser_volume_label
764 * Unserialize the Bacula Volume label into the device Volume_Label
767 * Assumes that the record is already read.
769 * Returns: false on error
773 bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec)
776 char buf1[100], buf2[100];
778 if (rec->FileIndex != VOL_LABEL && rec->FileIndex != PRE_LABEL) {
779 Mmsg3(dev->errmsg, _("Expecting Volume Label, got FI=%s Stream=%s len=%d\n"),
780 FI_to_ascii(buf1, rec->FileIndex),
781 stream_to_ascii(buf2, rec->Stream, rec->FileIndex),
788 dev->VolHdr.LabelType = rec->FileIndex;
789 dev->VolHdr.LabelSize = rec->data_len;
792 /* Unserialize the record into the Volume Header */
793 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
794 ser_begin(rec->data, SER_LENGTH_Volume_Label);
795 unser_string(dev->VolHdr.Id);
796 unser_uint32(dev->VolHdr.VerNum);
798 if (dev->VolHdr.VerNum >= 11) {
799 unser_btime(dev->VolHdr.label_btime);
800 unser_btime(dev->VolHdr.write_btime);
801 } else { /* old way */
802 unser_float64(dev->VolHdr.label_date);
803 unser_float64(dev->VolHdr.label_time);
805 unser_float64(dev->VolHdr.write_date); /* Unused with VerNum >= 11 */
806 unser_float64(dev->VolHdr.write_time); /* Unused with VerNum >= 11 */
808 unser_string(dev->VolHdr.VolumeName);
809 unser_string(dev->VolHdr.PrevVolumeName);
810 unser_string(dev->VolHdr.PoolName);
811 unser_string(dev->VolHdr.PoolType);
812 unser_string(dev->VolHdr.MediaType);
814 unser_string(dev->VolHdr.HostName);
815 unser_string(dev->VolHdr.LabelProg);
816 unser_string(dev->VolHdr.ProgVersion);
817 unser_string(dev->VolHdr.ProgDate);
819 ser_end(rec->data, SER_LENGTH_Volume_Label);
820 Dmsg0(190, "unser_vol_label\n");
821 if (debug_level >= 190) {
822 dump_volume_label(dev);
828 bool unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec)
832 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
833 unser_begin(rec->data, SER_LENGTH_Session_Label);
834 unser_string(label->Id);
835 unser_uint32(label->VerNum);
836 unser_uint32(label->JobId);
837 if (label->VerNum >= 11) {
838 unser_btime(label->write_btime);
840 unser_float64(label->write_date);
842 unser_float64(label->write_time);
843 unser_string(label->PoolName);
844 unser_string(label->PoolType);
845 unser_string(label->JobName);
846 unser_string(label->ClientName);
847 if (label->VerNum >= 10) {
848 unser_string(label->Job); /* Unique name of this Job */
849 unser_string(label->FileSetName);
850 unser_uint32(label->JobType);
851 unser_uint32(label->JobLevel);
853 if (label->VerNum >= 11) {
854 unser_string(label->FileSetMD5);
856 label->FileSetMD5[0] = 0;
858 if (rec->FileIndex == EOS_LABEL) {
859 unser_uint32(label->JobFiles);
860 unser_uint64(label->JobBytes);
861 unser_uint32(label->StartBlock);
862 unser_uint32(label->EndBlock);
863 unser_uint32(label->StartFile);
864 unser_uint32(label->EndFile);
865 unser_uint32(label->JobErrors);
866 if (label->VerNum >= 11) {
867 unser_uint32(label->JobStatus);
869 label->JobStatus = JS_Terminated; /* kludge */
875 void dump_volume_label(DEVICE *dev)
877 int dbl = debug_level;
879 const char *LabelType;
886 switch (dev->VolHdr.LabelType) {
888 LabelType = "PRE_LABEL";
891 LabelType = "VOL_LABEL";
894 LabelType = "EOM_LABEL";
897 LabelType = "SOS_LABEL";
900 LabelType = "EOS_LABEL";
906 sprintf(buf, _("Unknown %d"), dev->VolHdr.LabelType);
910 Pmsg11(-1, _("\nVolume Label:\n"
923 dev->VolHdr.Id, dev->VolHdr.VerNum,
924 dev->VolHdr.VolumeName, dev->VolHdr.PrevVolumeName,
925 File, LabelType, dev->VolHdr.LabelSize,
926 dev->VolHdr.PoolName, dev->VolHdr.MediaType,
927 dev->VolHdr.PoolType, dev->VolHdr.HostName);
929 if (dev->VolHdr.VerNum >= 11) {
931 bstrftime(dt, sizeof(dt), btime_to_unix(dev->VolHdr.label_btime));
932 Pmsg1(-1, _("Date label written: %s\n"), dt);
934 dt.julian_day_number = dev->VolHdr.label_date;
935 dt.julian_day_fraction = dev->VolHdr.label_time;
938 _("Date label written: %04d-%02d-%02d at %02d:%02d\n"),
939 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
947 static void dump_session_label(DEV_RECORD *rec, const char *type)
953 char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], ec6[30], ec7[30];
955 unser_session_label(&label, rec);
958 Pmsg7(-1, _("\n%s Record:\n"
965 ""), type, label.JobId, label.VerNum,
966 label.PoolName, label.PoolType,
967 label.JobName, label.ClientName);
969 if (label.VerNum >= 10) {
971 "Job (unique name) : %s\n"
975 ""), label.Job, label.FileSetName, label.JobType, label.JobLevel);
978 if (rec->FileIndex == EOS_LABEL) {
989 edit_uint64_with_commas(label.JobFiles, ec1),
990 edit_uint64_with_commas(label.JobBytes, ec2),
991 edit_uint64_with_commas(label.StartBlock, ec3),
992 edit_uint64_with_commas(label.EndBlock, ec4),
993 edit_uint64_with_commas(label.StartFile, ec5),
994 edit_uint64_with_commas(label.EndFile, ec6),
995 edit_uint64_with_commas(label.JobErrors, ec7),
998 if (label.VerNum >= 11) {
1000 bstrftime(dt, sizeof(dt), btime_to_unix(label.write_btime));
1001 Pmsg1(-1, _("Date written : %s\n"), dt);
1003 dt.julian_day_number = label.write_date;
1004 dt.julian_day_fraction = label.write_time;
1005 tm_decode(&dt, &tm);
1006 Pmsg5(-1, _("Date written : %04d-%02d-%02d at %02d:%02d\n"),
1007 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
1013 void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose)
1018 if (rec->FileIndex == 0 && rec->VolSessionId == 0 && rec->VolSessionTime == 0) {
1023 switch (rec->FileIndex) {
1025 type = _("Fresh Volume");
1031 type = _("Begin Job Session");
1034 type = _("End Job Session");
1037 type = _("End of Media");
1040 type = _("End of Tape");
1043 type = _("Unknown");
1047 switch (rec->FileIndex) {
1050 unser_volume_label(dev, rec);
1051 dump_volume_label(dev);
1054 dump_session_label(rec, type);
1057 dump_session_label(rec, type);
1060 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1061 type, dev->file, dev->block_num, rec->VolSessionId,
1062 rec->VolSessionTime, rec->Stream, rec->data_len);
1065 Pmsg0(-1, _("End of physical tape.\n"));
1068 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1069 type, dev->file, dev->block_num, rec->VolSessionId,
1070 rec->VolSessionTime, rec->Stream, rec->data_len);
1074 SESSION_LABEL label;
1076 switch (rec->FileIndex) {
1078 unser_session_label(&label, rec);
1079 bstrftimes(dt, sizeof(dt), btime_to_unix(label.write_btime));
1080 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1081 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1082 Pmsg4(-1, _(" Job=%s Date=%s Level=%c Type=%c\n"),
1083 label.Job, dt, label.JobLevel, label.JobType);
1086 char ed1[30], ed2[30];
1087 unser_session_label(&label, rec);
1088 bstrftimes(dt, sizeof(dt), btime_to_unix(label.write_btime));
1089 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1090 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1091 Pmsg7(-1, _(" Date=%s Level=%c Type=%c Files=%s Bytes=%s Errors=%d Status=%c\n"),
1092 dt, label.JobLevel, label.JobType,
1093 edit_uint64_with_commas(label.JobFiles, ed1),
1094 edit_uint64_with_commas(label.JobBytes, ed2),
1095 label.JobErrors, (char)label.JobStatus);
1101 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1102 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime,
1103 rec->Stream, rec->data_len);