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