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