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) {
89 if (dev->is_labeled()) { /* did we already read label? */
90 /* Compare Volume Names allow special wild card */
91 if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolumeName, VolName) != 0) {
92 Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
93 dev->print_name(), VolName, dev->VolHdr.VolumeName);
95 * Cancel Job if too many label errors
98 if (!dev->poll && jcr->label_errors++ > 100) {
99 Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
101 Dmsg0(150, "return VOL_NAME_ERROR\n");
102 stat = VOL_NAME_ERROR;
105 Dmsg0(130, "Leave read_volume_label() VOL_OK\n");
106 return VOL_OK; /* label already read */
110 dev->clear_labeled();
113 dev->label_type = B_BACULA_LABEL;
115 if (!dev->rewind(dcr)) {
116 Mmsg(jcr->errmsg, _("Couldn't rewind device %s: ERR=%s\n"),
117 dev->print_name(), dev->print_errmsg());
118 Dmsg1(130, "return VOL_NO_MEDIA: %s", jcr->errmsg);
121 bstrncpy(dev->VolHdr.Id, "**error**", sizeof(dev->VolHdr.Id));
123 /* Read ANSI/IBM label if so requested */
124 want_ansi_label = dcr->VolCatInfo.LabelType != B_BACULA_LABEL ||
125 dcr->device->label_type != B_BACULA_LABEL;
126 if (want_ansi_label || dev->has_cap(CAP_CHECKLABELS)) {
127 stat = read_ansi_ibm_label(dcr);
128 /* If we want a label and didn't find it, return error */
129 if (want_ansi_label && stat != VOL_OK) {
132 if (stat == VOL_NAME_ERROR || stat == VOL_LABEL_ERROR) {
133 Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
134 dev->print_name(), VolName, dev->VolHdr.VolumeName);
135 if (!dev->poll && jcr->label_errors++ > 100) {
136 Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
140 if (stat != VOL_OK) { /* Not an ANSI/IBM label, so re-read */
143 have_ansi_label = true;
147 /* Read the Bacula Volume label block */
148 record = new_record();
151 Dmsg0(130, "Big if statement in read_volume_label\n");
152 if (!read_block_from_dev(dcr, NO_BLOCK_NUMBER_CHECK)) {
153 Mmsg(jcr->errmsg, _("Requested Volume \"%s\" on %s is not a Bacula "
154 "labeled Volume, because: ERR=%s"), NPRT(VolName),
155 dev->print_name(), dev->print_errmsg());
156 Dmsg1(130, "%s", jcr->errmsg);
157 } else if (!read_record_from_block(dcr, block, record)) {
158 Mmsg(jcr->errmsg, _("Could not read Volume label from block.\n"));
159 Dmsg1(130, "%s", jcr->errmsg);
160 } else if (!unser_volume_label(dev, record)) {
161 Mmsg(jcr->errmsg, _("Could not unserialize Volume label: ERR=%s\n"),
162 dev->print_errmsg());
163 Dmsg1(130, "%s", jcr->errmsg);
164 } else if (strcmp(dev->VolHdr.Id, BaculaId) != 0 &&
165 strcmp(dev->VolHdr.Id, OldBaculaId) != 0) {
166 Mmsg(jcr->errmsg, _("Volume Header Id bad: %s\n"), dev->VolHdr.Id);
167 Dmsg1(130, "%s", jcr->errmsg);
171 free_record(record); /* finished reading Volume record */
173 if (!dev->is_volume_to_unload()) {
178 if (forge_on || jcr->ignore_label_errors) {
179 dev->set_labeled(); /* set has Bacula label */
180 Jmsg(jcr, M_ERROR, 0, "%s", jcr->errmsg);
184 Dmsg0(100, "No volume label - bailing out\n");
189 /* At this point, we have read the first Bacula block, and
190 * then read the Bacula Volume label. Now we need to
191 * make sure we have the right Volume.
195 if (dev->VolHdr.VerNum != BaculaTapeVersion &&
196 dev->VolHdr.VerNum != OldCompatibleBaculaTapeVersion1 &&
197 dev->VolHdr.VerNum != OldCompatibleBaculaTapeVersion2) {
198 Mmsg(jcr->errmsg, _("Volume on %s has wrong Bacula version. Wanted %d got %d\n"),
199 dev->print_name(), BaculaTapeVersion, dev->VolHdr.VerNum);
200 Dmsg1(130, "VOL_VERSION_ERROR: %s", jcr->errmsg);
201 stat = VOL_VERSION_ERROR;
205 /* We are looking for either an unused Bacula tape (PRE_LABEL) or
206 * a Bacula volume label (VOL_LABEL)
208 if (dev->VolHdr.LabelType != PRE_LABEL && dev->VolHdr.LabelType != VOL_LABEL) {
209 Mmsg(jcr->errmsg, _("Volume on %s has bad Bacula label type: %x\n"),
210 dev->print_name(), dev->VolHdr.LabelType);
211 Dmsg1(130, "%s", jcr->errmsg);
212 if (!dev->poll && jcr->label_errors++ > 100) {
213 Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
215 Dmsg0(150, "return VOL_LABEL_ERROR\n");
216 stat = VOL_LABEL_ERROR;
220 dev->set_labeled(); /* set has Bacula label */
222 /* Compare Volume Names */
223 Dmsg2(130, "Compare Vol names: VolName=%s hdr=%s\n", VolName?VolName:"*", dev->VolHdr.VolumeName);
224 if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolumeName, VolName) != 0) {
225 Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
226 dev->print_name(), VolName, dev->VolHdr.VolumeName);
227 Dmsg1(130, "%s", jcr->errmsg);
229 * Cancel Job if too many label errors
230 * => we are in a loop
232 if (!dev->poll && jcr->label_errors++ > 100) {
233 Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
235 Dmsg0(150, "return VOL_NAME_ERROR\n");
236 stat = VOL_NAME_ERROR;
241 if (debug_level >= 10) {
242 dump_volume_label(dev);
244 Dmsg0(130, "Leave read_volume_label() VOL_OK\n");
245 /* If we are a streaming device, we only get one chance to read */
246 if (!dev->has_cap(CAP_STREAM)) {
248 if (have_ansi_label) {
249 stat = read_ansi_ibm_label(dcr);
250 /* If we want a label and didn't find it, return error */
251 if (stat != VOL_OK) {
257 Dmsg1(100, "Call reserve_volume=%s\n", dev->VolHdr.VolumeName);
258 if (reserve_volume(dcr, dev->VolHdr.VolumeName) == NULL) {
259 Mmsg2(jcr->errmsg, _("Could not reserve volume %s on %s\n"),
260 dev->VolHdr.VolumeName, dev->print_name());
261 stat = VOL_NAME_ERROR;
271 Dmsg1(150, "return %d\n", stat);
276 * Put a volume label into the block
278 * Returns: false on failure
281 bool write_volume_label_to_block(DCR *dcr)
284 DEVICE *dev = dcr->dev;
286 DEV_BLOCK *block = dcr->block;
288 Dmsg0(130, "write Label in write_volume_label_to_block()\n");
289 memset(&rec, 0, sizeof(rec));
290 rec.data = get_memory(SER_LENGTH_Volume_Label);
291 empty_block(block); /* Volume label always at beginning */
293 create_volume_label_record(dcr, &rec);
295 block->BlockNumber = 0;
296 if (!write_record_to_block(block, &rec)) {
297 free_pool_memory(rec.data);
298 Jmsg1(jcr, M_FATAL, 0, _("Cannot write Volume label to block for device %s\n"),
302 Dmsg2(130, "Wrote label of %d bytes to block. Vol=%s\n", rec.data_len,
305 free_pool_memory(rec.data);
311 * Write a Volume Label
312 * !!! Note, this is ONLY used for writing
313 * a fresh volume label. Any data
314 * after the label will be destroyed,
315 * in fact, we write the label 5 times !!!!
317 * This routine should be used only when labeling a blank tape.
319 bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName,
320 const char *PoolName, bool relabel, bool dvdnow)
322 DEVICE * volatile dev = dcr->dev;
325 Dmsg0(150, "write_volume_label()\n");
326 empty_block(dcr->block);
329 volume_unused(dcr); /* mark current volume unused */
330 /* Truncate device */
331 if (!dev->truncate(dcr)) {
334 if (!dev->is_tape()) {
335 dev->close_part(dcr); /* make sure DVD/file closed for rename */
339 /* Set the new filename for open, ... */
340 bstrncpy(dev->VolCatInfo.VolCatName, VolName, sizeof(dev->VolCatInfo.VolCatName));
341 bstrncpy(dcr->VolCatInfo.VolCatName, VolName, sizeof(dcr->VolCatInfo.VolCatName));
342 Dmsg1(150, "New VolName=%s\n", VolName);
343 if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
344 /* If device is not tape, attempt to create it */
345 if (dev->is_tape() || dev->open(dcr, CREATE_READ_WRITE) < 0) {
346 Jmsg3(dcr->jcr, M_WARNING, 0, _("Open device %s Volume \"%s\" failed: ERR=%s\n"),
347 dev->print_name(), dcr->VolumeName, dev->bstrerror());
351 Dmsg1(150, "Label type=%d\n", dev->label_type);
352 if (!dev->rewind(dcr)) {
353 Dmsg2(130, "Bad status on %s from rewind: ERR=%s\n", dev->print_name(), dev->print_errmsg());
359 /* Temporarily mark in append state to enable writing */
362 /* Create PRE_LABEL or VOL_LABEL if DVD */
363 create_volume_label(dev, VolName, PoolName, dvdnow);
366 * If we have already detected an ANSI label, re-read it
367 * to skip past it. Otherwise, we write a new one if
370 if (dev->label_type != B_BACULA_LABEL) {
371 if (read_ansi_ibm_label(dcr) != VOL_OK) {
375 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, VolName)) {
379 create_volume_label_record(dcr, dcr->rec);
380 dcr->rec->Stream = 0;
382 if (!write_record_to_block(dcr->block, dcr->rec)) {
383 Dmsg2(130, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
386 Dmsg2(130, "Wrote label of %d bytes to %s\n", dcr->rec->data_len, dev->print_name());
389 Dmsg0(130, "Call write_block_to_dev()\n");
390 if (!write_block_to_dev(dcr)) {
391 Dmsg2(130, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
395 /* Now commit block to DVD if we should write now */
396 if (dev->is_dvd() && dvdnow) {
397 Dmsg1(150, "New VolName=%s\n", dev->VolCatInfo.VolCatName);
398 if (!dvd_write_part(dcr)) {
399 Dmsg2(130, "Bad DVD write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
404 Dmsg0(130, " Wrote block to device\n");
408 write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
411 if (debug_level >= 20) {
412 dump_volume_label(dev);
414 Dmsg0(100, "Call reserve_volume\n");
415 if (reserve_volume(dcr, VolName) == NULL) {
416 Mmsg2(dcr->jcr->errmsg, _("Could not reserve volume %s on %s\n"),
417 dev->VolHdr.VolumeName, dev->print_name());
420 dev = dcr->dev; /* may have changed in reserve_volume */
422 dev->clear_append(); /* remove append since this is PRE_LABEL */
428 dev->clear_append(); /* remove append since this is PRE_LABEL */
433 * Write a volume label. This is ONLY called if we have a valid Bacula
434 * label of type PRE_LABEL;
435 * Returns: true if OK
436 * false if unable to write it
438 bool rewrite_volume_label(DCR *dcr, bool recycle)
440 DEVICE *dev = dcr->dev;
443 if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
444 Jmsg3(jcr, M_WARNING, 0, _("Open device %s Volume \"%s\" failed: ERR=%s\n"),
445 dev->print_name(), dcr->VolumeName, dev->bstrerror());
448 Dmsg2(190, "set append found freshly labeled volume. fd=%d dev=%x\n", dev->fd(), dev);
449 dev->VolHdr.LabelType = VOL_LABEL; /* set Volume label */
451 if (!write_volume_label_to_block(dcr)) {
452 Dmsg0(200, "Error from write volume label.\n");
455 Dmsg1(150, "wrote vol label to block. Vol=%s\n", dcr->VolumeName);
457 dev->VolCatInfo.VolCatBytes = 0; /* reset byte count */
460 * If we are not dealing with a streaming device,
461 * write the block now to ensure we have write permission.
462 * It is better to find out now rather than later.
463 * We do not write the block now if this is an ANSI label. This
464 * avoids re-writing the ANSI label, which we do not want to do.
466 if (!dev->has_cap(CAP_STREAM)) {
467 if (!dev->rewind(dcr)) {
468 Jmsg2(jcr, M_FATAL, 0, _("Rewind error on device %s: ERR=%s\n"),
469 dev->print_name(), dev->print_errmsg());
473 Dmsg1(150, "Doing recycle. Vol=%s\n", dcr->VolumeName);
474 // volume_unused(dcr); /* mark volume unused */
475 if (!dev->truncate(dcr)) {
476 Jmsg2(jcr, M_FATAL, 0, _("Truncate error on device %s: ERR=%s\n"),
477 dev->print_name(), dev->print_errmsg());
480 if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
481 Jmsg2(jcr, M_FATAL, 0,
482 _("Failed to re-open DVD after truncate on device %s: ERR=%s\n"),
483 dev->print_name(), dev->print_errmsg());
489 * If we have already detected an ANSI label, re-read it
490 * to skip past it. Otherwise, we write a new one if
493 if (dev->label_type != B_BACULA_LABEL) {
494 if (read_ansi_ibm_label(dcr) != VOL_OK) {
498 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, dev->VolHdr.VolumeName)) {
502 /* Attempt write to check write permission */
503 Dmsg1(200, "Attempt to write to device fd=%d.\n", dev->fd());
504 if (!write_block_to_dev(dcr)) {
505 Jmsg2(jcr, M_ERROR, 0, _("Unable to write device %s: ERR=%s\n"),
506 dev->print_name(), dev->print_errmsg());
507 Dmsg0(200, "===ERROR write block to dev\n");
512 /* Set or reset Volume statistics */
513 dev->VolCatInfo.VolCatJobs = 0;
514 dev->VolCatInfo.VolCatFiles = 0;
515 dev->VolCatInfo.VolCatErrors = 0;
516 dev->VolCatInfo.VolCatBlocks = 0;
517 dev->VolCatInfo.VolCatRBytes = 0;
519 dev->VolCatInfo.VolCatMounts++;
520 dev->VolCatInfo.VolCatRecycles++;
522 dev->VolCatInfo.VolCatMounts = 1;
523 dev->VolCatInfo.VolCatRecycles = 0;
524 dev->VolCatInfo.VolCatWrites = 1;
525 dev->VolCatInfo.VolCatReads = 1;
527 Dmsg1(150, "dir_update_vol_info. Set Append vol=%s\n", dcr->VolumeName);
528 bstrncpy(dev->VolCatInfo.VolCatStatus, "Append", sizeof(dev->VolCatInfo.VolCatStatus));
529 bstrncpy(dev->VolCatInfo.VolCatName, dcr->VolumeName, sizeof(dev->VolCatInfo.VolCatName));
530 if (!dir_update_volume_info(dcr, true, true)) { /* indicate doing relabel */
534 Jmsg(jcr, M_INFO, 0, _("Recycled volume \"%s\" on device %s, all previous data lost.\n"),
535 dcr->VolumeName, dev->print_name());
537 Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume \"%s\" on device %s\n"),
538 dcr->VolumeName, dev->print_name());
541 * End writing real Volume label (from pre-labeled tape), or recycling
544 Dmsg1(150, "OK from rewrite vol label. Vol=%s\n", dcr->VolumeName);
550 * create_volume_label_record
551 * Serialize label (from dev->VolHdr structure) into device record.
552 * Assumes that the dev->VolHdr structure is properly
555 static void create_volume_label_record(DCR *dcr, DEV_RECORD *rec)
559 DEVICE *dev = dcr->dev;
563 /* Serialize the label into the device record. */
565 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
566 ser_begin(rec->data, SER_LENGTH_Volume_Label);
567 ser_string(dev->VolHdr.Id);
569 ser_uint32(dev->VolHdr.VerNum);
571 if (dev->VolHdr.VerNum >= 11) {
572 ser_btime(dev->VolHdr.label_btime);
573 dev->VolHdr.write_btime = get_current_btime();
574 ser_btime(dev->VolHdr.write_btime);
575 dev->VolHdr.write_date = 0;
576 dev->VolHdr.write_time = 0;
578 /* OLD WAY DEPRECATED */
579 ser_float64(dev->VolHdr.label_date);
580 ser_float64(dev->VolHdr.label_time);
581 get_current_time(&dt);
582 dev->VolHdr.write_date = dt.julian_day_number;
583 dev->VolHdr.write_time = dt.julian_day_fraction;
585 ser_float64(dev->VolHdr.write_date); /* 0 if VerNum >= 11 */
586 ser_float64(dev->VolHdr.write_time); /* 0 if VerNum >= 11 */
588 ser_string(dev->VolHdr.VolumeName);
589 ser_string(dev->VolHdr.PrevVolumeName);
590 ser_string(dev->VolHdr.PoolName);
591 ser_string(dev->VolHdr.PoolType);
592 ser_string(dev->VolHdr.MediaType);
594 ser_string(dev->VolHdr.HostName);
595 ser_string(dev->VolHdr.LabelProg);
596 ser_string(dev->VolHdr.ProgVersion);
597 ser_string(dev->VolHdr.ProgDate);
599 ser_end(rec->data, SER_LENGTH_Volume_Label);
600 bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName));
601 rec->data_len = ser_length(rec->data);
602 rec->FileIndex = dev->VolHdr.LabelType;
603 rec->VolSessionId = jcr->VolSessionId;
604 rec->VolSessionTime = jcr->VolSessionTime;
605 rec->Stream = jcr->NumWriteVolumes;
606 Dmsg2(150, "Created Vol label rec: FI=%s len=%d\n", FI_to_ascii(buf, rec->FileIndex),
612 * Create a volume label in memory
614 void create_volume_label(DEVICE *dev, const char *VolName,
615 const char *PoolName, bool dvdnow)
617 DEVRES *device = (DEVRES *)dev->device;
619 Dmsg0(130, "Start create_volume_label()\n");
623 dev->clear_volhdr(); /* clear any old volume info */
625 bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
626 dev->VolHdr.VerNum = BaculaTapeVersion;
627 if (dev->is_dvd() && dvdnow) {
628 /* We do not want to re-label a DVD so write VOL_LABEL now */
629 dev->VolHdr.LabelType = VOL_LABEL;
631 dev->VolHdr.LabelType = PRE_LABEL; /* Mark tape as unused */
633 bstrncpy(dev->VolHdr.VolumeName, VolName, sizeof(dev->VolHdr.VolumeName));
634 bstrncpy(dev->VolHdr.PoolName, PoolName, sizeof(dev->VolHdr.PoolName));
635 bstrncpy(dev->VolHdr.MediaType, device->media_type, sizeof(dev->VolHdr.MediaType));
637 bstrncpy(dev->VolHdr.PoolType, "Backup", sizeof(dev->VolHdr.PoolType));
639 dev->VolHdr.label_btime = get_current_btime();
640 dev->VolHdr.label_date = 0;
641 dev->VolHdr.label_time = 0;
643 if (gethostname(dev->VolHdr.HostName, sizeof(dev->VolHdr.HostName)) != 0) {
644 dev->VolHdr.HostName[0] = 0;
646 bstrncpy(dev->VolHdr.LabelProg, my_name, sizeof(dev->VolHdr.LabelProg));
647 sprintf(dev->VolHdr.ProgVersion, "Ver. %s %s", VERSION, BDATE);
648 sprintf(dev->VolHdr.ProgDate, "Build %s %s", __DATE__, __TIME__);
649 dev->set_labeled(); /* set has Bacula label */
650 if (debug_level >= 90) {
651 dump_volume_label(dev);
656 * Create session label
657 * The pool memory must be released by the calling program
659 void create_session_label(DCR *dcr, DEV_RECORD *rec, int label)
664 rec->VolSessionId = jcr->VolSessionId;
665 rec->VolSessionTime = jcr->VolSessionTime;
666 rec->Stream = jcr->JobId;
668 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
669 ser_begin(rec->data, SER_LENGTH_Session_Label);
670 ser_string(BaculaId);
671 ser_uint32(BaculaTapeVersion);
673 ser_uint32(jcr->JobId);
675 /* Changed in VerNum 11 */
676 ser_btime(get_current_btime());
679 ser_string(dcr->pool_name);
680 ser_string(dcr->pool_type);
681 ser_string(jcr->job_name); /* base Job name */
682 ser_string(jcr->client_name);
684 /* Added in VerNum 10 */
685 ser_string(jcr->Job); /* Unique name of this Job */
686 ser_string(jcr->fileset_name);
687 ser_uint32(jcr->JobType);
688 ser_uint32(jcr->JobLevel);
689 /* Added in VerNum 11 */
690 ser_string(jcr->fileset_md5);
692 if (label == EOS_LABEL) {
693 ser_uint32(jcr->JobFiles);
694 ser_uint64(jcr->JobBytes);
695 ser_uint32(dcr->StartBlock);
696 ser_uint32(dcr->EndBlock);
697 ser_uint32(dcr->StartFile);
698 ser_uint32(dcr->EndFile);
699 ser_uint32(jcr->JobErrors);
701 /* Added in VerNum 11 */
702 ser_uint32(jcr->JobStatus);
704 ser_end(rec->data, SER_LENGTH_Session_Label);
705 rec->data_len = ser_length(rec->data);
708 /* Write session label
709 * Returns: false on failure
712 bool write_session_label(DCR *dcr, int label)
715 DEVICE *dev = dcr->dev;
717 DEV_BLOCK *block = dcr->block;
718 char buf1[100], buf2[100];
721 Dmsg1(130, "session_label record=%x\n", rec);
724 set_start_vol_position(dcr);
727 if (dev->is_tape()) {
728 dcr->EndBlock = dev->EndBlock;
729 dcr->EndFile = dev->EndFile;
731 dcr->EndBlock = (uint32_t)dev->file_addr;
732 dcr->EndFile = (uint32_t)(dev->file_addr >> 32);
736 Jmsg1(jcr, M_ABORT, 0, _("Bad Volume session label = %d\n"), label);
739 create_session_label(dcr, rec, label);
740 rec->FileIndex = label;
743 * We guarantee that the session record can totally fit
744 * into a block. If not, write the block, and put it in
745 * the next block. Having the sesssion record totally in
746 * one block makes reading them much easier (no need to
747 * read the next block).
749 if (!can_write_record_to_block(block, rec)) {
750 Dmsg0(150, "Cannot write session label to block.\n");
751 if (!write_block_to_device(dcr)) {
752 Dmsg0(130, "Got session label write_block_to_dev error.\n");
757 if (!write_record_to_block(block, rec)) {
762 Dmsg6(150, "Write sesson_label record JobId=%d FI=%s SessId=%d Strm=%s len=%d "
763 "remainder=%d\n", jcr->JobId,
764 FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
765 stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
769 Dmsg2(150, "Leave write_session_label Block=%ud File=%ud\n",
770 dev->get_block_num(), dev->get_file());
774 /* unser_volume_label
776 * Unserialize the Bacula Volume label into the device Volume_Label
779 * Assumes that the record is already read.
781 * Returns: false on error
785 bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec)
788 char buf1[100], buf2[100];
790 if (rec->FileIndex != VOL_LABEL && rec->FileIndex != PRE_LABEL) {
791 Mmsg3(dev->errmsg, _("Expecting Volume Label, got FI=%s Stream=%s len=%d\n"),
792 FI_to_ascii(buf1, rec->FileIndex),
793 stream_to_ascii(buf2, rec->Stream, rec->FileIndex),
800 dev->VolHdr.LabelType = rec->FileIndex;
801 dev->VolHdr.LabelSize = rec->data_len;
804 /* Unserialize the record into the Volume Header */
805 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
806 ser_begin(rec->data, SER_LENGTH_Volume_Label);
807 unser_string(dev->VolHdr.Id);
808 unser_uint32(dev->VolHdr.VerNum);
810 if (dev->VolHdr.VerNum >= 11) {
811 unser_btime(dev->VolHdr.label_btime);
812 unser_btime(dev->VolHdr.write_btime);
813 } else { /* old way */
814 unser_float64(dev->VolHdr.label_date);
815 unser_float64(dev->VolHdr.label_time);
817 unser_float64(dev->VolHdr.write_date); /* Unused with VerNum >= 11 */
818 unser_float64(dev->VolHdr.write_time); /* Unused with VerNum >= 11 */
820 unser_string(dev->VolHdr.VolumeName);
821 unser_string(dev->VolHdr.PrevVolumeName);
822 unser_string(dev->VolHdr.PoolName);
823 unser_string(dev->VolHdr.PoolType);
824 unser_string(dev->VolHdr.MediaType);
826 unser_string(dev->VolHdr.HostName);
827 unser_string(dev->VolHdr.LabelProg);
828 unser_string(dev->VolHdr.ProgVersion);
829 unser_string(dev->VolHdr.ProgDate);
831 ser_end(rec->data, SER_LENGTH_Volume_Label);
832 Dmsg0(190, "unser_vol_label\n");
833 if (debug_level >= 190) {
834 dump_volume_label(dev);
840 bool unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec)
844 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
845 unser_begin(rec->data, SER_LENGTH_Session_Label);
846 unser_string(label->Id);
847 unser_uint32(label->VerNum);
848 unser_uint32(label->JobId);
849 if (label->VerNum >= 11) {
850 unser_btime(label->write_btime);
852 unser_float64(label->write_date);
854 unser_float64(label->write_time);
855 unser_string(label->PoolName);
856 unser_string(label->PoolType);
857 unser_string(label->JobName);
858 unser_string(label->ClientName);
859 if (label->VerNum >= 10) {
860 unser_string(label->Job); /* Unique name of this Job */
861 unser_string(label->FileSetName);
862 unser_uint32(label->JobType);
863 unser_uint32(label->JobLevel);
865 if (label->VerNum >= 11) {
866 unser_string(label->FileSetMD5);
868 label->FileSetMD5[0] = 0;
870 if (rec->FileIndex == EOS_LABEL) {
871 unser_uint32(label->JobFiles);
872 unser_uint64(label->JobBytes);
873 unser_uint32(label->StartBlock);
874 unser_uint32(label->EndBlock);
875 unser_uint32(label->StartFile);
876 unser_uint32(label->EndFile);
877 unser_uint32(label->JobErrors);
878 if (label->VerNum >= 11) {
879 unser_uint32(label->JobStatus);
881 label->JobStatus = JS_Terminated; /* kludge */
887 void dump_volume_label(DEVICE *dev)
889 int dbl = debug_level;
891 const char *LabelType;
898 switch (dev->VolHdr.LabelType) {
900 LabelType = "PRE_LABEL";
903 LabelType = "VOL_LABEL";
906 LabelType = "EOM_LABEL";
909 LabelType = "SOS_LABEL";
912 LabelType = "EOS_LABEL";
918 sprintf(buf, _("Unknown %d"), dev->VolHdr.LabelType);
922 Pmsg11(-1, _("\nVolume Label:\n"
935 dev->VolHdr.Id, dev->VolHdr.VerNum,
936 dev->VolHdr.VolumeName, dev->VolHdr.PrevVolumeName,
937 File, LabelType, dev->VolHdr.LabelSize,
938 dev->VolHdr.PoolName, dev->VolHdr.MediaType,
939 dev->VolHdr.PoolType, dev->VolHdr.HostName);
941 if (dev->VolHdr.VerNum >= 11) {
943 bstrftime(dt, sizeof(dt), btime_to_unix(dev->VolHdr.label_btime));
944 Pmsg1(-1, _("Date label written: %s\n"), dt);
946 dt.julian_day_number = dev->VolHdr.label_date;
947 dt.julian_day_fraction = dev->VolHdr.label_time;
950 _("Date label written: %04d-%02d-%02d at %02d:%02d\n"),
951 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
959 static void dump_session_label(DEV_RECORD *rec, const char *type)
965 char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], ec6[30], ec7[30];
967 unser_session_label(&label, rec);
970 Pmsg7(-1, _("\n%s Record:\n"
977 ""), type, label.JobId, label.VerNum,
978 label.PoolName, label.PoolType,
979 label.JobName, label.ClientName);
981 if (label.VerNum >= 10) {
983 "Job (unique name) : %s\n"
987 ""), label.Job, label.FileSetName, label.JobType, label.JobLevel);
990 if (rec->FileIndex == EOS_LABEL) {
1001 edit_uint64_with_commas(label.JobFiles, ec1),
1002 edit_uint64_with_commas(label.JobBytes, ec2),
1003 edit_uint64_with_commas(label.StartBlock, ec3),
1004 edit_uint64_with_commas(label.EndBlock, ec4),
1005 edit_uint64_with_commas(label.StartFile, ec5),
1006 edit_uint64_with_commas(label.EndFile, ec6),
1007 edit_uint64_with_commas(label.JobErrors, ec7),
1010 if (label.VerNum >= 11) {
1012 bstrftime(dt, sizeof(dt), btime_to_unix(label.write_btime));
1013 Pmsg1(-1, _("Date written : %s\n"), dt);
1015 dt.julian_day_number = label.write_date;
1016 dt.julian_day_fraction = label.write_time;
1017 tm_decode(&dt, &tm);
1018 Pmsg5(-1, _("Date written : %04d-%02d-%02d at %02d:%02d\n"),
1019 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
1025 void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose)
1030 if (rec->FileIndex == 0 && rec->VolSessionId == 0 && rec->VolSessionTime == 0) {
1035 switch (rec->FileIndex) {
1037 type = _("Fresh Volume");
1043 type = _("Begin Job Session");
1046 type = _("End Job Session");
1049 type = _("End of Media");
1052 type = _("End of Tape");
1055 type = _("Unknown");
1059 switch (rec->FileIndex) {
1062 unser_volume_label(dev, rec);
1063 dump_volume_label(dev);
1066 dump_session_label(rec, type);
1069 dump_session_label(rec, type);
1072 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1073 type, dev->file, dev->block_num, rec->VolSessionId,
1074 rec->VolSessionTime, rec->Stream, rec->data_len);
1077 Pmsg0(-1, _("End of physical tape.\n"));
1080 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1081 type, dev->file, dev->block_num, rec->VolSessionId,
1082 rec->VolSessionTime, rec->Stream, rec->data_len);
1086 SESSION_LABEL label;
1088 switch (rec->FileIndex) {
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 Pmsg4(-1, _(" Job=%s Date=%s Level=%c Type=%c\n"),
1095 label.Job, dt, label.JobLevel, label.JobType);
1098 char ed1[30], ed2[30];
1099 unser_session_label(&label, rec);
1100 bstrftimes(dt, sizeof(dt), btime_to_unix(label.write_btime));
1101 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1102 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1103 Pmsg7(-1, _(" Date=%s Level=%c Type=%c Files=%s Bytes=%s Errors=%d Status=%c\n"),
1104 dt, label.JobLevel, label.JobType,
1105 edit_uint64_with_commas(label.JobFiles, ed1),
1106 edit_uint64_with_commas(label.JobBytes, ed2),
1107 label.JobErrors, (char)label.JobStatus);
1113 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1114 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime,
1115 rec->Stream, rec->data_len);