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