]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/label.c
Eliminate dependency on man2html.
[bacula/bacula] / bacula / src / stored / label.c
1 /*
2  *
3  *  label.c  Bacula routines to handle labels
4  *
5  *   Kern Sibbald, MM
6  *
7  *
8  *   Version $Id$
9  */
10 /*
11    Copyright (C) 2000-2006 Kern Sibbald
12
13    This program is free software; you can redistribute it and/or
14    modify it under the terms of the GNU General Public License
15    version 2 as amended with additional clauses defined in the
16    file LICENSE in the main source directory.
17
18    This program is distributed in the hope that it will be useful,
19    but WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
21    the file LICENSE for additional details.
22
23  */
24
25 #include "bacula.h"                   /* pull in global headers */
26 #include "stored.h"                   /* pull in Storage Deamon headers */
27
28 /* Forward referenced functions */
29 static void create_volume_label_record(DCR *dcr, DEV_RECORD *rec);
30
31 /*
32  * Read the volume label
33  *
34  *  If dcr->VolumeName == NULL, we accept any Bacula Volume
35  *  If dcr->VolumeName[0] == 0, we accept any Bacula Volume
36  *  otherwise dcr->VolumeName must match the Volume.
37  *
38  *  If VolName given, ensure that it matches
39  *
40  *  Returns VOL_  code as defined in record.h
41  *    VOL_NOT_READ
42  *    VOL_OK                          good label found
43  *    VOL_NO_LABEL                    volume not labeled
44  *    VOL_IO_ERROR                    I/O error reading tape
45  *    VOL_NAME_ERROR                  label has wrong name
46  *    VOL_CREATE_ERROR                Error creating label
47  *    VOL_VERSION_ERROR               label has wrong version
48  *    VOL_LABEL_ERROR                 bad label type
49  *    VOL_NO_MEDIA                    no media in drive
50  *
51  *  The dcr block is emptied on return, and the Volume is
52  *    rewound.
53  */
54 int read_dev_volume_label(DCR *dcr)
55 {
56    JCR *jcr = dcr->jcr;
57    DEVICE *dev = dcr->dev;
58    char *VolName = dcr->VolumeName;
59    DEV_RECORD *record;
60    bool ok = false;
61    DEV_BLOCK *block = dcr->block;
62    int stat;
63    bool want_ansi_label;
64    bool have_ansi_label = false;
65
66    Dmsg4(100, "Enter read_volume_label res=%d device=%s vol=%s dev_Vol=%s\n",
67       dev->reserved_device, dev->print_name(), VolName, 
68       dev->VolHdr.VolumeName[0]?dev->VolHdr.VolumeName:"*NULL*");
69
70    if (!dev->is_open()) {
71       if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
72          return VOL_IO_ERROR;
73       }
74    }
75    if (dev->is_labeled()) {              /* did we already read label? */
76       /* Compare Volume Names allow special wild card */
77       if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolumeName, VolName) != 0) {
78          Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
79             dev->print_name(), VolName, dev->VolHdr.VolumeName);
80          /*
81           * Cancel Job if too many label errors
82           *  => we are in a loop
83           */
84          if (!dev->poll && jcr->label_errors++ > 100) {
85             Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
86          }
87          Dmsg0(150, "return VOL_NAME_ERROR\n");
88          stat = VOL_NAME_ERROR;
89          goto bail_out;
90       }
91       Dmsg0(30, "Leave read_volume_label() VOL_OK\n");
92       return VOL_OK;       /* label already read */
93    }
94
95    dev->clear_labeled();
96    dev->clear_append();
97    dev->clear_read();
98    dev->label_type = B_BACULA_LABEL;
99
100    if (!dev->rewind(dcr)) {
101       Mmsg(jcr->errmsg, _("Couldn't rewind device %s: ERR=%s\n"), 
102          dev->print_name(), dev->print_errmsg());
103       Dmsg1(30, "return VOL_NO_MEDIA: %s", jcr->errmsg);
104       return VOL_NO_MEDIA;
105    }
106    bstrncpy(dev->VolHdr.Id, "**error**", sizeof(dev->VolHdr.Id));
107
108   /* Read ANSI/IBM label if so requested */
109   
110   want_ansi_label = dcr->VolCatInfo.LabelType != B_BACULA_LABEL ||
111                     dcr->device->label_type != B_BACULA_LABEL;
112   if (want_ansi_label || dev_cap(dev, CAP_CHECKLABELS)) {
113       stat = read_ansi_ibm_label(dcr);            
114       /* If we want a label and didn't find it, return error */
115       if (want_ansi_label && stat != VOL_OK) {
116          goto bail_out;
117       }
118       if (stat == VOL_NAME_ERROR || stat == VOL_LABEL_ERROR) {
119          Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
120               dev->print_name(), VolName, dev->VolHdr.VolumeName);
121          if (!dev->poll && jcr->label_errors++ > 100) {
122             Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
123          }
124          goto bail_out;
125       }
126       if (stat != VOL_OK) {           /* Not an ANSI/IBM label, so re-read */
127          dev->rewind(dcr);
128       } else {
129          have_ansi_label = true;
130       }
131    }
132   
133    /* Read the Bacula Volume label block */
134    record = new_record();
135    empty_block(block);
136
137    Dmsg0(90, "Big if statement in read_volume_label\n");
138    if (!read_block_from_dev(dcr, NO_BLOCK_NUMBER_CHECK)) {
139       Mmsg(jcr->errmsg, _("Requested Volume \"%s\" on %s is not a Bacula "
140            "labeled Volume, because: ERR=%s"), NPRT(VolName), 
141            dev->print_name(), dev->print_errmsg());
142       Dmsg1(30, "%s", jcr->errmsg);
143    } else if (!read_record_from_block(block, record)) {
144       Mmsg(jcr->errmsg, _("Could not read Volume label from block.\n"));
145       Dmsg1(30, "%s", jcr->errmsg);
146    } else if (!unser_volume_label(dev, record)) {
147       Mmsg(jcr->errmsg, _("Could not unserialize Volume label: ERR=%s\n"),
148          dev->print_errmsg());
149       Dmsg1(30, "%s", jcr->errmsg);
150    } else if (strcmp(dev->VolHdr.Id, BaculaId) != 0 &&
151               strcmp(dev->VolHdr.Id, OldBaculaId) != 0) {
152       Mmsg(jcr->errmsg, _("Volume Header Id bad: %s\n"), dev->VolHdr.Id);
153       Dmsg1(30, "%s", jcr->errmsg);
154    } else {
155       ok = true;
156    }
157    free_record(record);               /* finished reading Volume record */
158
159    if (!ok) {
160       if (forge_on || jcr->ignore_label_errors) {
161          dev->set_labeled();         /* set has Bacula label */
162          Jmsg(jcr, M_ERROR, 0, "%s", jcr->errmsg);
163          empty_block(block);
164          return VOL_OK;
165       }
166       Dmsg0(100, "No volume label - bailing out\n");
167       stat = VOL_NO_LABEL;
168       goto bail_out;
169    }
170
171    /* At this point, we have read the first Bacula block, and
172     * then read the Bacula Volume label. Now we need to
173     * make sure we have the right Volume.
174     */
175
176
177    if (dev->VolHdr.VerNum != BaculaTapeVersion &&
178        dev->VolHdr.VerNum != OldCompatibleBaculaTapeVersion1 &&
179        dev->VolHdr.VerNum != OldCompatibleBaculaTapeVersion2) {
180       Mmsg(jcr->errmsg, _("Volume on %s has wrong Bacula version. Wanted %d got %d\n"),
181          dev->print_name(), BaculaTapeVersion, dev->VolHdr.VerNum);
182       Dmsg1(30, "VOL_VERSION_ERROR: %s", jcr->errmsg);
183       stat = VOL_VERSION_ERROR;
184       goto bail_out;
185    }
186
187    /* We are looking for either an unused Bacula tape (PRE_LABEL) or
188     * a Bacula volume label (VOL_LABEL)
189     */
190    if (dev->VolHdr.LabelType != PRE_LABEL && dev->VolHdr.LabelType != VOL_LABEL) {
191       Mmsg(jcr->errmsg, _("Volume on %s has bad Bacula label type: %x\n"),
192           dev->print_name(), dev->VolHdr.LabelType);
193       Dmsg1(30, "%s", jcr->errmsg);
194       if (!dev->poll && jcr->label_errors++ > 100) {
195          Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
196       }
197       Dmsg0(150, "return VOL_LABEL_ERROR\n");
198       stat = VOL_LABEL_ERROR;
199       goto bail_out;
200    }
201
202    dev->set_labeled();               /* set has Bacula label */
203    new_volume(dcr, dev->VolHdr.VolumeName);
204
205    /* Compare Volume Names */
206    Dmsg2(30, "Compare Vol names: VolName=%s hdr=%s\n", VolName?VolName:"*", dev->VolHdr.VolumeName);
207    if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolumeName, VolName) != 0) {
208       Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
209            dev->print_name(), VolName, dev->VolHdr.VolumeName);
210       Dmsg1(30, "%s", jcr->errmsg);
211       /*
212        * Cancel Job if too many label errors
213        *  => we are in a loop
214        */
215       if (!dev->poll && jcr->label_errors++ > 100) {
216          Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
217       }
218       Dmsg0(150, "return VOL_NAME_ERROR\n");
219       stat = VOL_NAME_ERROR;
220       goto bail_out;
221    }
222    Dmsg1(30, "Copy vol_name=%s\n", dev->VolHdr.VolumeName);
223
224    if (debug_level >= 10) {
225       dump_volume_label(dev);
226    }
227    Dmsg0(30, "Leave read_volume_label() VOL_OK\n");
228    /* If we are a streaming device, we only get one chance to read */
229    if (!dev_cap(dev, CAP_STREAM)) {
230       dev->rewind(dcr);
231       if (have_ansi_label) {
232          stat = read_ansi_ibm_label(dcr);            
233          /* If we want a label and didn't find it, return error */
234          if (stat != VOL_OK) {
235             goto bail_out;
236          }
237       }
238    }
239    empty_block(block);
240    return VOL_OK;
241
242 bail_out:
243    empty_block(block);
244    dev->rewind(dcr);
245    Dmsg1(150, "return %d\n", stat);
246    return stat;
247 }
248
249 /*
250  * Put a volume label into the block
251  *
252  *  Returns: false on failure
253  *           true  on success
254  */
255 bool write_volume_label_to_block(DCR *dcr)
256 {
257    DEV_RECORD rec;
258    DEVICE *dev = dcr->dev;
259    JCR *jcr = dcr->jcr;
260    DEV_BLOCK *block = dcr->block;
261
262    Dmsg0(20, "write Label in write_volume_label_to_block()\n");
263    memset(&rec, 0, sizeof(rec));
264    rec.data = get_memory(SER_LENGTH_Volume_Label);
265    empty_block(block);                /* Volume label always at beginning */
266
267    create_volume_label_record(dcr, &rec);
268
269    block->BlockNumber = 0;
270    if (!write_record_to_block(block, &rec)) {
271       free_pool_memory(rec.data);
272       Jmsg1(jcr, M_FATAL, 0, _("Cannot write Volume label to block for device %s\n"),
273          dev->print_name());
274       return false;
275    } else {
276       Dmsg1(90, "Wrote label of %d bytes to block\n", rec.data_len);
277    }
278    free_pool_memory(rec.data);
279    return true;
280 }
281
282
283 /*
284  * Write a Volume Label
285  *  !!! Note, this is ONLY used for writing
286  *            a fresh volume label.  Any data
287  *            after the label will be destroyed,
288  *            in fact, we write the label 5 times !!!!
289  *
290  *  This routine should be used only when labeling a blank tape.
291  */
292 bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName, 
293                                    const char *PoolName, bool relabel, bool dvdnow)
294 {
295    DEVICE *dev = dcr->dev;
296
297
298    Dmsg0(99, "write_volume_label()\n");
299    empty_block(dcr->block);
300
301    /* If relabeling, truncate the device */
302    if (relabel && !dev->truncate(dcr)) {
303       goto bail_out;
304    }
305
306    if (relabel) {
307       dev->close_part(dcr);              /* make sure closed for rename */
308    }
309
310    /* Set the new filename for open, ... */
311    bstrncpy(dev->VolCatInfo.VolCatName, VolName, sizeof(dev->VolCatInfo.VolCatName));
312    bstrncpy(dcr->VolCatInfo.VolCatName, VolName, sizeof(dcr->VolCatInfo.VolCatName));
313    Dmsg1(150, "New VolName=%s\n", VolName);
314    if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
315       /* If device is not tape, attempt to create it */
316       if (dev->is_tape() || dev->open(dcr, CREATE_READ_WRITE) < 0) {
317          goto bail_out;
318       }
319    }
320    Dmsg1(150, "Label type=%d\n", dev->label_type);
321    if (!dev->rewind(dcr)) {
322       free_volume(dev);
323       memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
324       Dmsg2(30, "Bad status on %s from rewind: ERR=%s\n", dev->print_name(), dev->print_errmsg());
325       if (!forge_on) {
326          goto bail_out;
327       }
328    }
329
330    /* Create PRE_LABEL or VOL_LABEL if DVD */
331    create_volume_label(dev, VolName, PoolName, dvdnow);
332
333    /*
334     * If we have already detected an ANSI label, re-read it
335     *   to skip past it. Otherwise, we write a new one if 
336     *   so requested.  
337     */
338    if (dev->label_type != B_BACULA_LABEL) {
339       if (read_ansi_ibm_label(dcr) != VOL_OK) {
340          dev->rewind(dcr);
341          goto bail_out;
342       }
343    } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, VolName)) {
344       goto bail_out;
345    }
346
347    create_volume_label_record(dcr, dcr->rec);
348    dcr->rec->Stream = 0;
349
350    /* Temporarily mark in append state to enable writing */
351    dev->set_append();
352    if (!write_record_to_block(dcr->block, dcr->rec)) {
353       Dmsg2(30, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
354       goto bail_out;
355    } else {
356       Dmsg2(30, "Wrote label of %d bytes to %s\n", dcr->rec->data_len, dev->print_name());
357    }
358
359    Dmsg0(99, "Call write_block_to_dev()\n");
360    if (!write_block_to_dev(dcr)) {
361       Dmsg2(30, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
362       goto bail_out;
363    }
364
365    /* Now commit block to DVD if we should write now */
366    if (dev->is_dvd() && dvdnow) {
367       Dmsg1(150, "New VolName=%s\n", dev->VolCatInfo.VolCatName);
368       if (!dvd_write_part(dcr)) {
369          Dmsg2(30, "Bad DVD write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
370          goto bail_out;
371       }
372    }
373
374    Dmsg0(99, " Wrote block to device\n");
375
376    if (dev->weof(1)) {
377       dev->set_labeled();
378       write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
379    }
380
381    if (debug_level >= 20)  {
382       dump_volume_label(dev);
383    }
384    new_volume(dcr, VolName);
385    dev->clear_append();               /* remove append since this is PRE_LABEL */
386    return true;
387
388 bail_out:
389    free_volume(dev);
390    memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
391    dev->clear_append();               /* remove append since this is PRE_LABEL */
392    return false;
393 }
394
395 /*
396  * Write a volume label. This is ONLY called if we have a valid Bacula
397  *   label of type PRE_LABEL;
398  *  Returns: true if OK
399  *           false if unable to write it
400  */
401 bool rewrite_volume_label(DCR *dcr, bool recycle)
402 {
403    DEVICE *dev = dcr->dev;
404    JCR *jcr = dcr->jcr;
405
406    if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
407       return false;
408    }
409    Dmsg2(190, "set append found freshly labeled volume. fd=%d dev=%x\n", dev->fd, dev);
410    dev->VolHdr.LabelType = VOL_LABEL; /* set Volume label */
411    dev->set_append();
412    if (!write_volume_label_to_block(dcr)) {
413       Dmsg0(200, "Error from write volume label.\n");
414       return false;
415    }
416
417    dev->VolCatInfo.VolCatBytes = 0;        /* reset byte count */
418
419    /*
420     * If we are not dealing with a streaming device,
421     *  write the block now to ensure we have write permission.
422     *  It is better to find out now rather than later.
423     * We do not write the block now if this is an ANSI label. This
424     *  avoids re-writing the ANSI label, which we do not want to do.
425     */
426    if (!dev_cap(dev, CAP_STREAM)) {
427       if (!dev->rewind(dcr)) {
428          Jmsg2(jcr, M_FATAL, 0, _("Rewind error on device %s: ERR=%s\n"),
429                dev->print_name(), dev->print_errmsg());
430          return false;
431       }
432       if (recycle) {
433          if (!dev->truncate(dcr)) {
434             Jmsg2(jcr, M_FATAL, 0, _("Truncate error on device %s: ERR=%s\n"),
435                   dev->print_name(), dev->print_errmsg());
436             return false;
437          }
438          if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
439             Jmsg2(jcr, M_FATAL, 0,
440                _("Failed to re-open DVD after truncate on device %s: ERR=%s\n"),
441                dev->print_name(), dev->print_errmsg());
442             return false;
443          }
444       }
445
446       /*
447        * If we have already detected an ANSI label, re-read it
448        *   to skip past it. Otherwise, we write a new one if 
449        *   so requested.  
450        */
451       if (dev->label_type != B_BACULA_LABEL) {
452          if (read_ansi_ibm_label(dcr) != VOL_OK) {
453             dev->rewind(dcr);
454             return false;
455          }
456       } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, dev->VolHdr.VolumeName)) {
457          return false;
458       }
459
460       /* Attempt write to check write permission */
461       Dmsg1(200, "Attempt to write to device fd=%d.\n", dev->fd);
462       if (!write_block_to_dev(dcr)) {
463          Jmsg2(jcr, M_ERROR, 0, _("Unable to write device %s: ERR=%s\n"),
464             dev->print_name(), dev->print_errmsg());
465          Dmsg0(200, "===ERROR write block to dev\n");
466          return false;
467       }
468    }
469    dev->set_labeled();
470    /* Set or reset Volume statistics */
471    dev->VolCatInfo.VolCatJobs = 0;
472    dev->VolCatInfo.VolCatFiles = 0;
473    dev->VolCatInfo.VolCatErrors = 0;
474    dev->VolCatInfo.VolCatBlocks = 0;
475    dev->VolCatInfo.VolCatRBytes = 0;
476    if (recycle) {
477       dev->VolCatInfo.VolCatMounts++;
478       dev->VolCatInfo.VolCatRecycles++;
479    } else {
480       dev->VolCatInfo.VolCatMounts = 1;
481       dev->VolCatInfo.VolCatRecycles = 0;
482       dev->VolCatInfo.VolCatWrites = 1;
483       dev->VolCatInfo.VolCatReads = 1;
484    }
485    Dmsg0(150, "dir_update_vol_info. Set Append\n");
486    bstrncpy(dev->VolCatInfo.VolCatStatus, "Append", sizeof(dev->VolCatInfo.VolCatStatus));
487    if (!dir_update_volume_info(dcr, true)) {  /* indicate doing relabel */
488       return false;
489    }
490    if (recycle) {
491       Jmsg(jcr, M_INFO, 0, _("Recycled volume \"%s\" on device %s, all previous data lost.\n"),
492          dcr->VolumeName, dev->print_name());
493    } else {
494       Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume \"%s\" on device %s\n"),
495          dcr->VolumeName, dev->print_name());
496    }
497    /*
498     * End writing real Volume label (from pre-labeled tape), or recycling
499     *  the volume.
500     */
501    Dmsg0(200, "OK from rewrite vol label.\n");
502    return true;
503 }
504
505
506 /*
507  *  create_volume_label_record
508  *   Serialize label (from dev->VolHdr structure) into device record.
509  *   Assumes that the dev->VolHdr structure is properly
510  *   initialized.
511 */
512 static void create_volume_label_record(DCR *dcr, DEV_RECORD *rec)
513 {
514    ser_declare;
515    struct date_time dt;
516    DEVICE *dev = dcr->dev;
517    JCR *jcr = dcr->jcr;
518    char buf[100];
519
520    /* Serialize the label into the device record. */
521
522    rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
523    ser_begin(rec->data, SER_LENGTH_Volume_Label);
524    ser_string(dev->VolHdr.Id);
525
526    ser_uint32(dev->VolHdr.VerNum);
527
528    if (dev->VolHdr.VerNum >= 11) {
529       ser_btime(dev->VolHdr.label_btime);
530       dev->VolHdr.write_btime = get_current_btime();
531       ser_btime(dev->VolHdr.write_btime);
532       dev->VolHdr.write_date = 0;
533       dev->VolHdr.write_time = 0;
534    } else {
535       /* OLD WAY DEPRECATED */
536       ser_float64(dev->VolHdr.label_date);
537       ser_float64(dev->VolHdr.label_time);
538       get_current_time(&dt);
539       dev->VolHdr.write_date = dt.julian_day_number;
540       dev->VolHdr.write_time = dt.julian_day_fraction;
541    }
542    ser_float64(dev->VolHdr.write_date);   /* 0 if VerNum >= 11 */
543    ser_float64(dev->VolHdr.write_time);   /* 0  if VerNum >= 11 */
544
545    ser_string(dev->VolHdr.VolumeName);
546    ser_string(dev->VolHdr.PrevVolumeName);
547    ser_string(dev->VolHdr.PoolName);
548    ser_string(dev->VolHdr.PoolType);
549    ser_string(dev->VolHdr.MediaType);
550
551    ser_string(dev->VolHdr.HostName);
552    ser_string(dev->VolHdr.LabelProg);
553    ser_string(dev->VolHdr.ProgVersion);
554    ser_string(dev->VolHdr.ProgDate);
555
556    ser_end(rec->data, SER_LENGTH_Volume_Label);
557    rec->data_len = ser_length(rec->data);
558    rec->FileIndex = dev->VolHdr.LabelType;
559    rec->VolSessionId = jcr->VolSessionId;
560    rec->VolSessionTime = jcr->VolSessionTime;
561    rec->Stream = jcr->NumVolumes;
562    Dmsg2(150, "Created Vol label rec: FI=%s len=%d\n", FI_to_ascii(buf, rec->FileIndex),
563       rec->data_len);
564 }
565
566
567 /*
568  * Create a volume label in memory
569  */
570 void create_volume_label(DEVICE *dev, const char *VolName, 
571                          const char *PoolName, bool dvdnow)
572 {
573    DEVRES *device = (DEVRES *)dev->device;
574
575    Dmsg0(90, "Start create_volume_label()\n");
576
577    ASSERT(dev != NULL);
578
579    free_volume(dev);         /* release any old volume */
580    memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
581
582    bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
583    dev->VolHdr.VerNum = BaculaTapeVersion;
584    if (dev->is_dvd() && dvdnow) {
585       /* We do not want to re-label a DVD so write VOL_LABEL now */
586       dev->VolHdr.LabelType = VOL_LABEL;
587    } else {
588       dev->VolHdr.LabelType = PRE_LABEL;  /* Mark tape as unused */
589    }
590    bstrncpy(dev->VolHdr.VolumeName, VolName, sizeof(dev->VolHdr.VolumeName));
591    bstrncpy(dev->VolHdr.PoolName, PoolName, sizeof(dev->VolHdr.PoolName));
592    bstrncpy(dev->VolHdr.MediaType, device->media_type, sizeof(dev->VolHdr.MediaType));
593
594    bstrncpy(dev->VolHdr.PoolType, "Backup", sizeof(dev->VolHdr.PoolType));
595
596    dev->VolHdr.label_btime = get_current_btime();
597    dev->VolHdr.label_date = 0;
598    dev->VolHdr.label_time = 0;
599
600    if (gethostname(dev->VolHdr.HostName, sizeof(dev->VolHdr.HostName)) != 0) {
601       dev->VolHdr.HostName[0] = 0;
602    }
603    bstrncpy(dev->VolHdr.LabelProg, my_name, sizeof(dev->VolHdr.LabelProg));
604    sprintf(dev->VolHdr.ProgVersion, "Ver. %s %s", VERSION, BDATE);
605    sprintf(dev->VolHdr.ProgDate, "Build %s %s", __DATE__, __TIME__);
606    dev->set_labeled();               /* set has Bacula label */
607    if (debug_level >= 90) {
608       dump_volume_label(dev);
609    }
610 }
611
612 /*
613  * Create session label
614  *  The pool memory must be released by the calling program
615  */
616 void create_session_label(DCR *dcr, DEV_RECORD *rec, int label)
617 {
618    JCR *jcr = dcr->jcr;
619    ser_declare;
620
621    rec->VolSessionId   = jcr->VolSessionId;
622    rec->VolSessionTime = jcr->VolSessionTime;
623    rec->Stream         = jcr->JobId;
624
625    rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
626    ser_begin(rec->data, SER_LENGTH_Session_Label);
627    ser_string(BaculaId);
628    ser_uint32(BaculaTapeVersion);
629
630    ser_uint32(jcr->JobId);
631
632    /* Changed in VerNum 11 */
633    ser_btime(get_current_btime());
634    ser_float64(0);
635
636    ser_string(dcr->pool_name);
637    ser_string(dcr->pool_type);
638    ser_string(jcr->job_name);         /* base Job name */
639    ser_string(jcr->client_name);
640
641    /* Added in VerNum 10 */
642    ser_string(jcr->Job);              /* Unique name of this Job */
643    ser_string(jcr->fileset_name);
644    ser_uint32(jcr->JobType);
645    ser_uint32(jcr->JobLevel);
646    /* Added in VerNum 11 */
647    ser_string(jcr->fileset_md5);
648
649    if (label == EOS_LABEL) {
650       ser_uint32(jcr->JobFiles);
651       ser_uint64(jcr->JobBytes);
652       ser_uint32(dcr->StartBlock);
653       ser_uint32(dcr->EndBlock);
654       ser_uint32(dcr->StartFile);
655       ser_uint32(dcr->EndFile);
656       ser_uint32(jcr->JobErrors);
657
658       /* Added in VerNum 11 */
659       ser_uint32(jcr->JobStatus);
660    }
661    ser_end(rec->data, SER_LENGTH_Session_Label);
662    rec->data_len = ser_length(rec->data);
663 }
664
665 /* Write session label
666  *  Returns: false on failure
667  *           true  on success
668  */
669 bool write_session_label(DCR *dcr, int label)
670 {
671    JCR *jcr = dcr->jcr;
672    DEVICE *dev = dcr->dev;
673    DEV_RECORD *rec;
674    DEV_BLOCK *block = dcr->block;
675    char buf1[100], buf2[100];
676
677    rec = new_record();
678    Dmsg1(90, "session_label record=%x\n", rec);
679    switch (label) {
680    case SOS_LABEL:
681       if (dev->is_tape()) {
682          dcr->StartBlock = dev->block_num;
683          dcr->StartFile  = dev->file;
684       } else {
685          dcr->StartBlock = (uint32_t)dev->file_addr;
686          dcr->StartFile = (uint32_t)(dev->file_addr >> 32);
687       }
688       break;
689    case EOS_LABEL:
690       if (dev->is_tape()) {
691          dcr->EndBlock = dev->EndBlock;
692          dcr->EndFile  = dev->EndFile;
693       } else {
694          dcr->EndBlock = (uint32_t)dev->file_addr;
695          dcr->EndFile = (uint32_t)(dev->file_addr >> 32);
696       }
697       break;
698    default:
699       Jmsg1(jcr, M_ABORT, 0, _("Bad session label = %d\n"), label);
700       break;
701    }
702    create_session_label(dcr, rec, label);
703    rec->FileIndex = label;
704
705    /*
706     * We guarantee that the session record can totally fit
707     *  into a block. If not, write the block, and put it in
708     *  the next block. Having the sesssion record totally in
709     *  one block makes reading them much easier (no need to
710     *  read the next block).
711     */
712    if (!can_write_record_to_block(block, rec)) {
713       Dmsg0(150, "Cannot write session label to block.\n");
714       if (!write_block_to_device(dcr)) {
715          Dmsg0(90, "Got session label write_block_to_dev error.\n");
716          /* ****FIXME***** errno is not set here */
717          Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"),
718                            dev_vol_name(dev), strerror(errno));
719          free_record(rec);
720          return false;
721       }
722    }
723    if (!write_record_to_block(block, rec)) {
724       Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"),
725                         dev_vol_name(dev), strerror(errno));
726       free_record(rec);
727       return false;
728    }
729
730    Dmsg6(50, "Write sesson_label record JobId=%d FI=%s SessId=%d Strm=%s len=%d "
731              "remainder=%d\n", jcr->JobId,
732       FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
733       stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
734       rec->remainder);
735
736    free_record(rec);
737    Dmsg2(50, "Leave write_session_label Block=%ud File=%ud\n",
738       dev->get_block(), dev->get_file());
739    return true;
740 }
741
742 /*  unser_volume_label
743  *
744  * Unserialize the Bacula Volume label into the device Volume_Label
745  * structure.
746  *
747  * Assumes that the record is already read.
748  *
749  * Returns: false on error
750  *          true  on success
751 */
752
753 bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec)
754 {
755    ser_declare;
756    char buf1[100], buf2[100];
757
758    if (rec->FileIndex != VOL_LABEL && rec->FileIndex != PRE_LABEL) {
759       Mmsg3(dev->errmsg, _("Expecting Volume Label, got FI=%s Stream=%s len=%d\n"),
760               FI_to_ascii(buf1, rec->FileIndex),
761               stream_to_ascii(buf2, rec->Stream, rec->FileIndex),
762               rec->data_len);
763       if (!forge_on) {
764          return false;
765       }
766    }
767
768    dev->VolHdr.LabelType = rec->FileIndex;
769    dev->VolHdr.LabelSize = rec->data_len;
770
771
772    /* Unserialize the record into the Volume Header */
773    rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
774    ser_begin(rec->data, SER_LENGTH_Volume_Label);
775    unser_string(dev->VolHdr.Id);
776    unser_uint32(dev->VolHdr.VerNum);
777
778    if (dev->VolHdr.VerNum >= 11) {
779       unser_btime(dev->VolHdr.label_btime);
780       unser_btime(dev->VolHdr.write_btime);
781    } else { /* old way */
782       unser_float64(dev->VolHdr.label_date);
783       unser_float64(dev->VolHdr.label_time);
784    }
785    unser_float64(dev->VolHdr.write_date);    /* Unused with VerNum >= 11 */
786    unser_float64(dev->VolHdr.write_time);    /* Unused with VerNum >= 11 */
787
788    unser_string(dev->VolHdr.VolumeName);
789    unser_string(dev->VolHdr.PrevVolumeName);
790    unser_string(dev->VolHdr.PoolName);
791    unser_string(dev->VolHdr.PoolType);
792    unser_string(dev->VolHdr.MediaType);
793
794    unser_string(dev->VolHdr.HostName);
795    unser_string(dev->VolHdr.LabelProg);
796    unser_string(dev->VolHdr.ProgVersion);
797    unser_string(dev->VolHdr.ProgDate);
798
799    ser_end(rec->data, SER_LENGTH_Volume_Label);
800    Dmsg0(190, "unser_vol_label\n");
801    if (debug_level >= 190) {
802       dump_volume_label(dev);
803    }
804    return true;
805 }
806
807
808 bool unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec)
809 {
810    ser_declare;
811
812    rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
813    unser_begin(rec->data, SER_LENGTH_Session_Label);
814    unser_string(label->Id);
815    unser_uint32(label->VerNum);
816    unser_uint32(label->JobId);
817    if (label->VerNum >= 11) {
818       unser_btime(label->write_btime);
819    } else {
820       unser_float64(label->write_date);
821    }
822    unser_float64(label->write_time);
823    unser_string(label->PoolName);
824    unser_string(label->PoolType);
825    unser_string(label->JobName);
826    unser_string(label->ClientName);
827    if (label->VerNum >= 10) {
828       unser_string(label->Job);          /* Unique name of this Job */
829       unser_string(label->FileSetName);
830       unser_uint32(label->JobType);
831       unser_uint32(label->JobLevel);
832    }
833    if (label->VerNum >= 11) {
834       unser_string(label->FileSetMD5);
835    } else {
836       label->FileSetMD5[0] = 0;
837    }
838    if (rec->FileIndex == EOS_LABEL) {
839       unser_uint32(label->JobFiles);
840       unser_uint64(label->JobBytes);
841       unser_uint32(label->StartBlock);
842       unser_uint32(label->EndBlock);
843       unser_uint32(label->StartFile);
844       unser_uint32(label->EndFile);
845       unser_uint32(label->JobErrors);
846       if (label->VerNum >= 11) {
847          unser_uint32(label->JobStatus);
848       } else {
849          label->JobStatus = JS_Terminated; /* kludge */
850       }
851    }
852    return true;
853 }
854
855 void dump_volume_label(DEVICE *dev)
856 {
857    int dbl = debug_level;
858    uint32_t File;
859    const char *LabelType;
860    char buf[30];
861    struct tm tm;
862    struct date_time dt;
863
864    debug_level = 1;
865    File = dev->file;
866    switch (dev->VolHdr.LabelType) {
867    case PRE_LABEL:
868       LabelType = "PRE_LABEL";
869       break;
870    case VOL_LABEL:
871       LabelType = "VOL_LABEL";
872       break;
873    case EOM_LABEL:
874       LabelType = "EOM_LABEL";
875       break;
876    case SOS_LABEL:
877       LabelType = "SOS_LABEL";
878       break;
879    case EOS_LABEL:
880       LabelType = "EOS_LABEL";
881       break;
882    case EOT_LABEL:
883       goto bail_out;
884    default:
885       LabelType = buf;
886       sprintf(buf, _("Unknown %d"), dev->VolHdr.LabelType);
887       break;
888    }
889
890    Pmsg11(-1, _("\nVolume Label:\n"
891 "Id                : %s"
892 "VerNo             : %d\n"
893 "VolName           : %s\n"
894 "PrevVolName       : %s\n"
895 "VolFile           : %d\n"
896 "LabelType         : %s\n"
897 "LabelSize         : %d\n"
898 "PoolName          : %s\n"
899 "MediaType         : %s\n"
900 "PoolType          : %s\n"
901 "HostName          : %s\n"
902 ""),
903              dev->VolHdr.Id, dev->VolHdr.VerNum,
904              dev->VolHdr.VolumeName, dev->VolHdr.PrevVolumeName,
905              File, LabelType, dev->VolHdr.LabelSize,
906              dev->VolHdr.PoolName, dev->VolHdr.MediaType,
907              dev->VolHdr.PoolType, dev->VolHdr.HostName);
908
909    if (dev->VolHdr.VerNum >= 11) {
910       char dt[50];
911       bstrftime(dt, sizeof(dt), btime_to_unix(dev->VolHdr.label_btime));
912       Pmsg1(-1, _("Date label written: %s\n"), dt);
913    } else {
914    dt.julian_day_number   = dev->VolHdr.label_date;
915    dt.julian_day_fraction = dev->VolHdr.label_time;
916    tm_decode(&dt, &tm);
917    Pmsg5(-1,
918 _("Date label written: %04d-%02d-%02d at %02d:%02d\n"),
919       tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
920    }
921
922 bail_out:
923    debug_level = dbl;
924 }
925
926
927 static void dump_session_label(DEV_RECORD *rec, const char *type)
928 {
929    int dbl;
930    struct date_time dt;
931    struct tm tm;
932    SESSION_LABEL label;
933    char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], ec6[30], ec7[30];
934
935    unser_session_label(&label, rec);
936    dbl = debug_level;
937    debug_level = 1;
938    Pmsg7(-1, _("\n%s Record:\n"
939 "JobId             : %d\n"
940 "VerNum            : %d\n"
941 "PoolName          : %s\n"
942 "PoolType          : %s\n"
943 "JobName           : %s\n"
944 "ClientName        : %s\n"
945 ""),    type, label.JobId, label.VerNum,
946       label.PoolName, label.PoolType,
947       label.JobName, label.ClientName);
948
949    if (label.VerNum >= 10) {
950       Pmsg4(-1, _(
951 "Job (unique name) : %s\n"
952 "FileSet           : %s\n"
953 "JobType           : %c\n"
954 "JobLevel          : %c\n"
955 ""), label.Job, label.FileSetName, label.JobType, label.JobLevel);
956    }
957
958    if (rec->FileIndex == EOS_LABEL) {
959       Pmsg8(-1, _(
960 "JobFiles          : %s\n"
961 "JobBytes          : %s\n"
962 "StartBlock        : %s\n"
963 "EndBlock          : %s\n"
964 "StartFile         : %s\n"
965 "EndFile           : %s\n"
966 "JobErrors         : %s\n"
967 "JobStatus         : %c\n"
968 ""),
969          edit_uint64_with_commas(label.JobFiles, ec1),
970          edit_uint64_with_commas(label.JobBytes, ec2),
971          edit_uint64_with_commas(label.StartBlock, ec3),
972          edit_uint64_with_commas(label.EndBlock, ec4),
973          edit_uint64_with_commas(label.StartFile, ec5),
974          edit_uint64_with_commas(label.EndFile, ec6),
975          edit_uint64_with_commas(label.JobErrors, ec7),
976          label.JobStatus);
977    }
978    if (label.VerNum >= 11) {
979       char dt[50];
980       bstrftime(dt, sizeof(dt), btime_to_unix(label.write_btime));
981       Pmsg1(-1, _("Date written      : %s\n"), dt);
982    } else {
983       dt.julian_day_number   = label.write_date;
984       dt.julian_day_fraction = label.write_time;
985       tm_decode(&dt, &tm);
986       Pmsg5(-1, _("Date written      : %04d-%02d-%02d at %02d:%02d\n"),
987       tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
988    }
989
990    debug_level = dbl;
991 }
992
993 void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose)
994 {
995    const char *type;
996    int dbl;
997
998    if (rec->FileIndex == 0 && rec->VolSessionId == 0 && rec->VolSessionTime == 0) {
999       return;
1000    }
1001    dbl = debug_level;
1002    debug_level = 1;
1003    switch (rec->FileIndex) {
1004    case PRE_LABEL:
1005       type = _("Fresh Volume");
1006       break;
1007    case VOL_LABEL:
1008       type = _("Volume");
1009       break;
1010    case SOS_LABEL:
1011       type = _("Begin Job Session");
1012       break;
1013    case EOS_LABEL:
1014       type = _("End Job Session");
1015       break;
1016    case EOM_LABEL:
1017       type = _("End of Media");
1018       break;
1019    case EOT_LABEL:
1020       type = _("End of Tape");
1021       break;
1022    default:
1023       type = _("Unknown");
1024       break;
1025    }
1026    if (verbose) {
1027       switch (rec->FileIndex) {
1028       case PRE_LABEL:
1029       case VOL_LABEL:
1030          unser_volume_label(dev, rec);
1031          dump_volume_label(dev);
1032          break;
1033       case SOS_LABEL:
1034          dump_session_label(rec, type);
1035          break;
1036       case EOS_LABEL:
1037          dump_session_label(rec, type);
1038          break;
1039       case EOM_LABEL:
1040          Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1041             type, dev->file, dev->block_num, rec->VolSessionId, 
1042             rec->VolSessionTime, rec->Stream, rec->data_len);
1043          break;
1044       case EOT_LABEL:
1045          Pmsg0(-1, _("End of physical tape.\n"));
1046          break;
1047       default:
1048          Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1049             type, dev->file, dev->block_num, rec->VolSessionId, 
1050             rec->VolSessionTime, rec->Stream, rec->data_len);
1051          break;
1052       }
1053    } else {
1054       SESSION_LABEL label;
1055       char dt[50];
1056       switch (rec->FileIndex) {
1057       case SOS_LABEL:
1058          unser_session_label(&label, rec);
1059          bstrftimes(dt, sizeof(dt), btime_to_unix(label.write_btime));
1060          Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1061             type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1062          Pmsg4(-1, _("   Job=%s Date=%s Level=%c Type=%c\n"),
1063             label.Job, dt, label.JobLevel, label.JobType);
1064          break;
1065       case EOS_LABEL:
1066          char ed1[30], ed2[30];
1067          unser_session_label(&label, rec);
1068          bstrftimes(dt, sizeof(dt), btime_to_unix(label.write_btime));
1069          Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1070             type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1071          Pmsg7(-1, _("   Date=%s Level=%c Type=%c Files=%s Bytes=%s Errors=%d Status=%c\n"),
1072             dt, label.JobLevel, label.JobType,
1073             edit_uint64_with_commas(label.JobFiles, ed1),
1074             edit_uint64_with_commas(label.JobBytes, ed2),
1075             label.JobErrors, (char)label.JobStatus);
1076          break;
1077       case EOM_LABEL:
1078       case PRE_LABEL:
1079       case VOL_LABEL:
1080       default:
1081          Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1082             type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, 
1083             rec->Stream, rec->data_len);
1084          break;
1085       case EOT_LABEL:
1086          break;
1087       }
1088    }
1089    debug_level = dbl;
1090 }