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