2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2008 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 * volatile 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->num_reserved(), 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 */
122 want_ansi_label = dcr->VolCatInfo.LabelType != B_BACULA_LABEL ||
123 dcr->device->label_type != B_BACULA_LABEL;
124 if (want_ansi_label || dev->has_cap(CAP_CHECKLABELS)) {
125 stat = read_ansi_ibm_label(dcr);
126 /* If we want a label and didn't find it, return error */
127 if (want_ansi_label && stat != VOL_OK) {
130 if (stat == VOL_NAME_ERROR || stat == VOL_LABEL_ERROR) {
131 Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
132 dev->print_name(), VolName, dev->VolHdr.VolumeName);
133 if (!dev->poll && jcr->label_errors++ > 100) {
134 Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
138 if (stat != VOL_OK) { /* Not an ANSI/IBM label, so re-read */
141 have_ansi_label = true;
145 /* Read the Bacula Volume label block */
146 record = new_record();
149 Dmsg0(130, "Big if statement in read_volume_label\n");
150 if (!read_block_from_dev(dcr, NO_BLOCK_NUMBER_CHECK)) {
151 Mmsg(jcr->errmsg, _("Requested Volume \"%s\" on %s is not a Bacula "
152 "labeled Volume, because: ERR=%s"), NPRT(VolName),
153 dev->print_name(), dev->print_errmsg());
154 Dmsg1(130, "%s", jcr->errmsg);
155 } else if (!read_record_from_block(dcr, block, record)) {
156 Mmsg(jcr->errmsg, _("Could not read Volume label from block.\n"));
157 Dmsg1(130, "%s", jcr->errmsg);
158 } else if (!unser_volume_label(dev, record)) {
159 Mmsg(jcr->errmsg, _("Could not unserialize Volume label: ERR=%s\n"),
160 dev->print_errmsg());
161 Dmsg1(130, "%s", jcr->errmsg);
162 } else if (strcmp(dev->VolHdr.Id, BaculaId) != 0 &&
163 strcmp(dev->VolHdr.Id, OldBaculaId) != 0) {
164 Mmsg(jcr->errmsg, _("Volume Header Id bad: %s\n"), dev->VolHdr.Id);
165 Dmsg1(130, "%s", jcr->errmsg);
169 free_record(record); /* finished reading Volume record */
172 if (forge_on || jcr->ignore_label_errors) {
173 dev->set_labeled(); /* set has Bacula label */
174 Jmsg(jcr, M_ERROR, 0, "%s", jcr->errmsg);
178 Dmsg0(100, "No volume label - bailing out\n");
183 /* At this point, we have read the first Bacula block, and
184 * then read the Bacula Volume label. Now we need to
185 * make sure we have the right Volume.
189 if (dev->VolHdr.VerNum != BaculaTapeVersion &&
190 dev->VolHdr.VerNum != OldCompatibleBaculaTapeVersion1 &&
191 dev->VolHdr.VerNum != OldCompatibleBaculaTapeVersion2) {
192 Mmsg(jcr->errmsg, _("Volume on %s has wrong Bacula version. Wanted %d got %d\n"),
193 dev->print_name(), BaculaTapeVersion, dev->VolHdr.VerNum);
194 Dmsg1(130, "VOL_VERSION_ERROR: %s", jcr->errmsg);
195 stat = VOL_VERSION_ERROR;
199 /* We are looking for either an unused Bacula tape (PRE_LABEL) or
200 * a Bacula volume label (VOL_LABEL)
202 if (dev->VolHdr.LabelType != PRE_LABEL && dev->VolHdr.LabelType != VOL_LABEL) {
203 Mmsg(jcr->errmsg, _("Volume on %s has bad Bacula label type: %x\n"),
204 dev->print_name(), dev->VolHdr.LabelType);
205 Dmsg1(130, "%s", jcr->errmsg);
206 if (!dev->poll && jcr->label_errors++ > 100) {
207 Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
209 Dmsg0(150, "return VOL_LABEL_ERROR\n");
210 stat = VOL_LABEL_ERROR;
214 dev->set_labeled(); /* set has Bacula label */
215 Dmsg1(100, "Call reserve_volume=%s\n", dev->VolHdr.VolumeName);
216 Dmsg2(100, "=== dcr->dev=%p dev=%p\n", dcr->dev, dev);
217 if (reserve_volume(dcr, dev->VolHdr.VolumeName) == NULL) {
218 Mmsg2(jcr->errmsg, _("Could not reserve volume %s on %s\n"),
219 dev->VolHdr.VolumeName, dev->print_name());
220 stat = VOL_NAME_ERROR;
223 Dmsg2(100, "=== dcr->dev=%p dev=%p\n", dcr->dev, dev);
225 /* Compare Volume Names */
226 Dmsg2(130, "Compare Vol names: VolName=%s hdr=%s\n", VolName?VolName:"*", dev->VolHdr.VolumeName);
227 if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolumeName, VolName) != 0) {
228 Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
229 dev->print_name(), VolName, dev->VolHdr.VolumeName);
230 Dmsg1(130, "%s", jcr->errmsg);
232 * Cancel Job if too many label errors
233 * => we are in a loop
235 if (!dev->poll && jcr->label_errors++ > 100) {
236 Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
238 Dmsg0(150, "return VOL_NAME_ERROR\n");
239 stat = VOL_NAME_ERROR;
240 volume_unused(dcr); /* mark volume "released" */
243 Dmsg1(130, "Copy vol_name=%s\n", dev->VolHdr.VolumeName);
245 if (debug_level >= 10) {
246 dump_volume_label(dev);
248 Dmsg0(130, "Leave read_volume_label() VOL_OK\n");
249 /* If we are a streaming device, we only get one chance to read */
250 if (!dev->has_cap(CAP_STREAM)) {
252 if (have_ansi_label) {
253 stat = read_ansi_ibm_label(dcr);
254 /* If we want a label and didn't find it, return error */
255 if (stat != VOL_OK) {
256 volume_unused(dcr); /* mark volume "released" */
267 Dmsg1(150, "return %d\n", stat);
272 * Put a volume label into the block
274 * Returns: false on failure
277 bool write_volume_label_to_block(DCR *dcr)
280 DEVICE *dev = dcr->dev;
282 DEV_BLOCK *block = dcr->block;
284 Dmsg0(130, "write Label in write_volume_label_to_block()\n");
285 memset(&rec, 0, sizeof(rec));
286 rec.data = get_memory(SER_LENGTH_Volume_Label);
287 empty_block(block); /* Volume label always at beginning */
289 create_volume_label_record(dcr, &rec);
291 block->BlockNumber = 0;
292 if (!write_record_to_block(block, &rec)) {
293 free_pool_memory(rec.data);
294 Jmsg1(jcr, M_FATAL, 0, _("Cannot write Volume label to block for device %s\n"),
298 Dmsg2(130, "Wrote label of %d bytes to block. Vol=%s\n", rec.data_len,
301 free_pool_memory(rec.data);
307 * Write a Volume Label
308 * !!! Note, this is ONLY used for writing
309 * a fresh volume label. Any data
310 * after the label will be destroyed,
311 * in fact, we write the label 5 times !!!!
313 * This routine should be used only when labeling a blank tape.
315 bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName,
316 const char *PoolName, bool relabel, bool dvdnow)
318 DEVICE * volatile dev = dcr->dev;
321 Dmsg0(150, "write_volume_label()\n");
322 empty_block(dcr->block);
325 volume_unused(dcr); /* mark current volume unused */
326 /* Truncate device */
327 if (!dev->truncate(dcr)) {
330 if (!dev->is_tape()) {
331 dev->close_part(dcr); /* make sure DVD/file closed for rename */
335 /* Set the new filename for open, ... */
336 bstrncpy(dev->VolCatInfo.VolCatName, VolName, sizeof(dev->VolCatInfo.VolCatName));
337 bstrncpy(dcr->VolCatInfo.VolCatName, VolName, sizeof(dcr->VolCatInfo.VolCatName));
338 Dmsg1(150, "New VolName=%s\n", VolName);
339 if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
340 /* If device is not tape, attempt to create it */
341 if (dev->is_tape() || dev->open(dcr, CREATE_READ_WRITE) < 0) {
342 Jmsg3(dcr->jcr, M_WARNING, 0, _("Open device %s Volume \"%s\" failed: ERR=%s\n"),
343 dev->print_name(), dcr->VolumeName, dev->bstrerror());
347 Dmsg1(150, "Label type=%d\n", dev->label_type);
348 if (!dev->rewind(dcr)) {
349 Dmsg2(130, "Bad status on %s from rewind: ERR=%s\n", dev->print_name(), dev->print_errmsg());
355 /* Temporarily mark in append state to enable writing */
358 /* Create PRE_LABEL or VOL_LABEL if DVD */
359 create_volume_label(dev, VolName, PoolName, dvdnow);
362 * If we have already detected an ANSI label, re-read it
363 * to skip past it. Otherwise, we write a new one if
366 if (dev->label_type != B_BACULA_LABEL) {
367 if (read_ansi_ibm_label(dcr) != VOL_OK) {
371 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, VolName)) {
375 create_volume_label_record(dcr, dcr->rec);
376 dcr->rec->Stream = 0;
378 if (!write_record_to_block(dcr->block, dcr->rec)) {
379 Dmsg2(130, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
382 Dmsg2(130, "Wrote label of %d bytes to %s\n", dcr->rec->data_len, dev->print_name());
385 Dmsg0(130, "Call write_block_to_dev()\n");
386 if (!write_block_to_dev(dcr)) {
387 Dmsg2(130, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
391 /* Now commit block to DVD if we should write now */
392 if (dev->is_dvd() && dvdnow) {
393 Dmsg1(150, "New VolName=%s\n", dev->VolCatInfo.VolCatName);
394 if (!dvd_write_part(dcr)) {
395 Dmsg2(130, "Bad DVD write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
400 Dmsg0(130, " Wrote block to device\n");
404 write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
407 if (debug_level >= 20) {
408 dump_volume_label(dev);
410 Dmsg0(100, "Call reserve_volume\n");
411 if (reserve_volume(dcr, VolName) == NULL) {
412 Mmsg2(dcr->jcr->errmsg, _("Could not reserve volume %s on %s\n"),
413 dev->VolHdr.VolumeName, dev->print_name());
416 dev = dcr->dev; /* may have changed in reserve_volume */
418 dev->clear_append(); /* remove append since this is PRE_LABEL */
424 dev->clear_append(); /* remove append since this is PRE_LABEL */
429 * Write a volume label. This is ONLY called if we have a valid Bacula
430 * label of type PRE_LABEL;
431 * Returns: true if OK
432 * false if unable to write it
434 bool rewrite_volume_label(DCR *dcr, bool recycle)
436 DEVICE *dev = dcr->dev;
439 if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
440 Jmsg3(jcr, M_WARNING, 0, _("Open device %s Volume \"%s\" failed: ERR=%s\n"),
441 dev->print_name(), dcr->VolumeName, dev->bstrerror());
444 Dmsg2(190, "set append found freshly labeled volume. fd=%d dev=%x\n", dev->fd(), dev);
445 dev->VolHdr.LabelType = VOL_LABEL; /* set Volume label */
447 if (!write_volume_label_to_block(dcr)) {
448 Dmsg0(200, "Error from write volume label.\n");
451 Dmsg1(150, "wrote vol label to block. Vol=%s\n", dcr->VolumeName);
453 dev->VolCatInfo.VolCatBytes = 0; /* reset byte count */
456 * If we are not dealing with a streaming device,
457 * write the block now to ensure we have write permission.
458 * It is better to find out now rather than later.
459 * We do not write the block now if this is an ANSI label. This
460 * avoids re-writing the ANSI label, which we do not want to do.
462 if (!dev->has_cap(CAP_STREAM)) {
463 if (!dev->rewind(dcr)) {
464 Jmsg2(jcr, M_FATAL, 0, _("Rewind error on device %s: ERR=%s\n"),
465 dev->print_name(), dev->print_errmsg());
469 Dmsg1(150, "Doing recycle. Vol=%s\n", dcr->VolumeName);
470 // volume_unused(dcr); /* mark volume unused */
471 if (!dev->truncate(dcr)) {
472 Jmsg2(jcr, M_FATAL, 0, _("Truncate error on device %s: ERR=%s\n"),
473 dev->print_name(), dev->print_errmsg());
476 if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
477 Jmsg2(jcr, M_FATAL, 0,
478 _("Failed to re-open DVD after truncate on device %s: ERR=%s\n"),
479 dev->print_name(), dev->print_errmsg());
485 * If we have already detected an ANSI label, re-read it
486 * to skip past it. Otherwise, we write a new one if
489 if (dev->label_type != B_BACULA_LABEL) {
490 if (read_ansi_ibm_label(dcr) != VOL_OK) {
494 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, dev->VolHdr.VolumeName)) {
498 /* Attempt write to check write permission */
499 Dmsg1(200, "Attempt to write to device fd=%d.\n", dev->fd());
500 if (!write_block_to_dev(dcr)) {
501 Jmsg2(jcr, M_ERROR, 0, _("Unable to write device %s: ERR=%s\n"),
502 dev->print_name(), dev->print_errmsg());
503 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.VolCatErrors = 0;
512 dev->VolCatInfo.VolCatBlocks = 0;
513 dev->VolCatInfo.VolCatRBytes = 0;
515 dev->VolCatInfo.VolCatMounts++;
516 dev->VolCatInfo.VolCatRecycles++;
518 dev->VolCatInfo.VolCatMounts = 1;
519 dev->VolCatInfo.VolCatRecycles = 0;
520 dev->VolCatInfo.VolCatWrites = 1;
521 dev->VolCatInfo.VolCatReads = 1;
523 Dmsg1(150, "dir_update_vol_info. Set Append vol=%s\n", dcr->VolumeName);
524 bstrncpy(dev->VolCatInfo.VolCatStatus, "Append", sizeof(dev->VolCatInfo.VolCatStatus));
525 bstrncpy(dev->VolCatInfo.VolCatName, dcr->VolumeName, sizeof(dev->VolCatInfo.VolCatName));
526 if (!dir_update_volume_info(dcr, true, 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 Dmsg1(150, "OK from rewrite vol label. Vol=%s\n", dcr->VolumeName);
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;
559 /* Serialize the label into the device record. */
561 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
562 ser_begin(rec->data, SER_LENGTH_Volume_Label);
563 ser_string(dev->VolHdr.Id);
565 ser_uint32(dev->VolHdr.VerNum);
567 if (dev->VolHdr.VerNum >= 11) {
568 ser_btime(dev->VolHdr.label_btime);
569 dev->VolHdr.write_btime = get_current_btime();
570 ser_btime(dev->VolHdr.write_btime);
571 dev->VolHdr.write_date = 0;
572 dev->VolHdr.write_time = 0;
574 /* OLD WAY DEPRECATED */
575 ser_float64(dev->VolHdr.label_date);
576 ser_float64(dev->VolHdr.label_time);
577 get_current_time(&dt);
578 dev->VolHdr.write_date = dt.julian_day_number;
579 dev->VolHdr.write_time = dt.julian_day_fraction;
581 ser_float64(dev->VolHdr.write_date); /* 0 if VerNum >= 11 */
582 ser_float64(dev->VolHdr.write_time); /* 0 if VerNum >= 11 */
584 ser_string(dev->VolHdr.VolumeName);
585 ser_string(dev->VolHdr.PrevVolumeName);
586 ser_string(dev->VolHdr.PoolName);
587 ser_string(dev->VolHdr.PoolType);
588 ser_string(dev->VolHdr.MediaType);
590 ser_string(dev->VolHdr.HostName);
591 ser_string(dev->VolHdr.LabelProg);
592 ser_string(dev->VolHdr.ProgVersion);
593 ser_string(dev->VolHdr.ProgDate);
595 ser_end(rec->data, SER_LENGTH_Volume_Label);
596 bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName));
597 rec->data_len = ser_length(rec->data);
598 rec->FileIndex = dev->VolHdr.LabelType;
599 rec->VolSessionId = jcr->VolSessionId;
600 rec->VolSessionTime = jcr->VolSessionTime;
601 rec->Stream = jcr->NumWriteVolumes;
602 Dmsg2(150, "Created Vol label rec: FI=%s len=%d\n", FI_to_ascii(buf, rec->FileIndex),
608 * Create a volume label in memory
610 void create_volume_label(DEVICE *dev, const char *VolName,
611 const char *PoolName, bool dvdnow)
613 DEVRES *device = (DEVRES *)dev->device;
615 Dmsg0(130, "Start create_volume_label()\n");
619 dev->clear_volhdr(); /* clear any old volume info */
621 bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
622 dev->VolHdr.VerNum = BaculaTapeVersion;
623 if (dev->is_dvd() && dvdnow) {
624 /* We do not want to re-label a DVD so write VOL_LABEL now */
625 dev->VolHdr.LabelType = VOL_LABEL;
627 dev->VolHdr.LabelType = PRE_LABEL; /* Mark tape as unused */
629 bstrncpy(dev->VolHdr.VolumeName, VolName, sizeof(dev->VolHdr.VolumeName));
630 bstrncpy(dev->VolHdr.PoolName, PoolName, sizeof(dev->VolHdr.PoolName));
631 bstrncpy(dev->VolHdr.MediaType, device->media_type, sizeof(dev->VolHdr.MediaType));
633 bstrncpy(dev->VolHdr.PoolType, "Backup", sizeof(dev->VolHdr.PoolType));
635 dev->VolHdr.label_btime = get_current_btime();
636 dev->VolHdr.label_date = 0;
637 dev->VolHdr.label_time = 0;
639 if (gethostname(dev->VolHdr.HostName, sizeof(dev->VolHdr.HostName)) != 0) {
640 dev->VolHdr.HostName[0] = 0;
642 bstrncpy(dev->VolHdr.LabelProg, my_name, sizeof(dev->VolHdr.LabelProg));
643 sprintf(dev->VolHdr.ProgVersion, "Ver. %s %s", VERSION, BDATE);
644 sprintf(dev->VolHdr.ProgDate, "Build %s %s", __DATE__, __TIME__);
645 dev->set_labeled(); /* set has Bacula label */
646 if (debug_level >= 90) {
647 dump_volume_label(dev);
652 * Create session label
653 * The pool memory must be released by the calling program
655 void create_session_label(DCR *dcr, DEV_RECORD *rec, int label)
660 rec->VolSessionId = jcr->VolSessionId;
661 rec->VolSessionTime = jcr->VolSessionTime;
662 rec->Stream = jcr->JobId;
664 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
665 ser_begin(rec->data, SER_LENGTH_Session_Label);
666 ser_string(BaculaId);
667 ser_uint32(BaculaTapeVersion);
669 ser_uint32(jcr->JobId);
671 /* Changed in VerNum 11 */
672 ser_btime(get_current_btime());
675 ser_string(dcr->pool_name);
676 ser_string(dcr->pool_type);
677 ser_string(jcr->job_name); /* base Job name */
678 ser_string(jcr->client_name);
680 /* Added in VerNum 10 */
681 ser_string(jcr->Job); /* Unique name of this Job */
682 ser_string(jcr->fileset_name);
683 ser_uint32(jcr->JobType);
684 ser_uint32(jcr->JobLevel);
685 /* Added in VerNum 11 */
686 ser_string(jcr->fileset_md5);
688 if (label == EOS_LABEL) {
689 ser_uint32(jcr->JobFiles);
690 ser_uint64(jcr->JobBytes);
691 ser_uint32(dcr->StartBlock);
692 ser_uint32(dcr->EndBlock);
693 ser_uint32(dcr->StartFile);
694 ser_uint32(dcr->EndFile);
695 ser_uint32(jcr->JobErrors);
697 /* Added in VerNum 11 */
698 ser_uint32(jcr->JobStatus);
700 ser_end(rec->data, SER_LENGTH_Session_Label);
701 rec->data_len = ser_length(rec->data);
704 /* Write session label
705 * Returns: false on failure
708 bool write_session_label(DCR *dcr, int label)
711 DEVICE *dev = dcr->dev;
713 DEV_BLOCK *block = dcr->block;
714 char buf1[100], buf2[100];
717 Dmsg1(130, "session_label record=%x\n", rec);
720 set_start_vol_position(dcr);
723 if (dev->is_tape()) {
724 dcr->EndBlock = dev->EndBlock;
725 dcr->EndFile = dev->EndFile;
727 dcr->EndBlock = (uint32_t)dev->file_addr;
728 dcr->EndFile = (uint32_t)(dev->file_addr >> 32);
732 Jmsg1(jcr, M_ABORT, 0, _("Bad Volume session label = %d\n"), label);
735 create_session_label(dcr, rec, label);
736 rec->FileIndex = label;
739 * We guarantee that the session record can totally fit
740 * into a block. If not, write the block, and put it in
741 * the next block. Having the sesssion record totally in
742 * one block makes reading them much easier (no need to
743 * read the next block).
745 if (!can_write_record_to_block(block, rec)) {
746 Dmsg0(150, "Cannot write session label to block.\n");
747 if (!write_block_to_device(dcr)) {
748 Dmsg0(130, "Got session label write_block_to_dev error.\n");
753 if (!write_record_to_block(block, rec)) {
758 Dmsg6(150, "Write sesson_label record JobId=%d FI=%s SessId=%d Strm=%s len=%d "
759 "remainder=%d\n", jcr->JobId,
760 FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
761 stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
765 Dmsg2(150, "Leave write_session_label Block=%ud File=%ud\n",
766 dev->get_block_num(), dev->get_file());
770 /* unser_volume_label
772 * Unserialize the Bacula Volume label into the device Volume_Label
775 * Assumes that the record is already read.
777 * Returns: false on error
781 bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec)
784 char buf1[100], buf2[100];
786 if (rec->FileIndex != VOL_LABEL && rec->FileIndex != PRE_LABEL) {
787 Mmsg3(dev->errmsg, _("Expecting Volume Label, got FI=%s Stream=%s len=%d\n"),
788 FI_to_ascii(buf1, rec->FileIndex),
789 stream_to_ascii(buf2, rec->Stream, rec->FileIndex),
796 dev->VolHdr.LabelType = rec->FileIndex;
797 dev->VolHdr.LabelSize = rec->data_len;
800 /* Unserialize the record into the Volume Header */
801 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
802 ser_begin(rec->data, SER_LENGTH_Volume_Label);
803 unser_string(dev->VolHdr.Id);
804 unser_uint32(dev->VolHdr.VerNum);
806 if (dev->VolHdr.VerNum >= 11) {
807 unser_btime(dev->VolHdr.label_btime);
808 unser_btime(dev->VolHdr.write_btime);
809 } else { /* old way */
810 unser_float64(dev->VolHdr.label_date);
811 unser_float64(dev->VolHdr.label_time);
813 unser_float64(dev->VolHdr.write_date); /* Unused with VerNum >= 11 */
814 unser_float64(dev->VolHdr.write_time); /* Unused with VerNum >= 11 */
816 unser_string(dev->VolHdr.VolumeName);
817 unser_string(dev->VolHdr.PrevVolumeName);
818 unser_string(dev->VolHdr.PoolName);
819 unser_string(dev->VolHdr.PoolType);
820 unser_string(dev->VolHdr.MediaType);
822 unser_string(dev->VolHdr.HostName);
823 unser_string(dev->VolHdr.LabelProg);
824 unser_string(dev->VolHdr.ProgVersion);
825 unser_string(dev->VolHdr.ProgDate);
827 ser_end(rec->data, SER_LENGTH_Volume_Label);
828 Dmsg0(190, "unser_vol_label\n");
829 if (debug_level >= 190) {
830 dump_volume_label(dev);
836 bool unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec)
840 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
841 unser_begin(rec->data, SER_LENGTH_Session_Label);
842 unser_string(label->Id);
843 unser_uint32(label->VerNum);
844 unser_uint32(label->JobId);
845 if (label->VerNum >= 11) {
846 unser_btime(label->write_btime);
848 unser_float64(label->write_date);
850 unser_float64(label->write_time);
851 unser_string(label->PoolName);
852 unser_string(label->PoolType);
853 unser_string(label->JobName);
854 unser_string(label->ClientName);
855 if (label->VerNum >= 10) {
856 unser_string(label->Job); /* Unique name of this Job */
857 unser_string(label->FileSetName);
858 unser_uint32(label->JobType);
859 unser_uint32(label->JobLevel);
861 if (label->VerNum >= 11) {
862 unser_string(label->FileSetMD5);
864 label->FileSetMD5[0] = 0;
866 if (rec->FileIndex == EOS_LABEL) {
867 unser_uint32(label->JobFiles);
868 unser_uint64(label->JobBytes);
869 unser_uint32(label->StartBlock);
870 unser_uint32(label->EndBlock);
871 unser_uint32(label->StartFile);
872 unser_uint32(label->EndFile);
873 unser_uint32(label->JobErrors);
874 if (label->VerNum >= 11) {
875 unser_uint32(label->JobStatus);
877 label->JobStatus = JS_Terminated; /* kludge */
883 void dump_volume_label(DEVICE *dev)
885 int dbl = debug_level;
887 const char *LabelType;
894 switch (dev->VolHdr.LabelType) {
896 LabelType = "PRE_LABEL";
899 LabelType = "VOL_LABEL";
902 LabelType = "EOM_LABEL";
905 LabelType = "SOS_LABEL";
908 LabelType = "EOS_LABEL";
914 sprintf(buf, _("Unknown %d"), dev->VolHdr.LabelType);
918 Pmsg11(-1, _("\nVolume Label:\n"
931 dev->VolHdr.Id, dev->VolHdr.VerNum,
932 dev->VolHdr.VolumeName, dev->VolHdr.PrevVolumeName,
933 File, LabelType, dev->VolHdr.LabelSize,
934 dev->VolHdr.PoolName, dev->VolHdr.MediaType,
935 dev->VolHdr.PoolType, dev->VolHdr.HostName);
937 if (dev->VolHdr.VerNum >= 11) {
939 bstrftime(dt, sizeof(dt), btime_to_unix(dev->VolHdr.label_btime));
940 Pmsg1(-1, _("Date label written: %s\n"), dt);
942 dt.julian_day_number = dev->VolHdr.label_date;
943 dt.julian_day_fraction = dev->VolHdr.label_time;
946 _("Date label written: %04d-%02d-%02d at %02d:%02d\n"),
947 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
955 static void dump_session_label(DEV_RECORD *rec, const char *type)
961 char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], ec6[30], ec7[30];
963 unser_session_label(&label, rec);
966 Pmsg7(-1, _("\n%s Record:\n"
973 ""), type, label.JobId, label.VerNum,
974 label.PoolName, label.PoolType,
975 label.JobName, label.ClientName);
977 if (label.VerNum >= 10) {
979 "Job (unique name) : %s\n"
983 ""), label.Job, label.FileSetName, label.JobType, label.JobLevel);
986 if (rec->FileIndex == EOS_LABEL) {
997 edit_uint64_with_commas(label.JobFiles, ec1),
998 edit_uint64_with_commas(label.JobBytes, ec2),
999 edit_uint64_with_commas(label.StartBlock, ec3),
1000 edit_uint64_with_commas(label.EndBlock, ec4),
1001 edit_uint64_with_commas(label.StartFile, ec5),
1002 edit_uint64_with_commas(label.EndFile, ec6),
1003 edit_uint64_with_commas(label.JobErrors, ec7),
1006 if (label.VerNum >= 11) {
1008 bstrftime(dt, sizeof(dt), btime_to_unix(label.write_btime));
1009 Pmsg1(-1, _("Date written : %s\n"), dt);
1011 dt.julian_day_number = label.write_date;
1012 dt.julian_day_fraction = label.write_time;
1013 tm_decode(&dt, &tm);
1014 Pmsg5(-1, _("Date written : %04d-%02d-%02d at %02d:%02d\n"),
1015 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
1021 void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose)
1026 if (rec->FileIndex == 0 && rec->VolSessionId == 0 && rec->VolSessionTime == 0) {
1031 switch (rec->FileIndex) {
1033 type = _("Fresh Volume");
1039 type = _("Begin Job Session");
1042 type = _("End Job Session");
1045 type = _("End of Media");
1048 type = _("End of Tape");
1051 type = _("Unknown");
1055 switch (rec->FileIndex) {
1058 unser_volume_label(dev, rec);
1059 dump_volume_label(dev);
1062 dump_session_label(rec, type);
1065 dump_session_label(rec, type);
1068 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1069 type, dev->file, dev->block_num, rec->VolSessionId,
1070 rec->VolSessionTime, rec->Stream, rec->data_len);
1073 Pmsg0(-1, _("End of physical tape.\n"));
1076 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1077 type, dev->file, dev->block_num, rec->VolSessionId,
1078 rec->VolSessionTime, rec->Stream, rec->data_len);
1082 SESSION_LABEL label;
1084 switch (rec->FileIndex) {
1086 unser_session_label(&label, rec);
1087 bstrftimes(dt, sizeof(dt), btime_to_unix(label.write_btime));
1088 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1089 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1090 Pmsg4(-1, _(" Job=%s Date=%s Level=%c Type=%c\n"),
1091 label.Job, dt, label.JobLevel, label.JobType);
1094 char ed1[30], ed2[30];
1095 unser_session_label(&label, rec);
1096 bstrftimes(dt, sizeof(dt), btime_to_unix(label.write_btime));
1097 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1098 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1099 Pmsg7(-1, _(" Date=%s Level=%c Type=%c Files=%s Bytes=%s Errors=%d Status=%c\n"),
1100 dt, label.JobLevel, label.JobType,
1101 edit_uint64_with_commas(label.JobFiles, ed1),
1102 edit_uint64_with_commas(label.JobBytes, ed2),
1103 label.JobErrors, (char)label.JobStatus);
1109 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1110 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime,
1111 rec->Stream, rec->data_len);