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.VolName);
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.VolName, VolName) != 0) {
77 Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
78 dev->print_name(), VolName, dev->VolHdr.VolName);
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 */
92 dev->state &= ~(ST_LABEL|ST_APPEND|ST_READ); /* set no label, no append */
93 dev->label_type = B_BACULA_LABEL;
95 if (!rewind_dev(dev)) {
96 Mmsg(jcr->errmsg, _("Couldn't rewind device %s: ERR=%s\n"),
97 dev->print_name(), strerror_dev(dev));
98 Dmsg1(30, "%s", jcr->errmsg);
101 bstrncpy(dev->VolHdr.Id, "**error**", sizeof(dev->VolHdr.Id));
103 /* Read ANSI/IBM label if so requested */
105 want_ansi_label = dcr->VolCatInfo.LabelType != B_BACULA_LABEL ||
106 dcr->device->label_type != B_BACULA_LABEL;
107 if (want_ansi_label || dev_cap(dev, CAP_CHECKLABELS)) {
108 stat = read_ansi_ibm_label(dcr);
109 /* If we want a label and didn't find it, return error */
110 if (want_ansi_label && stat != VOL_OK) {
115 if (stat == VOL_NAME_ERROR || stat == VOL_LABEL_ERROR) {
116 Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
117 dev->print_name(), VolName, dev->VolHdr.VolName);
118 if (!dev->poll && jcr->label_errors++ > 100) {
119 Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
125 if (stat != VOL_OK) { /* Not an ANSI/IBM label, so re-read */
130 /* Read the Bacula Volume label block */
131 record = new_record();
134 Dmsg0(90, "Big if statement in read_volume_label\n");
135 if (!read_block_from_dev(dcr, NO_BLOCK_NUMBER_CHECK)) {
136 Mmsg(jcr->errmsg, _("Requested Volume \"%s\" on %s is not a Bacula "
137 "labeled Volume, because: ERR=%s"), NPRT(VolName),
138 dev->print_name(), strerror_dev(dev));
139 Dmsg1(30, "%s", jcr->errmsg);
140 } else if (!read_record_from_block(block, record)) {
141 Mmsg(jcr->errmsg, _("Could not read Volume label from block.\n"));
142 Dmsg1(30, "%s", jcr->errmsg);
143 } else if (!unser_volume_label(dev, record)) {
144 Mmsg(jcr->errmsg, _("Could not unserialize Volume label: ERR=%s\n"),
146 Dmsg1(30, "%s", jcr->errmsg);
147 } else if (strcmp(dev->VolHdr.Id, BaculaId) != 0 &&
148 strcmp(dev->VolHdr.Id, OldBaculaId) != 0) {
149 Mmsg(jcr->errmsg, _("Volume Header Id bad: %s\n"), dev->VolHdr.Id);
150 Dmsg1(30, "%s", jcr->errmsg);
154 free_record(record); /* finished reading Volume record */
155 empty_block(block); /* done with block */
158 if (forge_on || jcr->ignore_label_errors) {
159 dev->set_labeled(); /* set has Bacula label */
160 Jmsg(jcr, M_ERROR, 0, "%s", jcr->errmsg);
167 /* At this point, we have read the first Bacula block, and
168 * then read the Bacula Volume label. Now we need to
169 * make sure we have the right Volume.
172 /* If we are a streaming device, we only get one chance to read */
173 if (!dev_cap(dev, CAP_STREAM)) {
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, "%s", jcr->errmsg);
183 return VOL_VERSION_ERROR;
186 /* We are looking for either an unused Bacula tape (PRE_LABEL) or
187 * a Bacula volume label (VOL_LABEL)
189 if (dev->VolHdr.LabelType != PRE_LABEL && dev->VolHdr.LabelType != VOL_LABEL) {
190 Mmsg(jcr->errmsg, _("Volume on %s has bad Bacula label type: %x\n"),
191 dev->print_name(), dev->VolHdr.LabelType);
192 Dmsg1(30, "%s", jcr->errmsg);
193 if (!dev->poll && jcr->label_errors++ > 100) {
194 Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
196 return VOL_LABEL_ERROR;
199 dev->set_labeled(); /* set has Bacula label */
200 new_volume(dev->VolHdr.VolName, dev);
202 /* Compare Volume Names */
203 Dmsg2(30, "Compare Vol names: VolName=%s hdr=%s\n", VolName?VolName:"*", dev->VolHdr.VolName);
204 if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolName, VolName) != 0) {
205 Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
206 dev->print_name(), VolName, dev->VolHdr.VolName);
207 Dmsg1(30, "%s", jcr->errmsg);
209 * Cancel Job if too many label errors
210 * => we are in a loop
212 if (!dev->poll && jcr->label_errors++ > 100) {
213 Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
215 return VOL_NAME_ERROR;
217 Dmsg1(30, "Copy vol_name=%s\n", dev->VolHdr.VolName);
219 if (debug_level >= 10) {
220 dump_volume_label(dev);
222 Dmsg0(30, "Leave read_volume_label() VOL_OK\n");
226 /* Read the volume label by guessing the volume name. (only for DVD devices)
227 * write is true if we are reading the label before writing to the device.
229 * If the volume name cannot be guessed :
230 * Writing : returns the label of the current file (on the harddisk).
231 * Reading : returns an error
233 int read_dev_volume_label_guess(DCR *dcr, bool write)
235 int vol_label_status;
236 DEVICE *dev = dcr->dev;
238 Dmsg3(100, "Enter read_dev_volume_label_guess device=%s vol=%s dev_Vol=%s\n",
239 dev->print_name(), dcr->VolumeName, dev->VolHdr.VolName);
241 if (!dev->is_dvd()) {
242 Dmsg0(100, "Leave read_dev_volume_label_guess !CAP_REQMOUNT\n");
243 return read_dev_volume_label(dcr);
246 if (!write && (dcr->VolCatInfo.VolCatParts == 0)) {
247 Dmsg0(100, "Leave read_dev_volume_label_guess !writing, and VolCatParts == 0\n");
248 return read_dev_volume_label(dcr);
251 /* For mounted devices, tries to guess the volume name, and read the label if possible.
253 if (open_guess_name_dev(dev) < 0) {
254 if (!write || dcr->VolCatInfo.VolCatParts > 0) {
255 Mmsg2(jcr->errmsg, _("Requested Volume \"%s\" on %s is not a Bacula labeled Volume."),
256 dev->print_name(), dcr->VolumeName);
257 Dmsg0(100, "Leave read_dev_volume_label_guess VOL_NO_LABEL (!open_guess_name_dev)\n");
261 if (write && dev->free_space_errno < 0) {
262 Dmsg0(100, "Leave read_dev_volume_label_guess !free_space VOL_NO_MEDIA\n");
263 Mmsg2(jcr->errmsg, _("free_space error on %s. The current medium is probably not writable: ERR=%s.\n"),
264 dev->print_name(), dev->errmsg);
268 /* If we can't guess the name, and we are writing, just reopen the right file with open_first_part. */
269 if (open_first_part(dev) < 0) {
271 Mmsg2(jcr->errmsg, _("open_first_part error on %s: ERR=%s.\n"),
272 dev->print_name(), be.strerror());
273 Dmsg0(100, "Leave read_dev_volume_label_guess VOL_IO_ERROR (!open_guess_name_dev && !open_first_part)\n");
277 Dmsg0(100, "Leave read_dev_volume_label_guess !open_guess_name_dev\n");
278 return read_dev_volume_label(dcr);
280 if (write && dcr->dev->free_space_errno < 0) {
281 Dmsg0(100, "Leave read_dev_volume_label_guess !free_space VOL_NO_MEDIA\n");
282 Mmsg2(jcr->errmsg, _("free_space error on %s. The current medium is probably not writable: ERR=%s.\n"),
283 dev->print_name(), dev->errmsg);
287 vol_label_status = read_dev_volume_label(dcr);
289 if (!write || dcr->VolCatInfo.VolCatParts > 0) {
290 Dmsg0(100, "Leave read_dev_volume_label_guess (open_guess_name_dev && (!write || dcr->VolCatInfo.VolCatParts > 0))\n");
291 return vol_label_status;
294 if (open_first_part(dcr->dev) < 0) {
296 Mmsg2(jcr->errmsg, _("open_first_part error on %s: ERR=%s.\n"),
297 dev->print_name(), be.strerror());
298 Dmsg0(100, "Leave read_dev_volume_label_guess VOL_IO_ERROR (open_guess_name_dev && !open_first_part)\n");
302 /* When writing, if the guessed volume name is no the right volume name,
303 * report the error, otherwise, just continue with the right file.
305 if (vol_label_status != VOL_NAME_ERROR) {
306 Dmsg0(100, "Leave read_dev_volume_label_guess (open_guess_name_dev && !VOL_NAME_ERROR)\n");
307 dev->clear_labeled();
308 return read_dev_volume_label(dcr);
310 Dmsg0(100, "Leave read_dev_volume_label_guess (open_guess_name_dev && VOL_NAME_ERROR)\n");
311 return vol_label_status;
317 * Put a volume label into the block
319 * Returns: false on failure
322 bool write_volume_label_to_block(DCR *dcr)
325 DEVICE *dev = dcr->dev;
327 DEV_BLOCK *block = dcr->block;
329 Dmsg0(20, "write Label in write_volume_label_to_block()\n");
330 memset(&rec, 0, sizeof(rec));
331 rec.data = get_memory(SER_LENGTH_Volume_Label);
332 empty_block(block); /* Volume label always at beginning */
334 create_volume_label_record(dcr, &rec);
336 block->BlockNumber = 0;
337 if (!write_record_to_block(block, &rec)) {
338 free_pool_memory(rec.data);
339 Jmsg1(jcr, M_FATAL, 0, _("Cannot write Volume label to block for device %s\n"),
343 Dmsg1(90, "Wrote label of %d bytes to block\n", rec.data_len);
345 free_pool_memory(rec.data);
351 * Write a Volume Label
352 * !!! Note, this is ONLY used for writing
353 * a fresh volume label. Any data
354 * after the label will be destroyed,
355 * in fact, we write the label 5 times !!!!
357 * This routine expects that open_device() was previously called.
359 * This routine should be used only when labeling a blank tape.
361 bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName, const char *PoolName)
363 DEVICE *dev = dcr->dev;
366 Dmsg0(99, "write_volume_label()\n");
367 empty_block(dcr->block);
369 Dmsg1(100, "Label type=%d\n", dev->label_type);
370 if (!rewind_dev(dev)) {
371 memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
372 Dmsg2(30, "Bad status on %s from rewind: ERR=%s\n", dev->print_name(), strerror_dev(dev));
378 /* Create PRE_LABEL */
379 create_volume_label(dev, VolName, PoolName);
382 * If we have already detected an ANSI label, re-read it
383 * to skip past it. Otherwise, we write a new one if
386 if (dev->label_type != B_BACULA_LABEL) {
387 if (read_ansi_ibm_label(dcr) != VOL_OK) {
391 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, VolName)) {
395 create_volume_label_record(dcr, dcr->rec);
396 dcr->rec->Stream = 0;
398 /* Temporarily mark in append state to enable writing */
400 if (!write_record_to_block(dcr->block, dcr->rec)) {
401 Dmsg2(30, "Bad Label write on %s: ERR=%s\n", dev->print_name(), strerror_dev(dev));
404 Dmsg2(30, "Wrote label of %d bytes to %s\n", dcr->rec->data_len, dev->print_name());
407 Dmsg0(99, "Call write_block_to_dev()\n");
408 if (!write_block_to_dev(dcr)) {
409 Dmsg2(30, "Bad Label write on %s: ERR=%s\n", dev->print_name(), strerror_dev(dev));
412 Dmsg0(99, " Wrote block to device\n");
414 if (weof_dev(dev, 1) == 0) {
416 write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolName);
419 if (debug_level >= 20) {
420 dump_volume_label(dev);
422 dev->clear_append(); /* remove append since this is PRE_LABEL */
426 memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
427 dev->clear_append(); /* remove append since this is PRE_LABEL */
432 * Write a volume label. This is ONLY called if we have a valid Bacula
433 * label of type PRE_LABEL;
434 * Returns: true if OK
435 * false if unable to write it
437 bool rewrite_volume_label(DCR *dcr, bool recycle)
439 DEVICE *dev = dcr->dev;
442 Dmsg1(190, "set append found freshly labeled volume. dev=%x\n", dev);
443 dev->VolHdr.LabelType = VOL_LABEL; /* set Volume label */
445 if (!write_volume_label_to_block(dcr)) {
446 Dmsg0(200, "Error from write volume label.\n");
450 * If we are not dealing with a streaming device,
451 * write the block now to ensure we have write permission.
452 * It is better to find out now rather than later.
453 * We do not write the block now if this is an ANSI label. This
454 * avoids re-writing the ANSI label, which we do not want to do.
456 if (!dev_cap(dev, CAP_STREAM)) {
457 if (!rewind_dev(dev)) {
458 Jmsg2(jcr, M_WARNING, 0, _("Rewind error on device %s: ERR=%s\n"),
459 dev->print_name(), strerror_dev(dev));
462 if (!truncate_dev(dev)) {
463 Jmsg2(jcr, M_WARNING, 0, _("Truncate error on device %s: ERR=%s\n"),
464 dev->print_name(), strerror_dev(dev));
469 * If we have already detected an ANSI label, re-read it
470 * to skip past it. Otherwise, we write a new one if
473 if (dev->label_type != B_BACULA_LABEL) {
474 if (read_ansi_ibm_label(dcr) != VOL_OK) {
478 } else if (!write_ansi_ibm_labels (dcr, ANSI_VOL_LABEL, dev->VolHdr.VolName)) {
482 /* Attempt write to check write permission */
483 Dmsg0(200, "Attempt to write to device.\n");
484 if (!write_block_to_dev(dcr)) {
485 Jmsg2(jcr, M_ERROR, 0, _("Unable to write device %s: ERR=%s\n"),
486 dev->print_name(), strerror_dev(dev));
487 Dmsg0(200, "===ERROR write block to dev\n");
491 /* Set or reset Volume statistics */
492 dev->VolCatInfo.VolCatJobs = 0;
493 dev->VolCatInfo.VolCatFiles = 0;
494 dev->VolCatInfo.VolCatBytes = 1;
495 dev->VolCatInfo.VolCatErrors = 0;
496 dev->VolCatInfo.VolCatBlocks = 0;
497 dev->VolCatInfo.VolCatRBytes = 0;
499 dev->VolCatInfo.VolCatMounts++;
500 dev->VolCatInfo.VolCatRecycles++;
502 dev->VolCatInfo.VolCatMounts = 1;
503 dev->VolCatInfo.VolCatRecycles = 0;
504 dev->VolCatInfo.VolCatWrites = 1;
505 dev->VolCatInfo.VolCatReads = 1;
507 Dmsg0(100, "dir_update_vol_info. Set Append\n");
508 bstrncpy(dev->VolCatInfo.VolCatStatus, "Append", sizeof(dev->VolCatInfo.VolCatStatus));
509 if (!dir_update_volume_info(dcr, true)) { /* indicate doing relabel */
513 Jmsg(jcr, M_INFO, 0, _("Recycled volume \"%s\" on device %s, all previous data lost.\n"),
514 dcr->VolumeName, dev->print_name());
516 Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume \"%s\" on device %s\n"),
517 dcr->VolumeName, dev->print_name());
520 * End writing real Volume label (from pre-labeled tape), or recycling
523 Dmsg0(200, "OK from rewite vol label.\n");
529 * create_volume_label_record
530 * Serialize label (from dev->VolHdr structure) into device record.
531 * Assumes that the dev->VolHdr structure is properly
534 static void create_volume_label_record(DCR *dcr, DEV_RECORD *rec)
538 DEVICE *dev = dcr->dev;
541 /* Serialize the label into the device record. */
543 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
544 ser_begin(rec->data, SER_LENGTH_Volume_Label);
545 ser_string(dev->VolHdr.Id);
547 ser_uint32(dev->VolHdr.VerNum);
549 if (dev->VolHdr.VerNum >= 11) {
550 ser_btime(dev->VolHdr.label_btime);
551 dev->VolHdr.write_btime = get_current_btime();
552 ser_btime(dev->VolHdr.write_btime);
553 dev->VolHdr.write_date = 0;
554 dev->VolHdr.write_time = 0;
556 /* OLD WAY DEPRECATED */
557 ser_float64(dev->VolHdr.label_date);
558 ser_float64(dev->VolHdr.label_time);
559 get_current_time(&dt);
560 dev->VolHdr.write_date = dt.julian_day_number;
561 dev->VolHdr.write_time = dt.julian_day_fraction;
563 ser_float64(dev->VolHdr.write_date); /* 0 if VerNum >= 11 */
564 ser_float64(dev->VolHdr.write_time); /* 0 if VerNum >= 11 */
566 ser_string(dev->VolHdr.VolName);
567 ser_string(dev->VolHdr.PrevVolName);
568 ser_string(dev->VolHdr.PoolName);
569 ser_string(dev->VolHdr.PoolType);
570 ser_string(dev->VolHdr.MediaType);
572 ser_string(dev->VolHdr.HostName);
573 ser_string(dev->VolHdr.LabelProg);
574 ser_string(dev->VolHdr.ProgVersion);
575 ser_string(dev->VolHdr.ProgDate);
577 ser_end(rec->data, SER_LENGTH_Volume_Label);
578 rec->data_len = ser_length(rec->data);
579 rec->FileIndex = dev->VolHdr.LabelType;
580 rec->VolSessionId = jcr->VolSessionId;
581 rec->VolSessionTime = jcr->VolSessionTime;
582 rec->Stream = jcr->NumVolumes;
583 Dmsg2(100, "Created Vol label rec: FI=%s len=%d\n", FI_to_ascii(rec->FileIndex),
589 * Create a volume label in memory
591 void create_volume_label(DEVICE *dev, const char *VolName, const char *PoolName)
593 DEVRES *device = (DEVRES *)dev->device;
595 Dmsg0(90, "Start create_volume_label()\n");
599 memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
601 bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
602 dev->VolHdr.VerNum = BaculaTapeVersion;
603 dev->VolHdr.LabelType = PRE_LABEL; /* Mark tape as unused */
604 bstrncpy(dev->VolHdr.VolName, VolName, sizeof(dev->VolHdr.VolName));
605 bstrncpy(dev->VolHdr.PoolName, PoolName, sizeof(dev->VolHdr.PoolName));
606 bstrncpy(dev->VolHdr.MediaType, device->media_type, sizeof(dev->VolHdr.MediaType));
608 bstrncpy(dev->VolHdr.PoolType, "Backup", sizeof(dev->VolHdr.PoolType));
610 dev->VolHdr.label_btime = get_current_btime();
611 dev->VolHdr.label_date = 0;
612 dev->VolHdr.label_time = 0;
614 if (gethostname(dev->VolHdr.HostName, sizeof(dev->VolHdr.HostName)) != 0) {
615 dev->VolHdr.HostName[0] = 0;
617 bstrncpy(dev->VolHdr.LabelProg, my_name, sizeof(dev->VolHdr.LabelProg));
618 sprintf(dev->VolHdr.ProgVersion, "Ver. %s %s", VERSION, BDATE);
619 sprintf(dev->VolHdr.ProgDate, "Build %s %s", __DATE__, __TIME__);
620 dev->set_labeled(); /* set has Bacula label */
621 if (debug_level >= 90) {
622 dump_volume_label(dev);
627 * Create session label
628 * The pool memory must be released by the calling program
630 void create_session_label(DCR *dcr, DEV_RECORD *rec, int label)
635 rec->VolSessionId = jcr->VolSessionId;
636 rec->VolSessionTime = jcr->VolSessionTime;
637 rec->Stream = jcr->JobId;
639 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
640 ser_begin(rec->data, SER_LENGTH_Session_Label);
641 ser_string(BaculaId);
642 ser_uint32(BaculaTapeVersion);
644 ser_uint32(jcr->JobId);
646 /* Changed in VerNum 11 */
647 ser_btime(get_current_btime());
650 ser_string(dcr->pool_name);
651 ser_string(dcr->pool_type);
652 ser_string(jcr->job_name); /* base Job name */
653 ser_string(jcr->client_name);
655 /* Added in VerNum 10 */
656 ser_string(jcr->Job); /* Unique name of this Job */
657 ser_string(jcr->fileset_name);
658 ser_uint32(jcr->JobType);
659 ser_uint32(jcr->JobLevel);
660 /* Added in VerNum 11 */
661 ser_string(jcr->fileset_md5);
663 if (label == EOS_LABEL) {
664 ser_uint32(jcr->JobFiles);
665 ser_uint64(jcr->JobBytes);
666 ser_uint32(dcr->StartBlock);
667 ser_uint32(dcr->EndBlock);
668 ser_uint32(dcr->StartFile);
669 ser_uint32(dcr->EndFile);
670 ser_uint32(jcr->JobErrors);
672 /* Added in VerNum 11 */
673 ser_uint32(jcr->JobStatus);
675 ser_end(rec->data, SER_LENGTH_Session_Label);
676 rec->data_len = ser_length(rec->data);
679 /* Write session label
680 * Returns: false on failure
683 bool write_session_label(DCR *dcr, int label)
686 DEVICE *dev = dcr->dev;
688 DEV_BLOCK *block = dcr->block;
691 Dmsg1(90, "session_label record=%x\n", rec);
694 if (dev->is_tape()) {
695 dcr->StartBlock = dev->block_num;
696 dcr->StartFile = dev->file;
698 dcr->StartBlock = (uint32_t)dev->file_addr;
699 dcr->StartFile = (uint32_t)(dev->file_addr >> 32);
703 if (dev->is_tape()) {
704 dcr->EndBlock = dev->EndBlock;
705 dcr->EndFile = dev->EndFile;
707 dcr->EndBlock = (uint32_t)dev->file_addr;
708 dcr->EndFile = (uint32_t)(dev->file_addr >> 32);
712 Jmsg1(jcr, M_ABORT, 0, _("Bad session label = %d\n"), label);
715 create_session_label(dcr, rec, label);
716 rec->FileIndex = label;
719 * We guarantee that the session record can totally fit
720 * into a block. If not, write the block, and put it in
721 * the next block. Having the sesssion record totally in
722 * one block makes reading them much easier (no need to
723 * read the next block).
725 if (!can_write_record_to_block(block, rec)) {
726 Dmsg0(100, "Cannot write session label to block.\n");
727 if (!write_block_to_device(dcr)) {
728 Dmsg0(90, "Got session label write_block_to_dev error.\n");
729 /* ****FIXME***** errno is not set here */
730 Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"),
731 dev_vol_name(dev), strerror(errno));
736 if (!write_record_to_block(block, rec)) {
737 Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"),
738 dev_vol_name(dev), strerror(errno));
743 Dmsg6(20, "Write sesson_label record JobId=%d FI=%s SessId=%d Strm=%s len=%d "
744 "remainder=%d\n", jcr->JobId,
745 FI_to_ascii(rec->FileIndex), rec->VolSessionId,
746 stream_to_ascii(rec->Stream, rec->FileIndex), rec->data_len,
750 Dmsg2(20, "Leave write_session_label Block=%d File=%d\n",
751 dev->block_num, dev->file);
755 /* unser_volume_label
757 * Unserialize the Bacula Volume label into the device Volume_Label
760 * Assumes that the record is already read.
762 * Returns: false on error
766 bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec)
770 if (rec->FileIndex != VOL_LABEL && rec->FileIndex != PRE_LABEL) {
771 Mmsg3(dev->errmsg, _("Expecting Volume Label, got FI=%s Stream=%s len=%d\n"),
772 FI_to_ascii(rec->FileIndex),
773 stream_to_ascii(rec->Stream, rec->FileIndex),
780 dev->VolHdr.LabelType = rec->FileIndex;
781 dev->VolHdr.LabelSize = rec->data_len;
784 /* Unserialize the record into the Volume Header */
785 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
786 ser_begin(rec->data, SER_LENGTH_Volume_Label);
787 unser_string(dev->VolHdr.Id);
788 unser_uint32(dev->VolHdr.VerNum);
790 if (dev->VolHdr.VerNum >= 11) {
791 unser_btime(dev->VolHdr.label_btime);
792 unser_btime(dev->VolHdr.write_btime);
793 } else { /* old way */
794 unser_float64(dev->VolHdr.label_date);
795 unser_float64(dev->VolHdr.label_time);
797 unser_float64(dev->VolHdr.write_date); /* Unused with VerNum >= 11 */
798 unser_float64(dev->VolHdr.write_time); /* Unused with VerNum >= 11 */
800 unser_string(dev->VolHdr.VolName);
801 unser_string(dev->VolHdr.PrevVolName);
802 unser_string(dev->VolHdr.PoolName);
803 unser_string(dev->VolHdr.PoolType);
804 unser_string(dev->VolHdr.MediaType);
806 unser_string(dev->VolHdr.HostName);
807 unser_string(dev->VolHdr.LabelProg);
808 unser_string(dev->VolHdr.ProgVersion);
809 unser_string(dev->VolHdr.ProgDate);
811 ser_end(rec->data, SER_LENGTH_Volume_Label);
812 Dmsg0(90, "ser_read_vol\n");
813 if (debug_level >= 90) {
814 dump_volume_label(dev);
820 bool unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec)
824 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
825 unser_begin(rec->data, SER_LENGTH_Session_Label);
826 unser_string(label->Id);
827 unser_uint32(label->VerNum);
828 unser_uint32(label->JobId);
829 if (label->VerNum >= 11) {
830 unser_btime(label->write_btime);
832 unser_float64(label->write_date);
834 unser_float64(label->write_time);
835 unser_string(label->PoolName);
836 unser_string(label->PoolType);
837 unser_string(label->JobName);
838 unser_string(label->ClientName);
839 if (label->VerNum >= 10) {
840 unser_string(label->Job); /* Unique name of this Job */
841 unser_string(label->FileSetName);
842 unser_uint32(label->JobType);
843 unser_uint32(label->JobLevel);
845 if (label->VerNum >= 11) {
846 unser_string(label->FileSetMD5);
848 label->FileSetMD5[0] = 0;
850 if (rec->FileIndex == EOS_LABEL) {
851 unser_uint32(label->JobFiles);
852 unser_uint64(label->JobBytes);
853 unser_uint32(label->StartBlock);
854 unser_uint32(label->EndBlock);
855 unser_uint32(label->StartFile);
856 unser_uint32(label->EndFile);
857 unser_uint32(label->JobErrors);
858 if (label->VerNum >= 11) {
859 unser_uint32(label->JobStatus);
861 label->JobStatus = JS_Terminated; /* kludge */
867 void dump_volume_label(DEVICE *dev)
869 int dbl = debug_level;
871 const char *LabelType;
878 switch (dev->VolHdr.LabelType) {
880 LabelType = "PRE_LABEL";
883 LabelType = "VOL_LABEL";
886 LabelType = "EOM_LABEL";
889 LabelType = "SOS_LABEL";
892 LabelType = "EOS_LABEL";
898 sprintf(buf, "Unknown %d", dev->VolHdr.LabelType);
902 Pmsg11(-1, "\nVolume Label:\n"
915 dev->VolHdr.Id, dev->VolHdr.VerNum,
916 dev->VolHdr.VolName, dev->VolHdr.PrevVolName,
917 File, LabelType, dev->VolHdr.LabelSize,
918 dev->VolHdr.PoolName, dev->VolHdr.MediaType,
919 dev->VolHdr.PoolType, dev->VolHdr.HostName);
921 if (dev->VolHdr.VerNum >= 11) {
923 bstrftime(dt, sizeof(dt), btime_to_unix(dev->VolHdr.label_btime));
924 Pmsg1(-1, "Date label written: %s\n", dt);
926 dt.julian_day_number = dev->VolHdr.label_date;
927 dt.julian_day_fraction = dev->VolHdr.label_time;
930 "Date label written: %04d-%02d-%02d at %02d:%02d\n",
931 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
939 static void dump_session_label(DEV_RECORD *rec, const char *type)
945 char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], ec6[30], ec7[30];
947 unser_session_label(&label, rec);
950 Pmsg7(-1, "\n%s Record:\n"
957 "", type, label.JobId, label.VerNum,
958 label.PoolName, label.PoolType,
959 label.JobName, label.ClientName);
961 if (label.VerNum >= 10) {
963 "Job (unique name) : %s\n"
967 "", label.Job, label.FileSetName, label.JobType, label.JobLevel);
970 if (rec->FileIndex == EOS_LABEL) {
981 edit_uint64_with_commas(label.JobFiles, ec1),
982 edit_uint64_with_commas(label.JobBytes, ec2),
983 edit_uint64_with_commas(label.StartBlock, ec3),
984 edit_uint64_with_commas(label.EndBlock, ec4),
985 edit_uint64_with_commas(label.StartFile, ec5),
986 edit_uint64_with_commas(label.EndFile, ec6),
987 edit_uint64_with_commas(label.JobErrors, ec7),
990 if (label.VerNum >= 11) {
992 bstrftime(dt, sizeof(dt), btime_to_unix(label.write_btime));
993 Pmsg1(-1, _("Date written : %s\n"), dt);
995 dt.julian_day_number = label.write_date;
996 dt.julian_day_fraction = label.write_time;
999 "Date written : %04d-%02d-%02d at %02d:%02d\n"),
1000 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
1006 void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose)
1013 switch (rec->FileIndex) {
1015 type = _("Fresh Volume");
1021 type = _("Begin Job Session");
1024 type = _("End Job Session");
1027 type = _("End of Media");
1030 type = ("End of Tape");
1033 type = _("Unknown");
1037 switch (rec->FileIndex) {
1040 unser_volume_label(dev, rec);
1041 dump_volume_label(dev);
1044 dump_session_label(rec, type);
1047 dump_session_label(rec, type);
1050 Pmsg5(-1, "%s Record: SessId=%d SessTime=%d JobId=%d DataLen=%d\n",
1051 type, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
1054 Pmsg0(-1, _("End of physical tape.\n"));
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);
1062 SESSION_LABEL label;
1063 switch (rec->FileIndex) {
1065 unser_session_label(&label, rec);
1066 Pmsg6(-1, "%s Record: SessId=%d SessTime=%d JobId=%d Level=%c Type=%c\n",
1067 type, rec->VolSessionId, rec->VolSessionTime, rec->Stream,
1068 label.JobLevel, label.JobType);
1071 char ed1[30], ed2[30];
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);
1076 Pmsg4(-1, " Files=%s Bytes=%s Errors=%d Status=%c\n",
1077 edit_uint64_with_commas(label.JobFiles, ed1),
1078 edit_uint64_with_commas(label.JobBytes, ed2),
1079 label.JobErrors, (char)label.JobStatus);
1085 Pmsg5(-1, "%s Record: SessId=%d SessTime=%d JobId=%d DataLen=%d\n",
1086 type, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);