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");
233 /* Read the volume label by guessing the volume name. (only for DVD devices)
234 * write is true if we are reading the label before writing to the device.
236 * If the volume name cannot be guessed :
237 * Writing : returns the label of the current file (on the harddisk).
238 * Reading : returns an error
240 int read_dvd_volume_label(DCR *dcr, bool write)
242 int vol_label_status;
243 DEVICE *dev = dcr->dev;
245 Dmsg3(100, "Enter: dvd_volume_label device=%s vol=%s dev_Vol=%s\n",
246 dev->print_name(), dcr->VolumeName, dev->VolHdr.VolumeName);
248 if (!dev->is_dvd()) {
249 Jmsg1(jcr, M_ABORT, 0, _("Device %s is not a DVD.\n"), dev->print_name());
250 return -1; /* for compiler, won't get here */
253 if (!write && (dcr->VolCatInfo.VolCatParts == 0)) {
254 Dmsg0(100, "Leave read_dvd_volume_label !writing, and VolCatParts == 0\n");
255 return read_dev_volume_label(dcr);
259 * For mounted devices, try to guess the Volume name
260 * and read the label if possible.
262 if (!can_open_mounted_dev(dev)) {
263 if (!write || dcr->VolCatInfo.VolCatParts > 0) {
264 Mmsg2(jcr->errmsg, _("Requested Volume \"%s\" on %s is not a Bacula labeled Volume."),
265 dev->print_name(), dcr->VolumeName);
266 Dmsg0(100, "Leave read_dvd_volume_label VOL_NO_LABEL (!open_mounted_dev)\n");
270 /* At this point, we are writing */
271 if (dev->free_space_errno < 0) {
272 Dmsg0(100, "Exit: read_dvd_volume_label !free_space VOL_NO_MEDIA\n");
273 Mmsg2(jcr->errmsg, _("free_space error on %s. The current medium is probably not writable: ERR=%s.\n"),
274 dev->print_name(), dev->errmsg);
279 * If we can't guess the name, and we are writing,
280 * just reopen the right file with open_first_part.
282 if (open_first_part(dev, OPEN_READ_WRITE) < 0) {
284 Mmsg2(jcr->errmsg, _("open_first_part error on %s: ERR=%s.\n"),
285 dev->print_name(), be.strerror());
286 Dmsg0(100, "Leave read_dvd_volume_label VOL_IO_ERROR (!open_mounted_dev && !open_first_part)\n");
290 Dmsg0(100, "Leave read_dvd_volume_label !open_mounted_dev\n");
291 return read_dev_volume_label(dcr);
295 * If we get here, we can open the mounted device
297 if (write && dcr->dev->free_space_errno < 0) {
298 Dmsg0(100, "Leave read_dvd_volume_label !free_space VOL_NO_MEDIA\n");
299 Mmsg2(jcr->errmsg, _("free_space error on %s. The current medium is probably not writable: ERR=%s.\n"),
300 dev->print_name(), dev->errmsg);
304 if (!write || dcr->VolCatInfo.VolCatParts > 0) {
305 Dmsg0(100, "Exit: read_dvd_volume_label (open_mounted_dev && (!write || dcr->VolCatInfo.VolCatParts > 0))\n");
306 return read_dev_volume_label(dcr);
309 /* At this point, we are writing */
310 if (open_first_part(dcr->dev, OPEN_READ_WRITE) < 0) {
312 Mmsg2(jcr->errmsg, _("open_first_part error on %s: ERR=%s.\n"),
313 dev->print_name(), be.strerror());
314 Dmsg0(100, "Leave read_dvd_volume_label VOL_IO_ERROR (open_mounted_dev && !open_first_part)\n");
317 vol_label_status = read_dev_volume_label(dcr);
319 /* When writing, if the guessed volume name is not the right volume name,
320 * report the error, otherwise, just continue with the right file.
322 if (vol_label_status != VOL_NAME_ERROR) {
323 Dmsg0(100, "Leave read_dvd_volume_label (open_mounted_dev && !VOL_NAME_ERROR)\n");
324 dev->clear_labeled();
325 return read_dev_volume_label(dcr);
327 Dmsg0(100, "Leave read_dvd_volume_label (open_mounted_dev && VOL_NAME_ERROR)\n");
328 return vol_label_status;
334 * Put a volume label into the block
336 * Returns: false on failure
339 bool write_volume_label_to_block(DCR *dcr)
342 DEVICE *dev = dcr->dev;
344 DEV_BLOCK *block = dcr->block;
346 Dmsg0(20, "write Label in write_volume_label_to_block()\n");
347 memset(&rec, 0, sizeof(rec));
348 rec.data = get_memory(SER_LENGTH_Volume_Label);
349 empty_block(block); /* Volume label always at beginning */
351 create_volume_label_record(dcr, &rec);
353 block->BlockNumber = 0;
354 if (!write_record_to_block(block, &rec)) {
355 free_pool_memory(rec.data);
356 Jmsg1(jcr, M_FATAL, 0, _("Cannot write Volume label to block for device %s\n"),
360 Dmsg1(90, "Wrote label of %d bytes to block\n", rec.data_len);
362 free_pool_memory(rec.data);
368 * Write a Volume Label
369 * !!! Note, this is ONLY used for writing
370 * a fresh volume label. Any data
371 * after the label will be destroyed,
372 * in fact, we write the label 5 times !!!!
374 * This routine expects that open_device() was previously called.
376 * This routine should be used only when labeling a blank tape.
378 bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName, const char *PoolName)
380 DEVICE *dev = dcr->dev;
383 Dmsg0(99, "write_volume_label()\n");
384 empty_block(dcr->block);
386 Dmsg1(100, "Label type=%d\n", dev->label_type);
387 if (!rewind_dev(dev)) {
388 memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
389 Dmsg2(30, "Bad status on %s from rewind: ERR=%s\n", dev->print_name(), strerror_dev(dev));
395 /* Create PRE_LABEL */
396 create_volume_label(dev, VolName, PoolName);
399 * If we have already detected an ANSI label, re-read it
400 * to skip past it. Otherwise, we write a new one if
403 if (dev->label_type != B_BACULA_LABEL) {
404 if (read_ansi_ibm_label(dcr) != VOL_OK) {
408 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, VolName)) {
412 create_volume_label_record(dcr, dcr->rec);
413 dcr->rec->Stream = 0;
415 /* Temporarily mark in append state to enable writing */
417 if (!write_record_to_block(dcr->block, dcr->rec)) {
418 Dmsg2(30, "Bad Label write on %s: ERR=%s\n", dev->print_name(), strerror_dev(dev));
421 Dmsg2(30, "Wrote label of %d bytes to %s\n", dcr->rec->data_len, dev->print_name());
424 Dmsg0(99, "Call write_block_to_dev()\n");
425 if (!write_block_to_dev(dcr)) {
426 Dmsg2(30, "Bad Label write on %s: ERR=%s\n", dev->print_name(), strerror_dev(dev));
429 Dmsg0(99, " Wrote block to device\n");
431 if (weof_dev(dev, 1) == 0) {
433 write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
436 if (debug_level >= 20) {
437 dump_volume_label(dev);
439 dev->clear_append(); /* remove append since this is PRE_LABEL */
443 memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
444 dev->clear_append(); /* remove append since this is PRE_LABEL */
449 * Write a volume label. This is ONLY called if we have a valid Bacula
450 * label of type PRE_LABEL;
451 * Returns: true if OK
452 * false if unable to write it
454 bool rewrite_volume_label(DCR *dcr, bool recycle)
456 DEVICE *dev = dcr->dev;
459 Dmsg1(190, "set append found freshly labeled volume. dev=%x\n", dev);
460 dev->VolHdr.LabelType = VOL_LABEL; /* set Volume label */
462 if (!write_volume_label_to_block(dcr)) {
463 Dmsg0(200, "Error from write volume label.\n");
467 * If we are not dealing with a streaming device,
468 * write the block now to ensure we have write permission.
469 * It is better to find out now rather than later.
470 * We do not write the block now if this is an ANSI label. This
471 * avoids re-writing the ANSI label, which we do not want to do.
473 if (!dev_cap(dev, CAP_STREAM)) {
474 if (!rewind_dev(dev)) {
475 Jmsg2(jcr, M_WARNING, 0, _("Rewind error on device %s: ERR=%s\n"),
476 dev->print_name(), strerror_dev(dev));
479 if (!truncate_dev(dev)) {
480 Jmsg2(jcr, M_WARNING, 0, _("Truncate error on device %s: ERR=%s\n"),
481 dev->print_name(), strerror_dev(dev));
486 * If we have already detected an ANSI label, re-read it
487 * to skip past it. Otherwise, we write a new one if
490 if (dev->label_type != B_BACULA_LABEL) {
491 if (read_ansi_ibm_label(dcr) != VOL_OK) {
495 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, dev->VolHdr.VolumeName)) {
499 /* Attempt write to check write permission */
500 Dmsg0(200, "Attempt to write to device.\n");
501 if (!write_block_to_dev(dcr)) {
502 Jmsg2(jcr, M_ERROR, 0, _("Unable to write device %s: ERR=%s\n"),
503 dev->print_name(), strerror_dev(dev));
504 Dmsg0(200, "===ERROR write block to dev\n");
508 /* Set or reset Volume statistics */
509 dev->VolCatInfo.VolCatJobs = 0;
510 dev->VolCatInfo.VolCatFiles = 0;
511 dev->VolCatInfo.VolCatBytes = 1;
512 dev->VolCatInfo.VolCatErrors = 0;
513 dev->VolCatInfo.VolCatBlocks = 0;
514 dev->VolCatInfo.VolCatRBytes = 0;
516 dev->VolCatInfo.VolCatMounts++;
517 dev->VolCatInfo.VolCatRecycles++;
519 dev->VolCatInfo.VolCatMounts = 1;
520 dev->VolCatInfo.VolCatRecycles = 0;
521 dev->VolCatInfo.VolCatWrites = 1;
522 dev->VolCatInfo.VolCatReads = 1;
524 Dmsg0(100, "dir_update_vol_info. Set Append\n");
525 bstrncpy(dev->VolCatInfo.VolCatStatus, "Append", sizeof(dev->VolCatInfo.VolCatStatus));
526 if (!dir_update_volume_info(dcr, true)) { /* indicate doing relabel */
530 Jmsg(jcr, M_INFO, 0, _("Recycled volume \"%s\" on device %s, all previous data lost.\n"),
531 dcr->VolumeName, dev->print_name());
533 Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume \"%s\" on device %s\n"),
534 dcr->VolumeName, dev->print_name());
537 * End writing real Volume label (from pre-labeled tape), or recycling
540 Dmsg0(200, "OK from rewite vol label.\n");
546 * create_volume_label_record
547 * Serialize label (from dev->VolHdr structure) into device record.
548 * Assumes that the dev->VolHdr structure is properly
551 static void create_volume_label_record(DCR *dcr, DEV_RECORD *rec)
555 DEVICE *dev = dcr->dev;
558 /* Serialize the label into the device record. */
560 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
561 ser_begin(rec->data, SER_LENGTH_Volume_Label);
562 ser_string(dev->VolHdr.Id);
564 ser_uint32(dev->VolHdr.VerNum);
566 if (dev->VolHdr.VerNum >= 11) {
567 ser_btime(dev->VolHdr.label_btime);
568 dev->VolHdr.write_btime = get_current_btime();
569 ser_btime(dev->VolHdr.write_btime);
570 dev->VolHdr.write_date = 0;
571 dev->VolHdr.write_time = 0;
573 /* OLD WAY DEPRECATED */
574 ser_float64(dev->VolHdr.label_date);
575 ser_float64(dev->VolHdr.label_time);
576 get_current_time(&dt);
577 dev->VolHdr.write_date = dt.julian_day_number;
578 dev->VolHdr.write_time = dt.julian_day_fraction;
580 ser_float64(dev->VolHdr.write_date); /* 0 if VerNum >= 11 */
581 ser_float64(dev->VolHdr.write_time); /* 0 if VerNum >= 11 */
583 ser_string(dev->VolHdr.VolumeName);
584 ser_string(dev->VolHdr.PrevVolumeName);
585 ser_string(dev->VolHdr.PoolName);
586 ser_string(dev->VolHdr.PoolType);
587 ser_string(dev->VolHdr.MediaType);
589 ser_string(dev->VolHdr.HostName);
590 ser_string(dev->VolHdr.LabelProg);
591 ser_string(dev->VolHdr.ProgVersion);
592 ser_string(dev->VolHdr.ProgDate);
594 ser_end(rec->data, SER_LENGTH_Volume_Label);
595 rec->data_len = ser_length(rec->data);
596 rec->FileIndex = dev->VolHdr.LabelType;
597 rec->VolSessionId = jcr->VolSessionId;
598 rec->VolSessionTime = jcr->VolSessionTime;
599 rec->Stream = jcr->NumVolumes;
600 Dmsg2(100, "Created Vol label rec: FI=%s len=%d\n", FI_to_ascii(rec->FileIndex),
606 * Create a volume label in memory
608 void create_volume_label(DEVICE *dev, const char *VolName, const char *PoolName)
610 DEVRES *device = (DEVRES *)dev->device;
612 Dmsg0(90, "Start create_volume_label()\n");
616 memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
618 bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
619 dev->VolHdr.VerNum = BaculaTapeVersion;
620 dev->VolHdr.LabelType = PRE_LABEL; /* Mark tape as unused */
621 bstrncpy(dev->VolHdr.VolumeName, VolName, sizeof(dev->VolHdr.VolumeName));
622 bstrncpy(dev->VolHdr.PoolName, PoolName, sizeof(dev->VolHdr.PoolName));
623 bstrncpy(dev->VolHdr.MediaType, device->media_type, sizeof(dev->VolHdr.MediaType));
625 bstrncpy(dev->VolHdr.PoolType, "Backup", sizeof(dev->VolHdr.PoolType));
627 dev->VolHdr.label_btime = get_current_btime();
628 dev->VolHdr.label_date = 0;
629 dev->VolHdr.label_time = 0;
631 if (gethostname(dev->VolHdr.HostName, sizeof(dev->VolHdr.HostName)) != 0) {
632 dev->VolHdr.HostName[0] = 0;
634 bstrncpy(dev->VolHdr.LabelProg, my_name, sizeof(dev->VolHdr.LabelProg));
635 sprintf(dev->VolHdr.ProgVersion, "Ver. %s %s", VERSION, BDATE);
636 sprintf(dev->VolHdr.ProgDate, "Build %s %s", __DATE__, __TIME__);
637 dev->set_labeled(); /* set has Bacula label */
638 if (debug_level >= 90) {
639 dump_volume_label(dev);
644 * Create session label
645 * The pool memory must be released by the calling program
647 void create_session_label(DCR *dcr, DEV_RECORD *rec, int label)
652 rec->VolSessionId = jcr->VolSessionId;
653 rec->VolSessionTime = jcr->VolSessionTime;
654 rec->Stream = jcr->JobId;
656 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
657 ser_begin(rec->data, SER_LENGTH_Session_Label);
658 ser_string(BaculaId);
659 ser_uint32(BaculaTapeVersion);
661 ser_uint32(jcr->JobId);
663 /* Changed in VerNum 11 */
664 ser_btime(get_current_btime());
667 ser_string(dcr->pool_name);
668 ser_string(dcr->pool_type);
669 ser_string(jcr->job_name); /* base Job name */
670 ser_string(jcr->client_name);
672 /* Added in VerNum 10 */
673 ser_string(jcr->Job); /* Unique name of this Job */
674 ser_string(jcr->fileset_name);
675 ser_uint32(jcr->JobType);
676 ser_uint32(jcr->JobLevel);
677 /* Added in VerNum 11 */
678 ser_string(jcr->fileset_md5);
680 if (label == EOS_LABEL) {
681 ser_uint32(jcr->JobFiles);
682 ser_uint64(jcr->JobBytes);
683 ser_uint32(dcr->StartBlock);
684 ser_uint32(dcr->EndBlock);
685 ser_uint32(dcr->StartFile);
686 ser_uint32(dcr->EndFile);
687 ser_uint32(jcr->JobErrors);
689 /* Added in VerNum 11 */
690 ser_uint32(jcr->JobStatus);
692 ser_end(rec->data, SER_LENGTH_Session_Label);
693 rec->data_len = ser_length(rec->data);
696 /* Write session label
697 * Returns: false on failure
700 bool write_session_label(DCR *dcr, int label)
703 DEVICE *dev = dcr->dev;
705 DEV_BLOCK *block = dcr->block;
708 Dmsg1(90, "session_label record=%x\n", rec);
711 if (dev->is_tape()) {
712 dcr->StartBlock = dev->block_num;
713 dcr->StartFile = dev->file;
715 dcr->StartBlock = (uint32_t)dev->file_addr;
716 dcr->StartFile = (uint32_t)(dev->file_addr >> 32);
720 if (dev->is_tape()) {
721 dcr->EndBlock = dev->EndBlock;
722 dcr->EndFile = dev->EndFile;
724 dcr->EndBlock = (uint32_t)dev->file_addr;
725 dcr->EndFile = (uint32_t)(dev->file_addr >> 32);
729 Jmsg1(jcr, M_ABORT, 0, _("Bad session label = %d\n"), label);
732 create_session_label(dcr, rec, label);
733 rec->FileIndex = label;
736 * We guarantee that the session record can totally fit
737 * into a block. If not, write the block, and put it in
738 * the next block. Having the sesssion record totally in
739 * one block makes reading them much easier (no need to
740 * read the next block).
742 if (!can_write_record_to_block(block, rec)) {
743 Dmsg0(100, "Cannot write session label to block.\n");
744 if (!write_block_to_device(dcr)) {
745 Dmsg0(90, "Got session label write_block_to_dev error.\n");
746 /* ****FIXME***** errno is not set here */
747 Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"),
748 dev_vol_name(dev), strerror(errno));
753 if (!write_record_to_block(block, rec)) {
754 Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"),
755 dev_vol_name(dev), strerror(errno));
760 Dmsg6(20, "Write sesson_label record JobId=%d FI=%s SessId=%d Strm=%s len=%d "
761 "remainder=%d\n", jcr->JobId,
762 FI_to_ascii(rec->FileIndex), rec->VolSessionId,
763 stream_to_ascii(rec->Stream, rec->FileIndex), rec->data_len,
767 Dmsg2(20, "Leave write_session_label Block=%d File=%d\n",
768 dev->block_num, dev->file);
772 /* unser_volume_label
774 * Unserialize the Bacula Volume label into the device Volume_Label
777 * Assumes that the record is already read.
779 * Returns: false on error
783 bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec)
787 if (rec->FileIndex != VOL_LABEL && rec->FileIndex != PRE_LABEL) {
788 Mmsg3(dev->errmsg, _("Expecting Volume Label, got FI=%s Stream=%s len=%d\n"),
789 FI_to_ascii(rec->FileIndex),
790 stream_to_ascii(rec->Stream, rec->FileIndex),
797 dev->VolHdr.LabelType = rec->FileIndex;
798 dev->VolHdr.LabelSize = rec->data_len;
801 /* Unserialize the record into the Volume Header */
802 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
803 ser_begin(rec->data, SER_LENGTH_Volume_Label);
804 unser_string(dev->VolHdr.Id);
805 unser_uint32(dev->VolHdr.VerNum);
807 if (dev->VolHdr.VerNum >= 11) {
808 unser_btime(dev->VolHdr.label_btime);
809 unser_btime(dev->VolHdr.write_btime);
810 } else { /* old way */
811 unser_float64(dev->VolHdr.label_date);
812 unser_float64(dev->VolHdr.label_time);
814 unser_float64(dev->VolHdr.write_date); /* Unused with VerNum >= 11 */
815 unser_float64(dev->VolHdr.write_time); /* Unused with VerNum >= 11 */
817 unser_string(dev->VolHdr.VolumeName);
818 unser_string(dev->VolHdr.PrevVolumeName);
819 unser_string(dev->VolHdr.PoolName);
820 unser_string(dev->VolHdr.PoolType);
821 unser_string(dev->VolHdr.MediaType);
823 unser_string(dev->VolHdr.HostName);
824 unser_string(dev->VolHdr.LabelProg);
825 unser_string(dev->VolHdr.ProgVersion);
826 unser_string(dev->VolHdr.ProgDate);
828 ser_end(rec->data, SER_LENGTH_Volume_Label);
829 Dmsg0(90, "ser_read_vol\n");
830 if (debug_level >= 90) {
831 dump_volume_label(dev);
837 bool unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec)
841 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
842 unser_begin(rec->data, SER_LENGTH_Session_Label);
843 unser_string(label->Id);
844 unser_uint32(label->VerNum);
845 unser_uint32(label->JobId);
846 if (label->VerNum >= 11) {
847 unser_btime(label->write_btime);
849 unser_float64(label->write_date);
851 unser_float64(label->write_time);
852 unser_string(label->PoolName);
853 unser_string(label->PoolType);
854 unser_string(label->JobName);
855 unser_string(label->ClientName);
856 if (label->VerNum >= 10) {
857 unser_string(label->Job); /* Unique name of this Job */
858 unser_string(label->FileSetName);
859 unser_uint32(label->JobType);
860 unser_uint32(label->JobLevel);
862 if (label->VerNum >= 11) {
863 unser_string(label->FileSetMD5);
865 label->FileSetMD5[0] = 0;
867 if (rec->FileIndex == EOS_LABEL) {
868 unser_uint32(label->JobFiles);
869 unser_uint64(label->JobBytes);
870 unser_uint32(label->StartBlock);
871 unser_uint32(label->EndBlock);
872 unser_uint32(label->StartFile);
873 unser_uint32(label->EndFile);
874 unser_uint32(label->JobErrors);
875 if (label->VerNum >= 11) {
876 unser_uint32(label->JobStatus);
878 label->JobStatus = JS_Terminated; /* kludge */
884 void dump_volume_label(DEVICE *dev)
886 int dbl = debug_level;
888 const char *LabelType;
895 switch (dev->VolHdr.LabelType) {
897 LabelType = "PRE_LABEL";
900 LabelType = "VOL_LABEL";
903 LabelType = "EOM_LABEL";
906 LabelType = "SOS_LABEL";
909 LabelType = "EOS_LABEL";
915 sprintf(buf, "Unknown %d", dev->VolHdr.LabelType);
919 Pmsg11(-1, "\nVolume Label:\n"
932 dev->VolHdr.Id, dev->VolHdr.VerNum,
933 dev->VolHdr.VolumeName, dev->VolHdr.PrevVolumeName,
934 File, LabelType, dev->VolHdr.LabelSize,
935 dev->VolHdr.PoolName, dev->VolHdr.MediaType,
936 dev->VolHdr.PoolType, dev->VolHdr.HostName);
938 if (dev->VolHdr.VerNum >= 11) {
940 bstrftime(dt, sizeof(dt), btime_to_unix(dev->VolHdr.label_btime));
941 Pmsg1(-1, "Date label written: %s\n", dt);
943 dt.julian_day_number = dev->VolHdr.label_date;
944 dt.julian_day_fraction = dev->VolHdr.label_time;
947 "Date label written: %04d-%02d-%02d at %02d:%02d\n",
948 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
956 static void dump_session_label(DEV_RECORD *rec, const char *type)
962 char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], ec6[30], ec7[30];
964 unser_session_label(&label, rec);
967 Pmsg7(-1, "\n%s Record:\n"
974 "", type, label.JobId, label.VerNum,
975 label.PoolName, label.PoolType,
976 label.JobName, label.ClientName);
978 if (label.VerNum >= 10) {
980 "Job (unique name) : %s\n"
984 "", label.Job, label.FileSetName, label.JobType, label.JobLevel);
987 if (rec->FileIndex == EOS_LABEL) {
998 edit_uint64_with_commas(label.JobFiles, ec1),
999 edit_uint64_with_commas(label.JobBytes, ec2),
1000 edit_uint64_with_commas(label.StartBlock, ec3),
1001 edit_uint64_with_commas(label.EndBlock, ec4),
1002 edit_uint64_with_commas(label.StartFile, ec5),
1003 edit_uint64_with_commas(label.EndFile, ec6),
1004 edit_uint64_with_commas(label.JobErrors, ec7),
1007 if (label.VerNum >= 11) {
1009 bstrftime(dt, sizeof(dt), btime_to_unix(label.write_btime));
1010 Pmsg1(-1, _("Date written : %s\n"), dt);
1012 dt.julian_day_number = label.write_date;
1013 dt.julian_day_fraction = label.write_time;
1014 tm_decode(&dt, &tm);
1016 "Date written : %04d-%02d-%02d at %02d:%02d\n"),
1017 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
1023 void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose)
1030 switch (rec->FileIndex) {
1032 type = _("Fresh Volume");
1038 type = _("Begin Job Session");
1041 type = _("End Job Session");
1044 type = _("End of Media");
1047 type = ("End of Tape");
1050 type = _("Unknown");
1054 switch (rec->FileIndex) {
1057 unser_volume_label(dev, rec);
1058 dump_volume_label(dev);
1061 dump_session_label(rec, type);
1064 dump_session_label(rec, type);
1067 Pmsg5(-1, "%s Record: SessId=%d SessTime=%d JobId=%d DataLen=%d\n",
1068 type, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
1071 Pmsg0(-1, _("End of physical tape.\n"));
1074 Pmsg5(-1, "%s Record: SessId=%d SessTime=%d JobId=%d DataLen=%d\n",
1075 type, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
1079 SESSION_LABEL label;
1080 switch (rec->FileIndex) {
1082 unser_session_label(&label, rec);
1083 Pmsg6(-1, "%s Record: SessId=%d SessTime=%d JobId=%d Level=%c Type=%c\n",
1084 type, rec->VolSessionId, rec->VolSessionTime, rec->Stream,
1085 label.JobLevel, label.JobType);
1088 char ed1[30], ed2[30];
1089 unser_session_label(&label, rec);
1090 Pmsg6(-1, "%s Record: SessId=%d SessTime=%d JobId=%d Level=%c Type=%c\n",
1091 type, rec->VolSessionId, rec->VolSessionTime, rec->Stream,
1092 label.JobLevel, label.JobType);
1093 Pmsg4(-1, " Files=%s Bytes=%s Errors=%d Status=%c\n",
1094 edit_uint64_with_commas(label.JobFiles, ed1),
1095 edit_uint64_with_commas(label.JobBytes, ed2),
1096 label.JobErrors, (char)label.JobStatus);
1102 Pmsg5(-1, "%s Record: SessId=%d SessTime=%d JobId=%d DataLen=%d\n",
1103 type, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);