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);
224 // dev = dcr->dev; /* may have changed in reserve volume */
226 /* Compare Volume Names */
227 Dmsg2(130, "Compare Vol names: VolName=%s hdr=%s\n", VolName?VolName:"*", dev->VolHdr.VolumeName);
228 if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolumeName, VolName) != 0) {
229 Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
230 dev->print_name(), VolName, dev->VolHdr.VolumeName);
231 Dmsg1(130, "%s", jcr->errmsg);
233 * Cancel Job if too many label errors
234 * => we are in a loop
236 if (!dev->poll && jcr->label_errors++ > 100) {
237 Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
239 Dmsg0(150, "return VOL_NAME_ERROR\n");
240 stat = VOL_NAME_ERROR;
241 volume_unused(dcr); /* mark volume "released" */
244 Dmsg1(130, "Copy vol_name=%s\n", dev->VolHdr.VolumeName);
246 if (debug_level >= 10) {
247 dump_volume_label(dev);
249 Dmsg0(130, "Leave read_volume_label() VOL_OK\n");
250 /* If we are a streaming device, we only get one chance to read */
251 if (!dev->has_cap(CAP_STREAM)) {
253 if (have_ansi_label) {
254 stat = read_ansi_ibm_label(dcr);
255 /* If we want a label and didn't find it, return error */
256 if (stat != VOL_OK) {
257 volume_unused(dcr); /* mark volume "released" */
268 Dmsg1(150, "return %d\n", stat);
273 * Put a volume label into the block
275 * Returns: false on failure
278 bool write_volume_label_to_block(DCR *dcr)
281 DEVICE *dev = dcr->dev;
283 DEV_BLOCK *block = dcr->block;
285 Dmsg0(130, "write Label in write_volume_label_to_block()\n");
286 memset(&rec, 0, sizeof(rec));
287 rec.data = get_memory(SER_LENGTH_Volume_Label);
288 empty_block(block); /* Volume label always at beginning */
290 create_volume_label_record(dcr, &rec);
292 block->BlockNumber = 0;
293 if (!write_record_to_block(block, &rec)) {
294 free_pool_memory(rec.data);
295 Jmsg1(jcr, M_FATAL, 0, _("Cannot write Volume label to block for device %s\n"),
299 Dmsg1(130, "Wrote label of %d bytes to block\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");
452 dev->VolCatInfo.VolCatBytes = 0; /* reset byte count */
455 * If we are not dealing with a streaming device,
456 * write the block now to ensure we have write permission.
457 * It is better to find out now rather than later.
458 * We do not write the block now if this is an ANSI label. This
459 * avoids re-writing the ANSI label, which we do not want to do.
461 if (!dev->has_cap(CAP_STREAM)) {
462 if (!dev->rewind(dcr)) {
463 Jmsg2(jcr, M_FATAL, 0, _("Rewind error on device %s: ERR=%s\n"),
464 dev->print_name(), dev->print_errmsg());
468 // volume_unused(dcr); /* mark volume unused */
469 if (!dev->truncate(dcr)) {
470 Jmsg2(jcr, M_FATAL, 0, _("Truncate error on device %s: ERR=%s\n"),
471 dev->print_name(), dev->print_errmsg());
474 if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
475 Jmsg2(jcr, M_FATAL, 0,
476 _("Failed to re-open DVD after truncate on device %s: ERR=%s\n"),
477 dev->print_name(), dev->print_errmsg());
483 * If we have already detected an ANSI label, re-read it
484 * to skip past it. Otherwise, we write a new one if
487 if (dev->label_type != B_BACULA_LABEL) {
488 if (read_ansi_ibm_label(dcr) != VOL_OK) {
492 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, dev->VolHdr.VolumeName)) {
496 /* Attempt write to check write permission */
497 Dmsg1(200, "Attempt to write to device fd=%d.\n", dev->fd());
498 if (!write_block_to_dev(dcr)) {
499 Jmsg2(jcr, M_ERROR, 0, _("Unable to write device %s: ERR=%s\n"),
500 dev->print_name(), dev->print_errmsg());
501 Dmsg0(200, "===ERROR write block to dev\n");
506 /* Set or reset Volume statistics */
507 dev->VolCatInfo.VolCatJobs = 0;
508 dev->VolCatInfo.VolCatFiles = 0;
509 dev->VolCatInfo.VolCatErrors = 0;
510 dev->VolCatInfo.VolCatBlocks = 0;
511 dev->VolCatInfo.VolCatRBytes = 0;
513 dev->VolCatInfo.VolCatMounts++;
514 dev->VolCatInfo.VolCatRecycles++;
516 dev->VolCatInfo.VolCatMounts = 1;
517 dev->VolCatInfo.VolCatRecycles = 0;
518 dev->VolCatInfo.VolCatWrites = 1;
519 dev->VolCatInfo.VolCatReads = 1;
521 Dmsg0(150, "dir_update_vol_info. Set Append\n");
522 bstrncpy(dev->VolCatInfo.VolCatStatus, "Append", sizeof(dev->VolCatInfo.VolCatStatus));
523 if (!dir_update_volume_info(dcr, true, true)) { /* indicate doing relabel */
527 Jmsg(jcr, M_INFO, 0, _("Recycled volume \"%s\" on device %s, all previous data lost.\n"),
528 dcr->VolumeName, dev->print_name());
530 Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume \"%s\" on device %s\n"),
531 dcr->VolumeName, dev->print_name());
534 * End writing real Volume label (from pre-labeled tape), or recycling
537 Dmsg0(200, "OK from rewrite vol label.\n");
543 * create_volume_label_record
544 * Serialize label (from dev->VolHdr structure) into device record.
545 * Assumes that the dev->VolHdr structure is properly
548 static void create_volume_label_record(DCR *dcr, DEV_RECORD *rec)
552 DEVICE *dev = dcr->dev;
556 /* Serialize the label into the device record. */
558 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
559 ser_begin(rec->data, SER_LENGTH_Volume_Label);
560 ser_string(dev->VolHdr.Id);
562 ser_uint32(dev->VolHdr.VerNum);
564 if (dev->VolHdr.VerNum >= 11) {
565 ser_btime(dev->VolHdr.label_btime);
566 dev->VolHdr.write_btime = get_current_btime();
567 ser_btime(dev->VolHdr.write_btime);
568 dev->VolHdr.write_date = 0;
569 dev->VolHdr.write_time = 0;
571 /* OLD WAY DEPRECATED */
572 ser_float64(dev->VolHdr.label_date);
573 ser_float64(dev->VolHdr.label_time);
574 get_current_time(&dt);
575 dev->VolHdr.write_date = dt.julian_day_number;
576 dev->VolHdr.write_time = dt.julian_day_fraction;
578 ser_float64(dev->VolHdr.write_date); /* 0 if VerNum >= 11 */
579 ser_float64(dev->VolHdr.write_time); /* 0 if VerNum >= 11 */
581 ser_string(dev->VolHdr.VolumeName);
582 ser_string(dev->VolHdr.PrevVolumeName);
583 ser_string(dev->VolHdr.PoolName);
584 ser_string(dev->VolHdr.PoolType);
585 ser_string(dev->VolHdr.MediaType);
587 ser_string(dev->VolHdr.HostName);
588 ser_string(dev->VolHdr.LabelProg);
589 ser_string(dev->VolHdr.ProgVersion);
590 ser_string(dev->VolHdr.ProgDate);
592 ser_end(rec->data, SER_LENGTH_Volume_Label);
593 rec->data_len = ser_length(rec->data);
594 rec->FileIndex = dev->VolHdr.LabelType;
595 rec->VolSessionId = jcr->VolSessionId;
596 rec->VolSessionTime = jcr->VolSessionTime;
597 rec->Stream = jcr->NumWriteVolumes;
598 Dmsg2(150, "Created Vol label rec: FI=%s len=%d\n", FI_to_ascii(buf, rec->FileIndex),
604 * Create a volume label in memory
606 void create_volume_label(DEVICE *dev, const char *VolName,
607 const char *PoolName, bool dvdnow)
609 DEVRES *device = (DEVRES *)dev->device;
611 Dmsg0(130, "Start create_volume_label()\n");
615 dev->clear_volhdr(); /* clear any old volume info */
617 bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
618 dev->VolHdr.VerNum = BaculaTapeVersion;
619 if (dev->is_dvd() && dvdnow) {
620 /* We do not want to re-label a DVD so write VOL_LABEL now */
621 dev->VolHdr.LabelType = VOL_LABEL;
623 dev->VolHdr.LabelType = PRE_LABEL; /* Mark tape as unused */
625 bstrncpy(dev->VolHdr.VolumeName, VolName, sizeof(dev->VolHdr.VolumeName));
626 bstrncpy(dev->VolHdr.PoolName, PoolName, sizeof(dev->VolHdr.PoolName));
627 bstrncpy(dev->VolHdr.MediaType, device->media_type, sizeof(dev->VolHdr.MediaType));
629 bstrncpy(dev->VolHdr.PoolType, "Backup", sizeof(dev->VolHdr.PoolType));
631 dev->VolHdr.label_btime = get_current_btime();
632 dev->VolHdr.label_date = 0;
633 dev->VolHdr.label_time = 0;
635 if (gethostname(dev->VolHdr.HostName, sizeof(dev->VolHdr.HostName)) != 0) {
636 dev->VolHdr.HostName[0] = 0;
638 bstrncpy(dev->VolHdr.LabelProg, my_name, sizeof(dev->VolHdr.LabelProg));
639 sprintf(dev->VolHdr.ProgVersion, "Ver. %s %s", VERSION, BDATE);
640 sprintf(dev->VolHdr.ProgDate, "Build %s %s", __DATE__, __TIME__);
641 dev->set_labeled(); /* set has Bacula label */
642 if (debug_level >= 90) {
643 dump_volume_label(dev);
648 * Create session label
649 * The pool memory must be released by the calling program
651 void create_session_label(DCR *dcr, DEV_RECORD *rec, int label)
656 rec->VolSessionId = jcr->VolSessionId;
657 rec->VolSessionTime = jcr->VolSessionTime;
658 rec->Stream = jcr->JobId;
660 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
661 ser_begin(rec->data, SER_LENGTH_Session_Label);
662 ser_string(BaculaId);
663 ser_uint32(BaculaTapeVersion);
665 ser_uint32(jcr->JobId);
667 /* Changed in VerNum 11 */
668 ser_btime(get_current_btime());
671 ser_string(dcr->pool_name);
672 ser_string(dcr->pool_type);
673 ser_string(jcr->job_name); /* base Job name */
674 ser_string(jcr->client_name);
676 /* Added in VerNum 10 */
677 ser_string(jcr->Job); /* Unique name of this Job */
678 ser_string(jcr->fileset_name);
679 ser_uint32(jcr->JobType);
680 ser_uint32(jcr->JobLevel);
681 /* Added in VerNum 11 */
682 ser_string(jcr->fileset_md5);
684 if (label == EOS_LABEL) {
685 ser_uint32(jcr->JobFiles);
686 ser_uint64(jcr->JobBytes);
687 ser_uint32(dcr->StartBlock);
688 ser_uint32(dcr->EndBlock);
689 ser_uint32(dcr->StartFile);
690 ser_uint32(dcr->EndFile);
691 ser_uint32(jcr->JobErrors);
693 /* Added in VerNum 11 */
694 ser_uint32(jcr->JobStatus);
696 ser_end(rec->data, SER_LENGTH_Session_Label);
697 rec->data_len = ser_length(rec->data);
700 /* Write session label
701 * Returns: false on failure
704 bool write_session_label(DCR *dcr, int label)
707 DEVICE *dev = dcr->dev;
709 DEV_BLOCK *block = dcr->block;
710 char buf1[100], buf2[100];
713 Dmsg1(130, "session_label record=%x\n", rec);
716 set_start_vol_position(dcr);
719 if (dev->is_tape()) {
720 dcr->EndBlock = dev->EndBlock;
721 dcr->EndFile = dev->EndFile;
723 dcr->EndBlock = (uint32_t)dev->file_addr;
724 dcr->EndFile = (uint32_t)(dev->file_addr >> 32);
728 Jmsg1(jcr, M_ABORT, 0, _("Bad Volume session label = %d\n"), label);
731 create_session_label(dcr, rec, label);
732 rec->FileIndex = label;
735 * We guarantee that the session record can totally fit
736 * into a block. If not, write the block, and put it in
737 * the next block. Having the sesssion record totally in
738 * one block makes reading them much easier (no need to
739 * read the next block).
741 if (!can_write_record_to_block(block, rec)) {
742 Dmsg0(150, "Cannot write session label to block.\n");
743 if (!write_block_to_device(dcr)) {
744 Dmsg0(130, "Got session label write_block_to_dev error.\n");
749 if (!write_record_to_block(block, rec)) {
754 Dmsg6(150, "Write sesson_label record JobId=%d FI=%s SessId=%d Strm=%s len=%d "
755 "remainder=%d\n", jcr->JobId,
756 FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
757 stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
761 Dmsg2(150, "Leave write_session_label Block=%ud File=%ud\n",
762 dev->get_block_num(), dev->get_file());
766 /* unser_volume_label
768 * Unserialize the Bacula Volume label into the device Volume_Label
771 * Assumes that the record is already read.
773 * Returns: false on error
777 bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec)
780 char buf1[100], buf2[100];
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(buf1, rec->FileIndex),
785 stream_to_ascii(buf2, 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(190, "unser_vol_label\n");
825 if (debug_level >= 190) {
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);
1010 Pmsg5(-1, _("Date written : %04d-%02d-%02d at %02d:%02d\n"),
1011 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
1017 void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose)
1022 if (rec->FileIndex == 0 && rec->VolSessionId == 0 && rec->VolSessionTime == 0) {
1027 switch (rec->FileIndex) {
1029 type = _("Fresh Volume");
1035 type = _("Begin Job Session");
1038 type = _("End Job Session");
1041 type = _("End of Media");
1044 type = _("End of Tape");
1047 type = _("Unknown");
1051 switch (rec->FileIndex) {
1054 unser_volume_label(dev, rec);
1055 dump_volume_label(dev);
1058 dump_session_label(rec, type);
1061 dump_session_label(rec, type);
1064 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1065 type, dev->file, dev->block_num, rec->VolSessionId,
1066 rec->VolSessionTime, rec->Stream, rec->data_len);
1069 Pmsg0(-1, _("End of physical tape.\n"));
1072 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1073 type, dev->file, dev->block_num, rec->VolSessionId,
1074 rec->VolSessionTime, rec->Stream, rec->data_len);
1078 SESSION_LABEL label;
1080 switch (rec->FileIndex) {
1082 unser_session_label(&label, rec);
1083 bstrftimes(dt, sizeof(dt), btime_to_unix(label.write_btime));
1084 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1085 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1086 Pmsg4(-1, _(" Job=%s Date=%s Level=%c Type=%c\n"),
1087 label.Job, dt, label.JobLevel, label.JobType);
1090 char ed1[30], ed2[30];
1091 unser_session_label(&label, rec);
1092 bstrftimes(dt, sizeof(dt), btime_to_unix(label.write_btime));
1093 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1094 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1095 Pmsg7(-1, _(" Date=%s Level=%c Type=%c Files=%s Bytes=%s Errors=%d Status=%c\n"),
1096 dt, label.JobLevel, label.JobType,
1097 edit_uint64_with_commas(label.JobFiles, ed1),
1098 edit_uint64_with_commas(label.JobBytes, ed2),
1099 label.JobErrors, (char)label.JobStatus);
1105 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1106 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime,
1107 rec->Stream, rec->data_len);