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: 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 (!can_open_mounted_dev(dev)) {
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 /* At this point, we are writing */
266 if (dev->free_space_errno < 0) {
267 Dmsg0(100, "Exit: read_dvd_volume_label !free_space VOL_NO_MEDIA\n");
268 Mmsg2(jcr->errmsg, _("free_space error on %s. The current medium is probably not writable: ERR=%s.\n"),
269 dev->print_name(), dev->errmsg);
274 * If we can't guess the name, and we are writing,
275 * just reopen the right file with open_first_part.
277 if (open_first_part(dev, OPEN_READ_WRITE) < 0) {
279 Mmsg2(jcr->errmsg, _("open_first_part error on %s: ERR=%s.\n"),
280 dev->print_name(), be.strerror());
281 Dmsg0(100, "Leave read_dvd_volume_label VOL_IO_ERROR (!open_mounted_dev && !open_first_part)\n");
285 Dmsg0(100, "Leave read_dvd_volume_label !open_mounted_dev\n");
286 return read_dev_volume_label(dcr);
290 * If we get here, we can open the mounted device
292 if (write && dcr->dev->free_space_errno < 0) {
293 Dmsg0(100, "Leave read_dvd_volume_label !free_space VOL_NO_MEDIA\n");
294 Mmsg2(jcr->errmsg, _("free_space error on %s. The current medium is probably not writable: ERR=%s.\n"),
295 dev->print_name(), dev->errmsg);
299 if (!write || dcr->VolCatInfo.VolCatParts > 0) {
300 Dmsg0(100, "Exit: read_dvd_volume_label (open_mounted_dev && (!write || dcr->VolCatInfo.VolCatParts > 0))\n");
301 return read_dev_volume_label(dcr);
304 /* At this point, we are writing */
305 if (open_first_part(dcr->dev, OPEN_READ_WRITE) < 0) {
307 Mmsg2(jcr->errmsg, _("open_first_part error on %s: ERR=%s.\n"),
308 dev->print_name(), be.strerror());
309 Dmsg0(100, "Leave read_dvd_volume_label VOL_IO_ERROR (open_mounted_dev && !open_first_part)\n");
312 vol_label_status = read_dev_volume_label(dcr);
314 /* When writing, if the guessed volume name is not the right volume name,
315 * report the error, otherwise, just continue with the right file.
317 if (vol_label_status != VOL_NAME_ERROR) {
318 Dmsg0(100, "Leave read_dvd_volume_label (open_mounted_dev && !VOL_NAME_ERROR)\n");
319 dev->clear_labeled();
320 return read_dev_volume_label(dcr);
322 Dmsg0(100, "Leave read_dvd_volume_label (open_mounted_dev && VOL_NAME_ERROR)\n");
323 return vol_label_status;
329 * Put a volume label into the block
331 * Returns: false on failure
334 bool write_volume_label_to_block(DCR *dcr)
337 DEVICE *dev = dcr->dev;
339 DEV_BLOCK *block = dcr->block;
341 Dmsg0(20, "write Label in write_volume_label_to_block()\n");
342 memset(&rec, 0, sizeof(rec));
343 rec.data = get_memory(SER_LENGTH_Volume_Label);
344 empty_block(block); /* Volume label always at beginning */
346 create_volume_label_record(dcr, &rec);
348 block->BlockNumber = 0;
349 if (!write_record_to_block(block, &rec)) {
350 free_pool_memory(rec.data);
351 Jmsg1(jcr, M_FATAL, 0, _("Cannot write Volume label to block for device %s\n"),
355 Dmsg1(90, "Wrote label of %d bytes to block\n", rec.data_len);
357 free_pool_memory(rec.data);
363 * Write a Volume Label
364 * !!! Note, this is ONLY used for writing
365 * a fresh volume label. Any data
366 * after the label will be destroyed,
367 * in fact, we write the label 5 times !!!!
369 * This routine expects that open_device() was previously called.
371 * This routine should be used only when labeling a blank tape.
373 bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName, const char *PoolName)
375 DEVICE *dev = dcr->dev;
378 Dmsg0(99, "write_volume_label()\n");
379 empty_block(dcr->block);
381 Dmsg1(100, "Label type=%d\n", dev->label_type);
382 if (!rewind_dev(dev)) {
383 memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
384 Dmsg2(30, "Bad status on %s from rewind: ERR=%s\n", dev->print_name(), strerror_dev(dev));
390 /* Create PRE_LABEL */
391 create_volume_label(dev, VolName, PoolName);
394 * If we have already detected an ANSI label, re-read it
395 * to skip past it. Otherwise, we write a new one if
398 if (dev->label_type != B_BACULA_LABEL) {
399 if (read_ansi_ibm_label(dcr) != VOL_OK) {
403 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, VolName)) {
407 create_volume_label_record(dcr, dcr->rec);
408 dcr->rec->Stream = 0;
410 /* Temporarily mark in append state to enable writing */
412 if (!write_record_to_block(dcr->block, dcr->rec)) {
413 Dmsg2(30, "Bad Label write on %s: ERR=%s\n", dev->print_name(), strerror_dev(dev));
416 Dmsg2(30, "Wrote label of %d bytes to %s\n", dcr->rec->data_len, dev->print_name());
419 Dmsg0(99, "Call write_block_to_dev()\n");
420 if (!write_block_to_dev(dcr)) {
421 Dmsg2(30, "Bad Label write on %s: ERR=%s\n", dev->print_name(), strerror_dev(dev));
424 Dmsg0(99, " Wrote block to device\n");
426 if (weof_dev(dev, 1) == 0) {
428 write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
431 if (debug_level >= 20) {
432 dump_volume_label(dev);
434 dev->clear_append(); /* remove append since this is PRE_LABEL */
438 memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
439 dev->clear_append(); /* remove append since this is PRE_LABEL */
444 * Write a volume label. This is ONLY called if we have a valid Bacula
445 * label of type PRE_LABEL;
446 * Returns: true if OK
447 * false if unable to write it
449 bool rewrite_volume_label(DCR *dcr, bool recycle)
451 DEVICE *dev = dcr->dev;
454 Dmsg1(190, "set append found freshly labeled volume. dev=%x\n", dev);
455 dev->VolHdr.LabelType = VOL_LABEL; /* set Volume label */
457 if (!write_volume_label_to_block(dcr)) {
458 Dmsg0(200, "Error from write volume label.\n");
462 * If we are not dealing with a streaming device,
463 * write the block now to ensure we have write permission.
464 * It is better to find out now rather than later.
465 * We do not write the block now if this is an ANSI label. This
466 * avoids re-writing the ANSI label, which we do not want to do.
468 if (!dev_cap(dev, CAP_STREAM)) {
469 if (!rewind_dev(dev)) {
470 Jmsg2(jcr, M_WARNING, 0, _("Rewind error on device %s: ERR=%s\n"),
471 dev->print_name(), strerror_dev(dev));
474 if (!truncate_dev(dev)) {
475 Jmsg2(jcr, M_WARNING, 0, _("Truncate error on device %s: ERR=%s\n"),
476 dev->print_name(), strerror_dev(dev));
481 * If we have already detected an ANSI label, re-read it
482 * to skip past it. Otherwise, we write a new one if
485 if (dev->label_type != B_BACULA_LABEL) {
486 if (read_ansi_ibm_label(dcr) != VOL_OK) {
490 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, dev->VolHdr.VolumeName)) {
494 /* Attempt write to check write permission */
495 Dmsg0(200, "Attempt to write to device.\n");
496 if (!write_block_to_dev(dcr)) {
497 Jmsg2(jcr, M_ERROR, 0, _("Unable to write device %s: ERR=%s\n"),
498 dev->print_name(), strerror_dev(dev));
499 Dmsg0(200, "===ERROR write block to dev\n");
503 /* Set or reset Volume statistics */
504 dev->VolCatInfo.VolCatJobs = 0;
505 dev->VolCatInfo.VolCatFiles = 0;
506 dev->VolCatInfo.VolCatBytes = 1;
507 dev->VolCatInfo.VolCatErrors = 0;
508 dev->VolCatInfo.VolCatBlocks = 0;
509 dev->VolCatInfo.VolCatRBytes = 0;
511 dev->VolCatInfo.VolCatMounts++;
512 dev->VolCatInfo.VolCatRecycles++;
514 dev->VolCatInfo.VolCatMounts = 1;
515 dev->VolCatInfo.VolCatRecycles = 0;
516 dev->VolCatInfo.VolCatWrites = 1;
517 dev->VolCatInfo.VolCatReads = 1;
519 Dmsg0(100, "dir_update_vol_info. Set Append\n");
520 bstrncpy(dev->VolCatInfo.VolCatStatus, "Append", sizeof(dev->VolCatInfo.VolCatStatus));
521 if (!dir_update_volume_info(dcr, true)) { /* indicate doing relabel */
525 Jmsg(jcr, M_INFO, 0, _("Recycled volume \"%s\" on device %s, all previous data lost.\n"),
526 dcr->VolumeName, dev->print_name());
528 Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume \"%s\" on device %s\n"),
529 dcr->VolumeName, dev->print_name());
532 * End writing real Volume label (from pre-labeled tape), or recycling
535 Dmsg0(200, "OK from rewite vol label.\n");
541 * create_volume_label_record
542 * Serialize label (from dev->VolHdr structure) into device record.
543 * Assumes that the dev->VolHdr structure is properly
546 static void create_volume_label_record(DCR *dcr, DEV_RECORD *rec)
550 DEVICE *dev = dcr->dev;
553 /* Serialize the label into the device record. */
555 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
556 ser_begin(rec->data, SER_LENGTH_Volume_Label);
557 ser_string(dev->VolHdr.Id);
559 ser_uint32(dev->VolHdr.VerNum);
561 if (dev->VolHdr.VerNum >= 11) {
562 ser_btime(dev->VolHdr.label_btime);
563 dev->VolHdr.write_btime = get_current_btime();
564 ser_btime(dev->VolHdr.write_btime);
565 dev->VolHdr.write_date = 0;
566 dev->VolHdr.write_time = 0;
568 /* OLD WAY DEPRECATED */
569 ser_float64(dev->VolHdr.label_date);
570 ser_float64(dev->VolHdr.label_time);
571 get_current_time(&dt);
572 dev->VolHdr.write_date = dt.julian_day_number;
573 dev->VolHdr.write_time = dt.julian_day_fraction;
575 ser_float64(dev->VolHdr.write_date); /* 0 if VerNum >= 11 */
576 ser_float64(dev->VolHdr.write_time); /* 0 if VerNum >= 11 */
578 ser_string(dev->VolHdr.VolumeName);
579 ser_string(dev->VolHdr.PrevVolumeName);
580 ser_string(dev->VolHdr.PoolName);
581 ser_string(dev->VolHdr.PoolType);
582 ser_string(dev->VolHdr.MediaType);
584 ser_string(dev->VolHdr.HostName);
585 ser_string(dev->VolHdr.LabelProg);
586 ser_string(dev->VolHdr.ProgVersion);
587 ser_string(dev->VolHdr.ProgDate);
589 ser_end(rec->data, SER_LENGTH_Volume_Label);
590 rec->data_len = ser_length(rec->data);
591 rec->FileIndex = dev->VolHdr.LabelType;
592 rec->VolSessionId = jcr->VolSessionId;
593 rec->VolSessionTime = jcr->VolSessionTime;
594 rec->Stream = jcr->NumVolumes;
595 Dmsg2(100, "Created Vol label rec: FI=%s len=%d\n", FI_to_ascii(rec->FileIndex),
601 * Create a volume label in memory
603 void create_volume_label(DEVICE *dev, const char *VolName, const char *PoolName)
605 DEVRES *device = (DEVRES *)dev->device;
607 Dmsg0(90, "Start create_volume_label()\n");
611 memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
613 bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
614 dev->VolHdr.VerNum = BaculaTapeVersion;
615 dev->VolHdr.LabelType = PRE_LABEL; /* Mark tape as unused */
616 bstrncpy(dev->VolHdr.VolumeName, VolName, sizeof(dev->VolHdr.VolumeName));
617 bstrncpy(dev->VolHdr.PoolName, PoolName, sizeof(dev->VolHdr.PoolName));
618 bstrncpy(dev->VolHdr.MediaType, device->media_type, sizeof(dev->VolHdr.MediaType));
620 bstrncpy(dev->VolHdr.PoolType, "Backup", sizeof(dev->VolHdr.PoolType));
622 dev->VolHdr.label_btime = get_current_btime();
623 dev->VolHdr.label_date = 0;
624 dev->VolHdr.label_time = 0;
626 if (gethostname(dev->VolHdr.HostName, sizeof(dev->VolHdr.HostName)) != 0) {
627 dev->VolHdr.HostName[0] = 0;
629 bstrncpy(dev->VolHdr.LabelProg, my_name, sizeof(dev->VolHdr.LabelProg));
630 sprintf(dev->VolHdr.ProgVersion, "Ver. %s %s", VERSION, BDATE);
631 sprintf(dev->VolHdr.ProgDate, "Build %s %s", __DATE__, __TIME__);
632 dev->set_labeled(); /* set has Bacula label */
633 if (debug_level >= 90) {
634 dump_volume_label(dev);
639 * Create session label
640 * The pool memory must be released by the calling program
642 void create_session_label(DCR *dcr, DEV_RECORD *rec, int label)
647 rec->VolSessionId = jcr->VolSessionId;
648 rec->VolSessionTime = jcr->VolSessionTime;
649 rec->Stream = jcr->JobId;
651 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
652 ser_begin(rec->data, SER_LENGTH_Session_Label);
653 ser_string(BaculaId);
654 ser_uint32(BaculaTapeVersion);
656 ser_uint32(jcr->JobId);
658 /* Changed in VerNum 11 */
659 ser_btime(get_current_btime());
662 ser_string(dcr->pool_name);
663 ser_string(dcr->pool_type);
664 ser_string(jcr->job_name); /* base Job name */
665 ser_string(jcr->client_name);
667 /* Added in VerNum 10 */
668 ser_string(jcr->Job); /* Unique name of this Job */
669 ser_string(jcr->fileset_name);
670 ser_uint32(jcr->JobType);
671 ser_uint32(jcr->JobLevel);
672 /* Added in VerNum 11 */
673 ser_string(jcr->fileset_md5);
675 if (label == EOS_LABEL) {
676 ser_uint32(jcr->JobFiles);
677 ser_uint64(jcr->JobBytes);
678 ser_uint32(dcr->StartBlock);
679 ser_uint32(dcr->EndBlock);
680 ser_uint32(dcr->StartFile);
681 ser_uint32(dcr->EndFile);
682 ser_uint32(jcr->JobErrors);
684 /* Added in VerNum 11 */
685 ser_uint32(jcr->JobStatus);
687 ser_end(rec->data, SER_LENGTH_Session_Label);
688 rec->data_len = ser_length(rec->data);
691 /* Write session label
692 * Returns: false on failure
695 bool write_session_label(DCR *dcr, int label)
698 DEVICE *dev = dcr->dev;
700 DEV_BLOCK *block = dcr->block;
703 Dmsg1(90, "session_label record=%x\n", rec);
706 if (dev->is_tape()) {
707 dcr->StartBlock = dev->block_num;
708 dcr->StartFile = dev->file;
710 dcr->StartBlock = (uint32_t)dev->file_addr;
711 dcr->StartFile = (uint32_t)(dev->file_addr >> 32);
715 if (dev->is_tape()) {
716 dcr->EndBlock = dev->EndBlock;
717 dcr->EndFile = dev->EndFile;
719 dcr->EndBlock = (uint32_t)dev->file_addr;
720 dcr->EndFile = (uint32_t)(dev->file_addr >> 32);
724 Jmsg1(jcr, M_ABORT, 0, _("Bad session label = %d\n"), label);
727 create_session_label(dcr, rec, label);
728 rec->FileIndex = label;
731 * We guarantee that the session record can totally fit
732 * into a block. If not, write the block, and put it in
733 * the next block. Having the sesssion record totally in
734 * one block makes reading them much easier (no need to
735 * read the next block).
737 if (!can_write_record_to_block(block, rec)) {
738 Dmsg0(100, "Cannot write session label to block.\n");
739 if (!write_block_to_device(dcr)) {
740 Dmsg0(90, "Got session label write_block_to_dev error.\n");
741 /* ****FIXME***** errno is not set here */
742 Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"),
743 dev_vol_name(dev), strerror(errno));
748 if (!write_record_to_block(block, rec)) {
749 Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"),
750 dev_vol_name(dev), strerror(errno));
755 Dmsg6(20, "Write sesson_label record JobId=%d FI=%s SessId=%d Strm=%s len=%d "
756 "remainder=%d\n", jcr->JobId,
757 FI_to_ascii(rec->FileIndex), rec->VolSessionId,
758 stream_to_ascii(rec->Stream, rec->FileIndex), rec->data_len,
762 Dmsg2(20, "Leave write_session_label Block=%d File=%d\n",
763 dev->block_num, dev->file);
767 /* unser_volume_label
769 * Unserialize the Bacula Volume label into the device Volume_Label
772 * Assumes that the record is already read.
774 * Returns: false on error
778 bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec)
782 if (rec->FileIndex != VOL_LABEL && rec->FileIndex != PRE_LABEL) {
783 Mmsg3(dev->errmsg, _("Expecting Volume Label, got FI=%s Stream=%s len=%d\n"),
784 FI_to_ascii(rec->FileIndex),
785 stream_to_ascii(rec->Stream, rec->FileIndex),
792 dev->VolHdr.LabelType = rec->FileIndex;
793 dev->VolHdr.LabelSize = rec->data_len;
796 /* Unserialize the record into the Volume Header */
797 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
798 ser_begin(rec->data, SER_LENGTH_Volume_Label);
799 unser_string(dev->VolHdr.Id);
800 unser_uint32(dev->VolHdr.VerNum);
802 if (dev->VolHdr.VerNum >= 11) {
803 unser_btime(dev->VolHdr.label_btime);
804 unser_btime(dev->VolHdr.write_btime);
805 } else { /* old way */
806 unser_float64(dev->VolHdr.label_date);
807 unser_float64(dev->VolHdr.label_time);
809 unser_float64(dev->VolHdr.write_date); /* Unused with VerNum >= 11 */
810 unser_float64(dev->VolHdr.write_time); /* Unused with VerNum >= 11 */
812 unser_string(dev->VolHdr.VolumeName);
813 unser_string(dev->VolHdr.PrevVolumeName);
814 unser_string(dev->VolHdr.PoolName);
815 unser_string(dev->VolHdr.PoolType);
816 unser_string(dev->VolHdr.MediaType);
818 unser_string(dev->VolHdr.HostName);
819 unser_string(dev->VolHdr.LabelProg);
820 unser_string(dev->VolHdr.ProgVersion);
821 unser_string(dev->VolHdr.ProgDate);
823 ser_end(rec->data, SER_LENGTH_Volume_Label);
824 Dmsg0(90, "ser_read_vol\n");
825 if (debug_level >= 90) {
826 dump_volume_label(dev);
832 bool unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec)
836 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
837 unser_begin(rec->data, SER_LENGTH_Session_Label);
838 unser_string(label->Id);
839 unser_uint32(label->VerNum);
840 unser_uint32(label->JobId);
841 if (label->VerNum >= 11) {
842 unser_btime(label->write_btime);
844 unser_float64(label->write_date);
846 unser_float64(label->write_time);
847 unser_string(label->PoolName);
848 unser_string(label->PoolType);
849 unser_string(label->JobName);
850 unser_string(label->ClientName);
851 if (label->VerNum >= 10) {
852 unser_string(label->Job); /* Unique name of this Job */
853 unser_string(label->FileSetName);
854 unser_uint32(label->JobType);
855 unser_uint32(label->JobLevel);
857 if (label->VerNum >= 11) {
858 unser_string(label->FileSetMD5);
860 label->FileSetMD5[0] = 0;
862 if (rec->FileIndex == EOS_LABEL) {
863 unser_uint32(label->JobFiles);
864 unser_uint64(label->JobBytes);
865 unser_uint32(label->StartBlock);
866 unser_uint32(label->EndBlock);
867 unser_uint32(label->StartFile);
868 unser_uint32(label->EndFile);
869 unser_uint32(label->JobErrors);
870 if (label->VerNum >= 11) {
871 unser_uint32(label->JobStatus);
873 label->JobStatus = JS_Terminated; /* kludge */
879 void dump_volume_label(DEVICE *dev)
881 int dbl = debug_level;
883 const char *LabelType;
890 switch (dev->VolHdr.LabelType) {
892 LabelType = "PRE_LABEL";
895 LabelType = "VOL_LABEL";
898 LabelType = "EOM_LABEL";
901 LabelType = "SOS_LABEL";
904 LabelType = "EOS_LABEL";
910 sprintf(buf, "Unknown %d", dev->VolHdr.LabelType);
914 Pmsg11(-1, "\nVolume Label:\n"
927 dev->VolHdr.Id, dev->VolHdr.VerNum,
928 dev->VolHdr.VolumeName, dev->VolHdr.PrevVolumeName,
929 File, LabelType, dev->VolHdr.LabelSize,
930 dev->VolHdr.PoolName, dev->VolHdr.MediaType,
931 dev->VolHdr.PoolType, dev->VolHdr.HostName);
933 if (dev->VolHdr.VerNum >= 11) {
935 bstrftime(dt, sizeof(dt), btime_to_unix(dev->VolHdr.label_btime));
936 Pmsg1(-1, "Date label written: %s\n", dt);
938 dt.julian_day_number = dev->VolHdr.label_date;
939 dt.julian_day_fraction = dev->VolHdr.label_time;
942 "Date label written: %04d-%02d-%02d at %02d:%02d\n",
943 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
951 static void dump_session_label(DEV_RECORD *rec, const char *type)
957 char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], ec6[30], ec7[30];
959 unser_session_label(&label, rec);
962 Pmsg7(-1, "\n%s Record:\n"
969 "", type, label.JobId, label.VerNum,
970 label.PoolName, label.PoolType,
971 label.JobName, label.ClientName);
973 if (label.VerNum >= 10) {
975 "Job (unique name) : %s\n"
979 "", label.Job, label.FileSetName, label.JobType, label.JobLevel);
982 if (rec->FileIndex == EOS_LABEL) {
993 edit_uint64_with_commas(label.JobFiles, ec1),
994 edit_uint64_with_commas(label.JobBytes, ec2),
995 edit_uint64_with_commas(label.StartBlock, ec3),
996 edit_uint64_with_commas(label.EndBlock, ec4),
997 edit_uint64_with_commas(label.StartFile, ec5),
998 edit_uint64_with_commas(label.EndFile, ec6),
999 edit_uint64_with_commas(label.JobErrors, ec7),
1002 if (label.VerNum >= 11) {
1004 bstrftime(dt, sizeof(dt), btime_to_unix(label.write_btime));
1005 Pmsg1(-1, _("Date written : %s\n"), dt);
1007 dt.julian_day_number = label.write_date;
1008 dt.julian_day_fraction = label.write_time;
1009 tm_decode(&dt, &tm);
1011 "Date written : %04d-%02d-%02d at %02d:%02d\n"),
1012 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
1018 void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose)
1025 switch (rec->FileIndex) {
1027 type = _("Fresh Volume");
1033 type = _("Begin Job Session");
1036 type = _("End Job Session");
1039 type = _("End of Media");
1042 type = ("End of Tape");
1045 type = _("Unknown");
1049 switch (rec->FileIndex) {
1052 unser_volume_label(dev, rec);
1053 dump_volume_label(dev);
1056 dump_session_label(rec, type);
1059 dump_session_label(rec, type);
1062 Pmsg5(-1, "%s Record: SessId=%d SessTime=%d JobId=%d DataLen=%d\n",
1063 type, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
1066 Pmsg0(-1, _("End of physical tape.\n"));
1069 Pmsg5(-1, "%s Record: SessId=%d SessTime=%d JobId=%d DataLen=%d\n",
1070 type, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
1074 SESSION_LABEL label;
1075 switch (rec->FileIndex) {
1077 unser_session_label(&label, rec);
1078 Pmsg6(-1, "%s Record: SessId=%d SessTime=%d JobId=%d Level=%c Type=%c\n",
1079 type, rec->VolSessionId, rec->VolSessionTime, rec->Stream,
1080 label.JobLevel, label.JobType);
1083 char ed1[30], ed2[30];
1084 unser_session_label(&label, rec);
1085 Pmsg6(-1, "%s Record: SessId=%d SessTime=%d JobId=%d Level=%c Type=%c\n",
1086 type, rec->VolSessionId, rec->VolSessionTime, rec->Stream,
1087 label.JobLevel, label.JobType);
1088 Pmsg4(-1, " Files=%s Bytes=%s Errors=%d Status=%c\n",
1089 edit_uint64_with_commas(label.JobFiles, ed1),
1090 edit_uint64_with_commas(label.JobBytes, ed2),
1091 label.JobErrors, (char)label.JobStatus);
1097 Pmsg5(-1, "%s Record: SessId=%d SessTime=%d JobId=%d DataLen=%d\n",
1098 type, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);