1 /*
2 Bacula(R) - The Network Backup Solution
3
4 Copyright (C) 2000-2020 Kern Sibbald
5
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
8
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
13
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
16
17 Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20 *
21 * label.c Bacula routines to handle labels
22 *
23 * Kern Sibbald, MM
24 *
25 */
26
27 #include "bacula.h" /* pull in global headers */
28 #include "stored.h" /* pull in Storage Deamon headers */
29
30 static const int dbglvl = 100;
31
32 /* Forward referenced functions */
33 static void create_volume_label_record(DCR *dcr, DEVICE *dev, DEV_RECORD *rec, bool adata);
34
35 /*
36 * Read the volume label
37 *
38 * If dcr->VolumeName == NULL, we accept any Bacula Volume
39 * If dcr->VolumeName[0] == 0, we accept any Bacula Volume
40 * otherwise dcr->VolumeName must match the Volume.
41 *
42 * If VolName given, ensure that it matches
43 *
44 * Returns VOL_ code as defined in record.h
45 * VOL_NOT_READ
46 * VOL_OK good label found
47 * VOL_NO_LABEL volume not labeled
48 * VOL_IO_ERROR I/O error reading tape
49 * VOL_NAME_ERROR label has wrong name
50 * VOL_CREATE_ERROR Error creating label
51 * VOL_VERSION_ERROR label has wrong version
52 * VOL_LABEL_ERROR bad label type
53 * VOL_NO_MEDIA no media in drive
54 * VOL_TYPE_ERROR aligned/non-aligned/dedup error
55 *
56 * The dcr block is emptied on return, and the Volume is
57 * rewound.
58 *
59 * Handle both the ameta and adata volumes.
60 */
read_dev_volume_label(DCR * dcr)61 int DEVICE::read_dev_volume_label(DCR *dcr)
62 {
63 JCR *jcr = dcr->jcr;
64 char *VolName = dcr->VolumeName;
65 DEV_RECORD *record;
66 bool ok = false;
67 DEV_BLOCK *block = dcr->block;
68 int stat;
69 bool want_ansi_label;
70 bool have_ansi_label = false;
71
72 Enter(dbglvl);
73 Dmsg5(dbglvl, "Enter read_volume_label adata=%d res=%d device=%s vol=%s dev_Vol=%s\n",
74 block->adata, num_reserved(), print_name(), VolName,
75 VolHdr.VolumeName[0]?VolHdr.VolumeName:"*NULL*");
76
77
78 if (!is_open()) {
79 if (!open_device(dcr, OPEN_READ_ONLY)) {
80 Leave(dbglvl);
81 return VOL_IO_ERROR;
82 }
83 }
84
85 clear_labeled();
86 clear_append();
87 clear_read();
88 label_type = B_BACULA_LABEL;
89 set_worm(get_tape_worm(dcr));
90 Dmsg1(dbglvl, "==== worm=%d ====\n", is_worm());
91
92 if (!rewind(dcr)) {
93 Mmsg(jcr->errmsg, _("Couldn't rewind %s device %s: ERR=%s\n"),
94 print_type(), print_name(), print_errmsg());
95 Dmsg1(dbglvl, "return VOL_NO_MEDIA: %s", jcr->errmsg);
96 Leave(dbglvl);
97 return VOL_NO_MEDIA;
98 }
99 bstrncpy(VolHdr.Id, "**error**", sizeof(VolHdr.Id));
100
101 /* Read ANSI/IBM label if so requested */
102 want_ansi_label = dcr->VolCatInfo.LabelType != B_BACULA_LABEL ||
103 dcr->device->label_type != B_BACULA_LABEL;
104 if (want_ansi_label || has_cap(CAP_CHECKLABELS)) {
105 stat = read_ansi_ibm_label(dcr);
106 /* If we want a label and didn't find it, return error */
107 if (want_ansi_label && stat != VOL_OK) {
108 goto bail_out;
109 }
110 if (stat == VOL_NAME_ERROR || stat == VOL_LABEL_ERROR) {
111 Mmsg(jcr->errmsg, _("Wrong Volume mounted on %s device %s: Wanted %s have %s\n"),
112 print_type(), print_name(), VolName, VolHdr.VolumeName);
113 if (!poll && jcr->label_errors++ > 100) {
114 Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
115 }
116 goto bail_out;
117 }
118 if (stat != VOL_OK) { /* Not an ANSI/IBM label, so re-read */
119 rewind(dcr);
120 } else {
121 have_ansi_label = true;
122 }
123 }
124
125 /* Read the Bacula Volume label block */
126 record = new_record();
127 empty_block(block);
128
129 Dmsg0(130, "Big if statement in read_volume_label\n");
130 dcr->reading_label = true;
131 if (!dcr->read_block_from_dev(NO_BLOCK_NUMBER_CHECK)) {
132 Mmsg(jcr->errmsg, _("Read label block failed: requested Volume \"%s\" on %s device %s is not a Bacula "
133 "labeled Volume, because: ERR=%s"), NPRT(VolName),
134 print_type(), print_name(), print_errmsg());
135 Dmsg1(dbglvl, "%s", jcr->errmsg);
136 } else if (!read_record_from_block(dcr, record)) {
137 Mmsg(jcr->errmsg, _("Could not read Volume label from block.\n"));
138 Dmsg1(dbglvl, "%s", jcr->errmsg);
139 } else if (!unser_volume_label(this, record)) {
140 Mmsg(jcr->errmsg, _("Could not unserialize Volume label: ERR=%s\n"),
141 print_errmsg());
142 Dmsg1(dbglvl, "%s", jcr->errmsg);
143 } else if (strcmp(VolHdr.Id, BaculaId) != 0 &&
144 strcmp(VolHdr.Id, OldBaculaId) != 0 &&
145 strcmp(VolHdr.Id, BaculaMetaDataId) != 0 &&
146 strcmp(VolHdr.Id, BaculaAlignedDataId) != 0 &&
147 strcmp(VolHdr.Id, BaculaS3CloudId) != 0) {
148 Mmsg(jcr->errmsg, _("Volume Header Id bad: %s\n"), VolHdr.Id);
149 Dmsg1(dbglvl, "%s", jcr->errmsg);
150 } else {
151 ok = true;
152 Dmsg1(dbglvl, "VolHdr.Id OK: %s\n", VolHdr.Id);
153 }
154 dcr->reading_label = false;
155 free_record(record); /* finished reading Volume record */
156
157 if (!is_volume_to_unload()) {
158 clear_unload();
159 }
160
161 if (!ok) {
162 if (jcr->ignore_label_errors) {
163 set_labeled(); /* set has Bacula label */
164 if (jcr->errmsg[0]) {
165 Jmsg(jcr, M_ERROR, 0, "%s", jcr->errmsg);
166 }
167 empty_block(block);
168 Leave(dbglvl);
169 return VOL_OK;
170 }
171 Dmsg0(dbglvl, "No volume label - bailing out\n");
172 stat = VOL_NO_LABEL;
173 goto bail_out;
174 }
175
176 /* At this point, we have read the first Bacula block, and
177 * then read the Bacula Volume label. Now we need to
178 * make sure we have the right Volume.
179 */
180 if (VolHdr.VerNum != BaculaTapeVersion &&
181 VolHdr.VerNum != BaculaMetaDataVersion &&
182 VolHdr.VerNum != BaculaS3CloudVersion &&
183 VolHdr.VerNum != OldCompatibleBaculaTapeVersion1 &&
184 VolHdr.VerNum != OldCompatibleBaculaTapeVersion2) {
185 Mmsg(jcr->errmsg, _("Volume on %s device %s has wrong Bacula version. Wanted %d got %d\n"),
186 print_type(), print_name(), BaculaTapeVersion, VolHdr.VerNum);
187 Dmsg1(dbglvl, "VOL_VERSION_ERROR: %s", jcr->errmsg);
188 stat = VOL_VERSION_ERROR;
189 goto bail_out;
190 }
191 Dmsg1(dbglvl, "VolHdr.VerNum=%ld OK.\n", VolHdr.VerNum);
192
193 /* We are looking for either an unused Bacula tape (PRE_LABEL) or
194 * a Bacula volume label (VOL_LABEL)
195 */
196 if (VolHdr.LabelType != PRE_LABEL && VolHdr.LabelType != VOL_LABEL) {
197 Mmsg(jcr->errmsg, _("Volume on %s device %s has bad Bacula label type: %ld\n"),
198 print_type(), print_name(), VolHdr.LabelType);
199 Dmsg1(dbglvl, "%s", jcr->errmsg);
200 if (!poll && jcr->label_errors++ > 100) {
201 Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
202 }
203 Dmsg0(dbglvl, "return VOL_LABEL_ERROR\n");
204 stat = VOL_LABEL_ERROR;
205 goto bail_out;
206 }
207
208 set_labeled(); /* set has Bacula label */
209
210 /* Compare Volume Names */
211 Dmsg2(130, "Compare Vol names: VolName=%s hdr=%s\n", VolName?VolName:"*", VolHdr.VolumeName);
212 if (VolName && *VolName && *VolName != '*' && strcmp(VolHdr.VolumeName, VolName) != 0) {
213 Mmsg(jcr->errmsg, _("Wrong Volume mounted on %s device %s: Wanted %s have %s\n"),
214 print_type(), print_name(), VolName, VolHdr.VolumeName);
215 Dmsg1(dbglvl, "%s", jcr->errmsg);
216 /*
217 * Cancel Job if too many label errors
218 * => we are in a loop
219 */
220 if (!poll && jcr->label_errors++ > 100) {
221 Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
222 }
223 Dmsg0(dbglvl, "return VOL_NAME_ERROR\n");
224 stat = VOL_NAME_ERROR;
225 goto bail_out;
226 }
227
228 /* Compare VolType to Device Type */
229 switch (dev_type) {
230 case B_FILE_DEV:
231 if (strcmp(VolHdr.Id, BaculaId) != 0) {
232 Mmsg(jcr->errmsg, _("Wrong Volume Type. Wanted a File or Tape Volume %s on device %s, but got: %s\n"),
233 VolHdr.VolumeName, print_name(), VolHdr.Id);
234 stat = VOL_TYPE_ERROR;
235 goto bail_out;
236 }
237 break;
238 case B_ALIGNED_DEV:
239 case B_ADATA_DEV:
240 if (strcmp(VolHdr.Id, BaculaMetaDataId) != 0) {
241 Mmsg(jcr->errmsg, _("Wrong Volume Type. Wanted an Aligned Volume %s on device %s, but got: %s\n"),
242 VolHdr.VolumeName, print_name(), VolHdr.Id);
243 stat = VOL_TYPE_ERROR;
244 goto bail_out;
245 }
246 break;
247 case B_CLOUD_DEV:
248 if (strcmp(VolHdr.Id, BaculaS3CloudId) != 0) {
249 Mmsg(jcr->errmsg, _("Wrong Volume Type. Wanted a Cloud Volume %s on device %s, but got: %s\n"),
250 VolHdr.VolumeName, print_name(), VolHdr.Id);
251 stat = VOL_TYPE_ERROR;
252 goto bail_out;
253 }
254 default:
255 break;
256 }
257
258 if (chk_dbglvl(100)) {
259 dump_volume_label();
260 }
261 Dmsg0(dbglvl, "Leave read_volume_label() VOL_OK\n");
262 /* If we are a streaming device, we only get one chance to read */
263 if (!has_cap(CAP_STREAM)) {
264 rewind(dcr);
265 if (have_ansi_label) {
266 stat = read_ansi_ibm_label(dcr);
267 /* If we want a label and didn't find it, return error */
268 if (stat != VOL_OK) {
269 goto bail_out;
270 }
271 }
272 }
273
274 Dmsg1(100, "Call reserve_volume=%s\n", VolHdr.VolumeName);
275 if (reserve_volume(dcr, VolHdr.VolumeName) == NULL) {
276 if (!jcr->errmsg[0]) {
277 Mmsg3(jcr->errmsg, _("Could not reserve volume %s on %s device %s\n"),
278 VolHdr.VolumeName, print_type(), print_name());
279 }
280 Dmsg2(dbglvl, "Could not reserve volume %s on %s\n", VolHdr.VolumeName, print_name());
281 stat = VOL_NAME_ERROR;
282 goto bail_out;
283 }
284
285 if (dcr->is_writing()) {
286 empty_block(block);
287 }
288
289 Leave(dbglvl);
290 return VOL_OK;
291
292 bail_out:
293 empty_block(block);
294 rewind(dcr);
295 Dmsg2(dbglvl, "return stat=%d %s", stat, jcr->errmsg);
296 Leave(dbglvl);
297 return stat;
298 }
299
300
301 /*
302 * Create and put a volume label into the block
303 *
304 * Returns: false on failure
305 * true on success
306 *
307 * Handle both the ameta and adata volumes.
308 */
write_volume_label_to_block(DCR * dcr)309 bool DEVICE::write_volume_label_to_block(DCR *dcr)
310 {
311 DEVICE *dev;
312 DEV_BLOCK *block;
313 DEV_RECORD rec;
314 JCR *jcr = dcr->jcr;
315 bool ok = true;
316
317 Enter(100);
318 dev = dcr->dev;
319 block = dcr->block;
320 memset(&rec, 0, sizeof(rec));
321 rec.data = get_memory(SER_LENGTH_Volume_Label);
322 memset(rec.data, 0, SER_LENGTH_Volume_Label);
323 empty_block(block); /* Volume label always at beginning */
324
325 create_volume_label_record(dcr, dcr->dev, &rec, dcr->block->adata);
326
327 block->BlockNumber = 0;
328 /* Note for adata this also writes to disk */
329 Dmsg1(100, "write_record_to_block adata=%d\n", dcr->dev->adata);
330 if (!write_record_to_block(dcr, &rec)) {
331 free_pool_memory(rec.data);
332 Jmsg2(jcr, M_FATAL, 0, _("Cannot write Volume label to block for %s device %s\n"),
333 dev->print_type(), dev->print_name());
334 ok = false;
335 goto get_out;
336 } else {
337 Dmsg4(100, "Wrote fd=%d adata=%d label of %d bytes to block. Vol=%s\n",
338 dev->fd(), block->adata, rec.data_len, dcr->VolumeName);
339 }
340 free_pool_memory(rec.data);
341
342 get_out:
343 Leave(100);
344 return ok;
345 }
346
347 /*
348 * Write a Volume Label
349 * !!! Note, this is ONLY used for writing
350 * a fresh volume label. Any data
351 * after the label will be destroyed,
352 * in fact, we write the label 5 times !!!!
353 *
354 * This routine should be used only when labeling a blank tape or
355 * when recylcing a volume.
356 *
357 * Handle both the ameta and adata volumes.
358 */
write_volume_label(DCR * dcr,const char * VolName,const char * PoolName,bool relabel,bool no_prelabel)359 bool DEVICE::write_volume_label(DCR *dcr, const char *VolName,
360 const char *PoolName, bool relabel, bool no_prelabel)
361 {
362 DEVICE *dev;
363
364 Enter(100);
365 Dmsg4(230, "Write: block=%p ameta=%p dev=%p ameta_dev=%p\n",
366 dcr->block, dcr->ameta_block, dcr->dev, dcr->ameta_dev);
367 dcr->set_ameta();
368 dev = dcr->dev;
369
370 Dmsg0(150, "write_volume_label()\n");
371 if (*VolName == 0) {
372 if (dcr->jcr) {
373 Mmsg(dcr->jcr->errmsg, "ERROR: new_volume_label_to_dev called with NULL VolName\n");
374 }
375 Pmsg0(0, "=== ERROR: write_volume_label called with NULL VolName\n");
376 goto bail_out;
377 }
378
379 if (relabel) {
380 volume_unused(dcr); /* mark current volume unused */
381 /* Truncate device */
382 if (!dev->truncate(dcr)) {
383 goto bail_out;
384 }
385 dev->close_part(dcr); /* make sure closed for rename */
386 }
387
388 /* Set the new filename for open, ... */
389 dev->setVolCatName(VolName);
390 dcr->setVolCatName(VolName);
391 dev->clearVolCatBytes();
392
393 Dmsg1(100, "New VolName=%s\n", VolName);
394 if (!dev->open_device(dcr, OPEN_READ_WRITE)) {
395 /* If device is not tape, attempt to create it */
396 if (dev->is_tape() || !dev->open_device(dcr, CREATE_READ_WRITE)) {
397 Jmsg4(dcr->jcr, M_WARNING, 0, _("Open %s device %s Volume \"%s\" failed: ERR=%s"),
398 dev->print_type(), dev->print_name(), dcr->VolumeName, dev->bstrerror());
399 goto bail_out;
400 }
401 }
402 Dmsg1(150, "Label type=%d\n", dev->label_type);
403
404 if (!write_volume_label_to_dev(dcr, VolName, PoolName, relabel, no_prelabel)) {
405 goto bail_out;
406 }
407
408 if (!dev->is_aligned()) {
409 /* Not aligned data */
410 if (dev->weof(dcr, 1)) {
411 dev->set_labeled();
412 }
413
414 if (chk_dbglvl(100)) {
415 dev->dump_volume_label();
416 }
417 Dmsg0(50, "Call reserve_volume\n");
418 /**** ***FIXME*** if dev changes, dcr must be updated */
419 if (reserve_volume(dcr, VolName) == NULL) {
420 if (!dcr->jcr->errmsg[0]) {
421 Mmsg3(dcr->jcr->errmsg, _("Could not reserve volume %s on %s device %s\n"),
422 dev->VolHdr.VolumeName, dev->print_type(), dev->print_name());
423 }
424 Dmsg1(50, "%s", dcr->jcr->errmsg);
425 goto bail_out;
426 }
427 dev = dcr->dev; /* may have changed in reserve_volume */
428 }
429 dev->clear_append(); /* remove append since this is PRE_LABEL */
430 Leave(100);
431 return true;
432
433 bail_out:
434 dcr->adata_label = false;
435 dcr->set_ameta();
436 volume_unused(dcr);
437 dcr->dev->clear_append(); /* remove append since this is PRE_LABEL */
438 Leave(100);
439 return false;
440 }
441
write_volume_label_to_dev(DCR * dcr,const char * VolName,const char * PoolName,bool relabel,bool no_prelabel)442 bool DEVICE::write_volume_label_to_dev(DCR *dcr, const char *VolName,
443 const char *PoolName, bool relabel, bool no_prelabel)
444 {
445 DEVICE *dev, *ameta_dev;
446 DEV_BLOCK *block;
447 DEV_RECORD *rec = new_record();
448 bool rtn = false;
449
450 Enter(100);
451 dev = dcr->dev;
452 ameta_dev = dcr->ameta_dev;
453 block = dcr->block;
454
455 empty_block(block);
456 if (!dev->rewind(dcr)) {
457 Dmsg2(130, "Bad status on %s from rewind: ERR=%s\n", dev->print_name(), dev->print_errmsg());
458 goto bail_out;
459 }
460
461 /* Temporarily mark in append state to enable writing */
462 dev->set_append();
463
464 /* Create PRE_LABEL or VOL_LABEL */
465 create_volume_header(dev, VolName, PoolName, no_prelabel);
466
467 /*
468 * If we have already detected an ANSI label, re-read it
469 * to skip past it. Otherwise, we write a new one if
470 * so requested.
471 */
472 if (!block->adata) {
473 if (dev->label_type != B_BACULA_LABEL) {
474 if (read_ansi_ibm_label(dcr) != VOL_OK) {
475 dev->rewind(dcr);
476 goto bail_out;
477 }
478 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, VolName)) {
479 goto bail_out;
480 }
481 }
482
483 create_volume_label_record(dcr, dev, rec, block->adata);
484 rec->Stream = 0;
485 rec->maskedStream = 0;
486
487 Dmsg2(100, "write_record_to_block adata=%d FI=%d\n", dcr->dev->adata,
488 rec->FileIndex);
489
490 /* For adata label this also writes to disk */
491 if (!write_record_to_block(dcr, rec)) {
492 Dmsg2(40, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
493 goto bail_out;
494 } else {
495 Dmsg3(100, "Wrote label=%d bytes adata=%d block: %s\n", rec->data_len, block->adata, dev->print_name());
496 }
497 Dmsg3(100, "New label adata=%d VolCatBytes=%lld VolCatStatus=%s\n",
498 dev->adata, ameta_dev->VolCatInfo.VolCatBytes, ameta_dev->VolCatInfo.VolCatStatus);
499
500 if (block->adata) {
501 /* Empty block and set data start address */
502 empty_block(dcr->adata_block);
503 } else {
504 Dmsg4(130, "Call write_block_to_dev() fd=%d adata=%d block=%p Addr=%lld\n",
505 dcr->dev->fd(), dcr->block->adata, dcr->block, block->dev->lseek(dcr, 0, SEEK_CUR));
506 Dmsg1(100, "write_record_to_dev adata=%d\n", dcr->dev->adata);
507 /* Write ameta block to device */
508 if (!dcr->write_block_to_dev()) {
509 Dmsg2(40, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
510 goto bail_out;
511 }
512 }
513 Dmsg3(100, "Wrote new Vol label adata=%d VolCatBytes=%lld VolCatStatus=%s\n",
514 dev->adata, ameta_dev->VolCatInfo.VolCatBytes, ameta_dev->VolCatInfo.VolCatStatus);
515 rtn = true;
516
517 bail_out:
518 free_record(rec);
519 Leave(100);
520 return rtn;
521 }
522
523 /*
524 * Write a volume label. This is ONLY called if we have a valid Bacula
525 * label of type PRE_LABEL or we are recyling an existing Volume.
526 *
527 * By calling write_volume_label_to_block, both ameta and adata
528 * are updated.
529 *
530 * Returns: true if OK
531 * false if unable to write it
532 */
rewrite_volume_label(DCR * dcr,bool recycle)533 bool DEVICE::rewrite_volume_label(DCR *dcr, bool recycle)
534 {
535 char ed1[50];
536 JCR *jcr = dcr->jcr;
537
538 Enter(100);
539 ASSERT2(dcr->VolumeName[0], "Empty Volume name");
540 ASSERT(!dcr->block->adata);
541 if (is_worm()) {
542 Jmsg3(jcr, M_FATAL, 0, _("Cannot relabel worm %s device %s Volume \"%s\"\n"),
543 print_type(), print_name(), dcr->VolumeName);
544 Leave(100);
545 return false;
546 }
547 if (!open_device(dcr, OPEN_READ_WRITE)) {
548 Jmsg4(jcr, M_WARNING, 0, _("Open %s device %s Volume \"%s\" failed: ERR=%s\n"),
549 print_type(), print_name(), dcr->VolumeName, bstrerror());
550 Leave(100);
551 return false;
552 }
553 Dmsg2(190, "set append found freshly labeled volume. fd=%d dev=%x\n", fd(), this);
554 VolHdr.LabelType = VOL_LABEL; /* set Volume label */
555 set_append();
556 Dmsg0(100, "Rewrite_volume_label set volcatbytes=0\n");
557 clearVolCatBytes(); /* resets both ameta and adata byte counts */
558 setVolCatStatus("Append"); /* set append status */
559
560 if (!has_cap(CAP_STREAM)) {
561 if (!rewind(dcr)) {
562 Jmsg3(jcr, M_FATAL, 0, _("Rewind error on %s device %s: ERR=%s\n"),
563 print_type(), print_name(), print_errmsg());
564 Leave(100);
565 return false;
566 }
567 if (recycle) {
568 Dmsg1(150, "Doing recycle. Vol=%s\n", dcr->VolumeName);
569 if (!truncate(dcr)) {
570 Jmsg3(jcr, M_FATAL, 0, _("Truncate error on %s device %s: ERR=%s\n"),
571 print_type(), print_name(), print_errmsg());
572 Leave(100);
573 return false;
574 }
575 if (!open_device(dcr, OPEN_READ_WRITE)) {
576 Jmsg3(jcr, M_FATAL, 0,
577 _("Failed to re-open device after truncate on %s device %s: ERR=%s"),
578 print_type(), print_name(), print_errmsg());
579 Leave(100);
580 return false;
581 }
582 }
583 }
584
585 if (!write_volume_label_to_block(dcr)) {
586 Dmsg0(150, "Error from write volume label.\n");
587 Leave(100);
588 return false;
589 }
590 Dmsg2(100, "wrote vol label to block. adata=%d Vol=%s\n", dcr->block->adata, dcr->VolumeName);
591
592 ASSERT2(dcr->VolumeName[0], "Empty Volume name");
593 setVolCatInfo(false);
594
595 /*
596 * If we are not dealing with a streaming device,
597 * write the block now to ensure we have write permission.
598 * It is better to find out now rather than later.
599 * We do not write the block now if this is an ANSI label. This
600 * avoids re-writing the ANSI label, which we do not want to do.
601 */
602 if (!has_cap(CAP_STREAM)) {
603 /*
604 * If we have already detected an ANSI label, re-read it
605 * to skip past it. Otherwise, we write a new one if
606 * so requested.
607 */
608 if (label_type != B_BACULA_LABEL) {
609 if (read_ansi_ibm_label(dcr) != VOL_OK) {
610 rewind(dcr);
611 Leave(100);
612 return false;
613 }
614 } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, VolHdr.VolumeName)) {
615 Leave(100);
616 return false;
617 }
618
619 /* Attempt write to check write permission */
620 Dmsg1(200, "Attempt to write to device fd=%d.\n", fd());
621 if (!dcr->write_block_to_dev()) {
622 Jmsg3(jcr, M_ERROR, 0, _("Unable to write %s device %s: ERR=%s\n"),
623 print_type(), print_name(), print_errmsg());
624 Dmsg0(200, "===ERROR write block to dev\n");
625 Leave(100);
626 return false;
627 }
628 }
629 ASSERT2(dcr->VolumeName[0], "Empty Volume name");
630 setVolCatName(dcr->VolumeName);
631 if (!dir_get_volume_info(dcr, dcr->VolumeName, GET_VOL_INFO_FOR_WRITE)) {
632 Leave(100);
633 return false;
634 }
635 set_labeled();
636 /* Set or reset Volume statistics */
637 VolCatInfo.VolCatJobs = 0;
638 VolCatInfo.VolCatFiles = 0;
639 VolCatInfo.VolCatErrors = 0;
640 VolCatInfo.VolCatBlocks = 0;
641 VolCatInfo.VolCatRBytes = 0;
642 VolCatInfo.VolCatCloudParts = 0;
643 VolCatInfo.VolLastPartBytes = 0;
644 VolCatInfo.VolCatType = 0; /* Will be set by dir_update_volume_info() */
645 if (recycle) {
646 VolCatInfo.VolCatMounts++;
647 VolCatInfo.VolCatRecycles++;
648 } else {
649 VolCatInfo.VolCatMounts = 1;
650 VolCatInfo.VolCatRecycles = 0;
651 VolCatInfo.VolCatWrites = 1;
652 VolCatInfo.VolCatReads = 1;
653 }
654 dcr->VolMediaId = dcr->VolCatInfo.VolMediaId; /* make create_jobmedia work */
655 dir_create_jobmedia_record(dcr, true);
656 Dmsg1(100, "dir_update_vol_info. Set Append vol=%s\n", dcr->VolumeName);
657 VolCatInfo.VolFirstWritten = time(NULL);
658 setVolCatStatus("Append");
659 if (!dir_update_volume_info(dcr, true, true)) { /* indicate relabel */
660 Leave(100);
661 return false;
662 }
663 if (recycle) {
664 Jmsg(jcr, M_INFO, 0, _("Recycled volume \"%s\" on %s device %s, all previous data lost.\n"),
665 dcr->VolumeName, print_type(), print_name());
666 } else {
667 Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume \"%s\" on %s device %s\n"),
668 dcr->VolumeName, print_type(), print_name());
669 }
670 /*
671 * End writing real Volume label (from pre-labeled tape), or recycling
672 * the volume.
673 */
674 Dmsg4(100, "OK rewrite vol label. Addr=%s adata=%d slot=%d Vol=%s\n",
675 print_addr(ed1, sizeof(ed1)), dcr->block->adata, VolCatInfo.Slot, dcr->VolumeName);
676 Leave(100);
677 return true;
678 }
679
680
681 /*
682 * create_volume_label_record
683 * Note: it is assumed that you have created the volume_header
684 * (label) prior to calling this subroutine.
685 * Serialize label (from dev->VolHdr structure) into device record.
686 * Assumes that the dev->VolHdr structure is properly
687 * initialized.
688 */
create_volume_label_record(DCR * dcr,DEVICE * dev,DEV_RECORD * rec,bool adata)689 static void create_volume_label_record(DCR *dcr, DEVICE *dev,
690 DEV_RECORD *rec, bool adata)
691 {
692 ser_declare;
693 struct date_time dt;
694 JCR *jcr = dcr->jcr;
695 char buf[100];
696
697 /* Serialize the label into the device record. */
698
699 Enter(100);
700 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
701 memset(rec->data, 0, SER_LENGTH_Volume_Label);
702 ser_begin(rec->data, SER_LENGTH_Volume_Label);
703 ser_string(dev->VolHdr.Id);
704
705 ser_uint32(dev->VolHdr.VerNum);
706
707 if (dev->VolHdr.VerNum >= 11) {
708 ser_btime(dev->VolHdr.label_btime);
709 dev->VolHdr.write_btime = get_current_btime();
710 ser_btime(dev->VolHdr.write_btime);
711 dev->VolHdr.write_date = 0;
712 dev->VolHdr.write_time = 0;
713 } else {
714 /* OLD WAY DEPRECATED */
715 ser_float64(dev->VolHdr.label_date);
716 ser_float64(dev->VolHdr.label_time);
717 get_current_time(&dt);
718 dev->VolHdr.write_date = dt.julian_day_number;
719 dev->VolHdr.write_time = dt.julian_day_fraction;
720 }
721 ser_float64(dev->VolHdr.write_date); /* 0 if VerNum >= 11 */
722 ser_float64(dev->VolHdr.write_time); /* 0 if VerNum >= 11 */
723
724 ser_string(dev->VolHdr.VolumeName);
725 ser_string(dev->VolHdr.PrevVolumeName);
726 ser_string(dev->VolHdr.PoolName);
727 ser_string(dev->VolHdr.PoolType);
728 ser_string(dev->VolHdr.MediaType);
729
730 ser_string(dev->VolHdr.HostName);
731 ser_string(dev->VolHdr.LabelProg);
732 ser_string(dev->VolHdr.ProgVersion);
733 ser_string(dev->VolHdr.ProgDate);
734 /* ***FIXME*** */
735 dev->VolHdr.AlignedVolumeName[0] = 0;
736 ser_string(dev->VolHdr.AlignedVolumeName);
737
738 /* This is adata Volume information */
739 ser_uint64(dev->VolHdr.FirstData);
740 ser_uint32(dev->VolHdr.FileAlignment);
741 ser_uint32(dev->VolHdr.PaddingSize);
742 /* adata and dedup volumes */
743 ser_uint32(dev->VolHdr.BlockSize);
744
745 ser_end(rec->data, SER_LENGTH_Volume_Label);
746 if (!adata) {
747 bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName));
748 }
749 ASSERT2(dcr->VolumeName[0], "Empty Volume name");
750 rec->data_len = ser_length(rec->data);
751 rec->FileIndex = dev->VolHdr.LabelType;
752 Dmsg2(100, "LabelType=%d adata=%d\n", dev->VolHdr.LabelType, dev->adata);
753 rec->VolSessionId = jcr->VolSessionId;
754 rec->VolSessionTime = jcr->VolSessionTime;
755 rec->Stream = jcr->NumWriteVolumes;
756 rec->maskedStream = jcr->NumWriteVolumes;
757 Dmsg3(100, "Created adata=%d Vol label rec: FI=%s len=%d\n", adata, FI_to_ascii(buf, rec->FileIndex),
758 rec->data_len);
759 Dmsg2(100, "reclen=%d recdata=%s", rec->data_len, rec->data);
760 Leave(100);
761 }
762
763
764 /*
765 * Create a volume header (label) in memory
766 * The volume record is created after this header (label)
767 * is created.
768 */
create_volume_header(DEVICE * dev,const char * VolName,const char * PoolName,bool no_prelabel)769 void create_volume_header(DEVICE *dev, const char *VolName,
770 const char *PoolName, bool no_prelabel)
771 {
772 DEVRES *device = (DEVRES *)dev->device;
773
774 Enter(130);
775
776 ASSERT2(dev != NULL, "dev ptr is NULL");
777
778 if (dev->is_aligned()) {
779 bstrncpy(dev->VolHdr.Id, BaculaMetaDataId, sizeof(dev->VolHdr.Id));
780 dev->VolHdr.VerNum = BaculaMetaDataVersion;
781 dev->VolHdr.FirstData = dev->file_alignment;
782 dev->VolHdr.FileAlignment = dev->file_alignment;
783 dev->VolHdr.PaddingSize = dev->padding_size;
784 dev->VolHdr.BlockSize = dev->adata_size;
785 } else if (dev->is_adata()) {
786 bstrncpy(dev->VolHdr.Id, BaculaAlignedDataId, sizeof(dev->VolHdr.Id));
787 dev->VolHdr.VerNum = BaculaAlignedDataVersion;
788 dev->VolHdr.FirstData = dev->file_alignment;
789 dev->VolHdr.FileAlignment = dev->file_alignment;
790 dev->VolHdr.PaddingSize = dev->padding_size;
791 dev->VolHdr.BlockSize = dev->adata_size;
792 } else if (dev->is_cloud()) {
793 bstrncpy(dev->VolHdr.Id, BaculaS3CloudId, sizeof(dev->VolHdr.Id));
794 dev->VolHdr.VerNum = BaculaS3CloudVersion;
795 dev->VolHdr.BlockSize = dev->max_block_size;
796 dev->VolHdr.MaxPartSize = dev->max_part_size;
797 } else {
798 bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
799 dev->VolHdr.VerNum = BaculaTapeVersion;
800 dev->VolHdr.BlockSize = dev->max_block_size;
801 }
802
803 if ((dev->has_cap(CAP_STREAM) && no_prelabel) || dev->is_worm()) {
804 /* We do not want to re-label so write VOL_LABEL now */
805 dev->VolHdr.LabelType = VOL_LABEL;
806 } else {
807 dev->VolHdr.LabelType = PRE_LABEL; /* Mark Volume as unused */
808 }
809 bstrncpy(dev->VolHdr.VolumeName, VolName, sizeof(dev->VolHdr.VolumeName));
810 bstrncpy(dev->VolHdr.PoolName, PoolName, sizeof(dev->VolHdr.PoolName));
811 bstrncpy(dev->VolHdr.MediaType, device->media_type, sizeof(dev->VolHdr.MediaType));
812
813 bstrncpy(dev->VolHdr.PoolType, "Backup", sizeof(dev->VolHdr.PoolType));
814
815 dev->VolHdr.label_btime = get_current_btime();
816 dev->VolHdr.label_date = 0;
817 dev->VolHdr.label_time = 0;
818
819 if (gethostname(dev->VolHdr.HostName, sizeof(dev->VolHdr.HostName)) != 0) {
820 dev->VolHdr.HostName[0] = 0;
821 }
822 bstrncpy(dev->VolHdr.LabelProg, my_name, sizeof(dev->VolHdr.LabelProg));
823 sprintf(dev->VolHdr.ProgVersion, "Ver. %s %s ", VERSION, BDATE);
824 sprintf(dev->VolHdr.ProgDate, "Build %s %s ", __DATE__, __TIME__);
825 dev->set_labeled(); /* set has Bacula label */
826 if (chk_dbglvl(100)) {
827 dev->dump_volume_label();
828 }
829 }
830
831 /*
832 * Create session (Job) label
833 * The pool memory must be released by the calling program
834 */
create_session_label(DCR * dcr,DEV_RECORD * rec,int label)835 void create_session_label(DCR *dcr, DEV_RECORD *rec, int label)
836 {
837 JCR *jcr = dcr->jcr;
838 ser_declare;
839
840 Enter(100);
841 rec->VolSessionId = jcr->VolSessionId;
842 rec->VolSessionTime = jcr->VolSessionTime;
843 rec->Stream = jcr->JobId;
844 rec->maskedStream = jcr->JobId;
845
846 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
847 ser_begin(rec->data, SER_LENGTH_Session_Label);
848 ser_string(BaculaId);
849 ser_uint32(BaculaTapeVersion);
850
851 ser_uint32(jcr->JobId);
852
853 /* Changed in VerNum 11 */
854 ser_btime(get_current_btime());
855 ser_float64(0);
856
857 ser_string(dcr->pool_name);
858 ser_string(dcr->pool_type);
859 ser_string(jcr->job_name); /* base Job name */
860 ser_string(jcr->client_name);
861
862 /* Added in VerNum 10 */
863 ser_string(jcr->Job); /* Unique name of this Job */
864 ser_string(jcr->fileset_name);
865 ser_uint32(jcr->getJobType());
866 ser_uint32(jcr->getJobLevel());
867 /* Added in VerNum 11 */
868 ser_string(jcr->fileset_md5);
869
870 if (label == EOS_LABEL) {
871 ser_uint32(jcr->JobFiles);
872 ser_uint64(jcr->JobBytes);
873 ser_uint32((uint32_t)dcr->StartAddr); /* Start Block */
874 ser_uint32((uint32_t)dcr->EndAddr); /* End Block */
875 ser_uint32((uint32_t)(dcr->StartAddr>>32)); /* Start File */
876 ser_uint32((uint32_t)(dcr->EndAddr>>32)); /* End File */
877 ser_uint32(jcr->JobErrors);
878
879 /* Added in VerNum 11 */
880 ser_uint32(jcr->JobStatus);
881 }
882 ser_end(rec->data, SER_LENGTH_Session_Label);
883 rec->data_len = ser_length(rec->data);
884 Leave(100);
885 }
886
887 /* Write session (Job) label
888 * Returns: false on failure
889 * true on success
890 */
write_session_label(DCR * dcr,int label)891 bool write_session_label(DCR *dcr, int label)
892 {
893 JCR *jcr = dcr->jcr;
894 DEVICE *dev = dcr->dev;
895 DEV_RECORD *rec;
896 DEV_BLOCK *block = dcr->block;
897 char buf1[100], buf2[100];
898
899 Enter(100);
900 dev->Lock();
901 Dmsg2(140, "=== write_session_label label=%d Vol=%s.\n", label, dev->getVolCatName());
902 if (!check_for_newvol_or_newfile(dcr)) {
903 Pmsg0(000, "ERR: !check_for_new_vol_or_newfile\n");
904 dev->Unlock();
905 return false;
906 }
907
908 rec = new_record();
909 Dmsg1(130, "session_label record=%x\n", rec);
910 switch (label) {
911 case SOS_LABEL:
912 set_start_vol_position(dcr);
913 break;
914 case EOS_LABEL:
915 dcr->EndAddr = dev->get_full_addr();
916 break;
917 default:
918 Jmsg1(jcr, M_ABORT, 0, _("Bad Volume session label request=%d\n"), label);
919 break;
920 }
921
922 create_session_label(dcr, rec, label);
923 rec->FileIndex = label;
924 dev->Unlock();
925
926 /*
927 * We guarantee that the session record can totally fit
928 * into a block. If not, write the block, and put it in
929 * the next block. Having the sesssion record totally in
930 * one block makes reading them much easier (no need to
931 * read the next block).
932 */
933 if (!can_write_record_to_block(block, rec)) {
934 Dmsg0(150, "Cannot write session label to block.\n");
935 if (!dcr->write_block_to_device()) {
936 Dmsg0(130, "Got session label write_block_to_dev error.\n");
937 free_record(rec);
938 Leave(100);
939 return false;
940 }
941 }
942 /*
943 * We use write_record() because it handles the case that
944 * the maximum user size has been reached.
945 */
946 if (!dcr->write_record(rec)) {
947 Dmsg0(150, "Bad return from write_record\n");
948 free_record(rec);
949 Leave(100);
950 return false;
951 }
952
953 Dmsg6(150, "Write sesson_label record JobId=%d FI=%s SessId=%d Strm=%s len=%d "
954 "remainder=%d\n", jcr->JobId,
955 FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
956 stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
957 rec->remainder);
958
959 free_record(rec);
960 Dmsg2(150, "Leave write_session_label Block=%u File=%u\n",
961 dev->get_block_num(), dev->get_file());
962 Leave(100);
963 return true;
964 }
965
966 /* unser_volume_label
967 *
968 * Unserialize the Bacula Volume label into the device Volume_Label
969 * structure.
970 *
971 * Assumes that the record is already read.
972 *
973 * Returns: false on error
974 * true on success
975 */
976
unser_volume_label(DEVICE * dev,DEV_RECORD * rec)977 bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec)
978 {
979 ser_declare;
980 char buf1[100], buf2[100];
981
982 Enter(100);
983 if (rec->FileIndex != VOL_LABEL && rec->FileIndex != PRE_LABEL) {
984 Mmsg3(dev->errmsg, _("Expecting Volume Label, got FI=%s Stream=%s len=%d\n"),
985 FI_to_ascii(buf1, rec->FileIndex),
986 stream_to_ascii(buf2, rec->Stream, rec->FileIndex),
987 rec->data_len);
988 if (!forge_on) {
989 Leave(100);
990 return false;
991 }
992 }
993
994 dev->VolHdr.LabelType = rec->FileIndex;
995 dev->VolHdr.LabelSize = rec->data_len;
996
997
998 /* Unserialize the record into the Volume Header */
999 Dmsg2(100, "reclen=%d recdata=%s", rec->data_len, rec->data);
1000 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
1001 Dmsg2(100, "reclen=%d recdata=%s", rec->data_len, rec->data);
1002 ser_begin(rec->data, SER_LENGTH_Volume_Label);
1003 unser_string(dev->VolHdr.Id);
1004 unser_uint32(dev->VolHdr.VerNum);
1005
1006 if (dev->VolHdr.VerNum >= 11) {
1007 unser_btime(dev->VolHdr.label_btime);
1008 unser_btime(dev->VolHdr.write_btime);
1009 } else { /* old way */
1010 unser_float64(dev->VolHdr.label_date);
1011 unser_float64(dev->VolHdr.label_time);
1012 }
1013 unser_float64(dev->VolHdr.write_date); /* Unused with VerNum >= 11 */
1014 unser_float64(dev->VolHdr.write_time); /* Unused with VerNum >= 11 */
1015
1016 unser_string(dev->VolHdr.VolumeName);
1017 unser_string(dev->VolHdr.PrevVolumeName);
1018 unser_string(dev->VolHdr.PoolName);
1019 unser_string(dev->VolHdr.PoolType);
1020 unser_string(dev->VolHdr.MediaType);
1021
1022 unser_string(dev->VolHdr.HostName);
1023 unser_string(dev->VolHdr.LabelProg);
1024 unser_string(dev->VolHdr.ProgVersion);
1025 unser_string(dev->VolHdr.ProgDate);
1026
1027 // unser_string(dev->VolHdr.AlignedVolumeName);
1028 dev->VolHdr.AlignedVolumeName[0] = 0;
1029 unser_uint64(dev->VolHdr.FirstData);
1030 unser_uint32(dev->VolHdr.FileAlignment);
1031 unser_uint32(dev->VolHdr.PaddingSize);
1032 unser_uint32(dev->VolHdr.BlockSize);
1033
1034 ser_end(rec->data, SER_LENGTH_Volume_Label);
1035 Dmsg0(190, "unser_vol_label\n");
1036 if (chk_dbglvl(100)) {
1037 dev->dump_volume_label();
1038 }
1039 Leave(100);
1040 return true;
1041 }
1042
1043
unser_session_label(SESSION_LABEL * label,DEV_RECORD * rec)1044 bool unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec)
1045 {
1046 ser_declare;
1047
1048 Enter(100);
1049 rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
1050 unser_begin(rec->data, SER_LENGTH_Session_Label);
1051 unser_string(label->Id);
1052 unser_uint32(label->VerNum);
1053 unser_uint32(label->JobId);
1054 if (label->VerNum >= 11) {
1055 unser_btime(label->write_btime);
1056 } else {
1057 unser_float64(label->write_date);
1058 }
1059 unser_float64(label->write_time);
1060 unser_string(label->PoolName);
1061 unser_string(label->PoolType);
1062 unser_string(label->JobName);
1063 unser_string(label->ClientName);
1064 if (label->VerNum >= 10) {
1065 unser_string(label->Job); /* Unique name of this Job */
1066 unser_string(label->FileSetName);
1067 unser_uint32(label->JobType);
1068 unser_uint32(label->JobLevel);
1069 }
1070 if (label->VerNum >= 11) {
1071 unser_string(label->FileSetMD5);
1072 } else {
1073 label->FileSetMD5[0] = 0;
1074 }
1075 if (rec->FileIndex == EOS_LABEL) {
1076 unser_uint32(label->JobFiles);
1077 unser_uint64(label->JobBytes);
1078 unser_uint32(label->StartBlock);
1079 unser_uint32(label->EndBlock);
1080 unser_uint32(label->StartFile);
1081 unser_uint32(label->EndFile);
1082 unser_uint32(label->JobErrors);
1083 if (label->VerNum >= 11) {
1084 unser_uint32(label->JobStatus);
1085 } else {
1086 label->JobStatus = JS_Terminated; /* kludge */
1087 }
1088 }
1089 Leave(100);
1090 return true;
1091 }
1092
dump_volume_label()1093 void DEVICE::dump_volume_label()
1094 {
1095 int64_t dbl = debug_level;
1096 uint32_t File;
1097 const char *LabelType;
1098 char buf[30];
1099 struct tm tm;
1100 struct date_time dt;
1101
1102 debug_level = 1;
1103 File = file;
1104 switch (VolHdr.LabelType) {
1105 case PRE_LABEL:
1106 LabelType = "PRE_LABEL";
1107 break;
1108 case VOL_LABEL:
1109 LabelType = "VOL_LABEL";
1110 break;
1111 case EOM_LABEL:
1112 LabelType = "EOM_LABEL";
1113 break;
1114 case SOS_LABEL:
1115 LabelType = "SOS_LABEL";
1116 break;
1117 case EOS_LABEL:
1118 LabelType = "EOS_LABEL";
1119 break;
1120 case EOT_LABEL:
1121 goto bail_out;
1122 default:
1123 LabelType = buf;
1124 sprintf(buf, _("Unknown %d"), VolHdr.LabelType);
1125 break;
1126 }
1127
1128 Pmsg12(-1, _("\nVolume Label:\n"
1129 "Adata : %d\n"
1130 "Id : %s"
1131 "VerNo : %d\n"
1132 "VolName : %s\n"
1133 "PrevVolName : %s\n"
1134 "VolFile : %d\n"
1135 "LabelType : %s\n"
1136 "LabelSize : %d\n"
1137 "PoolName : %s\n"
1138 "MediaType : %s\n"
1139 "PoolType : %s\n"
1140 "HostName : %s\n"
1141 ""),
1142 adata,
1143 VolHdr.Id, VolHdr.VerNum,
1144 VolHdr.VolumeName, VolHdr.PrevVolumeName,
1145 File, LabelType, VolHdr.LabelSize,
1146 VolHdr.PoolName, VolHdr.MediaType,
1147 VolHdr.PoolType, VolHdr.HostName);
1148
1149 if (VolHdr.VerNum >= 11) {
1150 char dt[50];
1151 bstrftime(dt, sizeof(dt), btime_to_utime(VolHdr.label_btime));
1152 Pmsg1(-1, _("Date label written: %s\n"), dt);
1153 } else {
1154 dt.julian_day_number = VolHdr.label_date;
1155 dt.julian_day_fraction = VolHdr.label_time;
1156 tm_decode(&dt, &tm);
1157 Pmsg5(-1,
1158 _("Date label written: %04d-%02d-%02d at %02d:%02d\n"),
1159 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
1160 }
1161
1162 bail_out:
1163 debug_level = dbl;
1164 }
1165
1166
dump_session_label(DEV_RECORD * rec,const char * type)1167 static void dump_session_label(DEV_RECORD *rec, const char *type)
1168 {
1169 int64_t dbl;
1170 struct date_time dt;
1171 struct tm tm;
1172 SESSION_LABEL label;
1173 char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], ec6[30], ec7[30];
1174
1175 unser_session_label(&label, rec);
1176 dbl = debug_level;
1177 debug_level = 1;
1178 Pmsg7(-1, _("\n%s Record:\n"
1179 "JobId : %d\n"
1180 "VerNum : %d\n"
1181 "PoolName : %s\n"
1182 "PoolType : %s\n"
1183 "JobName : %s\n"
1184 "ClientName : %s\n"
1185 ""), type, label.JobId, label.VerNum,
1186 label.PoolName, label.PoolType,
1187 label.JobName, label.ClientName);
1188
1189 if (label.VerNum >= 10) {
1190 Pmsg4(-1, _(
1191 "Job (unique name) : %s\n"
1192 "FileSet : %s\n"
1193 "JobType : %c\n"
1194 "JobLevel : %c\n"
1195 ""), label.Job, label.FileSetName, label.JobType, label.JobLevel);
1196 }
1197
1198 if (rec->FileIndex == EOS_LABEL) {
1199 Pmsg8(-1, _(
1200 "JobFiles : %s\n"
1201 "JobBytes : %s\n"
1202 "StartBlock : %s\n"
1203 "EndBlock : %s\n"
1204 "StartFile : %s\n"
1205 "EndFile : %s\n"
1206 "JobErrors : %s\n"
1207 "JobStatus : %c\n"
1208 ""),
1209 edit_uint64_with_commas(label.JobFiles, ec1),
1210 edit_uint64_with_commas(label.JobBytes, ec2),
1211 edit_uint64_with_commas(label.StartBlock, ec3),
1212 edit_uint64_with_commas(label.EndBlock, ec4),
1213 edit_uint64_with_commas(label.StartFile, ec5),
1214 edit_uint64_with_commas(label.EndFile, ec6),
1215 edit_uint64_with_commas(label.JobErrors, ec7),
1216 label.JobStatus);
1217 }
1218 if (label.VerNum >= 11) {
1219 char dt[50];
1220 bstrftime(dt, sizeof(dt), btime_to_utime(label.write_btime));
1221 Pmsg1(-1, _("Date written : %s\n"), dt);
1222 } else {
1223 dt.julian_day_number = label.write_date;
1224 dt.julian_day_fraction = label.write_time;
1225 tm_decode(&dt, &tm);
1226 Pmsg5(-1, _("Date written : %04d-%02d-%02d at %02d:%02d\n"),
1227 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
1228 }
1229
1230 debug_level = dbl;
1231 }
1232
check_label(SESSION_LABEL * label)1233 static int check_label(SESSION_LABEL *label)
1234 {
1235 int errors = 0;
1236
1237 if (label->JobId > 10000000 || label->JobId < 0) {
1238 Pmsg0(-1, _("***** ERROR ****** : Found error with the JobId\n"));
1239 errors++;
1240 }
1241
1242 if (!errors) {
1243 switch (label->JobLevel) {
1244 case L_FULL:
1245 case L_INCREMENTAL:
1246 case L_DIFFERENTIAL:
1247 case L_SINCE:
1248 case L_VERIFY_CATALOG:
1249 case L_VERIFY_INIT:
1250 case L_VERIFY_VOLUME_TO_CATALOG:
1251 case L_VERIFY_DISK_TO_CATALOG:
1252 case L_VERIFY_DATA:
1253 case L_BASE:
1254 case L_NONE:
1255 case L_VIRTUAL_FULL:
1256 break;
1257 default:
1258 Pmsg0(-1, _("***** ERROR ****** : Found error with the JobLevel\n"));
1259 errors++;
1260 }
1261 }
1262 if (!errors) {
1263 switch (label->JobType) {
1264 case JT_BACKUP:
1265 case JT_MIGRATED_JOB:
1266 case JT_VERIFY:
1267 case JT_RESTORE:
1268 case JT_CONSOLE:
1269 case JT_SYSTEM:
1270 case JT_ADMIN:
1271 case JT_ARCHIVE:
1272 case JT_JOB_COPY:
1273 case JT_COPY:
1274 case JT_MIGRATE:
1275 case JT_SCAN:
1276 break;
1277 default:
1278 Pmsg0(-1, _("***** ERROR ****** : Found error with the JobType\n"));
1279 errors++;
1280 }
1281 }
1282 if (!errors) {
1283 POOLMEM *err = get_pool_memory(PM_EMSG);
1284 if (!is_name_valid(label->Job, &err)) {
1285 Pmsg1(-1, _("***** ERROR ****** : Found error with the Job name %s\n"), err);
1286 errors++;
1287 }
1288 free_pool_memory(err);
1289 }
1290 return errors;
1291 }
1292
dump_label_record(DEVICE * dev,DEV_RECORD * rec,int verbose,bool check_err)1293 int dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose, bool check_err)
1294 {
1295 const char *type;
1296 int64_t dbl;
1297 int errors = 0;
1298
1299 if (rec->FileIndex == 0 && rec->VolSessionId == 0 && rec->VolSessionTime == 0) {
1300 return 0;
1301 }
1302 dbl = debug_level;
1303 debug_level = 1;
1304 switch (rec->FileIndex) {
1305 case PRE_LABEL:
1306 type = _("Fresh Volume");
1307 break;
1308 case VOL_LABEL:
1309 type = _("Volume");
1310 break;
1311 case SOS_LABEL:
1312 type = _("Begin Job Session");
1313 break;
1314 case EOS_LABEL:
1315 type = _("End Job Session");
1316 break;
1317 case EOM_LABEL:
1318 type = _("End of Media");
1319 break;
1320 case EOT_LABEL:
1321 type = _("End of Tape");
1322 break;
1323 default:
1324 type = _("Unknown");
1325 break;
1326 }
1327 if (verbose) {
1328 switch (rec->FileIndex) {
1329 case PRE_LABEL:
1330 case VOL_LABEL:
1331 unser_volume_label(dev, rec);
1332 dev->dump_volume_label();
1333 break;
1334
1335 case EOS_LABEL:
1336 case SOS_LABEL:
1337 dump_session_label(rec, type);
1338 break;
1339 case EOM_LABEL:
1340 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1341 type, dev->file, dev->block_num, rec->VolSessionId,
1342 rec->VolSessionTime, rec->Stream, rec->data_len);
1343 break;
1344 case EOT_LABEL:
1345 Pmsg0(-1, _("Bacula \"End of Tape\" label found.\n"));
1346 break;
1347 default:
1348 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1349 type, dev->file, dev->block_num, rec->VolSessionId,
1350 rec->VolSessionTime, rec->Stream, rec->data_len);
1351 break;
1352 }
1353 } else {
1354 SESSION_LABEL label;
1355 char dt[50];
1356 switch (rec->FileIndex) {
1357 case SOS_LABEL:
1358 unser_session_label(&label, rec);
1359 bstrftimes(dt, sizeof(dt), btime_to_utime(label.write_btime));
1360 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1361 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1362 Pmsg4(-1, _(" Job=%s Date=%s Level=%c Type=%c\n"),
1363 label.Job, dt, label.JobLevel, label.JobType);
1364 if (check_err) {
1365 errors += check_label(&label);
1366 }
1367 break;
1368 case EOS_LABEL:
1369 char ed1[30], ed2[30];
1370 unser_session_label(&label, rec);
1371 bstrftimes(dt, sizeof(dt), btime_to_utime(label.write_btime));
1372 Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1373 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1374 Pmsg7(-1, _(" Date=%s Level=%c Type=%c Files=%s Bytes=%s Errors=%d Status=%c\n"),
1375 dt, label.JobLevel, label.JobType,
1376 edit_uint64_with_commas(label.JobFiles, ed1),
1377 edit_uint64_with_commas(label.JobBytes, ed2),
1378 label.JobErrors, (char)label.JobStatus);
1379 if (check_err) {
1380 errors += check_label(&label);
1381 }
1382 break;
1383 case EOM_LABEL:
1384 case PRE_LABEL:
1385 case VOL_LABEL:
1386 default:
1387 Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1388 type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime,
1389 rec->Stream, rec->data_len);
1390 break;
1391 case EOT_LABEL:
1392 break;
1393 }
1394 }
1395 debug_level = dbl;
1396 return errors;
1397 }
1398