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 *dev = dcr->dev;
71 char *VolName = dcr->VolumeName;
74 DEV_BLOCK *block = dcr->block;
77 bool have_ansi_label = false;
79 Dmsg4(100, "Enter read_volume_label res=%d device=%s vol=%s dev_Vol=%s\n",
80 dev->reserved_device, dev->print_name(), VolName,
81 dev->VolHdr.VolumeName[0]?dev->VolHdr.VolumeName:"*NULL*");
83 if (!dev->is_open()) {
84 if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
88 if (dev->is_labeled()) { /* did we already read label? */
89 /* Compare Volume Names allow special wild card */
90 if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolumeName, VolName) != 0) {
91 Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
92 dev->print_name(), VolName, dev->VolHdr.VolumeName);
94 * Cancel Job if too many label errors
97 if (!dev->poll && jcr->label_errors++ > 100) {
98 Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
100 Dmsg0(150, "return VOL_NAME_ERROR\n");
101 stat = VOL_NAME_ERROR;
104 Dmsg0(130, "Leave read_volume_label() VOL_OK\n");
105 return VOL_OK; /* label already read */
108 dev->clear_labeled();
111 dev->label_type = B_BACULA_LABEL;
113 if (!dev->rewind(dcr)) {
114 Mmsg(jcr->errmsg, _("Couldn't rewind device %s: ERR=%s\n"),
115 dev->print_name(), dev->print_errmsg());
116 Dmsg1(130, "return VOL_NO_MEDIA: %s", jcr->errmsg);
119 bstrncpy(dev->VolHdr.Id, "**error**", sizeof(dev->VolHdr.Id));
121 /* Read ANSI/IBM label if so requested */
122 want_ansi_label = dcr->VolCatInfo.LabelType != B_BACULA_LABEL ||
123 dcr->device->label_type != B_BACULA_LABEL;
124 if (want_ansi_label || dev->has_cap(CAP_CHECKLABELS)) {
125 stat = read_ansi_ibm_label(dcr);
126 /* If we want a label and didn't find it, return error */
127 if (want_ansi_label && stat != VOL_OK) {
130 if (stat == VOL_NAME_ERROR || stat == VOL_LABEL_ERROR) {
131 Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
132 dev->print_name(), VolName, dev->VolHdr.VolumeName);
133 if (!dev->poll && jcr->label_errors++ > 100) {
134 Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
138 if (stat != VOL_OK) { /* Not an ANSI/IBM label, so re-read */
141 have_ansi_label = true;
145 /* Read the Bacula Volume label block */
146 record = new_record();
149 Dmsg0(130, "Big if statement in read_volume_label\n");
150 if (!read_block_from_dev(dcr, NO_BLOCK_NUMBER_CHECK)) {
151 Mmsg(jcr->errmsg, _("Requested Volume \"%s\" on %s is not a Bacula "
152 "labeled Volume, because: ERR=%s"), NPRT(VolName),
153 dev->print_name(), dev->print_errmsg());
154 Dmsg1(130, "%s", jcr->errmsg);
155 } else if (!read_record_from_block(dcr, block, record)) {
156 Mmsg(jcr->errmsg, _("Could not read Volume label from block.\n"));
157 Dmsg1(130, "%s", jcr->errmsg);
158 } else if (!unser_volume_label(dev, record)) {
159 Mmsg(jcr->errmsg, _("Could not unserialize Volume label: ERR=%s\n"),
160 dev->print_errmsg());
161 Dmsg1(130, "%s", jcr->errmsg);
162 } else if (strcmp(dev->VolHdr.Id, BaculaId) != 0 &&
163 strcmp(dev->VolHdr.Id, OldBaculaId) != 0) {
164 Mmsg(jcr->errmsg, _("Volume Header Id bad: %s\n"), dev->VolHdr.Id);
165 Dmsg1(130, "%s", jcr->errmsg);
169 free_record(record); /* finished reading Volume record */
172 if (forge_on || jcr->ignore_label_errors) {
173 dev->set_labeled(); /* set has Bacula label */
174 Jmsg(jcr, M_ERROR, 0, "%s", jcr->errmsg);
178 Dmsg0(100, "No volume label - bailing out\n");
183 /* At this point, we have read the first Bacula block, and
184 * then read the Bacula Volume label. Now we need to
185 * make sure we have the right Volume.
189 if (dev->VolHdr.VerNum != BaculaTapeVersion &&
190 dev->VolHdr.VerNum != OldCompatibleBaculaTapeVersion1 &&
191 dev->VolHdr.VerNum != OldCompatibleBaculaTapeVersion2) {
192 Mmsg(jcr->errmsg, _("Volume on %s has wrong Bacula version. Wanted %d got %d\n"),
193 dev->print_name(), BaculaTapeVersion, dev->VolHdr.VerNum);
194 Dmsg1(130, "VOL_VERSION_ERROR: %s", jcr->errmsg);
195 stat = VOL_VERSION_ERROR;
199 /* We are looking for either an unused Bacula tape (PRE_LABEL) or
200 * a Bacula volume label (VOL_LABEL)
202 if (dev->VolHdr.LabelType != PRE_LABEL && dev->VolHdr.LabelType != VOL_LABEL) {
203 Mmsg(jcr->errmsg, _("Volume on %s has bad Bacula label type: %x\n"),
204 dev->print_name(), dev->VolHdr.LabelType);
205 Dmsg1(130, "%s", jcr->errmsg);
206 if (!dev->poll && jcr->label_errors++ > 100) {
207 Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
209 Dmsg0(150, "return VOL_LABEL_ERROR\n");
210 stat = VOL_LABEL_ERROR;
214 dev->set_labeled(); /* set has Bacula label */
215 if (reserve_volume(dcr, dev->VolHdr.VolumeName) == NULL) {
216 Mmsg2(jcr->errmsg, _("Could not reserve volume %s on %s\n"),
217 dev->VolHdr.VolumeName, dev->print_name());
218 stat = VOL_NAME_ERROR;
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;
239 Dmsg1(130, "Copy vol_name=%s\n", dev->VolHdr.VolumeName);
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) {
260 volume_unused(dcr); /* mark volume "released" */
263 Dmsg1(150, "return %d\n", stat);
268 * Put a volume label into the block
270 * Returns: false on failure
273 bool write_volume_label_to_block(DCR *dcr)
276 DEVICE *dev = dcr->dev;
278 DEV_BLOCK *block = dcr->block;
280 Dmsg0(130, "write Label in write_volume_label_to_block()\n");
281 memset(&rec, 0, sizeof(rec));
282 rec.data = get_memory(SER_LENGTH_Volume_Label);
283 empty_block(block); /* Volume label always at beginning */
285 create_volume_label_record(dcr, &rec);
287 block->BlockNumber = 0;
288 if (!write_record_to_block(block, &rec)) {
289 free_pool_memory(rec.data);
290 Jmsg1(jcr, M_FATAL, 0, _("Cannot write Volume label to block for device %s\n"),
294 Dmsg1(130, "Wrote label of %d bytes to block\n", rec.data_len);
296 free_pool_memory(rec.data);
302 * Write a Volume Label
303 * !!! Note, this is ONLY used for writing
304 * a fresh volume label. Any data
305 * after the label will be destroyed,
306 * in fact, we write the label 5 times !!!!
308 * This routine should be used only when labeling a blank tape.
310 bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName,
311 const char *PoolName, bool relabel, bool dvdnow)
313 DEVICE *dev = dcr->dev;
316 Dmsg0(150, "write_volume_label()\n");
317 empty_block(dcr->block);
320 volume_unused(dcr); /* mark current volume unused */
321 /* Truncate device */
322 if (!dev->truncate(dcr)) {
325 if (!dev->is_tape()) {
326 dev->close_part(dcr); /* make sure DVD/file closed for rename */
330 /* Set the new filename for open, ... */
331 bstrncpy(dev->VolCatInfo.VolCatName, VolName, sizeof(dev->VolCatInfo.VolCatName));
332 bstrncpy(dcr->VolCatInfo.VolCatName, VolName, sizeof(dcr->VolCatInfo.VolCatName));
333 Dmsg1(150, "New VolName=%s\n", VolName);
334 if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
335 /* If device is not tape, attempt to create it */
336 if (dev->is_tape() || dev->open(dcr, CREATE_READ_WRITE) < 0) {
340 Dmsg1(150, "Label type=%d\n", dev->label_type);
341 if (!dev->rewind(dcr)) {
342 Dmsg2(130, "Bad status on %s from rewind: ERR=%s\n", dev->print_name(), dev->print_errmsg());
348 /* Temporarily mark in append state to enable writing */
351 /* Create PRE_LABEL or VOL_LABEL if DVD */
352 create_volume_label(dev, VolName, PoolName, dvdnow);
355 * If we have already detected an ANSI label, re-read it
356 * to skip past it. Otherwise, we write a new one if
359 if (dev->label_type != B_BACULA_LABEL) {
360 if (read_ansi_ibm_label(dcr) != VOL_OK) {
364 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, VolName)) {
368 create_volume_label_record(dcr, dcr->rec);
369 dcr->rec->Stream = 0;
371 if (!write_record_to_block(dcr->block, dcr->rec)) {
372 Dmsg2(130, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
375 Dmsg2(130, "Wrote label of %d bytes to %s\n", dcr->rec->data_len, dev->print_name());
378 Dmsg0(130, "Call write_block_to_dev()\n");
379 if (!write_block_to_dev(dcr)) {
380 Dmsg2(130, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
384 /* Now commit block to DVD if we should write now */
385 if (dev->is_dvd() && dvdnow) {
386 Dmsg1(150, "New VolName=%s\n", dev->VolCatInfo.VolCatName);
387 if (!dvd_write_part(dcr)) {
388 Dmsg2(130, "Bad DVD write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
393 Dmsg0(130, " Wrote block to device\n");
397 write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
400 if (debug_level >= 20) {
401 dump_volume_label(dev);
403 if (reserve_volume(dcr, VolName) == NULL) {
404 Mmsg2(dcr->jcr->errmsg, _("Could not reserve volume %s on %s\n"),
405 dev->VolHdr.VolumeName, dev->print_name());
409 dev->clear_append(); /* remove append since this is PRE_LABEL */
415 dev->clear_append(); /* remove append since this is PRE_LABEL */
420 * Write a volume label. This is ONLY called if we have a valid Bacula
421 * label of type PRE_LABEL;
422 * Returns: true if OK
423 * false if unable to write it
425 bool rewrite_volume_label(DCR *dcr, bool recycle)
427 DEVICE *dev = dcr->dev;
430 if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
433 Dmsg2(190, "set append found freshly labeled volume. fd=%d dev=%x\n", dev->fd(), dev);
434 dev->VolHdr.LabelType = VOL_LABEL; /* set Volume label */
436 if (!write_volume_label_to_block(dcr)) {
437 Dmsg0(200, "Error from write volume label.\n");
441 dev->VolCatInfo.VolCatBytes = 0; /* reset byte count */
444 * If we are not dealing with a streaming device,
445 * write the block now to ensure we have write permission.
446 * It is better to find out now rather than later.
447 * We do not write the block now if this is an ANSI label. This
448 * avoids re-writing the ANSI label, which we do not want to do.
450 if (!dev->has_cap(CAP_STREAM)) {
451 if (!dev->rewind(dcr)) {
452 Jmsg2(jcr, M_FATAL, 0, _("Rewind error on device %s: ERR=%s\n"),
453 dev->print_name(), dev->print_errmsg());
457 volume_unused(dcr); /* mark volume unused */
458 if (!dev->truncate(dcr)) {
459 Jmsg2(jcr, M_FATAL, 0, _("Truncate error on device %s: ERR=%s\n"),
460 dev->print_name(), dev->print_errmsg());
463 if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
464 Jmsg2(jcr, M_FATAL, 0,
465 _("Failed to re-open DVD after truncate on device %s: ERR=%s\n"),
466 dev->print_name(), dev->print_errmsg());
472 * If we have already detected an ANSI label, re-read it
473 * to skip past it. Otherwise, we write a new one if
476 if (dev->label_type != B_BACULA_LABEL) {
477 if (read_ansi_ibm_label(dcr) != VOL_OK) {
481 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, dev->VolHdr.VolumeName)) {
485 /* Attempt write to check write permission */
486 Dmsg1(200, "Attempt to write to device fd=%d.\n", dev->fd());
487 if (!write_block_to_dev(dcr)) {
488 Jmsg2(jcr, M_ERROR, 0, _("Unable to write device %s: ERR=%s\n"),
489 dev->print_name(), dev->print_errmsg());
490 Dmsg0(200, "===ERROR write block to dev\n");
495 /* Set or reset Volume statistics */
496 dev->VolCatInfo.VolCatJobs = 0;
497 dev->VolCatInfo.VolCatFiles = 0;
498 dev->VolCatInfo.VolCatErrors = 0;
499 dev->VolCatInfo.VolCatBlocks = 0;
500 dev->VolCatInfo.VolCatRBytes = 0;
502 dev->VolCatInfo.VolCatMounts++;
503 dev->VolCatInfo.VolCatRecycles++;
505 dev->VolCatInfo.VolCatMounts = 1;
506 dev->VolCatInfo.VolCatRecycles = 0;
507 dev->VolCatInfo.VolCatWrites = 1;
508 dev->VolCatInfo.VolCatReads = 1;
510 Dmsg0(150, "dir_update_vol_info. Set Append\n");
511 bstrncpy(dev->VolCatInfo.VolCatStatus, "Append", sizeof(dev->VolCatInfo.VolCatStatus));
512 if (!dir_update_volume_info(dcr, true, true)) { /* indicate doing relabel */
516 Jmsg(jcr, M_INFO, 0, _("Recycled volume \"%s\" on device %s, all previous data lost.\n"),
517 dcr->VolumeName, dev->print_name());
519 Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume \"%s\" on device %s\n"),
520 dcr->VolumeName, dev->print_name());
523 * End writing real Volume label (from pre-labeled tape), or recycling
526 Dmsg0(200, "OK from rewrite vol label.\n");
532 * create_volume_label_record
533 * Serialize label (from dev->VolHdr structure) into device record.
534 * Assumes that the dev->VolHdr structure is properly
537 static void create_volume_label_record(DCR *dcr, DEV_RECORD *rec)
541 DEVICE *dev = dcr->dev;
545 /* Serialize the label into the device record. */
547 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
548 ser_begin(rec->data, SER_LENGTH_Volume_Label);
549 ser_string(dev->VolHdr.Id);
551 ser_uint32(dev->VolHdr.VerNum);
553 if (dev->VolHdr.VerNum >= 11) {
554 ser_btime(dev->VolHdr.label_btime);
555 dev->VolHdr.write_btime = get_current_btime();
556 ser_btime(dev->VolHdr.write_btime);
557 dev->VolHdr.write_date = 0;
558 dev->VolHdr.write_time = 0;
560 /* OLD WAY DEPRECATED */
561 ser_float64(dev->VolHdr.label_date);
562 ser_float64(dev->VolHdr.label_time);
563 get_current_time(&dt);
564 dev->VolHdr.write_date = dt.julian_day_number;
565 dev->VolHdr.write_time = dt.julian_day_fraction;
567 ser_float64(dev->VolHdr.write_date); /* 0 if VerNum >= 11 */
568 ser_float64(dev->VolHdr.write_time); /* 0 if VerNum >= 11 */
570 ser_string(dev->VolHdr.VolumeName);
571 ser_string(dev->VolHdr.PrevVolumeName);
572 ser_string(dev->VolHdr.PoolName);
573 ser_string(dev->VolHdr.PoolType);
574 ser_string(dev->VolHdr.MediaType);
576 ser_string(dev->VolHdr.HostName);
577 ser_string(dev->VolHdr.LabelProg);
578 ser_string(dev->VolHdr.ProgVersion);
579 ser_string(dev->VolHdr.ProgDate);
581 ser_end(rec->data, SER_LENGTH_Volume_Label);
582 rec->data_len = ser_length(rec->data);
583 rec->FileIndex = dev->VolHdr.LabelType;
584 rec->VolSessionId = jcr->VolSessionId;
585 rec->VolSessionTime = jcr->VolSessionTime;
586 rec->Stream = jcr->NumWriteVolumes;
587 Dmsg2(150, "Created Vol label rec: FI=%s len=%d\n", FI_to_ascii(buf, rec->FileIndex),
593 * Create a volume label in memory
595 void create_volume_label(DEVICE *dev, const char *VolName,
596 const char *PoolName, bool dvdnow)
598 DEVRES *device = (DEVRES *)dev->device;
600 Dmsg0(130, "Start create_volume_label()\n");
604 dev->clear_volhdr(); /* clear any old volume info */
606 bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
607 dev->VolHdr.VerNum = BaculaTapeVersion;
608 if (dev->is_dvd() && dvdnow) {
609 /* We do not want to re-label a DVD so write VOL_LABEL now */
610 dev->VolHdr.LabelType = VOL_LABEL;
612 dev->VolHdr.LabelType = PRE_LABEL; /* Mark tape as unused */
614 bstrncpy(dev->VolHdr.VolumeName, VolName, sizeof(dev->VolHdr.VolumeName));
615 bstrncpy(dev->VolHdr.PoolName, PoolName, sizeof(dev->VolHdr.PoolName));
616 bstrncpy(dev->VolHdr.MediaType, device->media_type, sizeof(dev->VolHdr.MediaType));
618 bstrncpy(dev->VolHdr.PoolType, "Backup", sizeof(dev->VolHdr.PoolType));
620 dev->VolHdr.label_btime = get_current_btime();
621 dev->VolHdr.label_date = 0;
622 dev->VolHdr.label_time = 0;
624 if (gethostname(dev->VolHdr.HostName, sizeof(dev->VolHdr.HostName)) != 0) {
625 dev->VolHdr.HostName[0] = 0;
627 bstrncpy(dev->VolHdr.LabelProg, my_name, sizeof(dev->VolHdr.LabelProg));
628 sprintf(dev->VolHdr.ProgVersion, "Ver. %s %s", VERSION, BDATE);
629 sprintf(dev->VolHdr.ProgDate, "Build %s %s", __DATE__, __TIME__);
630 dev->set_labeled(); /* set has Bacula label */
631 if (debug_level >= 90) {
632 dump_volume_label(dev);
637 * Create session label
638 * The pool memory must be released by the calling program
640 void create_session_label(DCR *dcr, DEV_RECORD *rec, int label)
645 rec->VolSessionId = jcr->VolSessionId;
646 rec->VolSessionTime = jcr->VolSessionTime;
647 rec->Stream = jcr->JobId;
649 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
650 ser_begin(rec->data, SER_LENGTH_Session_Label);
651 ser_string(BaculaId);
652 ser_uint32(BaculaTapeVersion);
654 ser_uint32(jcr->JobId);
656 /* Changed in VerNum 11 */
657 ser_btime(get_current_btime());
660 ser_string(dcr->pool_name);
661 ser_string(dcr->pool_type);
662 ser_string(jcr->job_name); /* base Job name */
663 ser_string(jcr->client_name);
665 /* Added in VerNum 10 */
666 ser_string(jcr->Job); /* Unique name of this Job */
667 ser_string(jcr->fileset_name);
668 ser_uint32(jcr->JobType);
669 ser_uint32(jcr->JobLevel);
670 /* Added in VerNum 11 */
671 ser_string(jcr->fileset_md5);
673 if (label == EOS_LABEL) {
674 ser_uint32(jcr->JobFiles);
675 ser_uint64(jcr->JobBytes);
676 ser_uint32(dcr->StartBlock);
677 ser_uint32(dcr->EndBlock);
678 ser_uint32(dcr->StartFile);
679 ser_uint32(dcr->EndFile);
680 ser_uint32(jcr->JobErrors);
682 /* Added in VerNum 11 */
683 ser_uint32(jcr->JobStatus);
685 ser_end(rec->data, SER_LENGTH_Session_Label);
686 rec->data_len = ser_length(rec->data);
689 /* Write session label
690 * Returns: false on failure
693 bool write_session_label(DCR *dcr, int label)
696 DEVICE *dev = dcr->dev;
698 DEV_BLOCK *block = dcr->block;
699 char buf1[100], buf2[100];
702 Dmsg1(130, "session_label record=%x\n", rec);
705 set_start_vol_position(dcr);
708 if (dev->is_tape()) {
709 dcr->EndBlock = dev->EndBlock;
710 dcr->EndFile = dev->EndFile;
712 dcr->EndBlock = (uint32_t)dev->file_addr;
713 dcr->EndFile = (uint32_t)(dev->file_addr >> 32);
717 Jmsg1(jcr, M_ABORT, 0, _("Bad Volume session label = %d\n"), label);
720 create_session_label(dcr, rec, label);
721 rec->FileIndex = label;
724 * We guarantee that the session record can totally fit
725 * into a block. If not, write the block, and put it in
726 * the next block. Having the sesssion record totally in
727 * one block makes reading them much easier (no need to
728 * read the next block).
730 if (!can_write_record_to_block(block, rec)) {
731 Dmsg0(150, "Cannot write session label to block.\n");
732 if (!write_block_to_device(dcr)) {
733 Dmsg0(130, "Got session label write_block_to_dev error.\n");
738 if (!write_record_to_block(block, rec)) {
743 Dmsg6(150, "Write sesson_label record JobId=%d FI=%s SessId=%d Strm=%s len=%d "
744 "remainder=%d\n", jcr->JobId,
745 FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
746 stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
750 Dmsg2(150, "Leave write_session_label Block=%ud File=%ud\n",
751 dev->get_block_num(), dev->get_file());
755 /* unser_volume_label
757 * Unserialize the Bacula Volume label into the device Volume_Label
760 * Assumes that the record is already read.
762 * Returns: false on error
766 bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec)
769 char buf1[100], buf2[100];
771 if (rec->FileIndex != VOL_LABEL && rec->FileIndex != PRE_LABEL) {
772 Mmsg3(dev->errmsg, _("Expecting Volume Label, got FI=%s Stream=%s len=%d\n"),
773 FI_to_ascii(buf1, rec->FileIndex),
774 stream_to_ascii(buf2, rec->Stream, rec->FileIndex),
781 dev->VolHdr.LabelType = rec->FileIndex;
782 dev->VolHdr.LabelSize = rec->data_len;
785 /* Unserialize the record into the Volume Header */
786 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
787 ser_begin(rec->data, SER_LENGTH_Volume_Label);
788 unser_string(dev->VolHdr.Id);
789 unser_uint32(dev->VolHdr.VerNum);
791 if (dev->VolHdr.VerNum >= 11) {
792 unser_btime(dev->VolHdr.label_btime);
793 unser_btime(dev->VolHdr.write_btime);
794 } else { /* old way */
795 unser_float64(dev->VolHdr.label_date);
796 unser_float64(dev->VolHdr.label_time);
798 unser_float64(dev->VolHdr.write_date); /* Unused with VerNum >= 11 */
799 unser_float64(dev->VolHdr.write_time); /* Unused with VerNum >= 11 */
801 unser_string(dev->VolHdr.VolumeName);
802 unser_string(dev->VolHdr.PrevVolumeName);
803 unser_string(dev->VolHdr.PoolName);
804 unser_string(dev->VolHdr.PoolType);
805 unser_string(dev->VolHdr.MediaType);
807 unser_string(dev->VolHdr.HostName);
808 unser_string(dev->VolHdr.LabelProg);
809 unser_string(dev->VolHdr.ProgVersion);
810 unser_string(dev->VolHdr.ProgDate);
812 ser_end(rec->data, SER_LENGTH_Volume_Label);
813 Dmsg0(190, "unser_vol_label\n");
814 if (debug_level >= 190) {
815 dump_volume_label(dev);
821 bool unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec)
825 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
826 unser_begin(rec->data, SER_LENGTH_Session_Label);
827 unser_string(label->Id);
828 unser_uint32(label->VerNum);
829 unser_uint32(label->JobId);
830 if (label->VerNum >= 11) {
831 unser_btime(label->write_btime);
833 unser_float64(label->write_date);
835 unser_float64(label->write_time);
836 unser_string(label->PoolName);
837 unser_string(label->PoolType);
838 unser_string(label->JobName);
839 unser_string(label->ClientName);
840 if (label->VerNum >= 10) {
841 unser_string(label->Job); /* Unique name of this Job */
842 unser_string(label->FileSetName);
843 unser_uint32(label->JobType);
844 unser_uint32(label->JobLevel);
846 if (label->VerNum >= 11) {
847 unser_string(label->FileSetMD5);
849 label->FileSetMD5[0] = 0;
851 if (rec->FileIndex == EOS_LABEL) {
852 unser_uint32(label->JobFiles);
853 unser_uint64(label->JobBytes);
854 unser_uint32(label->StartBlock);
855 unser_uint32(label->EndBlock);
856 unser_uint32(label->StartFile);
857 unser_uint32(label->EndFile);
858 unser_uint32(label->JobErrors);
859 if (label->VerNum >= 11) {
860 unser_uint32(label->JobStatus);
862 label->JobStatus = JS_Terminated; /* kludge */
868 void dump_volume_label(DEVICE *dev)
870 int dbl = debug_level;
872 const char *LabelType;
879 switch (dev->VolHdr.LabelType) {
881 LabelType = "PRE_LABEL";
884 LabelType = "VOL_LABEL";
887 LabelType = "EOM_LABEL";
890 LabelType = "SOS_LABEL";
893 LabelType = "EOS_LABEL";
899 sprintf(buf, _("Unknown %d"), dev->VolHdr.LabelType);
903 Pmsg11(-1, _("\nVolume Label:\n"
916 dev->VolHdr.Id, dev->VolHdr.VerNum,
917 dev->VolHdr.VolumeName, dev->VolHdr.PrevVolumeName,
918 File, LabelType, dev->VolHdr.LabelSize,
919 dev->VolHdr.PoolName, dev->VolHdr.MediaType,
920 dev->VolHdr.PoolType, dev->VolHdr.HostName);
922 if (dev->VolHdr.VerNum >= 11) {
924 bstrftime(dt, sizeof(dt), btime_to_unix(dev->VolHdr.label_btime));
925 Pmsg1(-1, _("Date label written: %s\n"), dt);
927 dt.julian_day_number = dev->VolHdr.label_date;
928 dt.julian_day_fraction = dev->VolHdr.label_time;
931 _("Date label written: %04d-%02d-%02d at %02d:%02d\n"),
932 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
940 static void dump_session_label(DEV_RECORD *rec, const char *type)
946 char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], ec6[30], ec7[30];
948 unser_session_label(&label, rec);
951 Pmsg7(-1, _("\n%s Record:\n"
958 ""), type, label.JobId, label.VerNum,
959 label.PoolName, label.PoolType,
960 label.JobName, label.ClientName);
962 if (label.VerNum >= 10) {
964 "Job (unique name) : %s\n"
968 ""), label.Job, label.FileSetName, label.JobType, label.JobLevel);
971 if (rec->FileIndex == EOS_LABEL) {
982 edit_uint64_with_commas(label.JobFiles, ec1),
983 edit_uint64_with_commas(label.JobBytes, ec2),
984 edit_uint64_with_commas(label.StartBlock, ec3),
985 edit_uint64_with_commas(label.EndBlock, ec4),
986 edit_uint64_with_commas(label.StartFile, ec5),
987 edit_uint64_with_commas(label.EndFile, ec6),
988 edit_uint64_with_commas(label.JobErrors, ec7),
991 if (label.VerNum >= 11) {
993 bstrftime(dt, sizeof(dt), btime_to_unix(label.write_btime));
994 Pmsg1(-1, _("Date written : %s\n"), dt);
996 dt.julian_day_number = label.write_date;
997 dt.julian_day_fraction = label.write_time;
999 Pmsg5(-1, _("Date written : %04d-%02d-%02d at %02d:%02d\n"),
1000 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
1006 void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose)
1011 if (rec->FileIndex == 0 && rec->VolSessionId == 0 && rec->VolSessionTime == 0) {
1016 switch (rec->FileIndex) {
1018 type = _("Fresh Volume");
1024 type = _("Begin Job Session");
1027 type = _("End Job Session");
1030 type = _("End of Media");
1033 type = _("End of Tape");
1036 type = _("Unknown");
1040 switch (rec->FileIndex) {
1043 unser_volume_label(dev, rec);
1044 dump_volume_label(dev);
1047 dump_session_label(rec, type);
1050 dump_session_label(rec, type);
1053 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1054 type, dev->file, dev->block_num, rec->VolSessionId,
1055 rec->VolSessionTime, rec->Stream, rec->data_len);
1058 Pmsg0(-1, _("End of physical tape.\n"));
1061 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1062 type, dev->file, dev->block_num, rec->VolSessionId,
1063 rec->VolSessionTime, rec->Stream, rec->data_len);
1067 SESSION_LABEL label;
1069 switch (rec->FileIndex) {
1071 unser_session_label(&label, rec);
1072 bstrftimes(dt, sizeof(dt), btime_to_unix(label.write_btime));
1073 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1074 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1075 Pmsg4(-1, _(" Job=%s Date=%s Level=%c Type=%c\n"),
1076 label.Job, dt, label.JobLevel, label.JobType);
1079 char ed1[30], ed2[30];
1080 unser_session_label(&label, rec);
1081 bstrftimes(dt, sizeof(dt), btime_to_unix(label.write_btime));
1082 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1083 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1084 Pmsg7(-1, _(" Date=%s Level=%c Type=%c Files=%s Bytes=%s Errors=%d Status=%c\n"),
1085 dt, label.JobLevel, label.JobType,
1086 edit_uint64_with_commas(label.JobFiles, ed1),
1087 edit_uint64_with_commas(label.JobBytes, ed2),
1088 label.JobErrors, (char)label.JobStatus);
1094 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1095 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime,
1096 rec->Stream, rec->data_len);