3 * label.c Bacula routines to handle labels
11 Copyright (C) 2000-2005 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 ammended 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);
31 extern char my_name[];
32 extern int debug_level;
35 * Read the volume label
37 * If dcr->VolumeName == NULL, we accept any Bacula Volume
38 * If dcr->VolumeName[0] == 0, we accept any Bacula Volume
39 * otherwise dcr->VolumeName must match the Volume.
41 * If VolName given, ensure that it matches
43 * Returns VOL_ code as defined in record.h
45 * VOL_OK good label found
46 * VOL_NO_LABEL volume not labeled
47 * VOL_IO_ERROR I/O error reading tape
48 * VOL_NAME_ERROR label has wrong name
49 * VOL_CREATE_ERROR Error creating label
50 * VOL_VERSION_ERROR label has wrong version
51 * VOL_LABEL_ERROR bad label type
52 * VOL_NO_MEDIA no media in drive
54 * The dcr block is emptied on return, and the Volume is
57 int read_dev_volume_label(DCR *dcr)
60 DEVICE *dev = dcr->dev;
61 char *VolName = dcr->VolumeName;
64 DEV_BLOCK *block = dcr->block;
68 Dmsg3(100, "Enter read_volume_label device=%s vol=%s dev_Vol=%s\n",
69 dev->name(), VolName, dev->VolHdr.VolumeName);
71 if (!dev->is_open()) {
72 Emsg0(M_ABORT, 0, _("BAD call to read_dev_volume_label\n"));
74 if (dev->is_labeled()) { /* did we already read label? */
75 /* Compare Volume Names allow special wild card */
76 if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolumeName, VolName) != 0) {
77 Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
78 dev->print_name(), VolName, dev->VolHdr.VolumeName);
80 * Cancel Job if too many label errors
83 if (!dev->poll && jcr->label_errors++ > 100) {
84 Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
86 Dmsg0(100, "return VOL_NAME_ERROR\n");
87 return VOL_NAME_ERROR;
89 Dmsg0(30, "Leave read_volume_label() VOL_OK\n");
90 return VOL_OK; /* label already read */
96 dev->label_type = B_BACULA_LABEL;
98 if (!rewind_dev(dev)) {
99 Mmsg(jcr->errmsg, _("Couldn't rewind device %s: ERR=%s\n"),
100 dev->print_name(), strerror_dev(dev));
101 Dmsg1(30, "return VOL_NO_MEDIA: %s", jcr->errmsg);
104 bstrncpy(dev->VolHdr.Id, "**error**", sizeof(dev->VolHdr.Id));
106 /* Read ANSI/IBM label if so requested */
108 want_ansi_label = dcr->VolCatInfo.LabelType != B_BACULA_LABEL ||
109 dcr->device->label_type != B_BACULA_LABEL;
110 if (want_ansi_label || dev_cap(dev, CAP_CHECKLABELS)) {
111 stat = read_ansi_ibm_label(dcr);
112 /* If we want a label and didn't find it, return error */
113 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 Dmsg1(100, "return %d\n", stat);
129 if (stat != VOL_OK) { /* Not an ANSI/IBM label, so re-read */
134 /* Read the Bacula Volume label block */
135 record = new_record();
138 Dmsg0(90, "Big if statement in read_volume_label\n");
139 if (!read_block_from_dev(dcr, NO_BLOCK_NUMBER_CHECK)) {
140 Mmsg(jcr->errmsg, _("Requested Volume \"%s\" on %s is not a Bacula "
141 "labeled Volume, because: ERR=%s"), NPRT(VolName),
142 dev->print_name(), strerror_dev(dev));
143 Dmsg1(30, "%s", jcr->errmsg);
144 } else if (!read_record_from_block(block, record)) {
145 Mmsg(jcr->errmsg, _("Could not read Volume label from block.\n"));
146 Dmsg1(30, "%s", jcr->errmsg);
147 } else if (!unser_volume_label(dev, record)) {
148 Mmsg(jcr->errmsg, _("Could not unserialize Volume label: ERR=%s\n"),
150 Dmsg1(30, "%s", jcr->errmsg);
151 } else if (strcmp(dev->VolHdr.Id, BaculaId) != 0 &&
152 strcmp(dev->VolHdr.Id, OldBaculaId) != 0) {
153 Mmsg(jcr->errmsg, _("Volume Header Id bad: %s\n"), dev->VolHdr.Id);
154 Dmsg1(30, "%s", jcr->errmsg);
158 free_record(record); /* finished reading Volume record */
159 empty_block(block); /* done with block */
162 if (forge_on || jcr->ignore_label_errors) {
163 dev->set_labeled(); /* set has Bacula label */
164 Jmsg(jcr, M_ERROR, 0, "%s", jcr->errmsg);
168 Dmsg0(100, "return VOL_NO_LABEL\n");
172 /* At this point, we have read the first Bacula block, and
173 * then read the Bacula Volume label. Now we need to
174 * make sure we have the right Volume.
177 /* If we are a streaming device, we only get one chance to read */
178 if (!dev_cap(dev, CAP_STREAM)) {
182 if (dev->VolHdr.VerNum != BaculaTapeVersion &&
183 dev->VolHdr.VerNum != OldCompatibleBaculaTapeVersion1 &&
184 dev->VolHdr.VerNum != OldCompatibleBaculaTapeVersion2) {
185 Mmsg(jcr->errmsg, _("Volume on %s has wrong Bacula version. Wanted %d got %d\n"),
186 dev->print_name(), BaculaTapeVersion, dev->VolHdr.VerNum);
187 Dmsg1(30, "VOL_VERSION_ERROR: %s", jcr->errmsg);
188 return VOL_VERSION_ERROR;
191 /* We are looking for either an unused Bacula tape (PRE_LABEL) or
192 * a Bacula volume label (VOL_LABEL)
194 if (dev->VolHdr.LabelType != PRE_LABEL && dev->VolHdr.LabelType != VOL_LABEL) {
195 Mmsg(jcr->errmsg, _("Volume on %s has bad Bacula label type: %x\n"),
196 dev->print_name(), dev->VolHdr.LabelType);
197 Dmsg1(30, "%s", jcr->errmsg);
198 if (!dev->poll && jcr->label_errors++ > 100) {
199 Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
201 Dmsg0(100, "return VOL_LABEL_ERROR\n");
202 return VOL_LABEL_ERROR;
205 dev->set_labeled(); /* set has Bacula label */
206 new_volume(dev->VolHdr.VolumeName, dev);
208 /* Compare Volume Names */
209 Dmsg2(30, "Compare Vol names: VolName=%s hdr=%s\n", VolName?VolName:"*", dev->VolHdr.VolumeName);
210 if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolumeName, VolName) != 0) {
211 Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
212 dev->print_name(), VolName, dev->VolHdr.VolumeName);
213 Dmsg1(30, "%s", jcr->errmsg);
215 * Cancel Job if too many label errors
216 * => we are in a loop
218 if (!dev->poll && jcr->label_errors++ > 100) {
219 Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
221 Dmsg0(100, "return VOL_NAME_ERROR\n");
222 return VOL_NAME_ERROR;
224 Dmsg1(30, "Copy vol_name=%s\n", dev->VolHdr.VolumeName);
226 if (debug_level >= 10) {
227 dump_volume_label(dev);
229 Dmsg0(30, "Leave read_volume_label() VOL_OK\n");
234 * Put a volume label into the block
236 * Returns: false on failure
239 bool write_volume_label_to_block(DCR *dcr)
242 DEVICE *dev = dcr->dev;
244 DEV_BLOCK *block = dcr->block;
246 Dmsg0(20, "write Label in write_volume_label_to_block()\n");
247 memset(&rec, 0, sizeof(rec));
248 rec.data = get_memory(SER_LENGTH_Volume_Label);
249 empty_block(block); /* Volume label always at beginning */
251 create_volume_label_record(dcr, &rec);
253 block->BlockNumber = 0;
254 if (!write_record_to_block(block, &rec)) {
255 free_pool_memory(rec.data);
256 Jmsg1(jcr, M_FATAL, 0, _("Cannot write Volume label to block for device %s\n"),
260 Dmsg1(90, "Wrote label of %d bytes to block\n", rec.data_len);
262 free_pool_memory(rec.data);
268 * Write a Volume Label
269 * !!! Note, this is ONLY used for writing
270 * a fresh volume label. Any data
271 * after the label will be destroyed,
272 * in fact, we write the label 5 times !!!!
274 * This routine expects that open_device() was previously called.
276 * This routine should be used only when labeling a blank tape.
278 bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName, const char *PoolName)
280 DEVICE *dev = dcr->dev;
283 Dmsg0(99, "write_volume_label()\n");
284 empty_block(dcr->block);
286 Dmsg1(100, "Label type=%d\n", dev->label_type);
287 if (!rewind_dev(dev)) {
288 memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
289 Dmsg2(30, "Bad status on %s from rewind: ERR=%s\n", dev->print_name(), strerror_dev(dev));
295 /* Create PRE_LABEL */
296 create_volume_label(dev, VolName, PoolName);
299 * If we have already detected an ANSI label, re-read it
300 * to skip past it. Otherwise, we write a new one if
303 if (dev->label_type != B_BACULA_LABEL) {
304 if (read_ansi_ibm_label(dcr) != VOL_OK) {
308 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, VolName)) {
312 create_volume_label_record(dcr, dcr->rec);
313 dcr->rec->Stream = 0;
315 /* Temporarily mark in append state to enable writing */
317 if (!write_record_to_block(dcr->block, dcr->rec)) {
318 Dmsg2(30, "Bad Label write on %s: ERR=%s\n", dev->print_name(), strerror_dev(dev));
321 Dmsg2(30, "Wrote label of %d bytes to %s\n", dcr->rec->data_len, dev->print_name());
324 Dmsg0(99, "Call write_block_to_dev()\n");
325 if (!write_block_to_dev(dcr)) {
326 Dmsg2(30, "Bad Label write on %s: ERR=%s\n", dev->print_name(), strerror_dev(dev));
329 Dmsg0(99, " Wrote block to device\n");
331 if (weof_dev(dev, 1) == 0) {
333 write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
336 if (debug_level >= 20) {
337 dump_volume_label(dev);
339 dev->clear_append(); /* remove append since this is PRE_LABEL */
343 memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
344 dev->clear_append(); /* remove append since this is PRE_LABEL */
349 * Write a volume label. This is ONLY called if we have a valid Bacula
350 * label of type PRE_LABEL;
351 * Returns: true if OK
352 * false if unable to write it
354 bool rewrite_volume_label(DCR *dcr, bool recycle)
356 DEVICE *dev = dcr->dev;
359 Dmsg1(190, "set append found freshly labeled volume. dev=%x\n", dev);
360 dev->VolHdr.LabelType = VOL_LABEL; /* set Volume label */
362 if (!write_volume_label_to_block(dcr)) {
363 Dmsg0(200, "Error from write volume label.\n");
367 * If we are not dealing with a streaming device,
368 * write the block now to ensure we have write permission.
369 * It is better to find out now rather than later.
370 * We do not write the block now if this is an ANSI label. This
371 * avoids re-writing the ANSI label, which we do not want to do.
373 if (!dev_cap(dev, CAP_STREAM)) {
374 if (!rewind_dev(dev)) {
375 Jmsg2(jcr, M_WARNING, 0, _("Rewind error on device %s: ERR=%s\n"),
376 dev->print_name(), strerror_dev(dev));
379 if (!truncate_dev(dev)) {
380 Jmsg2(jcr, M_WARNING, 0, _("Truncate error on device %s: ERR=%s\n"),
381 dev->print_name(), strerror_dev(dev));
386 * If we have already detected an ANSI label, re-read it
387 * to skip past it. Otherwise, we write a new one if
390 if (dev->label_type != B_BACULA_LABEL) {
391 if (read_ansi_ibm_label(dcr) != VOL_OK) {
395 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, dev->VolHdr.VolumeName)) {
399 /* Attempt write to check write permission */
400 Dmsg0(200, "Attempt to write to device.\n");
401 if (!write_block_to_dev(dcr)) {
402 Jmsg2(jcr, M_ERROR, 0, _("Unable to write device %s: ERR=%s\n"),
403 dev->print_name(), strerror_dev(dev));
404 Dmsg0(200, "===ERROR write block to dev\n");
408 /* Set or reset Volume statistics */
409 dev->VolCatInfo.VolCatJobs = 0;
410 dev->VolCatInfo.VolCatFiles = 0;
411 dev->VolCatInfo.VolCatBytes = 1;
412 dev->VolCatInfo.VolCatErrors = 0;
413 dev->VolCatInfo.VolCatBlocks = 0;
414 dev->VolCatInfo.VolCatRBytes = 0;
416 dev->VolCatInfo.VolCatMounts++;
417 dev->VolCatInfo.VolCatRecycles++;
419 dev->VolCatInfo.VolCatMounts = 1;
420 dev->VolCatInfo.VolCatRecycles = 0;
421 dev->VolCatInfo.VolCatWrites = 1;
422 dev->VolCatInfo.VolCatReads = 1;
424 Dmsg0(100, "dir_update_vol_info. Set Append\n");
425 bstrncpy(dev->VolCatInfo.VolCatStatus, "Append", sizeof(dev->VolCatInfo.VolCatStatus));
426 if (!dir_update_volume_info(dcr, true)) { /* indicate doing relabel */
430 Jmsg(jcr, M_INFO, 0, _("Recycled volume \"%s\" on device %s, all previous data lost.\n"),
431 dcr->VolumeName, dev->print_name());
433 Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume \"%s\" on device %s\n"),
434 dcr->VolumeName, dev->print_name());
437 * End writing real Volume label (from pre-labeled tape), or recycling
440 Dmsg0(200, "OK from rewite vol label.\n");
446 * create_volume_label_record
447 * Serialize label (from dev->VolHdr structure) into device record.
448 * Assumes that the dev->VolHdr structure is properly
451 static void create_volume_label_record(DCR *dcr, DEV_RECORD *rec)
455 DEVICE *dev = dcr->dev;
458 /* Serialize the label into the device record. */
460 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
461 ser_begin(rec->data, SER_LENGTH_Volume_Label);
462 ser_string(dev->VolHdr.Id);
464 ser_uint32(dev->VolHdr.VerNum);
466 if (dev->VolHdr.VerNum >= 11) {
467 ser_btime(dev->VolHdr.label_btime);
468 dev->VolHdr.write_btime = get_current_btime();
469 ser_btime(dev->VolHdr.write_btime);
470 dev->VolHdr.write_date = 0;
471 dev->VolHdr.write_time = 0;
473 /* OLD WAY DEPRECATED */
474 ser_float64(dev->VolHdr.label_date);
475 ser_float64(dev->VolHdr.label_time);
476 get_current_time(&dt);
477 dev->VolHdr.write_date = dt.julian_day_number;
478 dev->VolHdr.write_time = dt.julian_day_fraction;
480 ser_float64(dev->VolHdr.write_date); /* 0 if VerNum >= 11 */
481 ser_float64(dev->VolHdr.write_time); /* 0 if VerNum >= 11 */
483 ser_string(dev->VolHdr.VolumeName);
484 ser_string(dev->VolHdr.PrevVolumeName);
485 ser_string(dev->VolHdr.PoolName);
486 ser_string(dev->VolHdr.PoolType);
487 ser_string(dev->VolHdr.MediaType);
489 ser_string(dev->VolHdr.HostName);
490 ser_string(dev->VolHdr.LabelProg);
491 ser_string(dev->VolHdr.ProgVersion);
492 ser_string(dev->VolHdr.ProgDate);
494 ser_end(rec->data, SER_LENGTH_Volume_Label);
495 rec->data_len = ser_length(rec->data);
496 rec->FileIndex = dev->VolHdr.LabelType;
497 rec->VolSessionId = jcr->VolSessionId;
498 rec->VolSessionTime = jcr->VolSessionTime;
499 rec->Stream = jcr->NumVolumes;
500 Dmsg2(100, "Created Vol label rec: FI=%s len=%d\n", FI_to_ascii(rec->FileIndex),
506 * Create a volume label in memory
508 void create_volume_label(DEVICE *dev, const char *VolName, const char *PoolName)
510 DEVRES *device = (DEVRES *)dev->device;
512 Dmsg0(90, "Start create_volume_label()\n");
516 memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
518 bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
519 dev->VolHdr.VerNum = BaculaTapeVersion;
520 dev->VolHdr.LabelType = PRE_LABEL; /* Mark tape as unused */
521 bstrncpy(dev->VolHdr.VolumeName, VolName, sizeof(dev->VolHdr.VolumeName));
522 bstrncpy(dev->VolHdr.PoolName, PoolName, sizeof(dev->VolHdr.PoolName));
523 bstrncpy(dev->VolHdr.MediaType, device->media_type, sizeof(dev->VolHdr.MediaType));
525 bstrncpy(dev->VolHdr.PoolType, "Backup", sizeof(dev->VolHdr.PoolType));
527 dev->VolHdr.label_btime = get_current_btime();
528 dev->VolHdr.label_date = 0;
529 dev->VolHdr.label_time = 0;
531 if (gethostname(dev->VolHdr.HostName, sizeof(dev->VolHdr.HostName)) != 0) {
532 dev->VolHdr.HostName[0] = 0;
534 bstrncpy(dev->VolHdr.LabelProg, my_name, sizeof(dev->VolHdr.LabelProg));
535 sprintf(dev->VolHdr.ProgVersion, "Ver. %s %s", VERSION, BDATE);
536 sprintf(dev->VolHdr.ProgDate, "Build %s %s", __DATE__, __TIME__);
537 dev->set_labeled(); /* set has Bacula label */
538 if (debug_level >= 90) {
539 dump_volume_label(dev);
544 * Create session label
545 * The pool memory must be released by the calling program
547 void create_session_label(DCR *dcr, DEV_RECORD *rec, int label)
552 rec->VolSessionId = jcr->VolSessionId;
553 rec->VolSessionTime = jcr->VolSessionTime;
554 rec->Stream = jcr->JobId;
556 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
557 ser_begin(rec->data, SER_LENGTH_Session_Label);
558 ser_string(BaculaId);
559 ser_uint32(BaculaTapeVersion);
561 ser_uint32(jcr->JobId);
563 /* Changed in VerNum 11 */
564 ser_btime(get_current_btime());
567 ser_string(dcr->pool_name);
568 ser_string(dcr->pool_type);
569 ser_string(jcr->job_name); /* base Job name */
570 ser_string(jcr->client_name);
572 /* Added in VerNum 10 */
573 ser_string(jcr->Job); /* Unique name of this Job */
574 ser_string(jcr->fileset_name);
575 ser_uint32(jcr->JobType);
576 ser_uint32(jcr->JobLevel);
577 /* Added in VerNum 11 */
578 ser_string(jcr->fileset_md5);
580 if (label == EOS_LABEL) {
581 ser_uint32(jcr->JobFiles);
582 ser_uint64(jcr->JobBytes);
583 ser_uint32(dcr->StartBlock);
584 ser_uint32(dcr->EndBlock);
585 ser_uint32(dcr->StartFile);
586 ser_uint32(dcr->EndFile);
587 ser_uint32(jcr->JobErrors);
589 /* Added in VerNum 11 */
590 ser_uint32(jcr->JobStatus);
592 ser_end(rec->data, SER_LENGTH_Session_Label);
593 rec->data_len = ser_length(rec->data);
596 /* Write session label
597 * Returns: false on failure
600 bool write_session_label(DCR *dcr, int label)
603 DEVICE *dev = dcr->dev;
605 DEV_BLOCK *block = dcr->block;
608 Dmsg1(90, "session_label record=%x\n", rec);
611 if (dev->is_tape()) {
612 dcr->StartBlock = dev->block_num;
613 dcr->StartFile = dev->file;
615 dcr->StartBlock = (uint32_t)dev->file_addr;
616 dcr->StartFile = (uint32_t)(dev->file_addr >> 32);
620 if (dev->is_tape()) {
621 dcr->EndBlock = dev->EndBlock;
622 dcr->EndFile = dev->EndFile;
624 dcr->EndBlock = (uint32_t)dev->file_addr;
625 dcr->EndFile = (uint32_t)(dev->file_addr >> 32);
629 Jmsg1(jcr, M_ABORT, 0, _("Bad session label = %d\n"), label);
632 create_session_label(dcr, rec, label);
633 rec->FileIndex = label;
636 * We guarantee that the session record can totally fit
637 * into a block. If not, write the block, and put it in
638 * the next block. Having the sesssion record totally in
639 * one block makes reading them much easier (no need to
640 * read the next block).
642 if (!can_write_record_to_block(block, rec)) {
643 Dmsg0(100, "Cannot write session label to block.\n");
644 if (!write_block_to_device(dcr)) {
645 Dmsg0(90, "Got session label write_block_to_dev error.\n");
646 /* ****FIXME***** errno is not set here */
647 Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"),
648 dev_vol_name(dev), strerror(errno));
653 if (!write_record_to_block(block, rec)) {
654 Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"),
655 dev_vol_name(dev), strerror(errno));
660 Dmsg6(20, "Write sesson_label record JobId=%d FI=%s SessId=%d Strm=%s len=%d "
661 "remainder=%d\n", jcr->JobId,
662 FI_to_ascii(rec->FileIndex), rec->VolSessionId,
663 stream_to_ascii(rec->Stream, rec->FileIndex), rec->data_len,
667 Dmsg2(20, "Leave write_session_label Block=%d File=%d\n",
668 dev->block_num, dev->file);
672 /* unser_volume_label
674 * Unserialize the Bacula Volume label into the device Volume_Label
677 * Assumes that the record is already read.
679 * Returns: false on error
683 bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec)
687 if (rec->FileIndex != VOL_LABEL && rec->FileIndex != PRE_LABEL) {
688 Mmsg3(dev->errmsg, _("Expecting Volume Label, got FI=%s Stream=%s len=%d\n"),
689 FI_to_ascii(rec->FileIndex),
690 stream_to_ascii(rec->Stream, rec->FileIndex),
697 dev->VolHdr.LabelType = rec->FileIndex;
698 dev->VolHdr.LabelSize = rec->data_len;
701 /* Unserialize the record into the Volume Header */
702 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
703 ser_begin(rec->data, SER_LENGTH_Volume_Label);
704 unser_string(dev->VolHdr.Id);
705 unser_uint32(dev->VolHdr.VerNum);
707 if (dev->VolHdr.VerNum >= 11) {
708 unser_btime(dev->VolHdr.label_btime);
709 unser_btime(dev->VolHdr.write_btime);
710 } else { /* old way */
711 unser_float64(dev->VolHdr.label_date);
712 unser_float64(dev->VolHdr.label_time);
714 unser_float64(dev->VolHdr.write_date); /* Unused with VerNum >= 11 */
715 unser_float64(dev->VolHdr.write_time); /* Unused with VerNum >= 11 */
717 unser_string(dev->VolHdr.VolumeName);
718 unser_string(dev->VolHdr.PrevVolumeName);
719 unser_string(dev->VolHdr.PoolName);
720 unser_string(dev->VolHdr.PoolType);
721 unser_string(dev->VolHdr.MediaType);
723 unser_string(dev->VolHdr.HostName);
724 unser_string(dev->VolHdr.LabelProg);
725 unser_string(dev->VolHdr.ProgVersion);
726 unser_string(dev->VolHdr.ProgDate);
728 ser_end(rec->data, SER_LENGTH_Volume_Label);
729 Dmsg0(90, "ser_read_vol\n");
730 if (debug_level >= 90) {
731 dump_volume_label(dev);
737 bool unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec)
741 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
742 unser_begin(rec->data, SER_LENGTH_Session_Label);
743 unser_string(label->Id);
744 unser_uint32(label->VerNum);
745 unser_uint32(label->JobId);
746 if (label->VerNum >= 11) {
747 unser_btime(label->write_btime);
749 unser_float64(label->write_date);
751 unser_float64(label->write_time);
752 unser_string(label->PoolName);
753 unser_string(label->PoolType);
754 unser_string(label->JobName);
755 unser_string(label->ClientName);
756 if (label->VerNum >= 10) {
757 unser_string(label->Job); /* Unique name of this Job */
758 unser_string(label->FileSetName);
759 unser_uint32(label->JobType);
760 unser_uint32(label->JobLevel);
762 if (label->VerNum >= 11) {
763 unser_string(label->FileSetMD5);
765 label->FileSetMD5[0] = 0;
767 if (rec->FileIndex == EOS_LABEL) {
768 unser_uint32(label->JobFiles);
769 unser_uint64(label->JobBytes);
770 unser_uint32(label->StartBlock);
771 unser_uint32(label->EndBlock);
772 unser_uint32(label->StartFile);
773 unser_uint32(label->EndFile);
774 unser_uint32(label->JobErrors);
775 if (label->VerNum >= 11) {
776 unser_uint32(label->JobStatus);
778 label->JobStatus = JS_Terminated; /* kludge */
784 void dump_volume_label(DEVICE *dev)
786 int dbl = debug_level;
788 const char *LabelType;
795 switch (dev->VolHdr.LabelType) {
797 LabelType = "PRE_LABEL";
800 LabelType = "VOL_LABEL";
803 LabelType = "EOM_LABEL";
806 LabelType = "SOS_LABEL";
809 LabelType = "EOS_LABEL";
815 sprintf(buf, "Unknown %d", dev->VolHdr.LabelType);
819 Pmsg11(-1, "\nVolume Label:\n"
832 dev->VolHdr.Id, dev->VolHdr.VerNum,
833 dev->VolHdr.VolumeName, dev->VolHdr.PrevVolumeName,
834 File, LabelType, dev->VolHdr.LabelSize,
835 dev->VolHdr.PoolName, dev->VolHdr.MediaType,
836 dev->VolHdr.PoolType, dev->VolHdr.HostName);
838 if (dev->VolHdr.VerNum >= 11) {
840 bstrftime(dt, sizeof(dt), btime_to_unix(dev->VolHdr.label_btime));
841 Pmsg1(-1, "Date label written: %s\n", dt);
843 dt.julian_day_number = dev->VolHdr.label_date;
844 dt.julian_day_fraction = dev->VolHdr.label_time;
847 "Date label written: %04d-%02d-%02d at %02d:%02d\n",
848 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
856 static void dump_session_label(DEV_RECORD *rec, const char *type)
862 char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], ec6[30], ec7[30];
864 unser_session_label(&label, rec);
867 Pmsg7(-1, "\n%s Record:\n"
874 "", type, label.JobId, label.VerNum,
875 label.PoolName, label.PoolType,
876 label.JobName, label.ClientName);
878 if (label.VerNum >= 10) {
880 "Job (unique name) : %s\n"
884 "", label.Job, label.FileSetName, label.JobType, label.JobLevel);
887 if (rec->FileIndex == EOS_LABEL) {
898 edit_uint64_with_commas(label.JobFiles, ec1),
899 edit_uint64_with_commas(label.JobBytes, ec2),
900 edit_uint64_with_commas(label.StartBlock, ec3),
901 edit_uint64_with_commas(label.EndBlock, ec4),
902 edit_uint64_with_commas(label.StartFile, ec5),
903 edit_uint64_with_commas(label.EndFile, ec6),
904 edit_uint64_with_commas(label.JobErrors, ec7),
907 if (label.VerNum >= 11) {
909 bstrftime(dt, sizeof(dt), btime_to_unix(label.write_btime));
910 Pmsg1(-1, _("Date written : %s\n"), dt);
912 dt.julian_day_number = label.write_date;
913 dt.julian_day_fraction = label.write_time;
916 "Date written : %04d-%02d-%02d at %02d:%02d\n"),
917 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
923 void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose)
930 switch (rec->FileIndex) {
932 type = _("Fresh Volume");
938 type = _("Begin Job Session");
941 type = _("End Job Session");
944 type = _("End of Media");
947 type = ("End of Tape");
954 switch (rec->FileIndex) {
957 unser_volume_label(dev, rec);
958 dump_volume_label(dev);
961 dump_session_label(rec, type);
964 dump_session_label(rec, type);
967 Pmsg5(-1, "%s Record: SessId=%d SessTime=%d JobId=%d DataLen=%d\n",
968 type, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
971 Pmsg0(-1, _("End of physical tape.\n"));
974 Pmsg5(-1, "%s Record: SessId=%d SessTime=%d JobId=%d DataLen=%d\n",
975 type, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
980 switch (rec->FileIndex) {
982 unser_session_label(&label, rec);
983 Pmsg6(-1, "%s Record: SessId=%d SessTime=%d JobId=%d Level=%c Type=%c\n",
984 type, rec->VolSessionId, rec->VolSessionTime, rec->Stream,
985 label.JobLevel, label.JobType);
988 char ed1[30], ed2[30];
989 unser_session_label(&label, rec);
990 Pmsg6(-1, "%s Record: SessId=%d SessTime=%d JobId=%d Level=%c Type=%c\n",
991 type, rec->VolSessionId, rec->VolSessionTime, rec->Stream,
992 label.JobLevel, label.JobType);
993 Pmsg4(-1, " Files=%s Bytes=%s Errors=%d Status=%c\n",
994 edit_uint64_with_commas(label.JobFiles, ed1),
995 edit_uint64_with_commas(label.JobBytes, ed2),
996 label.JobErrors, (char)label.JobStatus);
1002 Pmsg5(-1, "%s Record: SessId=%d SessTime=%d JobId=%d DataLen=%d\n",
1003 type, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);