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->bstrerror());
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->bstrerror());
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"),
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 dvdnow)
295 DEVICE *dev = dcr->dev;
298 Dmsg0(99, "write_volume_label()\n");
299 empty_block(dcr->block);
301 if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
302 /* If device is not tape, attempt to create it */
303 if (dev->is_tape() || dev->open(dcr, CREATE_READ_WRITE) < 0) {
307 Dmsg1(150, "Label type=%d\n", dev->label_type);
308 if (!dev->rewind(dcr)) {
310 memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
311 Dmsg2(30, "Bad status on %s from rewind: ERR=%s\n", dev->print_name(), dev->bstrerror());
317 /* Create PRE_LABEL or VOL_LABEL if DVD */
318 create_volume_label(dev, VolName, PoolName, dvdnow);
321 * If we have already detected an ANSI label, re-read it
322 * to skip past it. Otherwise, we write a new one if
325 if (dev->label_type != B_BACULA_LABEL) {
326 if (read_ansi_ibm_label(dcr) != VOL_OK) {
330 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, VolName)) {
334 create_volume_label_record(dcr, dcr->rec);
335 dcr->rec->Stream = 0;
337 /* Temporarily mark in append state to enable writing */
339 if (!write_record_to_block(dcr->block, dcr->rec)) {
340 Dmsg2(30, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->bstrerror());
343 Dmsg2(30, "Wrote label of %d bytes to %s\n", dcr->rec->data_len, dev->print_name());
346 Dmsg0(99, "Call write_block_to_dev()\n");
347 if (!write_block_to_dev(dcr)) {
348 Dmsg2(30, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->bstrerror());
352 /* Now commit block to DVD if we should write now */
353 if (dev->is_dvd() && dvdnow) {
354 if (!dvd_write_part(dcr)) {
355 Dmsg2(30, "Bad DVD write on %s: ERR=%s\n", dev->print_name(), dev->bstrerror());
360 Dmsg0(99, " Wrote block to device\n");
364 write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
367 if (debug_level >= 20) {
368 dump_volume_label(dev);
370 new_volume(dcr, VolName);
371 dev->clear_append(); /* remove append since this is PRE_LABEL */
376 memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
377 dev->clear_append(); /* remove append since this is PRE_LABEL */
382 * Write a volume label. This is ONLY called if we have a valid Bacula
383 * label of type PRE_LABEL;
384 * Returns: true if OK
385 * false if unable to write it
387 bool rewrite_volume_label(DCR *dcr, bool recycle)
389 DEVICE *dev = dcr->dev;
391 bool can_write = true;
393 if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
394 /* If device is DVD, attempt to create it */
395 if (!dev->is_dvd()) {
398 if (dev->open(dcr, CREATE_READ_WRITE) < 0) {
399 /* We forge on for a DVD but don't do any writing */
403 Dmsg2(190, "set append found freshly labeled volume. fd=%d dev=%x\n", dev->fd, dev);
404 dev->VolHdr.LabelType = VOL_LABEL; /* set Volume label */
407 if (!write_volume_label_to_block(dcr)) {
408 Dmsg0(200, "Error from write volume label.\n");
413 * If we are not dealing with a streaming device,
414 * write the block now to ensure we have write permission.
415 * It is better to find out now rather than later.
416 * We do not write the block now if this is an ANSI label. This
417 * avoids re-writing the ANSI label, which we do not want to do.
419 if (can_write && !dev_cap(dev, CAP_STREAM)) {
420 if (!dev->rewind(dcr)) {
421 Jmsg2(jcr, M_WARNING, 0, _("Rewind error on device %s: ERR=%s\n"),
422 dev->print_name(), dev->bstrerror());
425 if (!dev->truncate(dcr)) {
426 Jmsg2(jcr, M_WARNING, 0, _("Truncate error on device %s: ERR=%s\n"),
427 dev->print_name(), dev->bstrerror());
432 * If we have already detected an ANSI label, re-read it
433 * to skip past it. Otherwise, we write a new one if
436 if (dev->label_type != B_BACULA_LABEL) {
437 if (read_ansi_ibm_label(dcr) != VOL_OK) {
441 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, dev->VolHdr.VolumeName)) {
445 /* Attempt write to check write permission */
446 Dmsg1(200, "Attempt to write to device fd=%d.\n", dev->fd);
447 if (!write_block_to_dev(dcr)) {
448 Jmsg2(jcr, M_ERROR, 0, _("Unable to write device %s: ERR=%s\n"),
449 dev->print_name(), dev->bstrerror());
450 Dmsg0(200, "===ERROR write block to dev\n");
454 /* Set or reset Volume statistics */
455 dev->VolCatInfo.VolCatJobs = 0;
456 dev->VolCatInfo.VolCatFiles = 0;
457 dev->VolCatInfo.VolCatBytes = 1;
458 dev->VolCatInfo.VolCatErrors = 0;
459 dev->VolCatInfo.VolCatBlocks = 0;
460 dev->VolCatInfo.VolCatRBytes = 0;
462 dev->VolCatInfo.VolCatMounts++;
463 dev->VolCatInfo.VolCatRecycles++;
465 dev->VolCatInfo.VolCatMounts = 1;
466 dev->VolCatInfo.VolCatRecycles = 0;
467 dev->VolCatInfo.VolCatWrites = 1;
468 dev->VolCatInfo.VolCatReads = 1;
470 Dmsg0(150, "dir_update_vol_info. Set Append\n");
471 bstrncpy(dev->VolCatInfo.VolCatStatus, "Append", sizeof(dev->VolCatInfo.VolCatStatus));
472 if (!dir_update_volume_info(dcr, true)) { /* indicate doing relabel */
476 Jmsg(jcr, M_INFO, 0, _("Recycled volume \"%s\" on device %s, all previous data lost.\n"),
477 dcr->VolumeName, dev->print_name());
479 Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume \"%s\" on device %s\n"),
480 dcr->VolumeName, dev->print_name());
483 * End writing real Volume label (from pre-labeled tape), or recycling
486 Dmsg0(200, "OK from rewite vol label.\n");
492 * create_volume_label_record
493 * Serialize label (from dev->VolHdr structure) into device record.
494 * Assumes that the dev->VolHdr structure is properly
497 static void create_volume_label_record(DCR *dcr, DEV_RECORD *rec)
501 DEVICE *dev = dcr->dev;
505 /* Serialize the label into the device record. */
507 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
508 ser_begin(rec->data, SER_LENGTH_Volume_Label);
509 ser_string(dev->VolHdr.Id);
511 ser_uint32(dev->VolHdr.VerNum);
513 if (dev->VolHdr.VerNum >= 11) {
514 ser_btime(dev->VolHdr.label_btime);
515 dev->VolHdr.write_btime = get_current_btime();
516 ser_btime(dev->VolHdr.write_btime);
517 dev->VolHdr.write_date = 0;
518 dev->VolHdr.write_time = 0;
520 /* OLD WAY DEPRECATED */
521 ser_float64(dev->VolHdr.label_date);
522 ser_float64(dev->VolHdr.label_time);
523 get_current_time(&dt);
524 dev->VolHdr.write_date = dt.julian_day_number;
525 dev->VolHdr.write_time = dt.julian_day_fraction;
527 ser_float64(dev->VolHdr.write_date); /* 0 if VerNum >= 11 */
528 ser_float64(dev->VolHdr.write_time); /* 0 if VerNum >= 11 */
530 ser_string(dev->VolHdr.VolumeName);
531 ser_string(dev->VolHdr.PrevVolumeName);
532 ser_string(dev->VolHdr.PoolName);
533 ser_string(dev->VolHdr.PoolType);
534 ser_string(dev->VolHdr.MediaType);
536 ser_string(dev->VolHdr.HostName);
537 ser_string(dev->VolHdr.LabelProg);
538 ser_string(dev->VolHdr.ProgVersion);
539 ser_string(dev->VolHdr.ProgDate);
541 ser_end(rec->data, SER_LENGTH_Volume_Label);
542 rec->data_len = ser_length(rec->data);
543 rec->FileIndex = dev->VolHdr.LabelType;
544 rec->VolSessionId = jcr->VolSessionId;
545 rec->VolSessionTime = jcr->VolSessionTime;
546 rec->Stream = jcr->NumVolumes;
547 Dmsg2(150, "Created Vol label rec: FI=%s len=%d\n", FI_to_ascii(buf, rec->FileIndex),
553 * Create a volume label in memory
555 void create_volume_label(DEVICE *dev, const char *VolName,
556 const char *PoolName, bool dvdnow)
558 DEVRES *device = (DEVRES *)dev->device;
560 Dmsg0(90, "Start create_volume_label()\n");
564 free_volume(dev); /* release any old volume */
565 memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
567 bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
568 dev->VolHdr.VerNum = BaculaTapeVersion;
569 if (dev->is_dvd() && dvdnow) {
570 /* We do not want to re-label a DVD so write VOL_LABEL now */
571 dev->VolHdr.LabelType = VOL_LABEL;
573 dev->VolHdr.LabelType = PRE_LABEL; /* Mark tape as unused */
575 bstrncpy(dev->VolHdr.VolumeName, VolName, sizeof(dev->VolHdr.VolumeName));
576 bstrncpy(dev->VolHdr.PoolName, PoolName, sizeof(dev->VolHdr.PoolName));
577 bstrncpy(dev->VolHdr.MediaType, device->media_type, sizeof(dev->VolHdr.MediaType));
579 bstrncpy(dev->VolHdr.PoolType, "Backup", sizeof(dev->VolHdr.PoolType));
581 dev->VolHdr.label_btime = get_current_btime();
582 dev->VolHdr.label_date = 0;
583 dev->VolHdr.label_time = 0;
585 if (gethostname(dev->VolHdr.HostName, sizeof(dev->VolHdr.HostName)) != 0) {
586 dev->VolHdr.HostName[0] = 0;
588 bstrncpy(dev->VolHdr.LabelProg, my_name, sizeof(dev->VolHdr.LabelProg));
589 sprintf(dev->VolHdr.ProgVersion, "Ver. %s %s", VERSION, BDATE);
590 sprintf(dev->VolHdr.ProgDate, "Build %s %s", __DATE__, __TIME__);
591 dev->set_labeled(); /* set has Bacula label */
592 if (debug_level >= 90) {
593 dump_volume_label(dev);
598 * Create session label
599 * The pool memory must be released by the calling program
601 void create_session_label(DCR *dcr, DEV_RECORD *rec, int label)
606 rec->VolSessionId = jcr->VolSessionId;
607 rec->VolSessionTime = jcr->VolSessionTime;
608 rec->Stream = jcr->JobId;
610 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
611 ser_begin(rec->data, SER_LENGTH_Session_Label);
612 ser_string(BaculaId);
613 ser_uint32(BaculaTapeVersion);
615 ser_uint32(jcr->JobId);
617 /* Changed in VerNum 11 */
618 ser_btime(get_current_btime());
621 ser_string(dcr->pool_name);
622 ser_string(dcr->pool_type);
623 ser_string(jcr->job_name); /* base Job name */
624 ser_string(jcr->client_name);
626 /* Added in VerNum 10 */
627 ser_string(jcr->Job); /* Unique name of this Job */
628 ser_string(jcr->fileset_name);
629 ser_uint32(jcr->JobType);
630 ser_uint32(jcr->JobLevel);
631 /* Added in VerNum 11 */
632 ser_string(jcr->fileset_md5);
634 if (label == EOS_LABEL) {
635 ser_uint32(jcr->JobFiles);
636 ser_uint64(jcr->JobBytes);
637 ser_uint32(dcr->StartBlock);
638 ser_uint32(dcr->EndBlock);
639 ser_uint32(dcr->StartFile);
640 ser_uint32(dcr->EndFile);
641 ser_uint32(jcr->JobErrors);
643 /* Added in VerNum 11 */
644 ser_uint32(jcr->JobStatus);
646 ser_end(rec->data, SER_LENGTH_Session_Label);
647 rec->data_len = ser_length(rec->data);
650 /* Write session label
651 * Returns: false on failure
654 bool write_session_label(DCR *dcr, int label)
657 DEVICE *dev = dcr->dev;
659 DEV_BLOCK *block = dcr->block;
660 char buf1[100], buf2[100];
663 Dmsg1(90, "session_label record=%x\n", rec);
666 if (dev->is_tape()) {
667 dcr->StartBlock = dev->block_num;
668 dcr->StartFile = dev->file;
670 dcr->StartBlock = (uint32_t)dev->file_addr;
671 dcr->StartFile = (uint32_t)(dev->file_addr >> 32);
675 if (dev->is_tape()) {
676 dcr->EndBlock = dev->EndBlock;
677 dcr->EndFile = dev->EndFile;
679 dcr->EndBlock = (uint32_t)dev->file_addr;
680 dcr->EndFile = (uint32_t)(dev->file_addr >> 32);
684 Jmsg1(jcr, M_ABORT, 0, _("Bad session label = %d\n"), label);
687 create_session_label(dcr, rec, label);
688 rec->FileIndex = label;
691 * We guarantee that the session record can totally fit
692 * into a block. If not, write the block, and put it in
693 * the next block. Having the sesssion record totally in
694 * one block makes reading them much easier (no need to
695 * read the next block).
697 if (!can_write_record_to_block(block, rec)) {
698 Dmsg0(150, "Cannot write session label to block.\n");
699 if (!write_block_to_device(dcr)) {
700 Dmsg0(90, "Got session label write_block_to_dev error.\n");
701 /* ****FIXME***** errno is not set here */
702 Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"),
703 dev_vol_name(dev), strerror(errno));
708 if (!write_record_to_block(block, rec)) {
709 Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"),
710 dev_vol_name(dev), strerror(errno));
715 Dmsg6(20, "Write sesson_label record JobId=%d FI=%s SessId=%d Strm=%s len=%d "
716 "remainder=%d\n", jcr->JobId,
717 FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
718 stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
722 Dmsg2(20, "Leave write_session_label Block=%d File=%d\n",
723 dev->block_num, dev->file);
727 /* unser_volume_label
729 * Unserialize the Bacula Volume label into the device Volume_Label
732 * Assumes that the record is already read.
734 * Returns: false on error
738 bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec)
741 char buf1[100], buf2[100];
743 if (rec->FileIndex != VOL_LABEL && rec->FileIndex != PRE_LABEL) {
744 Mmsg3(dev->errmsg, _("Expecting Volume Label, got FI=%s Stream=%s len=%d\n"),
745 FI_to_ascii(buf1, rec->FileIndex),
746 stream_to_ascii(buf2, rec->Stream, rec->FileIndex),
753 dev->VolHdr.LabelType = rec->FileIndex;
754 dev->VolHdr.LabelSize = rec->data_len;
757 /* Unserialize the record into the Volume Header */
758 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
759 ser_begin(rec->data, SER_LENGTH_Volume_Label);
760 unser_string(dev->VolHdr.Id);
761 unser_uint32(dev->VolHdr.VerNum);
763 if (dev->VolHdr.VerNum >= 11) {
764 unser_btime(dev->VolHdr.label_btime);
765 unser_btime(dev->VolHdr.write_btime);
766 } else { /* old way */
767 unser_float64(dev->VolHdr.label_date);
768 unser_float64(dev->VolHdr.label_time);
770 unser_float64(dev->VolHdr.write_date); /* Unused with VerNum >= 11 */
771 unser_float64(dev->VolHdr.write_time); /* Unused with VerNum >= 11 */
773 unser_string(dev->VolHdr.VolumeName);
774 unser_string(dev->VolHdr.PrevVolumeName);
775 unser_string(dev->VolHdr.PoolName);
776 unser_string(dev->VolHdr.PoolType);
777 unser_string(dev->VolHdr.MediaType);
779 unser_string(dev->VolHdr.HostName);
780 unser_string(dev->VolHdr.LabelProg);
781 unser_string(dev->VolHdr.ProgVersion);
782 unser_string(dev->VolHdr.ProgDate);
784 ser_end(rec->data, SER_LENGTH_Volume_Label);
785 Dmsg0(190, "unser_vol_label\n");
786 if (debug_level >= 190) {
787 dump_volume_label(dev);
793 bool unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec)
797 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
798 unser_begin(rec->data, SER_LENGTH_Session_Label);
799 unser_string(label->Id);
800 unser_uint32(label->VerNum);
801 unser_uint32(label->JobId);
802 if (label->VerNum >= 11) {
803 unser_btime(label->write_btime);
805 unser_float64(label->write_date);
807 unser_float64(label->write_time);
808 unser_string(label->PoolName);
809 unser_string(label->PoolType);
810 unser_string(label->JobName);
811 unser_string(label->ClientName);
812 if (label->VerNum >= 10) {
813 unser_string(label->Job); /* Unique name of this Job */
814 unser_string(label->FileSetName);
815 unser_uint32(label->JobType);
816 unser_uint32(label->JobLevel);
818 if (label->VerNum >= 11) {
819 unser_string(label->FileSetMD5);
821 label->FileSetMD5[0] = 0;
823 if (rec->FileIndex == EOS_LABEL) {
824 unser_uint32(label->JobFiles);
825 unser_uint64(label->JobBytes);
826 unser_uint32(label->StartBlock);
827 unser_uint32(label->EndBlock);
828 unser_uint32(label->StartFile);
829 unser_uint32(label->EndFile);
830 unser_uint32(label->JobErrors);
831 if (label->VerNum >= 11) {
832 unser_uint32(label->JobStatus);
834 label->JobStatus = JS_Terminated; /* kludge */
840 void dump_volume_label(DEVICE *dev)
842 int dbl = debug_level;
844 const char *LabelType;
851 switch (dev->VolHdr.LabelType) {
853 LabelType = "PRE_LABEL";
856 LabelType = "VOL_LABEL";
859 LabelType = "EOM_LABEL";
862 LabelType = "SOS_LABEL";
865 LabelType = "EOS_LABEL";
871 sprintf(buf, _("Unknown %d"), dev->VolHdr.LabelType);
875 Pmsg11(-1, _("\nVolume Label:\n"
888 dev->VolHdr.Id, dev->VolHdr.VerNum,
889 dev->VolHdr.VolumeName, dev->VolHdr.PrevVolumeName,
890 File, LabelType, dev->VolHdr.LabelSize,
891 dev->VolHdr.PoolName, dev->VolHdr.MediaType,
892 dev->VolHdr.PoolType, dev->VolHdr.HostName);
894 if (dev->VolHdr.VerNum >= 11) {
896 bstrftime(dt, sizeof(dt), btime_to_unix(dev->VolHdr.label_btime));
897 Pmsg1(-1, _("Date label written: %s\n"), dt);
899 dt.julian_day_number = dev->VolHdr.label_date;
900 dt.julian_day_fraction = dev->VolHdr.label_time;
903 _("Date label written: %04d-%02d-%02d at %02d:%02d\n"),
904 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
912 static void dump_session_label(DEV_RECORD *rec, const char *type)
918 char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], ec6[30], ec7[30];
920 unser_session_label(&label, rec);
923 Pmsg7(-1, _("\n%s Record:\n"
930 ""), type, label.JobId, label.VerNum,
931 label.PoolName, label.PoolType,
932 label.JobName, label.ClientName);
934 if (label.VerNum >= 10) {
936 "Job (unique name) : %s\n"
940 ""), label.Job, label.FileSetName, label.JobType, label.JobLevel);
943 if (rec->FileIndex == EOS_LABEL) {
954 edit_uint64_with_commas(label.JobFiles, ec1),
955 edit_uint64_with_commas(label.JobBytes, ec2),
956 edit_uint64_with_commas(label.StartBlock, ec3),
957 edit_uint64_with_commas(label.EndBlock, ec4),
958 edit_uint64_with_commas(label.StartFile, ec5),
959 edit_uint64_with_commas(label.EndFile, ec6),
960 edit_uint64_with_commas(label.JobErrors, ec7),
963 if (label.VerNum >= 11) {
965 bstrftime(dt, sizeof(dt), btime_to_unix(label.write_btime));
966 Pmsg1(-1, _("Date written : %s\n"), dt);
968 dt.julian_day_number = label.write_date;
969 dt.julian_day_fraction = label.write_time;
971 Pmsg5(-1, _("Date written : %04d-%02d-%02d at %02d:%02d\n"),
972 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
978 void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose)
983 if (rec->FileIndex == 0 && rec->VolSessionId == 0 && rec->VolSessionTime == 0) {
988 switch (rec->FileIndex) {
990 type = _("Fresh Volume");
996 type = _("Begin Job Session");
999 type = _("End Job Session");
1002 type = _("End of Media");
1005 type = _("End of Tape");
1008 type = _("Unknown");
1012 switch (rec->FileIndex) {
1015 unser_volume_label(dev, rec);
1016 dump_volume_label(dev);
1019 dump_session_label(rec, type);
1022 dump_session_label(rec, type);
1025 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1026 type, dev->file, dev->block_num, rec->VolSessionId,
1027 rec->VolSessionTime, rec->Stream, rec->data_len);
1030 Pmsg0(-1, _("End of physical tape.\n"));
1033 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1034 type, dev->file, dev->block_num, rec->VolSessionId,
1035 rec->VolSessionTime, rec->Stream, rec->data_len);
1039 SESSION_LABEL label;
1041 switch (rec->FileIndex) {
1043 unser_session_label(&label, rec);
1044 bstrftimes(dt, sizeof(dt), btime_to_unix(label.write_btime));
1045 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1046 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1047 Pmsg4(-1, _(" Job=%s Date=%s Level=%c Type=%c\n"),
1048 label.Job, dt, label.JobLevel, label.JobType);
1051 char ed1[30], ed2[30];
1052 unser_session_label(&label, rec);
1053 bstrftimes(dt, sizeof(dt), btime_to_unix(label.write_btime));
1054 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1055 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1056 Pmsg7(-1, _(" Date=%s Level=%c Type=%c Files=%s Bytes=%s Errors=%d Status=%c\n"),
1057 dt, label.JobLevel, label.JobType,
1058 edit_uint64_with_commas(label.JobFiles, ed1),
1059 edit_uint64_with_commas(label.JobBytes, ed2),
1060 label.JobErrors, (char)label.JobStatus);
1066 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1067 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime,
1068 rec->Stream, rec->data_len);