3 * label.c Bacula routines to handle labels
11 Copyright (C) 2000-2006 Kern Sibbald
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License
15 version 2 as amended with additional clauses defined in the
16 file LICENSE in the main source directory.
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 the file LICENSE for additional details.
25 #include "bacula.h" /* pull in global headers */
26 #include "stored.h" /* pull in Storage Deamon headers */
28 /* Forward referenced functions */
29 static void create_volume_label_record(DCR *dcr, DEV_RECORD *rec);
32 * Read the volume label
34 * If dcr->VolumeName == NULL, we accept any Bacula Volume
35 * If dcr->VolumeName[0] == 0, we accept any Bacula Volume
36 * otherwise dcr->VolumeName must match the Volume.
38 * If VolName given, ensure that it matches
40 * Returns VOL_ code as defined in record.h
42 * VOL_OK good label found
43 * VOL_NO_LABEL volume not labeled
44 * VOL_IO_ERROR I/O error reading tape
45 * VOL_NAME_ERROR label has wrong name
46 * VOL_CREATE_ERROR Error creating label
47 * VOL_VERSION_ERROR label has wrong version
48 * VOL_LABEL_ERROR bad label type
49 * VOL_NO_MEDIA no media in drive
51 * The dcr block is emptied on return, and the Volume is
54 int read_dev_volume_label(DCR *dcr)
57 DEVICE *dev = dcr->dev;
58 char *VolName = dcr->VolumeName;
61 DEV_BLOCK *block = dcr->block;
64 bool have_ansi_label = false;
66 Dmsg4(100, "Enter read_volume_label res=%d device=%s vol=%s dev_Vol=%s\n",
67 dev->reserved_device, dev->print_name(), VolName,
68 dev->VolHdr.VolumeName[0]?dev->VolHdr.VolumeName:"*NULL*");
70 if (!dev->is_open()) {
71 if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
75 if (dev->is_labeled()) { /* did we already read label? */
76 /* Compare Volume Names allow special wild card */
77 if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolumeName, VolName) != 0) {
78 Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
79 dev->print_name(), VolName, dev->VolHdr.VolumeName);
81 * Cancel Job if too many label errors
84 if (!dev->poll && jcr->label_errors++ > 100) {
85 Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
87 Dmsg0(150, "return VOL_NAME_ERROR\n");
88 stat = VOL_NAME_ERROR;
91 Dmsg0(30, "Leave read_volume_label() VOL_OK\n");
92 return VOL_OK; /* label already read */
98 dev->label_type = B_BACULA_LABEL;
100 if (!dev->rewind(dcr)) {
101 Mmsg(jcr->errmsg, _("Couldn't rewind device %s: ERR=%s\n"),
102 dev->print_name(), dev->print_errmsg());
103 Dmsg1(30, "return VOL_NO_MEDIA: %s", jcr->errmsg);
106 bstrncpy(dev->VolHdr.Id, "**error**", sizeof(dev->VolHdr.Id));
108 /* Read ANSI/IBM label if so requested */
110 want_ansi_label = dcr->VolCatInfo.LabelType != B_BACULA_LABEL ||
111 dcr->device->label_type != B_BACULA_LABEL;
112 if (want_ansi_label || dev_cap(dev, CAP_CHECKLABELS)) {
113 stat = read_ansi_ibm_label(dcr);
114 /* If we want a label and didn't find it, return error */
115 if (want_ansi_label && stat != VOL_OK) {
118 if (stat == VOL_NAME_ERROR || stat == VOL_LABEL_ERROR) {
119 Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
120 dev->print_name(), VolName, dev->VolHdr.VolumeName);
121 if (!dev->poll && jcr->label_errors++ > 100) {
122 Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
126 if (stat != VOL_OK) { /* Not an ANSI/IBM label, so re-read */
129 have_ansi_label = true;
133 /* Read the Bacula Volume label block */
134 record = new_record();
137 Dmsg0(90, "Big if statement in read_volume_label\n");
138 if (!read_block_from_dev(dcr, NO_BLOCK_NUMBER_CHECK)) {
139 Mmsg(jcr->errmsg, _("Requested Volume \"%s\" on %s is not a Bacula "
140 "labeled Volume, because: ERR=%s"), NPRT(VolName),
141 dev->print_name(), dev->print_errmsg());
142 Dmsg1(30, "%s", jcr->errmsg);
143 } else if (!read_record_from_block(block, record)) {
144 Mmsg(jcr->errmsg, _("Could not read Volume label from block.\n"));
145 Dmsg1(30, "%s", jcr->errmsg);
146 } else if (!unser_volume_label(dev, record)) {
147 Mmsg(jcr->errmsg, _("Could not unserialize Volume label: ERR=%s\n"),
148 dev->print_errmsg());
149 Dmsg1(30, "%s", jcr->errmsg);
150 } else if (strcmp(dev->VolHdr.Id, BaculaId) != 0 &&
151 strcmp(dev->VolHdr.Id, OldBaculaId) != 0) {
152 Mmsg(jcr->errmsg, _("Volume Header Id bad: %s\n"), dev->VolHdr.Id);
153 Dmsg1(30, "%s", jcr->errmsg);
157 free_record(record); /* finished reading Volume record */
160 if (forge_on || jcr->ignore_label_errors) {
161 dev->set_labeled(); /* set has Bacula label */
162 Jmsg(jcr, M_ERROR, 0, "%s", jcr->errmsg);
166 Dmsg0(100, "No volume label - bailing out\n");
171 /* At this point, we have read the first Bacula block, and
172 * then read the Bacula Volume label. Now we need to
173 * make sure we have the right Volume.
177 if (dev->VolHdr.VerNum != BaculaTapeVersion &&
178 dev->VolHdr.VerNum != OldCompatibleBaculaTapeVersion1 &&
179 dev->VolHdr.VerNum != OldCompatibleBaculaTapeVersion2) {
180 Mmsg(jcr->errmsg, _("Volume on %s has wrong Bacula version. Wanted %d got %d\n"),
181 dev->print_name(), BaculaTapeVersion, dev->VolHdr.VerNum);
182 Dmsg1(30, "VOL_VERSION_ERROR: %s", jcr->errmsg);
183 stat = VOL_VERSION_ERROR;
187 /* We are looking for either an unused Bacula tape (PRE_LABEL) or
188 * a Bacula volume label (VOL_LABEL)
190 if (dev->VolHdr.LabelType != PRE_LABEL && dev->VolHdr.LabelType != VOL_LABEL) {
191 Mmsg(jcr->errmsg, _("Volume on %s has bad Bacula label type: %x\n"),
192 dev->print_name(), dev->VolHdr.LabelType);
193 Dmsg1(30, "%s", jcr->errmsg);
194 if (!dev->poll && jcr->label_errors++ > 100) {
195 Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
197 Dmsg0(150, "return VOL_LABEL_ERROR\n");
198 stat = VOL_LABEL_ERROR;
202 dev->set_labeled(); /* set has Bacula label */
203 new_volume(dcr, dev->VolHdr.VolumeName);
205 /* Compare Volume Names */
206 Dmsg2(30, "Compare Vol names: VolName=%s hdr=%s\n", VolName?VolName:"*", dev->VolHdr.VolumeName);
207 if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolumeName, VolName) != 0) {
208 Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
209 dev->print_name(), VolName, dev->VolHdr.VolumeName);
210 Dmsg1(30, "%s", jcr->errmsg);
212 * Cancel Job if too many label errors
213 * => we are in a loop
215 if (!dev->poll && jcr->label_errors++ > 100) {
216 Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
218 Dmsg0(150, "return VOL_NAME_ERROR\n");
219 stat = VOL_NAME_ERROR;
222 Dmsg1(30, "Copy vol_name=%s\n", dev->VolHdr.VolumeName);
224 if (debug_level >= 10) {
225 dump_volume_label(dev);
227 Dmsg0(30, "Leave read_volume_label() VOL_OK\n");
228 /* If we are a streaming device, we only get one chance to read */
229 if (!dev_cap(dev, CAP_STREAM)) {
231 if (have_ansi_label) {
232 stat = read_ansi_ibm_label(dcr);
233 /* If we want a label and didn't find it, return error */
234 if (stat != VOL_OK) {
245 Dmsg1(150, "return %d\n", stat);
250 * Put a volume label into the block
252 * Returns: false on failure
255 bool write_volume_label_to_block(DCR *dcr)
258 DEVICE *dev = dcr->dev;
260 DEV_BLOCK *block = dcr->block;
262 Dmsg0(20, "write Label in write_volume_label_to_block()\n");
263 memset(&rec, 0, sizeof(rec));
264 rec.data = get_memory(SER_LENGTH_Volume_Label);
265 empty_block(block); /* Volume label always at beginning */
267 create_volume_label_record(dcr, &rec);
269 block->BlockNumber = 0;
270 if (!write_record_to_block(block, &rec)) {
271 free_pool_memory(rec.data);
272 Jmsg1(jcr, M_FATAL, 0, _("Cannot write Volume label to block for device %s\n"),
276 Dmsg1(90, "Wrote label of %d bytes to block\n", rec.data_len);
278 free_pool_memory(rec.data);
284 * Write a Volume Label
285 * !!! Note, this is ONLY used for writing
286 * a fresh volume label. Any data
287 * after the label will be destroyed,
288 * in fact, we write the label 5 times !!!!
290 * This routine should be used only when labeling a blank tape.
292 bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName,
293 const char *PoolName, bool relabel, bool dvdnow)
295 DEVICE *dev = dcr->dev;
298 Dmsg0(99, "write_volume_label()\n");
299 empty_block(dcr->block);
301 /* If relabeling, truncate the device */
302 if (relabel && !dev->truncate(dcr)) {
307 dev->close_part(dcr); /* make sure closed for rename */
310 /* Set the new filename for open, ... */
311 bstrncpy(dev->VolCatInfo.VolCatName, VolName, sizeof(dev->VolCatInfo.VolCatName));
312 bstrncpy(dcr->VolCatInfo.VolCatName, VolName, sizeof(dcr->VolCatInfo.VolCatName));
313 Dmsg1(150, "New VolName=%s\n", VolName);
314 if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
315 /* If device is not tape, attempt to create it */
316 if (dev->is_tape() || dev->open(dcr, CREATE_READ_WRITE) < 0) {
320 Dmsg1(150, "Label type=%d\n", dev->label_type);
321 if (!dev->rewind(dcr)) {
323 memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
324 Dmsg2(30, "Bad status on %s from rewind: ERR=%s\n", dev->print_name(), dev->print_errmsg());
330 /* Create PRE_LABEL or VOL_LABEL if DVD */
331 create_volume_label(dev, VolName, PoolName, dvdnow);
334 * If we have already detected an ANSI label, re-read it
335 * to skip past it. Otherwise, we write a new one if
338 if (dev->label_type != B_BACULA_LABEL) {
339 if (read_ansi_ibm_label(dcr) != VOL_OK) {
343 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, VolName)) {
347 create_volume_label_record(dcr, dcr->rec);
348 dcr->rec->Stream = 0;
350 /* Temporarily mark in append state to enable writing */
352 if (!write_record_to_block(dcr->block, dcr->rec)) {
353 Dmsg2(30, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
356 Dmsg2(30, "Wrote label of %d bytes to %s\n", dcr->rec->data_len, dev->print_name());
359 Dmsg0(99, "Call write_block_to_dev()\n");
360 if (!write_block_to_dev(dcr)) {
361 Dmsg2(30, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
365 /* Now commit block to DVD if we should write now */
366 if (dev->is_dvd() && dvdnow) {
367 Dmsg1(150, "New VolName=%s\n", dev->VolCatInfo.VolCatName);
368 if (!dvd_write_part(dcr)) {
369 Dmsg2(30, "Bad DVD write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
374 Dmsg0(99, " Wrote block to device\n");
378 write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
381 if (debug_level >= 20) {
382 dump_volume_label(dev);
384 new_volume(dcr, VolName);
385 dev->clear_append(); /* remove append since this is PRE_LABEL */
390 memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
391 dev->clear_append(); /* remove append since this is PRE_LABEL */
396 * Write a volume label. This is ONLY called if we have a valid Bacula
397 * label of type PRE_LABEL;
398 * Returns: true if OK
399 * false if unable to write it
401 bool rewrite_volume_label(DCR *dcr, bool recycle)
403 DEVICE *dev = dcr->dev;
406 if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
409 Dmsg2(190, "set append found freshly labeled volume. fd=%d dev=%x\n", dev->fd, dev);
410 dev->VolHdr.LabelType = VOL_LABEL; /* set Volume label */
412 if (!write_volume_label_to_block(dcr)) {
413 Dmsg0(200, "Error from write volume label.\n");
417 dev->VolCatInfo.VolCatBytes = 0; /* reset byte count */
420 * If we are not dealing with a streaming device,
421 * write the block now to ensure we have write permission.
422 * It is better to find out now rather than later.
423 * We do not write the block now if this is an ANSI label. This
424 * avoids re-writing the ANSI label, which we do not want to do.
426 if (!dev_cap(dev, CAP_STREAM)) {
427 if (!dev->rewind(dcr)) {
428 Jmsg2(jcr, M_FATAL, 0, _("Rewind error on device %s: ERR=%s\n"),
429 dev->print_name(), dev->print_errmsg());
433 if (!dev->truncate(dcr)) {
434 Jmsg2(jcr, M_FATAL, 0, _("Truncate error on device %s: ERR=%s\n"),
435 dev->print_name(), dev->print_errmsg());
438 if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
439 Jmsg2(jcr, M_FATAL, 0,
440 _("Failed to re-open DVD after truncate on device %s: ERR=%s\n"),
441 dev->print_name(), dev->print_errmsg());
447 * If we have already detected an ANSI label, re-read it
448 * to skip past it. Otherwise, we write a new one if
451 if (dev->label_type != B_BACULA_LABEL) {
452 if (read_ansi_ibm_label(dcr) != VOL_OK) {
456 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, dev->VolHdr.VolumeName)) {
460 /* Attempt write to check write permission */
461 Dmsg1(200, "Attempt to write to device fd=%d.\n", dev->fd);
462 if (!write_block_to_dev(dcr)) {
463 Jmsg2(jcr, M_ERROR, 0, _("Unable to write device %s: ERR=%s\n"),
464 dev->print_name(), dev->print_errmsg());
465 Dmsg0(200, "===ERROR write block to dev\n");
470 /* Set or reset Volume statistics */
471 dev->VolCatInfo.VolCatJobs = 0;
472 dev->VolCatInfo.VolCatFiles = 0;
473 dev->VolCatInfo.VolCatErrors = 0;
474 dev->VolCatInfo.VolCatBlocks = 0;
475 dev->VolCatInfo.VolCatRBytes = 0;
477 dev->VolCatInfo.VolCatMounts++;
478 dev->VolCatInfo.VolCatRecycles++;
480 dev->VolCatInfo.VolCatMounts = 1;
481 dev->VolCatInfo.VolCatRecycles = 0;
482 dev->VolCatInfo.VolCatWrites = 1;
483 dev->VolCatInfo.VolCatReads = 1;
485 Dmsg0(150, "dir_update_vol_info. Set Append\n");
486 bstrncpy(dev->VolCatInfo.VolCatStatus, "Append", sizeof(dev->VolCatInfo.VolCatStatus));
487 if (!dir_update_volume_info(dcr, true)) { /* indicate doing relabel */
491 Jmsg(jcr, M_INFO, 0, _("Recycled volume \"%s\" on device %s, all previous data lost.\n"),
492 dcr->VolumeName, dev->print_name());
494 Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume \"%s\" on device %s\n"),
495 dcr->VolumeName, dev->print_name());
498 * End writing real Volume label (from pre-labeled tape), or recycling
501 Dmsg0(200, "OK from rewrite vol label.\n");
507 * create_volume_label_record
508 * Serialize label (from dev->VolHdr structure) into device record.
509 * Assumes that the dev->VolHdr structure is properly
512 static void create_volume_label_record(DCR *dcr, DEV_RECORD *rec)
516 DEVICE *dev = dcr->dev;
520 /* Serialize the label into the device record. */
522 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
523 ser_begin(rec->data, SER_LENGTH_Volume_Label);
524 ser_string(dev->VolHdr.Id);
526 ser_uint32(dev->VolHdr.VerNum);
528 if (dev->VolHdr.VerNum >= 11) {
529 ser_btime(dev->VolHdr.label_btime);
530 dev->VolHdr.write_btime = get_current_btime();
531 ser_btime(dev->VolHdr.write_btime);
532 dev->VolHdr.write_date = 0;
533 dev->VolHdr.write_time = 0;
535 /* OLD WAY DEPRECATED */
536 ser_float64(dev->VolHdr.label_date);
537 ser_float64(dev->VolHdr.label_time);
538 get_current_time(&dt);
539 dev->VolHdr.write_date = dt.julian_day_number;
540 dev->VolHdr.write_time = dt.julian_day_fraction;
542 ser_float64(dev->VolHdr.write_date); /* 0 if VerNum >= 11 */
543 ser_float64(dev->VolHdr.write_time); /* 0 if VerNum >= 11 */
545 ser_string(dev->VolHdr.VolumeName);
546 ser_string(dev->VolHdr.PrevVolumeName);
547 ser_string(dev->VolHdr.PoolName);
548 ser_string(dev->VolHdr.PoolType);
549 ser_string(dev->VolHdr.MediaType);
551 ser_string(dev->VolHdr.HostName);
552 ser_string(dev->VolHdr.LabelProg);
553 ser_string(dev->VolHdr.ProgVersion);
554 ser_string(dev->VolHdr.ProgDate);
556 ser_end(rec->data, SER_LENGTH_Volume_Label);
557 rec->data_len = ser_length(rec->data);
558 rec->FileIndex = dev->VolHdr.LabelType;
559 rec->VolSessionId = jcr->VolSessionId;
560 rec->VolSessionTime = jcr->VolSessionTime;
561 rec->Stream = jcr->NumVolumes;
562 Dmsg2(150, "Created Vol label rec: FI=%s len=%d\n", FI_to_ascii(buf, rec->FileIndex),
568 * Create a volume label in memory
570 void create_volume_label(DEVICE *dev, const char *VolName,
571 const char *PoolName, bool dvdnow)
573 DEVRES *device = (DEVRES *)dev->device;
575 Dmsg0(90, "Start create_volume_label()\n");
579 free_volume(dev); /* release any old volume */
580 memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
582 bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
583 dev->VolHdr.VerNum = BaculaTapeVersion;
584 if (dev->is_dvd() && dvdnow) {
585 /* We do not want to re-label a DVD so write VOL_LABEL now */
586 dev->VolHdr.LabelType = VOL_LABEL;
588 dev->VolHdr.LabelType = PRE_LABEL; /* Mark tape as unused */
590 bstrncpy(dev->VolHdr.VolumeName, VolName, sizeof(dev->VolHdr.VolumeName));
591 bstrncpy(dev->VolHdr.PoolName, PoolName, sizeof(dev->VolHdr.PoolName));
592 bstrncpy(dev->VolHdr.MediaType, device->media_type, sizeof(dev->VolHdr.MediaType));
594 bstrncpy(dev->VolHdr.PoolType, "Backup", sizeof(dev->VolHdr.PoolType));
596 dev->VolHdr.label_btime = get_current_btime();
597 dev->VolHdr.label_date = 0;
598 dev->VolHdr.label_time = 0;
600 if (gethostname(dev->VolHdr.HostName, sizeof(dev->VolHdr.HostName)) != 0) {
601 dev->VolHdr.HostName[0] = 0;
603 bstrncpy(dev->VolHdr.LabelProg, my_name, sizeof(dev->VolHdr.LabelProg));
604 sprintf(dev->VolHdr.ProgVersion, "Ver. %s %s", VERSION, BDATE);
605 sprintf(dev->VolHdr.ProgDate, "Build %s %s", __DATE__, __TIME__);
606 dev->set_labeled(); /* set has Bacula label */
607 if (debug_level >= 90) {
608 dump_volume_label(dev);
613 * Create session label
614 * The pool memory must be released by the calling program
616 void create_session_label(DCR *dcr, DEV_RECORD *rec, int label)
621 rec->VolSessionId = jcr->VolSessionId;
622 rec->VolSessionTime = jcr->VolSessionTime;
623 rec->Stream = jcr->JobId;
625 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
626 ser_begin(rec->data, SER_LENGTH_Session_Label);
627 ser_string(BaculaId);
628 ser_uint32(BaculaTapeVersion);
630 ser_uint32(jcr->JobId);
632 /* Changed in VerNum 11 */
633 ser_btime(get_current_btime());
636 ser_string(dcr->pool_name);
637 ser_string(dcr->pool_type);
638 ser_string(jcr->job_name); /* base Job name */
639 ser_string(jcr->client_name);
641 /* Added in VerNum 10 */
642 ser_string(jcr->Job); /* Unique name of this Job */
643 ser_string(jcr->fileset_name);
644 ser_uint32(jcr->JobType);
645 ser_uint32(jcr->JobLevel);
646 /* Added in VerNum 11 */
647 ser_string(jcr->fileset_md5);
649 if (label == EOS_LABEL) {
650 ser_uint32(jcr->JobFiles);
651 ser_uint64(jcr->JobBytes);
652 ser_uint32(dcr->StartBlock);
653 ser_uint32(dcr->EndBlock);
654 ser_uint32(dcr->StartFile);
655 ser_uint32(dcr->EndFile);
656 ser_uint32(jcr->JobErrors);
658 /* Added in VerNum 11 */
659 ser_uint32(jcr->JobStatus);
661 ser_end(rec->data, SER_LENGTH_Session_Label);
662 rec->data_len = ser_length(rec->data);
665 /* Write session label
666 * Returns: false on failure
669 bool write_session_label(DCR *dcr, int label)
672 DEVICE *dev = dcr->dev;
674 DEV_BLOCK *block = dcr->block;
675 char buf1[100], buf2[100];
678 Dmsg1(90, "session_label record=%x\n", rec);
681 if (dev->is_tape()) {
682 dcr->StartBlock = dev->block_num;
683 dcr->StartFile = dev->file;
685 dcr->StartBlock = (uint32_t)dev->file_addr;
686 dcr->StartFile = (uint32_t)(dev->file_addr >> 32);
690 if (dev->is_tape()) {
691 dcr->EndBlock = dev->EndBlock;
692 dcr->EndFile = dev->EndFile;
694 dcr->EndBlock = (uint32_t)dev->file_addr;
695 dcr->EndFile = (uint32_t)(dev->file_addr >> 32);
699 Jmsg1(jcr, M_ABORT, 0, _("Bad session label = %d\n"), label);
702 create_session_label(dcr, rec, label);
703 rec->FileIndex = label;
706 * We guarantee that the session record can totally fit
707 * into a block. If not, write the block, and put it in
708 * the next block. Having the sesssion record totally in
709 * one block makes reading them much easier (no need to
710 * read the next block).
712 if (!can_write_record_to_block(block, rec)) {
713 Dmsg0(150, "Cannot write session label to block.\n");
714 if (!write_block_to_device(dcr)) {
715 Dmsg0(90, "Got session label write_block_to_dev error.\n");
716 /* ****FIXME***** errno is not set here */
717 Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"),
718 dev_vol_name(dev), strerror(errno));
723 if (!write_record_to_block(block, rec)) {
724 Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"),
725 dev_vol_name(dev), strerror(errno));
730 Dmsg6(50, "Write sesson_label record JobId=%d FI=%s SessId=%d Strm=%s len=%d "
731 "remainder=%d\n", jcr->JobId,
732 FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
733 stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
737 Dmsg2(50, "Leave write_session_label Block=%ud File=%ud\n",
738 dev->get_block(), dev->get_file());
742 /* unser_volume_label
744 * Unserialize the Bacula Volume label into the device Volume_Label
747 * Assumes that the record is already read.
749 * Returns: false on error
753 bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec)
756 char buf1[100], buf2[100];
758 if (rec->FileIndex != VOL_LABEL && rec->FileIndex != PRE_LABEL) {
759 Mmsg3(dev->errmsg, _("Expecting Volume Label, got FI=%s Stream=%s len=%d\n"),
760 FI_to_ascii(buf1, rec->FileIndex),
761 stream_to_ascii(buf2, rec->Stream, rec->FileIndex),
768 dev->VolHdr.LabelType = rec->FileIndex;
769 dev->VolHdr.LabelSize = rec->data_len;
772 /* Unserialize the record into the Volume Header */
773 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
774 ser_begin(rec->data, SER_LENGTH_Volume_Label);
775 unser_string(dev->VolHdr.Id);
776 unser_uint32(dev->VolHdr.VerNum);
778 if (dev->VolHdr.VerNum >= 11) {
779 unser_btime(dev->VolHdr.label_btime);
780 unser_btime(dev->VolHdr.write_btime);
781 } else { /* old way */
782 unser_float64(dev->VolHdr.label_date);
783 unser_float64(dev->VolHdr.label_time);
785 unser_float64(dev->VolHdr.write_date); /* Unused with VerNum >= 11 */
786 unser_float64(dev->VolHdr.write_time); /* Unused with VerNum >= 11 */
788 unser_string(dev->VolHdr.VolumeName);
789 unser_string(dev->VolHdr.PrevVolumeName);
790 unser_string(dev->VolHdr.PoolName);
791 unser_string(dev->VolHdr.PoolType);
792 unser_string(dev->VolHdr.MediaType);
794 unser_string(dev->VolHdr.HostName);
795 unser_string(dev->VolHdr.LabelProg);
796 unser_string(dev->VolHdr.ProgVersion);
797 unser_string(dev->VolHdr.ProgDate);
799 ser_end(rec->data, SER_LENGTH_Volume_Label);
800 Dmsg0(190, "unser_vol_label\n");
801 if (debug_level >= 190) {
802 dump_volume_label(dev);
808 bool unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec)
812 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
813 unser_begin(rec->data, SER_LENGTH_Session_Label);
814 unser_string(label->Id);
815 unser_uint32(label->VerNum);
816 unser_uint32(label->JobId);
817 if (label->VerNum >= 11) {
818 unser_btime(label->write_btime);
820 unser_float64(label->write_date);
822 unser_float64(label->write_time);
823 unser_string(label->PoolName);
824 unser_string(label->PoolType);
825 unser_string(label->JobName);
826 unser_string(label->ClientName);
827 if (label->VerNum >= 10) {
828 unser_string(label->Job); /* Unique name of this Job */
829 unser_string(label->FileSetName);
830 unser_uint32(label->JobType);
831 unser_uint32(label->JobLevel);
833 if (label->VerNum >= 11) {
834 unser_string(label->FileSetMD5);
836 label->FileSetMD5[0] = 0;
838 if (rec->FileIndex == EOS_LABEL) {
839 unser_uint32(label->JobFiles);
840 unser_uint64(label->JobBytes);
841 unser_uint32(label->StartBlock);
842 unser_uint32(label->EndBlock);
843 unser_uint32(label->StartFile);
844 unser_uint32(label->EndFile);
845 unser_uint32(label->JobErrors);
846 if (label->VerNum >= 11) {
847 unser_uint32(label->JobStatus);
849 label->JobStatus = JS_Terminated; /* kludge */
855 void dump_volume_label(DEVICE *dev)
857 int dbl = debug_level;
859 const char *LabelType;
866 switch (dev->VolHdr.LabelType) {
868 LabelType = "PRE_LABEL";
871 LabelType = "VOL_LABEL";
874 LabelType = "EOM_LABEL";
877 LabelType = "SOS_LABEL";
880 LabelType = "EOS_LABEL";
886 sprintf(buf, _("Unknown %d"), dev->VolHdr.LabelType);
890 Pmsg11(-1, _("\nVolume Label:\n"
903 dev->VolHdr.Id, dev->VolHdr.VerNum,
904 dev->VolHdr.VolumeName, dev->VolHdr.PrevVolumeName,
905 File, LabelType, dev->VolHdr.LabelSize,
906 dev->VolHdr.PoolName, dev->VolHdr.MediaType,
907 dev->VolHdr.PoolType, dev->VolHdr.HostName);
909 if (dev->VolHdr.VerNum >= 11) {
911 bstrftime(dt, sizeof(dt), btime_to_unix(dev->VolHdr.label_btime));
912 Pmsg1(-1, _("Date label written: %s\n"), dt);
914 dt.julian_day_number = dev->VolHdr.label_date;
915 dt.julian_day_fraction = dev->VolHdr.label_time;
918 _("Date label written: %04d-%02d-%02d at %02d:%02d\n"),
919 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
927 static void dump_session_label(DEV_RECORD *rec, const char *type)
933 char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], ec6[30], ec7[30];
935 unser_session_label(&label, rec);
938 Pmsg7(-1, _("\n%s Record:\n"
945 ""), type, label.JobId, label.VerNum,
946 label.PoolName, label.PoolType,
947 label.JobName, label.ClientName);
949 if (label.VerNum >= 10) {
951 "Job (unique name) : %s\n"
955 ""), label.Job, label.FileSetName, label.JobType, label.JobLevel);
958 if (rec->FileIndex == EOS_LABEL) {
969 edit_uint64_with_commas(label.JobFiles, ec1),
970 edit_uint64_with_commas(label.JobBytes, ec2),
971 edit_uint64_with_commas(label.StartBlock, ec3),
972 edit_uint64_with_commas(label.EndBlock, ec4),
973 edit_uint64_with_commas(label.StartFile, ec5),
974 edit_uint64_with_commas(label.EndFile, ec6),
975 edit_uint64_with_commas(label.JobErrors, ec7),
978 if (label.VerNum >= 11) {
980 bstrftime(dt, sizeof(dt), btime_to_unix(label.write_btime));
981 Pmsg1(-1, _("Date written : %s\n"), dt);
983 dt.julian_day_number = label.write_date;
984 dt.julian_day_fraction = label.write_time;
986 Pmsg5(-1, _("Date written : %04d-%02d-%02d at %02d:%02d\n"),
987 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
993 void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose)
998 if (rec->FileIndex == 0 && rec->VolSessionId == 0 && rec->VolSessionTime == 0) {
1003 switch (rec->FileIndex) {
1005 type = _("Fresh Volume");
1011 type = _("Begin Job Session");
1014 type = _("End Job Session");
1017 type = _("End of Media");
1020 type = _("End of Tape");
1023 type = _("Unknown");
1027 switch (rec->FileIndex) {
1030 unser_volume_label(dev, rec);
1031 dump_volume_label(dev);
1034 dump_session_label(rec, type);
1037 dump_session_label(rec, type);
1040 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1041 type, dev->file, dev->block_num, rec->VolSessionId,
1042 rec->VolSessionTime, rec->Stream, rec->data_len);
1045 Pmsg0(-1, _("End of physical tape.\n"));
1048 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1049 type, dev->file, dev->block_num, rec->VolSessionId,
1050 rec->VolSessionTime, rec->Stream, rec->data_len);
1054 SESSION_LABEL label;
1056 switch (rec->FileIndex) {
1058 unser_session_label(&label, rec);
1059 bstrftimes(dt, sizeof(dt), btime_to_unix(label.write_btime));
1060 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1061 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1062 Pmsg4(-1, _(" Job=%s Date=%s Level=%c Type=%c\n"),
1063 label.Job, dt, label.JobLevel, label.JobType);
1066 char ed1[30], ed2[30];
1067 unser_session_label(&label, rec);
1068 bstrftimes(dt, sizeof(dt), btime_to_unix(label.write_btime));
1069 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1070 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1071 Pmsg7(-1, _(" Date=%s Level=%c Type=%c Files=%s Bytes=%s Errors=%d Status=%c\n"),
1072 dt, label.JobLevel, label.JobType,
1073 edit_uint64_with_commas(label.JobFiles, ed1),
1074 edit_uint64_with_commas(label.JobBytes, ed2),
1075 label.JobErrors, (char)label.JobStatus);
1081 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1082 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime,
1083 rec->Stream, rec->data_len);