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