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 return VOL_NAME_ERROR;
88 Dmsg0(30, "Leave read_volume_label() VOL_OK\n");
89 return VOL_OK; /* label already read */
95 dev->label_type = B_BACULA_LABEL;
97 if (!rewind_dev(dev)) {
98 Mmsg(jcr->errmsg, _("Couldn't rewind device %s: ERR=%s\n"),
99 dev->print_name(), strerror_dev(dev));
100 Dmsg1(30, "%s", jcr->errmsg);
103 bstrncpy(dev->VolHdr.Id, "**error**", sizeof(dev->VolHdr.Id));
105 /* Read ANSI/IBM label if so requested */
107 want_ansi_label = dcr->VolCatInfo.LabelType != B_BACULA_LABEL ||
108 dcr->device->label_type != B_BACULA_LABEL;
109 if (want_ansi_label || dev_cap(dev, CAP_CHECKLABELS)) {
110 stat = read_ansi_ibm_label(dcr);
111 /* If we want a label and didn't find it, return error */
112 if (want_ansi_label && stat != VOL_OK) {
117 if (stat == VOL_NAME_ERROR || stat == VOL_LABEL_ERROR) {
118 Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
119 dev->print_name(), VolName, dev->VolHdr.VolumeName);
120 if (!dev->poll && jcr->label_errors++ > 100) {
121 Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
127 if (stat != VOL_OK) { /* Not an ANSI/IBM label, so re-read */
132 /* Read the Bacula Volume label block */
133 record = new_record();
136 Dmsg0(90, "Big if statement in read_volume_label\n");
137 if (!read_block_from_dev(dcr, NO_BLOCK_NUMBER_CHECK)) {
138 Mmsg(jcr->errmsg, _("Requested Volume \"%s\" on %s is not a Bacula "
139 "labeled Volume, because: ERR=%s"), NPRT(VolName),
140 dev->print_name(), strerror_dev(dev));
141 Dmsg1(30, "%s", jcr->errmsg);
142 } else if (!read_record_from_block(block, record)) {
143 Mmsg(jcr->errmsg, _("Could not read Volume label from block.\n"));
144 Dmsg1(30, "%s", jcr->errmsg);
145 } else if (!unser_volume_label(dev, record)) {
146 Mmsg(jcr->errmsg, _("Could not unserialize Volume label: ERR=%s\n"),
148 Dmsg1(30, "%s", jcr->errmsg);
149 } else if (strcmp(dev->VolHdr.Id, BaculaId) != 0 &&
150 strcmp(dev->VolHdr.Id, OldBaculaId) != 0) {
151 Mmsg(jcr->errmsg, _("Volume Header Id bad: %s\n"), dev->VolHdr.Id);
152 Dmsg1(30, "%s", jcr->errmsg);
156 free_record(record); /* finished reading Volume record */
157 empty_block(block); /* done with block */
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);
169 /* At this point, we have read the first Bacula block, and
170 * then read the Bacula Volume label. Now we need to
171 * make sure we have the right Volume.
174 /* If we are a streaming device, we only get one chance to read */
175 if (!dev_cap(dev, CAP_STREAM)) {
179 if (dev->VolHdr.VerNum != BaculaTapeVersion &&
180 dev->VolHdr.VerNum != OldCompatibleBaculaTapeVersion1 &&
181 dev->VolHdr.VerNum != OldCompatibleBaculaTapeVersion2) {
182 Mmsg(jcr->errmsg, _("Volume on %s has wrong Bacula version. Wanted %d got %d\n"),
183 dev->print_name(), BaculaTapeVersion, dev->VolHdr.VerNum);
184 Dmsg1(30, "%s", jcr->errmsg);
185 return VOL_VERSION_ERROR;
188 /* We are looking for either an unused Bacula tape (PRE_LABEL) or
189 * a Bacula volume label (VOL_LABEL)
191 if (dev->VolHdr.LabelType != PRE_LABEL && dev->VolHdr.LabelType != VOL_LABEL) {
192 Mmsg(jcr->errmsg, _("Volume on %s has bad Bacula label type: %x\n"),
193 dev->print_name(), dev->VolHdr.LabelType);
194 Dmsg1(30, "%s", jcr->errmsg);
195 if (!dev->poll && jcr->label_errors++ > 100) {
196 Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
198 return VOL_LABEL_ERROR;
201 dev->set_labeled(); /* set has Bacula label */
202 new_volume(dev->VolHdr.VolumeName, dev);
204 /* Compare Volume Names */
205 Dmsg2(30, "Compare Vol names: VolName=%s hdr=%s\n", VolName?VolName:"*", dev->VolHdr.VolumeName);
206 if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolumeName, VolName) != 0) {
207 Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
208 dev->print_name(), VolName, dev->VolHdr.VolumeName);
209 Dmsg1(30, "%s", jcr->errmsg);
211 * Cancel Job if too many label errors
212 * => we are in a loop
214 if (!dev->poll && jcr->label_errors++ > 100) {
215 Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
217 return VOL_NAME_ERROR;
219 Dmsg1(30, "Copy vol_name=%s\n", dev->VolHdr.VolumeName);
221 if (debug_level >= 10) {
222 dump_volume_label(dev);
224 Dmsg0(30, "Leave read_volume_label() VOL_OK\n");
228 /* Read the volume label by guessing the volume name. (only for DVD devices)
229 * write is true if we are reading the label before writing to the device.
231 * If the volume name cannot be guessed :
232 * Writing : returns the label of the current file (on the harddisk).
233 * Reading : returns an error
235 int read_dvd_volume_label(DCR *dcr, bool write)
237 int vol_label_status;
238 DEVICE *dev = dcr->dev;
240 Dmsg3(100, "Enter read_dvd_volume_label device=%s vol=%s dev_Vol=%s\n",
241 dev->print_name(), dcr->VolumeName, dev->VolHdr.VolumeName);
243 if (!dev->is_dvd()) {
244 Jmsg1(jcr, M_ABORT, 0, _("Device %s is not a DVD.\n"), dev->print_name());
245 return -1; /* for compiler, won't get here */
248 if (!write && (dcr->VolCatInfo.VolCatParts == 0)) {
249 Dmsg0(100, "Leave read_dvd_volume_label !writing, and VolCatParts == 0\n");
250 return read_dev_volume_label(dcr);
254 * For mounted devices, try to guess the Volume name
255 * and read the label if possible.
257 if (open_mounted_dev(dev) < 0) {
258 if (!write || dcr->VolCatInfo.VolCatParts > 0) {
259 Mmsg2(jcr->errmsg, _("Requested Volume \"%s\" on %s is not a Bacula labeled Volume."),
260 dev->print_name(), dcr->VolumeName);
261 Dmsg0(100, "Leave read_dvd_volume_label VOL_NO_LABEL (!open_mounted_dev)\n");
265 if (write && dev->free_space_errno < 0) {
266 Dmsg0(100, "Leave read_dvd_volume_label !free_space VOL_NO_MEDIA\n");
267 Mmsg2(jcr->errmsg, _("free_space error on %s. The current medium is probably not writable: ERR=%s.\n"),
268 dev->print_name(), dev->errmsg);
273 * If we can't guess the name, and we are writing,
274 * just reopen the right file with open_first_part.
276 if (open_first_part(dev) < 0) {
278 Mmsg2(jcr->errmsg, _("open_first_part error on %s: ERR=%s.\n"),
279 dev->print_name(), be.strerror());
280 Dmsg0(100, "Leave read_dvd_volume_label VOL_IO_ERROR (!open_mounted_dev && !open_first_part)\n");
284 Dmsg0(100, "Leave read_dvd_volume_label !open_mounted_dev\n");
285 return read_dev_volume_label(dcr);
287 if (write && dcr->dev->free_space_errno < 0) {
288 Dmsg0(100, "Leave read_dvd_volume_label !free_space VOL_NO_MEDIA\n");
289 Mmsg2(jcr->errmsg, _("free_space error on %s. The current medium is probably not writable: ERR=%s.\n"),
290 dev->print_name(), dev->errmsg);
294 vol_label_status = read_dev_volume_label(dcr);
296 if (!write || dcr->VolCatInfo.VolCatParts > 0) {
297 Dmsg0(100, "Leave read_dvd_volume_label (open_mounted_dev && (!write || dcr->VolCatInfo.VolCatParts > 0))\n");
298 return vol_label_status;
301 if (open_first_part(dcr->dev) < 0) {
303 Mmsg2(jcr->errmsg, _("open_first_part error on %s: ERR=%s.\n"),
304 dev->print_name(), be.strerror());
305 Dmsg0(100, "Leave read_dvd_volume_label VOL_IO_ERROR (open_mounted_dev && !open_first_part)\n");
309 /* When writing, if the guessed volume name is not the right volume name,
310 * report the error, otherwise, just continue with the right file.
312 if (vol_label_status != VOL_NAME_ERROR) {
313 Dmsg0(100, "Leave read_dvd_volume_label (open_mounted_dev && !VOL_NAME_ERROR)\n");
314 dev->clear_labeled();
315 return read_dev_volume_label(dcr);
317 Dmsg0(100, "Leave read_dvd_volume_label (open_mounted_dev && VOL_NAME_ERROR)\n");
318 return vol_label_status;
324 * Put a volume label into the block
326 * Returns: false on failure
329 bool write_volume_label_to_block(DCR *dcr)
332 DEVICE *dev = dcr->dev;
334 DEV_BLOCK *block = dcr->block;
336 Dmsg0(20, "write Label in write_volume_label_to_block()\n");
337 memset(&rec, 0, sizeof(rec));
338 rec.data = get_memory(SER_LENGTH_Volume_Label);
339 empty_block(block); /* Volume label always at beginning */
341 create_volume_label_record(dcr, &rec);
343 block->BlockNumber = 0;
344 if (!write_record_to_block(block, &rec)) {
345 free_pool_memory(rec.data);
346 Jmsg1(jcr, M_FATAL, 0, _("Cannot write Volume label to block for device %s\n"),
350 Dmsg1(90, "Wrote label of %d bytes to block\n", rec.data_len);
352 free_pool_memory(rec.data);
358 * Write a Volume Label
359 * !!! Note, this is ONLY used for writing
360 * a fresh volume label. Any data
361 * after the label will be destroyed,
362 * in fact, we write the label 5 times !!!!
364 * This routine expects that open_device() was previously called.
366 * This routine should be used only when labeling a blank tape.
368 bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName, const char *PoolName)
370 DEVICE *dev = dcr->dev;
373 Dmsg0(99, "write_volume_label()\n");
374 empty_block(dcr->block);
376 Dmsg1(100, "Label type=%d\n", dev->label_type);
377 if (!rewind_dev(dev)) {
378 memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
379 Dmsg2(30, "Bad status on %s from rewind: ERR=%s\n", dev->print_name(), strerror_dev(dev));
385 /* Create PRE_LABEL */
386 create_volume_label(dev, VolName, PoolName);
389 * If we have already detected an ANSI label, re-read it
390 * to skip past it. Otherwise, we write a new one if
393 if (dev->label_type != B_BACULA_LABEL) {
394 if (read_ansi_ibm_label(dcr) != VOL_OK) {
398 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, VolName)) {
402 create_volume_label_record(dcr, dcr->rec);
403 dcr->rec->Stream = 0;
405 /* Temporarily mark in append state to enable writing */
407 if (!write_record_to_block(dcr->block, dcr->rec)) {
408 Dmsg2(30, "Bad Label write on %s: ERR=%s\n", dev->print_name(), strerror_dev(dev));
411 Dmsg2(30, "Wrote label of %d bytes to %s\n", dcr->rec->data_len, dev->print_name());
414 Dmsg0(99, "Call write_block_to_dev()\n");
415 if (!write_block_to_dev(dcr)) {
416 Dmsg2(30, "Bad Label write on %s: ERR=%s\n", dev->print_name(), strerror_dev(dev));
419 Dmsg0(99, " Wrote block to device\n");
421 if (weof_dev(dev, 1) == 0) {
423 write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
426 if (debug_level >= 20) {
427 dump_volume_label(dev);
429 dev->clear_append(); /* remove append since this is PRE_LABEL */
433 memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
434 dev->clear_append(); /* remove append since this is PRE_LABEL */
439 * Write a volume label. This is ONLY called if we have a valid Bacula
440 * label of type PRE_LABEL;
441 * Returns: true if OK
442 * false if unable to write it
444 bool rewrite_volume_label(DCR *dcr, bool recycle)
446 DEVICE *dev = dcr->dev;
449 Dmsg1(190, "set append found freshly labeled volume. dev=%x\n", dev);
450 dev->VolHdr.LabelType = VOL_LABEL; /* set Volume label */
452 if (!write_volume_label_to_block(dcr)) {
453 Dmsg0(200, "Error from write volume label.\n");
457 * If we are not dealing with a streaming device,
458 * write the block now to ensure we have write permission.
459 * It is better to find out now rather than later.
460 * We do not write the block now if this is an ANSI label. This
461 * avoids re-writing the ANSI label, which we do not want to do.
463 if (!dev_cap(dev, CAP_STREAM)) {
464 if (!rewind_dev(dev)) {
465 Jmsg2(jcr, M_WARNING, 0, _("Rewind error on device %s: ERR=%s\n"),
466 dev->print_name(), strerror_dev(dev));
469 if (!truncate_dev(dev)) {
470 Jmsg2(jcr, M_WARNING, 0, _("Truncate error on device %s: ERR=%s\n"),
471 dev->print_name(), strerror_dev(dev));
476 * If we have already detected an ANSI label, re-read it
477 * to skip past it. Otherwise, we write a new one if
480 if (dev->label_type != B_BACULA_LABEL) {
481 if (read_ansi_ibm_label(dcr) != VOL_OK) {
485 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, dev->VolHdr.VolumeName)) {
489 /* Attempt write to check write permission */
490 Dmsg0(200, "Attempt to write to device.\n");
491 if (!write_block_to_dev(dcr)) {
492 Jmsg2(jcr, M_ERROR, 0, _("Unable to write device %s: ERR=%s\n"),
493 dev->print_name(), strerror_dev(dev));
494 Dmsg0(200, "===ERROR write block to dev\n");
498 /* Set or reset Volume statistics */
499 dev->VolCatInfo.VolCatJobs = 0;
500 dev->VolCatInfo.VolCatFiles = 0;
501 dev->VolCatInfo.VolCatBytes = 1;
502 dev->VolCatInfo.VolCatErrors = 0;
503 dev->VolCatInfo.VolCatBlocks = 0;
504 dev->VolCatInfo.VolCatRBytes = 0;
506 dev->VolCatInfo.VolCatMounts++;
507 dev->VolCatInfo.VolCatRecycles++;
509 dev->VolCatInfo.VolCatMounts = 1;
510 dev->VolCatInfo.VolCatRecycles = 0;
511 dev->VolCatInfo.VolCatWrites = 1;
512 dev->VolCatInfo.VolCatReads = 1;
514 Dmsg0(100, "dir_update_vol_info. Set Append\n");
515 bstrncpy(dev->VolCatInfo.VolCatStatus, "Append", sizeof(dev->VolCatInfo.VolCatStatus));
516 if (!dir_update_volume_info(dcr, true)) { /* indicate doing relabel */
520 Jmsg(jcr, M_INFO, 0, _("Recycled volume \"%s\" on device %s, all previous data lost.\n"),
521 dcr->VolumeName, dev->print_name());
523 Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume \"%s\" on device %s\n"),
524 dcr->VolumeName, dev->print_name());
527 * End writing real Volume label (from pre-labeled tape), or recycling
530 Dmsg0(200, "OK from rewite vol label.\n");
536 * create_volume_label_record
537 * Serialize label (from dev->VolHdr structure) into device record.
538 * Assumes that the dev->VolHdr structure is properly
541 static void create_volume_label_record(DCR *dcr, DEV_RECORD *rec)
545 DEVICE *dev = dcr->dev;
548 /* Serialize the label into the device record. */
550 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
551 ser_begin(rec->data, SER_LENGTH_Volume_Label);
552 ser_string(dev->VolHdr.Id);
554 ser_uint32(dev->VolHdr.VerNum);
556 if (dev->VolHdr.VerNum >= 11) {
557 ser_btime(dev->VolHdr.label_btime);
558 dev->VolHdr.write_btime = get_current_btime();
559 ser_btime(dev->VolHdr.write_btime);
560 dev->VolHdr.write_date = 0;
561 dev->VolHdr.write_time = 0;
563 /* OLD WAY DEPRECATED */
564 ser_float64(dev->VolHdr.label_date);
565 ser_float64(dev->VolHdr.label_time);
566 get_current_time(&dt);
567 dev->VolHdr.write_date = dt.julian_day_number;
568 dev->VolHdr.write_time = dt.julian_day_fraction;
570 ser_float64(dev->VolHdr.write_date); /* 0 if VerNum >= 11 */
571 ser_float64(dev->VolHdr.write_time); /* 0 if VerNum >= 11 */
573 ser_string(dev->VolHdr.VolumeName);
574 ser_string(dev->VolHdr.PrevVolumeName);
575 ser_string(dev->VolHdr.PoolName);
576 ser_string(dev->VolHdr.PoolType);
577 ser_string(dev->VolHdr.MediaType);
579 ser_string(dev->VolHdr.HostName);
580 ser_string(dev->VolHdr.LabelProg);
581 ser_string(dev->VolHdr.ProgVersion);
582 ser_string(dev->VolHdr.ProgDate);
584 ser_end(rec->data, SER_LENGTH_Volume_Label);
585 rec->data_len = ser_length(rec->data);
586 rec->FileIndex = dev->VolHdr.LabelType;
587 rec->VolSessionId = jcr->VolSessionId;
588 rec->VolSessionTime = jcr->VolSessionTime;
589 rec->Stream = jcr->NumVolumes;
590 Dmsg2(100, "Created Vol label rec: FI=%s len=%d\n", FI_to_ascii(rec->FileIndex),
596 * Create a volume label in memory
598 void create_volume_label(DEVICE *dev, const char *VolName, const char *PoolName)
600 DEVRES *device = (DEVRES *)dev->device;
602 Dmsg0(90, "Start create_volume_label()\n");
606 memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
608 bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
609 dev->VolHdr.VerNum = BaculaTapeVersion;
610 dev->VolHdr.LabelType = PRE_LABEL; /* Mark tape as unused */
611 bstrncpy(dev->VolHdr.VolumeName, VolName, sizeof(dev->VolHdr.VolumeName));
612 bstrncpy(dev->VolHdr.PoolName, PoolName, sizeof(dev->VolHdr.PoolName));
613 bstrncpy(dev->VolHdr.MediaType, device->media_type, sizeof(dev->VolHdr.MediaType));
615 bstrncpy(dev->VolHdr.PoolType, "Backup", sizeof(dev->VolHdr.PoolType));
617 dev->VolHdr.label_btime = get_current_btime();
618 dev->VolHdr.label_date = 0;
619 dev->VolHdr.label_time = 0;
621 if (gethostname(dev->VolHdr.HostName, sizeof(dev->VolHdr.HostName)) != 0) {
622 dev->VolHdr.HostName[0] = 0;
624 bstrncpy(dev->VolHdr.LabelProg, my_name, sizeof(dev->VolHdr.LabelProg));
625 sprintf(dev->VolHdr.ProgVersion, "Ver. %s %s", VERSION, BDATE);
626 sprintf(dev->VolHdr.ProgDate, "Build %s %s", __DATE__, __TIME__);
627 dev->set_labeled(); /* set has Bacula label */
628 if (debug_level >= 90) {
629 dump_volume_label(dev);
634 * Create session label
635 * The pool memory must be released by the calling program
637 void create_session_label(DCR *dcr, DEV_RECORD *rec, int label)
642 rec->VolSessionId = jcr->VolSessionId;
643 rec->VolSessionTime = jcr->VolSessionTime;
644 rec->Stream = jcr->JobId;
646 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
647 ser_begin(rec->data, SER_LENGTH_Session_Label);
648 ser_string(BaculaId);
649 ser_uint32(BaculaTapeVersion);
651 ser_uint32(jcr->JobId);
653 /* Changed in VerNum 11 */
654 ser_btime(get_current_btime());
657 ser_string(dcr->pool_name);
658 ser_string(dcr->pool_type);
659 ser_string(jcr->job_name); /* base Job name */
660 ser_string(jcr->client_name);
662 /* Added in VerNum 10 */
663 ser_string(jcr->Job); /* Unique name of this Job */
664 ser_string(jcr->fileset_name);
665 ser_uint32(jcr->JobType);
666 ser_uint32(jcr->JobLevel);
667 /* Added in VerNum 11 */
668 ser_string(jcr->fileset_md5);
670 if (label == EOS_LABEL) {
671 ser_uint32(jcr->JobFiles);
672 ser_uint64(jcr->JobBytes);
673 ser_uint32(dcr->StartBlock);
674 ser_uint32(dcr->EndBlock);
675 ser_uint32(dcr->StartFile);
676 ser_uint32(dcr->EndFile);
677 ser_uint32(jcr->JobErrors);
679 /* Added in VerNum 11 */
680 ser_uint32(jcr->JobStatus);
682 ser_end(rec->data, SER_LENGTH_Session_Label);
683 rec->data_len = ser_length(rec->data);
686 /* Write session label
687 * Returns: false on failure
690 bool write_session_label(DCR *dcr, int label)
693 DEVICE *dev = dcr->dev;
695 DEV_BLOCK *block = dcr->block;
698 Dmsg1(90, "session_label record=%x\n", rec);
701 if (dev->is_tape()) {
702 dcr->StartBlock = dev->block_num;
703 dcr->StartFile = dev->file;
705 dcr->StartBlock = (uint32_t)dev->file_addr;
706 dcr->StartFile = (uint32_t)(dev->file_addr >> 32);
710 if (dev->is_tape()) {
711 dcr->EndBlock = dev->EndBlock;
712 dcr->EndFile = dev->EndFile;
714 dcr->EndBlock = (uint32_t)dev->file_addr;
715 dcr->EndFile = (uint32_t)(dev->file_addr >> 32);
719 Jmsg1(jcr, M_ABORT, 0, _("Bad session label = %d\n"), label);
722 create_session_label(dcr, rec, label);
723 rec->FileIndex = label;
726 * We guarantee that the session record can totally fit
727 * into a block. If not, write the block, and put it in
728 * the next block. Having the sesssion record totally in
729 * one block makes reading them much easier (no need to
730 * read the next block).
732 if (!can_write_record_to_block(block, rec)) {
733 Dmsg0(100, "Cannot write session label to block.\n");
734 if (!write_block_to_device(dcr)) {
735 Dmsg0(90, "Got session label write_block_to_dev error.\n");
736 /* ****FIXME***** errno is not set here */
737 Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"),
738 dev_vol_name(dev), strerror(errno));
743 if (!write_record_to_block(block, rec)) {
744 Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"),
745 dev_vol_name(dev), strerror(errno));
750 Dmsg6(20, "Write sesson_label record JobId=%d FI=%s SessId=%d Strm=%s len=%d "
751 "remainder=%d\n", jcr->JobId,
752 FI_to_ascii(rec->FileIndex), rec->VolSessionId,
753 stream_to_ascii(rec->Stream, rec->FileIndex), rec->data_len,
757 Dmsg2(20, "Leave write_session_label Block=%d File=%d\n",
758 dev->block_num, dev->file);
762 /* unser_volume_label
764 * Unserialize the Bacula Volume label into the device Volume_Label
767 * Assumes that the record is already read.
769 * Returns: false on error
773 bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec)
777 if (rec->FileIndex != VOL_LABEL && rec->FileIndex != PRE_LABEL) {
778 Mmsg3(dev->errmsg, _("Expecting Volume Label, got FI=%s Stream=%s len=%d\n"),
779 FI_to_ascii(rec->FileIndex),
780 stream_to_ascii(rec->Stream, rec->FileIndex),
787 dev->VolHdr.LabelType = rec->FileIndex;
788 dev->VolHdr.LabelSize = rec->data_len;
791 /* Unserialize the record into the Volume Header */
792 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
793 ser_begin(rec->data, SER_LENGTH_Volume_Label);
794 unser_string(dev->VolHdr.Id);
795 unser_uint32(dev->VolHdr.VerNum);
797 if (dev->VolHdr.VerNum >= 11) {
798 unser_btime(dev->VolHdr.label_btime);
799 unser_btime(dev->VolHdr.write_btime);
800 } else { /* old way */
801 unser_float64(dev->VolHdr.label_date);
802 unser_float64(dev->VolHdr.label_time);
804 unser_float64(dev->VolHdr.write_date); /* Unused with VerNum >= 11 */
805 unser_float64(dev->VolHdr.write_time); /* Unused with VerNum >= 11 */
807 unser_string(dev->VolHdr.VolumeName);
808 unser_string(dev->VolHdr.PrevVolumeName);
809 unser_string(dev->VolHdr.PoolName);
810 unser_string(dev->VolHdr.PoolType);
811 unser_string(dev->VolHdr.MediaType);
813 unser_string(dev->VolHdr.HostName);
814 unser_string(dev->VolHdr.LabelProg);
815 unser_string(dev->VolHdr.ProgVersion);
816 unser_string(dev->VolHdr.ProgDate);
818 ser_end(rec->data, SER_LENGTH_Volume_Label);
819 Dmsg0(90, "ser_read_vol\n");
820 if (debug_level >= 90) {
821 dump_volume_label(dev);
827 bool unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec)
831 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
832 unser_begin(rec->data, SER_LENGTH_Session_Label);
833 unser_string(label->Id);
834 unser_uint32(label->VerNum);
835 unser_uint32(label->JobId);
836 if (label->VerNum >= 11) {
837 unser_btime(label->write_btime);
839 unser_float64(label->write_date);
841 unser_float64(label->write_time);
842 unser_string(label->PoolName);
843 unser_string(label->PoolType);
844 unser_string(label->JobName);
845 unser_string(label->ClientName);
846 if (label->VerNum >= 10) {
847 unser_string(label->Job); /* Unique name of this Job */
848 unser_string(label->FileSetName);
849 unser_uint32(label->JobType);
850 unser_uint32(label->JobLevel);
852 if (label->VerNum >= 11) {
853 unser_string(label->FileSetMD5);
855 label->FileSetMD5[0] = 0;
857 if (rec->FileIndex == EOS_LABEL) {
858 unser_uint32(label->JobFiles);
859 unser_uint64(label->JobBytes);
860 unser_uint32(label->StartBlock);
861 unser_uint32(label->EndBlock);
862 unser_uint32(label->StartFile);
863 unser_uint32(label->EndFile);
864 unser_uint32(label->JobErrors);
865 if (label->VerNum >= 11) {
866 unser_uint32(label->JobStatus);
868 label->JobStatus = JS_Terminated; /* kludge */
874 void dump_volume_label(DEVICE *dev)
876 int dbl = debug_level;
878 const char *LabelType;
885 switch (dev->VolHdr.LabelType) {
887 LabelType = "PRE_LABEL";
890 LabelType = "VOL_LABEL";
893 LabelType = "EOM_LABEL";
896 LabelType = "SOS_LABEL";
899 LabelType = "EOS_LABEL";
905 sprintf(buf, "Unknown %d", dev->VolHdr.LabelType);
909 Pmsg11(-1, "\nVolume Label:\n"
922 dev->VolHdr.Id, dev->VolHdr.VerNum,
923 dev->VolHdr.VolumeName, dev->VolHdr.PrevVolumeName,
924 File, LabelType, dev->VolHdr.LabelSize,
925 dev->VolHdr.PoolName, dev->VolHdr.MediaType,
926 dev->VolHdr.PoolType, dev->VolHdr.HostName);
928 if (dev->VolHdr.VerNum >= 11) {
930 bstrftime(dt, sizeof(dt), btime_to_unix(dev->VolHdr.label_btime));
931 Pmsg1(-1, "Date label written: %s\n", dt);
933 dt.julian_day_number = dev->VolHdr.label_date;
934 dt.julian_day_fraction = dev->VolHdr.label_time;
937 "Date label written: %04d-%02d-%02d at %02d:%02d\n",
938 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
946 static void dump_session_label(DEV_RECORD *rec, const char *type)
952 char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], ec6[30], ec7[30];
954 unser_session_label(&label, rec);
957 Pmsg7(-1, "\n%s Record:\n"
964 "", type, label.JobId, label.VerNum,
965 label.PoolName, label.PoolType,
966 label.JobName, label.ClientName);
968 if (label.VerNum >= 10) {
970 "Job (unique name) : %s\n"
974 "", label.Job, label.FileSetName, label.JobType, label.JobLevel);
977 if (rec->FileIndex == EOS_LABEL) {
988 edit_uint64_with_commas(label.JobFiles, ec1),
989 edit_uint64_with_commas(label.JobBytes, ec2),
990 edit_uint64_with_commas(label.StartBlock, ec3),
991 edit_uint64_with_commas(label.EndBlock, ec4),
992 edit_uint64_with_commas(label.StartFile, ec5),
993 edit_uint64_with_commas(label.EndFile, ec6),
994 edit_uint64_with_commas(label.JobErrors, ec7),
997 if (label.VerNum >= 11) {
999 bstrftime(dt, sizeof(dt), btime_to_unix(label.write_btime));
1000 Pmsg1(-1, _("Date written : %s\n"), dt);
1002 dt.julian_day_number = label.write_date;
1003 dt.julian_day_fraction = label.write_time;
1004 tm_decode(&dt, &tm);
1006 "Date written : %04d-%02d-%02d at %02d:%02d\n"),
1007 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
1013 void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose)
1020 switch (rec->FileIndex) {
1022 type = _("Fresh Volume");
1028 type = _("Begin Job Session");
1031 type = _("End Job Session");
1034 type = _("End of Media");
1037 type = ("End of Tape");
1040 type = _("Unknown");
1044 switch (rec->FileIndex) {
1047 unser_volume_label(dev, rec);
1048 dump_volume_label(dev);
1051 dump_session_label(rec, type);
1054 dump_session_label(rec, type);
1057 Pmsg5(-1, "%s Record: SessId=%d SessTime=%d JobId=%d DataLen=%d\n",
1058 type, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
1061 Pmsg0(-1, _("End of physical tape.\n"));
1064 Pmsg5(-1, "%s Record: SessId=%d SessTime=%d JobId=%d DataLen=%d\n",
1065 type, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
1069 SESSION_LABEL label;
1070 switch (rec->FileIndex) {
1072 unser_session_label(&label, rec);
1073 Pmsg6(-1, "%s Record: SessId=%d SessTime=%d JobId=%d Level=%c Type=%c\n",
1074 type, rec->VolSessionId, rec->VolSessionTime, rec->Stream,
1075 label.JobLevel, label.JobType);
1078 char ed1[30], ed2[30];
1079 unser_session_label(&label, rec);
1080 Pmsg6(-1, "%s Record: SessId=%d SessTime=%d JobId=%d Level=%c Type=%c\n",
1081 type, rec->VolSessionId, rec->VolSessionTime, rec->Stream,
1082 label.JobLevel, label.JobType);
1083 Pmsg4(-1, " Files=%s Bytes=%s Errors=%d Status=%c\n",
1084 edit_uint64_with_commas(label.JobFiles, ed1),
1085 edit_uint64_with_commas(label.JobBytes, ed2),
1086 label.JobErrors, (char)label.JobStatus);
1092 Pmsg5(-1, "%s Record: SessId=%d SessTime=%d JobId=%d DataLen=%d\n",
1093 type, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);