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