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