2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version two of the GNU General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of John Walker.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
30 * label.c Bacula routines to handle labels
38 #include "bacula.h" /* pull in global headers */
39 #include "stored.h" /* pull in Storage Deamon headers */
41 /* Forward referenced functions */
42 static void create_volume_label_record(DCR *dcr, DEV_RECORD *rec);
45 * Read the volume label
47 * If dcr->VolumeName == NULL, we accept any Bacula Volume
48 * If dcr->VolumeName[0] == 0, we accept any Bacula Volume
49 * otherwise dcr->VolumeName must match the Volume.
51 * If VolName given, ensure that it matches
53 * Returns VOL_ code as defined in record.h
55 * VOL_OK good label found
56 * VOL_NO_LABEL volume not labeled
57 * VOL_IO_ERROR I/O error reading tape
58 * VOL_NAME_ERROR label has wrong name
59 * VOL_CREATE_ERROR Error creating label
60 * VOL_VERSION_ERROR label has wrong version
61 * VOL_LABEL_ERROR bad label type
62 * VOL_NO_MEDIA no media in drive
64 * The dcr block is emptied on return, and the Volume is
67 int read_dev_volume_label(DCR *dcr)
70 DEVICE *dev = dcr->dev;
71 char *VolName = dcr->VolumeName;
74 DEV_BLOCK *block = dcr->block;
77 bool have_ansi_label = false;
79 Dmsg4(100, "Enter read_volume_label res=%d device=%s vol=%s dev_Vol=%s\n",
80 dev->reserved_device, dev->print_name(), VolName,
81 dev->VolHdr.VolumeName[0]?dev->VolHdr.VolumeName:"*NULL*");
83 if (!dev->is_open()) {
84 if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
88 if (dev->is_labeled()) { /* did we already read label? */
89 /* Compare Volume Names allow special wild card */
90 if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolumeName, VolName) != 0) {
91 Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
92 dev->print_name(), VolName, dev->VolHdr.VolumeName);
94 * Cancel Job if too many label errors
97 if (!dev->poll && jcr->label_errors++ > 100) {
98 Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
100 Dmsg0(150, "return VOL_NAME_ERROR\n");
101 stat = VOL_NAME_ERROR;
104 Dmsg0(130, "Leave read_volume_label() VOL_OK\n");
105 return VOL_OK; /* label already read */
108 dev->clear_labeled();
111 dev->label_type = B_BACULA_LABEL;
113 if (!dev->rewind(dcr)) {
114 Mmsg(jcr->errmsg, _("Couldn't rewind device %s: ERR=%s\n"),
115 dev->print_name(), dev->print_errmsg());
116 Dmsg1(130, "return VOL_NO_MEDIA: %s", jcr->errmsg);
119 bstrncpy(dev->VolHdr.Id, "**error**", sizeof(dev->VolHdr.Id));
121 /* Read ANSI/IBM label if so requested */
123 want_ansi_label = dcr->VolCatInfo.LabelType != B_BACULA_LABEL ||
124 dcr->device->label_type != B_BACULA_LABEL;
125 if (want_ansi_label || dev->has_cap(CAP_CHECKLABELS)) {
126 stat = read_ansi_ibm_label(dcr);
127 /* If we want a label and didn't find it, return error */
128 if (want_ansi_label && stat != VOL_OK) {
131 if (stat == VOL_NAME_ERROR || stat == VOL_LABEL_ERROR) {
132 Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
133 dev->print_name(), VolName, dev->VolHdr.VolumeName);
134 if (!dev->poll && jcr->label_errors++ > 100) {
135 Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
139 if (stat != VOL_OK) { /* Not an ANSI/IBM label, so re-read */
142 have_ansi_label = true;
146 /* Read the Bacula Volume label block */
147 record = new_record();
150 Dmsg0(130, "Big if statement in read_volume_label\n");
151 if (!read_block_from_dev(dcr, NO_BLOCK_NUMBER_CHECK)) {
152 Mmsg(jcr->errmsg, _("Requested Volume \"%s\" on %s is not a Bacula "
153 "labeled Volume, because: ERR=%s"), NPRT(VolName),
154 dev->print_name(), dev->print_errmsg());
155 Dmsg1(130, "%s", jcr->errmsg);
156 } else if (!read_record_from_block(dcr, block, record)) {
157 Mmsg(jcr->errmsg, _("Could not read Volume label from block.\n"));
158 Dmsg1(130, "%s", jcr->errmsg);
159 } else if (!unser_volume_label(dev, record)) {
160 Mmsg(jcr->errmsg, _("Could not unserialize Volume label: ERR=%s\n"),
161 dev->print_errmsg());
162 Dmsg1(130, "%s", jcr->errmsg);
163 } else if (strcmp(dev->VolHdr.Id, BaculaId) != 0 &&
164 strcmp(dev->VolHdr.Id, OldBaculaId) != 0) {
165 Mmsg(jcr->errmsg, _("Volume Header Id bad: %s\n"), dev->VolHdr.Id);
166 Dmsg1(130, "%s", jcr->errmsg);
170 free_record(record); /* finished reading Volume record */
173 if (forge_on || jcr->ignore_label_errors) {
174 dev->set_labeled(); /* set has Bacula label */
175 Jmsg(jcr, M_ERROR, 0, "%s", jcr->errmsg);
179 Dmsg0(100, "No volume label - bailing out\n");
184 /* At this point, we have read the first Bacula block, and
185 * then read the Bacula Volume label. Now we need to
186 * make sure we have the right Volume.
190 if (dev->VolHdr.VerNum != BaculaTapeVersion &&
191 dev->VolHdr.VerNum != OldCompatibleBaculaTapeVersion1 &&
192 dev->VolHdr.VerNum != OldCompatibleBaculaTapeVersion2) {
193 Mmsg(jcr->errmsg, _("Volume on %s has wrong Bacula version. Wanted %d got %d\n"),
194 dev->print_name(), BaculaTapeVersion, dev->VolHdr.VerNum);
195 Dmsg1(130, "VOL_VERSION_ERROR: %s", jcr->errmsg);
196 stat = VOL_VERSION_ERROR;
200 /* We are looking for either an unused Bacula tape (PRE_LABEL) or
201 * a Bacula volume label (VOL_LABEL)
203 if (dev->VolHdr.LabelType != PRE_LABEL && dev->VolHdr.LabelType != VOL_LABEL) {
204 Mmsg(jcr->errmsg, _("Volume on %s has bad Bacula label type: %x\n"),
205 dev->print_name(), dev->VolHdr.LabelType);
206 Dmsg1(130, "%s", jcr->errmsg);
207 if (!dev->poll && jcr->label_errors++ > 100) {
208 Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
210 Dmsg0(150, "return VOL_LABEL_ERROR\n");
211 stat = VOL_LABEL_ERROR;
215 dev->set_labeled(); /* set has Bacula label */
216 if (reserve_volume(dcr, dev->VolHdr.VolumeName) == NULL) {
217 Mmsg2(jcr->errmsg, _("Could not reserve volume %s on %s\n"),
218 dev->VolHdr.VolumeName, dev->print_name());
219 stat = VOL_NAME_ERROR;
223 /* Compare Volume Names */
224 Dmsg2(130, "Compare Vol names: VolName=%s hdr=%s\n", VolName?VolName:"*", dev->VolHdr.VolumeName);
225 if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolumeName, VolName) != 0) {
226 Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
227 dev->print_name(), VolName, dev->VolHdr.VolumeName);
228 Dmsg1(130, "%s", jcr->errmsg);
230 * Cancel Job if too many label errors
231 * => we are in a loop
233 if (!dev->poll && jcr->label_errors++ > 100) {
234 Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
236 Dmsg0(150, "return VOL_NAME_ERROR\n");
237 stat = VOL_NAME_ERROR;
240 Dmsg1(130, "Copy vol_name=%s\n", dev->VolHdr.VolumeName);
242 if (debug_level >= 10) {
243 dump_volume_label(dev);
245 Dmsg0(130, "Leave read_volume_label() VOL_OK\n");
246 /* If we are a streaming device, we only get one chance to read */
247 if (!dev->has_cap(CAP_STREAM)) {
249 if (have_ansi_label) {
250 stat = read_ansi_ibm_label(dcr);
251 /* If we want a label and didn't find it, return error */
252 if (stat != VOL_OK) {
263 Dmsg1(150, "return %d\n", stat);
268 * Put a volume label into the block
270 * Returns: false on failure
273 bool write_volume_label_to_block(DCR *dcr)
276 DEVICE *dev = dcr->dev;
278 DEV_BLOCK *block = dcr->block;
280 Dmsg0(130, "write Label in write_volume_label_to_block()\n");
281 memset(&rec, 0, sizeof(rec));
282 rec.data = get_memory(SER_LENGTH_Volume_Label);
283 empty_block(block); /* Volume label always at beginning */
285 create_volume_label_record(dcr, &rec);
287 block->BlockNumber = 0;
288 if (!write_record_to_block(block, &rec)) {
289 free_pool_memory(rec.data);
290 Jmsg1(jcr, M_FATAL, 0, _("Cannot write Volume label to block for device %s\n"),
294 Dmsg1(130, "Wrote label of %d bytes to block\n", rec.data_len);
296 free_pool_memory(rec.data);
302 * Write a Volume Label
303 * !!! Note, this is ONLY used for writing
304 * a fresh volume label. Any data
305 * after the label will be destroyed,
306 * in fact, we write the label 5 times !!!!
308 * This routine should be used only when labeling a blank tape.
310 bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName,
311 const char *PoolName, bool relabel, bool dvdnow)
313 DEVICE *dev = dcr->dev;
316 Dmsg0(150, "write_volume_label()\n");
317 empty_block(dcr->block);
319 /* If relabeling, truncate the device */
320 if (relabel && !dev->truncate(dcr)) {
324 if (relabel && !dev->is_tape()) {
325 dev->close_part(dcr); /* make sure DVD/file closed for rename */
328 /* Set the new filename for open, ... */
329 bstrncpy(dev->VolCatInfo.VolCatName, VolName, sizeof(dev->VolCatInfo.VolCatName));
330 bstrncpy(dcr->VolCatInfo.VolCatName, VolName, sizeof(dcr->VolCatInfo.VolCatName));
331 Dmsg1(150, "New VolName=%s\n", VolName);
332 if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
333 /* If device is not tape, attempt to create it */
334 if (dev->is_tape() || dev->open(dcr, CREATE_READ_WRITE) < 0) {
338 Dmsg1(150, "Label type=%d\n", dev->label_type);
339 if (!dev->rewind(dcr)) {
341 Dmsg2(130, "Bad status on %s from rewind: ERR=%s\n", dev->print_name(), dev->print_errmsg());
347 /* Temporarily mark in append state to enable writing */
350 /* Create PRE_LABEL or VOL_LABEL if DVD */
351 create_volume_label(dev, VolName, PoolName, dvdnow);
354 * If we have already detected an ANSI label, re-read it
355 * to skip past it. Otherwise, we write a new one if
358 if (dev->label_type != B_BACULA_LABEL) {
359 if (read_ansi_ibm_label(dcr) != VOL_OK) {
363 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, VolName)) {
367 create_volume_label_record(dcr, dcr->rec);
368 dcr->rec->Stream = 0;
370 if (!write_record_to_block(dcr->block, dcr->rec)) {
371 Dmsg2(130, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
374 Dmsg2(130, "Wrote label of %d bytes to %s\n", dcr->rec->data_len, dev->print_name());
377 Dmsg0(130, "Call write_block_to_dev()\n");
378 if (!write_block_to_dev(dcr)) {
379 Dmsg2(130, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
383 /* Now commit block to DVD if we should write now */
384 if (dev->is_dvd() && dvdnow) {
385 Dmsg1(150, "New VolName=%s\n", dev->VolCatInfo.VolCatName);
386 if (!dvd_write_part(dcr)) {
387 Dmsg2(130, "Bad DVD write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
392 Dmsg0(130, " Wrote block to device\n");
396 write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
399 if (debug_level >= 20) {
400 dump_volume_label(dev);
402 if (reserve_volume(dcr, VolName) == NULL) {
403 Mmsg2(dcr->jcr->errmsg, _("Could not reserve volume %s on %s\n"),
404 dev->VolHdr.VolumeName, dev->print_name());
408 dev->clear_append(); /* remove append since this is PRE_LABEL */
413 dev->clear_append(); /* remove append since this is PRE_LABEL */
418 * Write a volume label. This is ONLY called if we have a valid Bacula
419 * label of type PRE_LABEL;
420 * Returns: true if OK
421 * false if unable to write it
423 bool rewrite_volume_label(DCR *dcr, bool recycle)
425 DEVICE *dev = dcr->dev;
428 if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
431 Dmsg2(190, "set append found freshly labeled volume. fd=%d dev=%x\n", dev->fd(), dev);
432 dev->VolHdr.LabelType = VOL_LABEL; /* set Volume label */
434 if (!write_volume_label_to_block(dcr)) {
435 Dmsg0(200, "Error from write volume label.\n");
439 dev->VolCatInfo.VolCatBytes = 0; /* reset byte count */
442 * If we are not dealing with a streaming device,
443 * write the block now to ensure we have write permission.
444 * It is better to find out now rather than later.
445 * We do not write the block now if this is an ANSI label. This
446 * avoids re-writing the ANSI label, which we do not want to do.
448 if (!dev->has_cap(CAP_STREAM)) {
449 if (!dev->rewind(dcr)) {
450 Jmsg2(jcr, M_FATAL, 0, _("Rewind error on device %s: ERR=%s\n"),
451 dev->print_name(), dev->print_errmsg());
455 if (!dev->truncate(dcr)) {
456 Jmsg2(jcr, M_FATAL, 0, _("Truncate error on device %s: ERR=%s\n"),
457 dev->print_name(), dev->print_errmsg());
460 if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
461 Jmsg2(jcr, M_FATAL, 0,
462 _("Failed to re-open DVD after truncate on device %s: ERR=%s\n"),
463 dev->print_name(), dev->print_errmsg());
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.VolumeName)) {
482 /* Attempt write to check write permission */
483 Dmsg1(200, "Attempt to write to device fd=%d.\n", dev->fd());
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(), dev->print_errmsg());
487 Dmsg0(200, "===ERROR write block to dev\n");
492 /* Set or reset Volume statistics */
493 dev->VolCatInfo.VolCatJobs = 0;
494 dev->VolCatInfo.VolCatFiles = 0;
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(150, "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 rewrite 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;
542 /* Serialize the label into the device record. */
544 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
545 ser_begin(rec->data, SER_LENGTH_Volume_Label);
546 ser_string(dev->VolHdr.Id);
548 ser_uint32(dev->VolHdr.VerNum);
550 if (dev->VolHdr.VerNum >= 11) {
551 ser_btime(dev->VolHdr.label_btime);
552 dev->VolHdr.write_btime = get_current_btime();
553 ser_btime(dev->VolHdr.write_btime);
554 dev->VolHdr.write_date = 0;
555 dev->VolHdr.write_time = 0;
557 /* OLD WAY DEPRECATED */
558 ser_float64(dev->VolHdr.label_date);
559 ser_float64(dev->VolHdr.label_time);
560 get_current_time(&dt);
561 dev->VolHdr.write_date = dt.julian_day_number;
562 dev->VolHdr.write_time = dt.julian_day_fraction;
564 ser_float64(dev->VolHdr.write_date); /* 0 if VerNum >= 11 */
565 ser_float64(dev->VolHdr.write_time); /* 0 if VerNum >= 11 */
567 ser_string(dev->VolHdr.VolumeName);
568 ser_string(dev->VolHdr.PrevVolumeName);
569 ser_string(dev->VolHdr.PoolName);
570 ser_string(dev->VolHdr.PoolType);
571 ser_string(dev->VolHdr.MediaType);
573 ser_string(dev->VolHdr.HostName);
574 ser_string(dev->VolHdr.LabelProg);
575 ser_string(dev->VolHdr.ProgVersion);
576 ser_string(dev->VolHdr.ProgDate);
578 ser_end(rec->data, SER_LENGTH_Volume_Label);
579 rec->data_len = ser_length(rec->data);
580 rec->FileIndex = dev->VolHdr.LabelType;
581 rec->VolSessionId = jcr->VolSessionId;
582 rec->VolSessionTime = jcr->VolSessionTime;
583 rec->Stream = jcr->NumWriteVolumes;
584 Dmsg2(150, "Created Vol label rec: FI=%s len=%d\n", FI_to_ascii(buf, rec->FileIndex),
590 * Create a volume label in memory
592 void create_volume_label(DEVICE *dev, const char *VolName,
593 const char *PoolName, bool dvdnow)
595 DEVRES *device = (DEVRES *)dev->device;
597 Dmsg0(130, "Start create_volume_label()\n");
601 dev->clear_volhdr(); /* release any old volume */
603 bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
604 dev->VolHdr.VerNum = BaculaTapeVersion;
605 if (dev->is_dvd() && dvdnow) {
606 /* We do not want to re-label a DVD so write VOL_LABEL now */
607 dev->VolHdr.LabelType = VOL_LABEL;
609 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;
696 char buf1[100], buf2[100];
699 Dmsg1(130, "session_label record=%x\n", rec);
702 if (dev->is_tape()) {
703 dcr->StartBlock = dev->block_num;
704 dcr->StartFile = dev->file;
706 dcr->StartBlock = (uint32_t)dev->file_addr;
707 dcr->StartFile = (uint32_t)(dev->file_addr >> 32);
711 if (dev->is_tape()) {
712 dcr->EndBlock = dev->EndBlock;
713 dcr->EndFile = dev->EndFile;
715 dcr->EndBlock = (uint32_t)dev->file_addr;
716 dcr->EndFile = (uint32_t)(dev->file_addr >> 32);
720 Jmsg1(jcr, M_ABORT, 0, _("Bad session label = %d\n"), label);
723 create_session_label(dcr, rec, label);
724 rec->FileIndex = label;
727 * We guarantee that the session record can totally fit
728 * into a block. If not, write the block, and put it in
729 * the next block. Having the sesssion record totally in
730 * one block makes reading them much easier (no need to
731 * read the next block).
733 if (!can_write_record_to_block(block, rec)) {
734 Dmsg0(150, "Cannot write session label to block.\n");
735 if (!write_block_to_device(dcr)) {
736 Dmsg0(130, "Got session label write_block_to_dev error.\n");
737 /* ****FIXME***** errno is not set here */
738 Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"),
739 dev_vol_name(dev), strerror(errno));
744 if (!write_record_to_block(block, rec)) {
745 Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"),
746 dev_vol_name(dev), strerror(errno));
751 Dmsg6(150, "Write sesson_label record JobId=%d FI=%s SessId=%d Strm=%s len=%d "
752 "remainder=%d\n", jcr->JobId,
753 FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
754 stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
758 Dmsg2(150, "Leave write_session_label Block=%ud File=%ud\n",
759 dev->get_block_num(), dev->get_file());
763 /* unser_volume_label
765 * Unserialize the Bacula Volume label into the device Volume_Label
768 * Assumes that the record is already read.
770 * Returns: false on error
774 bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec)
777 char buf1[100], buf2[100];
779 if (rec->FileIndex != VOL_LABEL && rec->FileIndex != PRE_LABEL) {
780 Mmsg3(dev->errmsg, _("Expecting Volume Label, got FI=%s Stream=%s len=%d\n"),
781 FI_to_ascii(buf1, rec->FileIndex),
782 stream_to_ascii(buf2, rec->Stream, rec->FileIndex),
789 dev->VolHdr.LabelType = rec->FileIndex;
790 dev->VolHdr.LabelSize = rec->data_len;
793 /* Unserialize the record into the Volume Header */
794 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
795 ser_begin(rec->data, SER_LENGTH_Volume_Label);
796 unser_string(dev->VolHdr.Id);
797 unser_uint32(dev->VolHdr.VerNum);
799 if (dev->VolHdr.VerNum >= 11) {
800 unser_btime(dev->VolHdr.label_btime);
801 unser_btime(dev->VolHdr.write_btime);
802 } else { /* old way */
803 unser_float64(dev->VolHdr.label_date);
804 unser_float64(dev->VolHdr.label_time);
806 unser_float64(dev->VolHdr.write_date); /* Unused with VerNum >= 11 */
807 unser_float64(dev->VolHdr.write_time); /* Unused with VerNum >= 11 */
809 unser_string(dev->VolHdr.VolumeName);
810 unser_string(dev->VolHdr.PrevVolumeName);
811 unser_string(dev->VolHdr.PoolName);
812 unser_string(dev->VolHdr.PoolType);
813 unser_string(dev->VolHdr.MediaType);
815 unser_string(dev->VolHdr.HostName);
816 unser_string(dev->VolHdr.LabelProg);
817 unser_string(dev->VolHdr.ProgVersion);
818 unser_string(dev->VolHdr.ProgDate);
820 ser_end(rec->data, SER_LENGTH_Volume_Label);
821 Dmsg0(190, "unser_vol_label\n");
822 if (debug_level >= 190) {
823 dump_volume_label(dev);
829 bool unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec)
833 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
834 unser_begin(rec->data, SER_LENGTH_Session_Label);
835 unser_string(label->Id);
836 unser_uint32(label->VerNum);
837 unser_uint32(label->JobId);
838 if (label->VerNum >= 11) {
839 unser_btime(label->write_btime);
841 unser_float64(label->write_date);
843 unser_float64(label->write_time);
844 unser_string(label->PoolName);
845 unser_string(label->PoolType);
846 unser_string(label->JobName);
847 unser_string(label->ClientName);
848 if (label->VerNum >= 10) {
849 unser_string(label->Job); /* Unique name of this Job */
850 unser_string(label->FileSetName);
851 unser_uint32(label->JobType);
852 unser_uint32(label->JobLevel);
854 if (label->VerNum >= 11) {
855 unser_string(label->FileSetMD5);
857 label->FileSetMD5[0] = 0;
859 if (rec->FileIndex == EOS_LABEL) {
860 unser_uint32(label->JobFiles);
861 unser_uint64(label->JobBytes);
862 unser_uint32(label->StartBlock);
863 unser_uint32(label->EndBlock);
864 unser_uint32(label->StartFile);
865 unser_uint32(label->EndFile);
866 unser_uint32(label->JobErrors);
867 if (label->VerNum >= 11) {
868 unser_uint32(label->JobStatus);
870 label->JobStatus = JS_Terminated; /* kludge */
876 void dump_volume_label(DEVICE *dev)
878 int dbl = debug_level;
880 const char *LabelType;
887 switch (dev->VolHdr.LabelType) {
889 LabelType = "PRE_LABEL";
892 LabelType = "VOL_LABEL";
895 LabelType = "EOM_LABEL";
898 LabelType = "SOS_LABEL";
901 LabelType = "EOS_LABEL";
907 sprintf(buf, _("Unknown %d"), dev->VolHdr.LabelType);
911 Pmsg11(-1, _("\nVolume Label:\n"
924 dev->VolHdr.Id, dev->VolHdr.VerNum,
925 dev->VolHdr.VolumeName, dev->VolHdr.PrevVolumeName,
926 File, LabelType, dev->VolHdr.LabelSize,
927 dev->VolHdr.PoolName, dev->VolHdr.MediaType,
928 dev->VolHdr.PoolType, dev->VolHdr.HostName);
930 if (dev->VolHdr.VerNum >= 11) {
932 bstrftime(dt, sizeof(dt), btime_to_unix(dev->VolHdr.label_btime));
933 Pmsg1(-1, _("Date label written: %s\n"), dt);
935 dt.julian_day_number = dev->VolHdr.label_date;
936 dt.julian_day_fraction = dev->VolHdr.label_time;
939 _("Date label written: %04d-%02d-%02d at %02d:%02d\n"),
940 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
948 static void dump_session_label(DEV_RECORD *rec, const char *type)
954 char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], ec6[30], ec7[30];
956 unser_session_label(&label, rec);
959 Pmsg7(-1, _("\n%s Record:\n"
966 ""), type, label.JobId, label.VerNum,
967 label.PoolName, label.PoolType,
968 label.JobName, label.ClientName);
970 if (label.VerNum >= 10) {
972 "Job (unique name) : %s\n"
976 ""), label.Job, label.FileSetName, label.JobType, label.JobLevel);
979 if (rec->FileIndex == EOS_LABEL) {
990 edit_uint64_with_commas(label.JobFiles, ec1),
991 edit_uint64_with_commas(label.JobBytes, ec2),
992 edit_uint64_with_commas(label.StartBlock, ec3),
993 edit_uint64_with_commas(label.EndBlock, ec4),
994 edit_uint64_with_commas(label.StartFile, ec5),
995 edit_uint64_with_commas(label.EndFile, ec6),
996 edit_uint64_with_commas(label.JobErrors, ec7),
999 if (label.VerNum >= 11) {
1001 bstrftime(dt, sizeof(dt), btime_to_unix(label.write_btime));
1002 Pmsg1(-1, _("Date written : %s\n"), dt);
1004 dt.julian_day_number = label.write_date;
1005 dt.julian_day_fraction = label.write_time;
1006 tm_decode(&dt, &tm);
1007 Pmsg5(-1, _("Date written : %04d-%02d-%02d at %02d:%02d\n"),
1008 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
1014 void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose)
1019 if (rec->FileIndex == 0 && rec->VolSessionId == 0 && rec->VolSessionTime == 0) {
1024 switch (rec->FileIndex) {
1026 type = _("Fresh Volume");
1032 type = _("Begin Job Session");
1035 type = _("End Job Session");
1038 type = _("End of Media");
1041 type = _("End of Tape");
1044 type = _("Unknown");
1048 switch (rec->FileIndex) {
1051 unser_volume_label(dev, rec);
1052 dump_volume_label(dev);
1055 dump_session_label(rec, type);
1058 dump_session_label(rec, type);
1061 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1062 type, dev->file, dev->block_num, rec->VolSessionId,
1063 rec->VolSessionTime, rec->Stream, rec->data_len);
1066 Pmsg0(-1, _("End of physical tape.\n"));
1069 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1070 type, dev->file, dev->block_num, rec->VolSessionId,
1071 rec->VolSessionTime, rec->Stream, rec->data_len);
1075 SESSION_LABEL label;
1077 switch (rec->FileIndex) {
1079 unser_session_label(&label, rec);
1080 bstrftimes(dt, sizeof(dt), btime_to_unix(label.write_btime));
1081 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1082 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1083 Pmsg4(-1, _(" Job=%s Date=%s Level=%c Type=%c\n"),
1084 label.Job, dt, label.JobLevel, label.JobType);
1087 char ed1[30], ed2[30];
1088 unser_session_label(&label, rec);
1089 bstrftimes(dt, sizeof(dt), btime_to_unix(label.write_btime));
1090 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1091 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1092 Pmsg7(-1, _(" Date=%s Level=%c Type=%c Files=%s Bytes=%s Errors=%d Status=%c\n"),
1093 dt, label.JobLevel, label.JobType,
1094 edit_uint64_with_commas(label.JobFiles, ed1),
1095 edit_uint64_with_commas(label.JobBytes, ed2),
1096 label.JobErrors, (char)label.JobStatus);
1102 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1103 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime,
1104 rec->Stream, rec->data_len);