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 */
171 if (!dev->is_volume_to_unload()) {
176 if (forge_on || jcr->ignore_label_errors) {
177 dev->set_labeled(); /* set has Bacula label */
178 Jmsg(jcr, M_ERROR, 0, "%s", jcr->errmsg);
182 Dmsg0(100, "No volume label - bailing out\n");
187 /* At this point, we have read the first Bacula block, and
188 * then read the Bacula Volume label. Now we need to
189 * make sure we have the right Volume.
193 if (dev->VolHdr.VerNum != BaculaTapeVersion &&
194 dev->VolHdr.VerNum != OldCompatibleBaculaTapeVersion1 &&
195 dev->VolHdr.VerNum != OldCompatibleBaculaTapeVersion2) {
196 Mmsg(jcr->errmsg, _("Volume on %s has wrong Bacula version. Wanted %d got %d\n"),
197 dev->print_name(), BaculaTapeVersion, dev->VolHdr.VerNum);
198 Dmsg1(130, "VOL_VERSION_ERROR: %s", jcr->errmsg);
199 stat = VOL_VERSION_ERROR;
203 /* We are looking for either an unused Bacula tape (PRE_LABEL) or
204 * a Bacula volume label (VOL_LABEL)
206 if (dev->VolHdr.LabelType != PRE_LABEL && dev->VolHdr.LabelType != VOL_LABEL) {
207 Mmsg(jcr->errmsg, _("Volume on %s has bad Bacula label type: %x\n"),
208 dev->print_name(), dev->VolHdr.LabelType);
209 Dmsg1(130, "%s", jcr->errmsg);
210 if (!dev->poll && jcr->label_errors++ > 100) {
211 Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
213 Dmsg0(150, "return VOL_LABEL_ERROR\n");
214 stat = VOL_LABEL_ERROR;
218 dev->set_labeled(); /* set has Bacula label */
220 /* Compare Volume Names */
221 Dmsg2(130, "Compare Vol names: VolName=%s hdr=%s\n", VolName?VolName:"*", dev->VolHdr.VolumeName);
222 if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolumeName, VolName) != 0) {
223 Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
224 dev->print_name(), VolName, dev->VolHdr.VolumeName);
225 Dmsg1(130, "%s", jcr->errmsg);
227 * Cancel Job if too many label errors
228 * => we are in a loop
230 if (!dev->poll && jcr->label_errors++ > 100) {
231 Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
233 Dmsg0(150, "return VOL_NAME_ERROR\n");
234 stat = VOL_NAME_ERROR;
239 if (debug_level >= 10) {
240 dump_volume_label(dev);
242 Dmsg0(130, "Leave read_volume_label() VOL_OK\n");
243 /* If we are a streaming device, we only get one chance to read */
244 if (!dev->has_cap(CAP_STREAM)) {
246 if (have_ansi_label) {
247 stat = read_ansi_ibm_label(dcr);
248 /* If we want a label and didn't find it, return error */
249 if (stat != VOL_OK) {
255 Dmsg1(100, "Call reserve_volume=%s\n", dev->VolHdr.VolumeName);
256 if (reserve_volume(dcr, dev->VolHdr.VolumeName) == NULL) {
257 Mmsg2(jcr->errmsg, _("Could not reserve volume %s on %s\n"),
258 dev->VolHdr.VolumeName, dev->print_name());
259 stat = VOL_NAME_ERROR;
269 Dmsg1(150, "return %d\n", stat);
274 * Put a volume label into the block
276 * Returns: false on failure
279 bool write_volume_label_to_block(DCR *dcr)
282 DEVICE *dev = dcr->dev;
284 DEV_BLOCK *block = dcr->block;
286 Dmsg0(130, "write Label in write_volume_label_to_block()\n");
287 memset(&rec, 0, sizeof(rec));
288 rec.data = get_memory(SER_LENGTH_Volume_Label);
289 empty_block(block); /* Volume label always at beginning */
291 create_volume_label_record(dcr, &rec);
293 block->BlockNumber = 0;
294 if (!write_record_to_block(block, &rec)) {
295 free_pool_memory(rec.data);
296 Jmsg1(jcr, M_FATAL, 0, _("Cannot write Volume label to block for device %s\n"),
300 Dmsg2(130, "Wrote label of %d bytes to block. Vol=%s\n", rec.data_len,
303 free_pool_memory(rec.data);
309 * Write a Volume Label
310 * !!! Note, this is ONLY used for writing
311 * a fresh volume label. Any data
312 * after the label will be destroyed,
313 * in fact, we write the label 5 times !!!!
315 * This routine should be used only when labeling a blank tape.
317 bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName,
318 const char *PoolName, bool relabel, bool dvdnow)
320 DEVICE * volatile dev = dcr->dev;
323 Dmsg0(150, "write_volume_label()\n");
324 empty_block(dcr->block);
327 volume_unused(dcr); /* mark current volume unused */
328 /* Truncate device */
329 if (!dev->truncate(dcr)) {
332 if (!dev->is_tape()) {
333 dev->close_part(dcr); /* make sure DVD/file closed for rename */
337 /* Set the new filename for open, ... */
338 bstrncpy(dev->VolCatInfo.VolCatName, VolName, sizeof(dev->VolCatInfo.VolCatName));
339 bstrncpy(dcr->VolCatInfo.VolCatName, VolName, sizeof(dcr->VolCatInfo.VolCatName));
340 Dmsg1(150, "New VolName=%s\n", VolName);
341 if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
342 /* If device is not tape, attempt to create it */
343 if (dev->is_tape() || dev->open(dcr, CREATE_READ_WRITE) < 0) {
344 Jmsg3(dcr->jcr, M_WARNING, 0, _("Open device %s Volume \"%s\" failed: ERR=%s\n"),
345 dev->print_name(), dcr->VolumeName, dev->bstrerror());
349 Dmsg1(150, "Label type=%d\n", dev->label_type);
350 if (!dev->rewind(dcr)) {
351 Dmsg2(130, "Bad status on %s from rewind: ERR=%s\n", dev->print_name(), dev->print_errmsg());
357 /* Temporarily mark in append state to enable writing */
360 /* Create PRE_LABEL or VOL_LABEL if DVD */
361 create_volume_label(dev, VolName, PoolName, dvdnow);
364 * If we have already detected an ANSI label, re-read it
365 * to skip past it. Otherwise, we write a new one if
368 if (dev->label_type != B_BACULA_LABEL) {
369 if (read_ansi_ibm_label(dcr) != VOL_OK) {
373 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, VolName)) {
377 create_volume_label_record(dcr, dcr->rec);
378 dcr->rec->Stream = 0;
380 if (!write_record_to_block(dcr->block, dcr->rec)) {
381 Dmsg2(130, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
384 Dmsg2(130, "Wrote label of %d bytes to %s\n", dcr->rec->data_len, dev->print_name());
387 Dmsg0(130, "Call write_block_to_dev()\n");
388 if (!write_block_to_dev(dcr)) {
389 Dmsg2(130, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
393 /* Now commit block to DVD if we should write now */
394 if (dev->is_dvd() && dvdnow) {
395 Dmsg1(150, "New VolName=%s\n", dev->VolCatInfo.VolCatName);
396 if (!dvd_write_part(dcr)) {
397 Dmsg2(130, "Bad DVD write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
402 Dmsg0(130, " Wrote block to device\n");
406 write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
409 if (debug_level >= 20) {
410 dump_volume_label(dev);
412 Dmsg0(100, "Call reserve_volume\n");
413 if (reserve_volume(dcr, VolName) == NULL) {
414 Mmsg2(dcr->jcr->errmsg, _("Could not reserve volume %s on %s\n"),
415 dev->VolHdr.VolumeName, dev->print_name());
418 dev = dcr->dev; /* may have changed in reserve_volume */
420 dev->clear_append(); /* remove append since this is PRE_LABEL */
426 dev->clear_append(); /* remove append since this is PRE_LABEL */
431 * Write a volume label. This is ONLY called if we have a valid Bacula
432 * label of type PRE_LABEL;
433 * Returns: true if OK
434 * false if unable to write it
436 bool rewrite_volume_label(DCR *dcr, bool recycle)
438 DEVICE *dev = dcr->dev;
441 if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
442 Jmsg3(jcr, M_WARNING, 0, _("Open device %s Volume \"%s\" failed: ERR=%s\n"),
443 dev->print_name(), dcr->VolumeName, dev->bstrerror());
446 Dmsg2(190, "set append found freshly labeled volume. fd=%d dev=%x\n", dev->fd(), dev);
447 dev->VolHdr.LabelType = VOL_LABEL; /* set Volume label */
449 if (!write_volume_label_to_block(dcr)) {
450 Dmsg0(200, "Error from write volume label.\n");
453 Dmsg1(150, "wrote vol label to block. Vol=%s\n", dcr->VolumeName);
455 dev->VolCatInfo.VolCatBytes = 0; /* reset byte count */
458 * If we are not dealing with a streaming device,
459 * write the block now to ensure we have write permission.
460 * It is better to find out now rather than later.
461 * We do not write the block now if this is an ANSI label. This
462 * avoids re-writing the ANSI label, which we do not want to do.
464 if (!dev->has_cap(CAP_STREAM)) {
465 if (!dev->rewind(dcr)) {
466 Jmsg2(jcr, M_FATAL, 0, _("Rewind error on device %s: ERR=%s\n"),
467 dev->print_name(), dev->print_errmsg());
471 Dmsg1(150, "Doing recycle. Vol=%s\n", dcr->VolumeName);
472 // volume_unused(dcr); /* mark volume unused */
473 if (!dev->truncate(dcr)) {
474 Jmsg2(jcr, M_FATAL, 0, _("Truncate error on device %s: ERR=%s\n"),
475 dev->print_name(), dev->print_errmsg());
478 if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
479 Jmsg2(jcr, M_FATAL, 0,
480 _("Failed to re-open DVD after truncate on device %s: ERR=%s\n"),
481 dev->print_name(), dev->print_errmsg());
487 * If we have already detected an ANSI label, re-read it
488 * to skip past it. Otherwise, we write a new one if
491 if (dev->label_type != B_BACULA_LABEL) {
492 if (read_ansi_ibm_label(dcr) != VOL_OK) {
496 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, dev->VolHdr.VolumeName)) {
500 /* Attempt write to check write permission */
501 Dmsg1(200, "Attempt to write to device fd=%d.\n", dev->fd());
502 if (!write_block_to_dev(dcr)) {
503 Jmsg2(jcr, M_ERROR, 0, _("Unable to write device %s: ERR=%s\n"),
504 dev->print_name(), dev->print_errmsg());
505 Dmsg0(200, "===ERROR write block to dev\n");
510 /* Set or reset Volume statistics */
511 dev->VolCatInfo.VolCatJobs = 0;
512 dev->VolCatInfo.VolCatFiles = 0;
513 dev->VolCatInfo.VolCatErrors = 0;
514 dev->VolCatInfo.VolCatBlocks = 0;
515 dev->VolCatInfo.VolCatRBytes = 0;
517 dev->VolCatInfo.VolCatMounts++;
518 dev->VolCatInfo.VolCatRecycles++;
520 dev->VolCatInfo.VolCatMounts = 1;
521 dev->VolCatInfo.VolCatRecycles = 0;
522 dev->VolCatInfo.VolCatWrites = 1;
523 dev->VolCatInfo.VolCatReads = 1;
525 Dmsg1(150, "dir_update_vol_info. Set Append vol=%s\n", dcr->VolumeName);
526 bstrncpy(dev->VolCatInfo.VolCatStatus, "Append", sizeof(dev->VolCatInfo.VolCatStatus));
527 bstrncpy(dev->VolCatInfo.VolCatName, dcr->VolumeName, sizeof(dev->VolCatInfo.VolCatName));
528 if (!dir_update_volume_info(dcr, true, true)) { /* indicate doing relabel */
532 Jmsg(jcr, M_INFO, 0, _("Recycled volume \"%s\" on device %s, all previous data lost.\n"),
533 dcr->VolumeName, dev->print_name());
535 Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume \"%s\" on device %s\n"),
536 dcr->VolumeName, dev->print_name());
539 * End writing real Volume label (from pre-labeled tape), or recycling
542 Dmsg1(150, "OK from rewrite vol label. Vol=%s\n", dcr->VolumeName);
548 * create_volume_label_record
549 * Serialize label (from dev->VolHdr structure) into device record.
550 * Assumes that the dev->VolHdr structure is properly
553 static void create_volume_label_record(DCR *dcr, DEV_RECORD *rec)
557 DEVICE *dev = dcr->dev;
561 /* Serialize the label into the device record. */
563 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
564 ser_begin(rec->data, SER_LENGTH_Volume_Label);
565 ser_string(dev->VolHdr.Id);
567 ser_uint32(dev->VolHdr.VerNum);
569 if (dev->VolHdr.VerNum >= 11) {
570 ser_btime(dev->VolHdr.label_btime);
571 dev->VolHdr.write_btime = get_current_btime();
572 ser_btime(dev->VolHdr.write_btime);
573 dev->VolHdr.write_date = 0;
574 dev->VolHdr.write_time = 0;
576 /* OLD WAY DEPRECATED */
577 ser_float64(dev->VolHdr.label_date);
578 ser_float64(dev->VolHdr.label_time);
579 get_current_time(&dt);
580 dev->VolHdr.write_date = dt.julian_day_number;
581 dev->VolHdr.write_time = dt.julian_day_fraction;
583 ser_float64(dev->VolHdr.write_date); /* 0 if VerNum >= 11 */
584 ser_float64(dev->VolHdr.write_time); /* 0 if VerNum >= 11 */
586 ser_string(dev->VolHdr.VolumeName);
587 ser_string(dev->VolHdr.PrevVolumeName);
588 ser_string(dev->VolHdr.PoolName);
589 ser_string(dev->VolHdr.PoolType);
590 ser_string(dev->VolHdr.MediaType);
592 ser_string(dev->VolHdr.HostName);
593 ser_string(dev->VolHdr.LabelProg);
594 ser_string(dev->VolHdr.ProgVersion);
595 ser_string(dev->VolHdr.ProgDate);
597 ser_end(rec->data, SER_LENGTH_Volume_Label);
598 bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName));
599 rec->data_len = ser_length(rec->data);
600 rec->FileIndex = dev->VolHdr.LabelType;
601 rec->VolSessionId = jcr->VolSessionId;
602 rec->VolSessionTime = jcr->VolSessionTime;
603 rec->Stream = jcr->NumWriteVolumes;
604 Dmsg2(150, "Created Vol label rec: FI=%s len=%d\n", FI_to_ascii(buf, rec->FileIndex),
610 * Create a volume label in memory
612 void create_volume_label(DEVICE *dev, const char *VolName,
613 const char *PoolName, bool dvdnow)
615 DEVRES *device = (DEVRES *)dev->device;
617 Dmsg0(130, "Start create_volume_label()\n");
621 dev->clear_volhdr(); /* clear any old volume info */
623 bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
624 dev->VolHdr.VerNum = BaculaTapeVersion;
625 if (dev->is_dvd() && dvdnow) {
626 /* We do not want to re-label a DVD so write VOL_LABEL now */
627 dev->VolHdr.LabelType = VOL_LABEL;
629 dev->VolHdr.LabelType = PRE_LABEL; /* Mark tape as unused */
631 bstrncpy(dev->VolHdr.VolumeName, VolName, sizeof(dev->VolHdr.VolumeName));
632 bstrncpy(dev->VolHdr.PoolName, PoolName, sizeof(dev->VolHdr.PoolName));
633 bstrncpy(dev->VolHdr.MediaType, device->media_type, sizeof(dev->VolHdr.MediaType));
635 bstrncpy(dev->VolHdr.PoolType, "Backup", sizeof(dev->VolHdr.PoolType));
637 dev->VolHdr.label_btime = get_current_btime();
638 dev->VolHdr.label_date = 0;
639 dev->VolHdr.label_time = 0;
641 if (gethostname(dev->VolHdr.HostName, sizeof(dev->VolHdr.HostName)) != 0) {
642 dev->VolHdr.HostName[0] = 0;
644 bstrncpy(dev->VolHdr.LabelProg, my_name, sizeof(dev->VolHdr.LabelProg));
645 sprintf(dev->VolHdr.ProgVersion, "Ver. %s %s", VERSION, BDATE);
646 sprintf(dev->VolHdr.ProgDate, "Build %s %s", __DATE__, __TIME__);
647 dev->set_labeled(); /* set has Bacula label */
648 if (debug_level >= 90) {
649 dump_volume_label(dev);
654 * Create session label
655 * The pool memory must be released by the calling program
657 void create_session_label(DCR *dcr, DEV_RECORD *rec, int label)
662 rec->VolSessionId = jcr->VolSessionId;
663 rec->VolSessionTime = jcr->VolSessionTime;
664 rec->Stream = jcr->JobId;
666 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
667 ser_begin(rec->data, SER_LENGTH_Session_Label);
668 ser_string(BaculaId);
669 ser_uint32(BaculaTapeVersion);
671 ser_uint32(jcr->JobId);
673 /* Changed in VerNum 11 */
674 ser_btime(get_current_btime());
677 ser_string(dcr->pool_name);
678 ser_string(dcr->pool_type);
679 ser_string(jcr->job_name); /* base Job name */
680 ser_string(jcr->client_name);
682 /* Added in VerNum 10 */
683 ser_string(jcr->Job); /* Unique name of this Job */
684 ser_string(jcr->fileset_name);
685 ser_uint32(jcr->JobType);
686 ser_uint32(jcr->JobLevel);
687 /* Added in VerNum 11 */
688 ser_string(jcr->fileset_md5);
690 if (label == EOS_LABEL) {
691 ser_uint32(jcr->JobFiles);
692 ser_uint64(jcr->JobBytes);
693 ser_uint32(dcr->StartBlock);
694 ser_uint32(dcr->EndBlock);
695 ser_uint32(dcr->StartFile);
696 ser_uint32(dcr->EndFile);
697 ser_uint32(jcr->JobErrors);
699 /* Added in VerNum 11 */
700 ser_uint32(jcr->JobStatus);
702 ser_end(rec->data, SER_LENGTH_Session_Label);
703 rec->data_len = ser_length(rec->data);
706 /* Write session label
707 * Returns: false on failure
710 bool write_session_label(DCR *dcr, int label)
713 DEVICE *dev = dcr->dev;
715 DEV_BLOCK *block = dcr->block;
716 char buf1[100], buf2[100];
719 Dmsg1(130, "session_label record=%x\n", rec);
722 set_start_vol_position(dcr);
725 if (dev->is_tape()) {
726 dcr->EndBlock = dev->EndBlock;
727 dcr->EndFile = dev->EndFile;
729 dcr->EndBlock = (uint32_t)dev->file_addr;
730 dcr->EndFile = (uint32_t)(dev->file_addr >> 32);
734 Jmsg1(jcr, M_ABORT, 0, _("Bad Volume session label = %d\n"), label);
737 create_session_label(dcr, rec, label);
738 rec->FileIndex = label;
741 * We guarantee that the session record can totally fit
742 * into a block. If not, write the block, and put it in
743 * the next block. Having the sesssion record totally in
744 * one block makes reading them much easier (no need to
745 * read the next block).
747 if (!can_write_record_to_block(block, rec)) {
748 Dmsg0(150, "Cannot write session label to block.\n");
749 if (!write_block_to_device(dcr)) {
750 Dmsg0(130, "Got session label write_block_to_dev error.\n");
755 if (!write_record_to_block(block, rec)) {
760 Dmsg6(150, "Write sesson_label record JobId=%d FI=%s SessId=%d Strm=%s len=%d "
761 "remainder=%d\n", jcr->JobId,
762 FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
763 stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
767 Dmsg2(150, "Leave write_session_label Block=%ud File=%ud\n",
768 dev->get_block_num(), dev->get_file());
772 /* unser_volume_label
774 * Unserialize the Bacula Volume label into the device Volume_Label
777 * Assumes that the record is already read.
779 * Returns: false on error
783 bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec)
786 char buf1[100], buf2[100];
788 if (rec->FileIndex != VOL_LABEL && rec->FileIndex != PRE_LABEL) {
789 Mmsg3(dev->errmsg, _("Expecting Volume Label, got FI=%s Stream=%s len=%d\n"),
790 FI_to_ascii(buf1, rec->FileIndex),
791 stream_to_ascii(buf2, rec->Stream, rec->FileIndex),
798 dev->VolHdr.LabelType = rec->FileIndex;
799 dev->VolHdr.LabelSize = rec->data_len;
802 /* Unserialize the record into the Volume Header */
803 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
804 ser_begin(rec->data, SER_LENGTH_Volume_Label);
805 unser_string(dev->VolHdr.Id);
806 unser_uint32(dev->VolHdr.VerNum);
808 if (dev->VolHdr.VerNum >= 11) {
809 unser_btime(dev->VolHdr.label_btime);
810 unser_btime(dev->VolHdr.write_btime);
811 } else { /* old way */
812 unser_float64(dev->VolHdr.label_date);
813 unser_float64(dev->VolHdr.label_time);
815 unser_float64(dev->VolHdr.write_date); /* Unused with VerNum >= 11 */
816 unser_float64(dev->VolHdr.write_time); /* Unused with VerNum >= 11 */
818 unser_string(dev->VolHdr.VolumeName);
819 unser_string(dev->VolHdr.PrevVolumeName);
820 unser_string(dev->VolHdr.PoolName);
821 unser_string(dev->VolHdr.PoolType);
822 unser_string(dev->VolHdr.MediaType);
824 unser_string(dev->VolHdr.HostName);
825 unser_string(dev->VolHdr.LabelProg);
826 unser_string(dev->VolHdr.ProgVersion);
827 unser_string(dev->VolHdr.ProgDate);
829 ser_end(rec->data, SER_LENGTH_Volume_Label);
830 Dmsg0(190, "unser_vol_label\n");
831 if (debug_level >= 190) {
832 dump_volume_label(dev);
838 bool unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec)
842 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
843 unser_begin(rec->data, SER_LENGTH_Session_Label);
844 unser_string(label->Id);
845 unser_uint32(label->VerNum);
846 unser_uint32(label->JobId);
847 if (label->VerNum >= 11) {
848 unser_btime(label->write_btime);
850 unser_float64(label->write_date);
852 unser_float64(label->write_time);
853 unser_string(label->PoolName);
854 unser_string(label->PoolType);
855 unser_string(label->JobName);
856 unser_string(label->ClientName);
857 if (label->VerNum >= 10) {
858 unser_string(label->Job); /* Unique name of this Job */
859 unser_string(label->FileSetName);
860 unser_uint32(label->JobType);
861 unser_uint32(label->JobLevel);
863 if (label->VerNum >= 11) {
864 unser_string(label->FileSetMD5);
866 label->FileSetMD5[0] = 0;
868 if (rec->FileIndex == EOS_LABEL) {
869 unser_uint32(label->JobFiles);
870 unser_uint64(label->JobBytes);
871 unser_uint32(label->StartBlock);
872 unser_uint32(label->EndBlock);
873 unser_uint32(label->StartFile);
874 unser_uint32(label->EndFile);
875 unser_uint32(label->JobErrors);
876 if (label->VerNum >= 11) {
877 unser_uint32(label->JobStatus);
879 label->JobStatus = JS_Terminated; /* kludge */
885 void dump_volume_label(DEVICE *dev)
887 int dbl = debug_level;
889 const char *LabelType;
896 switch (dev->VolHdr.LabelType) {
898 LabelType = "PRE_LABEL";
901 LabelType = "VOL_LABEL";
904 LabelType = "EOM_LABEL";
907 LabelType = "SOS_LABEL";
910 LabelType = "EOS_LABEL";
916 sprintf(buf, _("Unknown %d"), dev->VolHdr.LabelType);
920 Pmsg11(-1, _("\nVolume Label:\n"
933 dev->VolHdr.Id, dev->VolHdr.VerNum,
934 dev->VolHdr.VolumeName, dev->VolHdr.PrevVolumeName,
935 File, LabelType, dev->VolHdr.LabelSize,
936 dev->VolHdr.PoolName, dev->VolHdr.MediaType,
937 dev->VolHdr.PoolType, dev->VolHdr.HostName);
939 if (dev->VolHdr.VerNum >= 11) {
941 bstrftime(dt, sizeof(dt), btime_to_unix(dev->VolHdr.label_btime));
942 Pmsg1(-1, _("Date label written: %s\n"), dt);
944 dt.julian_day_number = dev->VolHdr.label_date;
945 dt.julian_day_fraction = dev->VolHdr.label_time;
948 _("Date label written: %04d-%02d-%02d at %02d:%02d\n"),
949 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
957 static void dump_session_label(DEV_RECORD *rec, const char *type)
963 char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], ec6[30], ec7[30];
965 unser_session_label(&label, rec);
968 Pmsg7(-1, _("\n%s Record:\n"
975 ""), type, label.JobId, label.VerNum,
976 label.PoolName, label.PoolType,
977 label.JobName, label.ClientName);
979 if (label.VerNum >= 10) {
981 "Job (unique name) : %s\n"
985 ""), label.Job, label.FileSetName, label.JobType, label.JobLevel);
988 if (rec->FileIndex == EOS_LABEL) {
999 edit_uint64_with_commas(label.JobFiles, ec1),
1000 edit_uint64_with_commas(label.JobBytes, ec2),
1001 edit_uint64_with_commas(label.StartBlock, ec3),
1002 edit_uint64_with_commas(label.EndBlock, ec4),
1003 edit_uint64_with_commas(label.StartFile, ec5),
1004 edit_uint64_with_commas(label.EndFile, ec6),
1005 edit_uint64_with_commas(label.JobErrors, ec7),
1008 if (label.VerNum >= 11) {
1010 bstrftime(dt, sizeof(dt), btime_to_unix(label.write_btime));
1011 Pmsg1(-1, _("Date written : %s\n"), dt);
1013 dt.julian_day_number = label.write_date;
1014 dt.julian_day_fraction = label.write_time;
1015 tm_decode(&dt, &tm);
1016 Pmsg5(-1, _("Date written : %04d-%02d-%02d at %02d:%02d\n"),
1017 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
1023 void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose)
1028 if (rec->FileIndex == 0 && rec->VolSessionId == 0 && rec->VolSessionTime == 0) {
1033 switch (rec->FileIndex) {
1035 type = _("Fresh Volume");
1041 type = _("Begin Job Session");
1044 type = _("End Job Session");
1047 type = _("End of Media");
1050 type = _("End of Tape");
1053 type = _("Unknown");
1057 switch (rec->FileIndex) {
1060 unser_volume_label(dev, rec);
1061 dump_volume_label(dev);
1064 dump_session_label(rec, type);
1067 dump_session_label(rec, type);
1070 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1071 type, dev->file, dev->block_num, rec->VolSessionId,
1072 rec->VolSessionTime, rec->Stream, rec->data_len);
1075 Pmsg0(-1, _("End of physical tape.\n"));
1078 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1079 type, dev->file, dev->block_num, rec->VolSessionId,
1080 rec->VolSessionTime, rec->Stream, rec->data_len);
1084 SESSION_LABEL label;
1086 switch (rec->FileIndex) {
1088 unser_session_label(&label, rec);
1089 bstrftimes(dt, sizeof(dt), btime_to_unix(label.write_btime));
1090 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1091 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1092 Pmsg4(-1, _(" Job=%s Date=%s Level=%c Type=%c\n"),
1093 label.Job, dt, label.JobLevel, label.JobType);
1096 char ed1[30], ed2[30];
1097 unser_session_label(&label, rec);
1098 bstrftimes(dt, sizeof(dt), btime_to_unix(label.write_btime));
1099 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1100 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1101 Pmsg7(-1, _(" Date=%s Level=%c Type=%c Files=%s Bytes=%s Errors=%d Status=%c\n"),
1102 dt, label.JobLevel, label.JobType,
1103 edit_uint64_with_commas(label.JobFiles, ed1),
1104 edit_uint64_with_commas(label.JobBytes, ed2),
1105 label.JobErrors, (char)label.JobStatus);
1111 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1112 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime,
1113 rec->Stream, rec->data_len);