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