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