]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/label.c
Missed commiting one file last time
[bacula/bacula] / bacula / src / stored / label.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2009 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       Dmsg1(100, "%s", dcr->jcr->errmsg);
402       goto bail_out;
403    }
404    dev = dcr->dev;                    /* may have changed in reserve_volume */
405
406    dev->clear_append();               /* remove append since this is PRE_LABEL */
407    return true;
408
409 bail_out:
410    volume_unused(dcr);
411    dev->clear_volhdr();
412    dev->clear_append();               /* remove append since this is PRE_LABEL */
413    return false;
414 }
415
416 /*
417  * Write a volume label. This is ONLY called if we have a valid Bacula
418  *   label of type PRE_LABEL or we are recyling an existing Volume.
419  *
420  *  Returns: true if OK
421  *           false if unable to write it
422  */
423 bool rewrite_volume_label(DCR *dcr, bool recycle)
424 {
425    DEVICE *dev = dcr->dev;
426    JCR *jcr = dcr->jcr;
427
428    if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
429        Jmsg3(jcr, M_WARNING, 0, _("Open device %s Volume \"%s\" failed: ERR=%s\n"),
430              dev->print_name(), dcr->VolumeName, dev->bstrerror());
431       return false;
432    }
433    Dmsg2(190, "set append found freshly labeled volume. fd=%d dev=%x\n", dev->fd(), dev);
434    dev->VolHdr.LabelType = VOL_LABEL; /* set Volume label */
435    dev->set_append();
436    if (!write_volume_label_to_block(dcr)) {
437       Dmsg0(200, "Error from write volume label.\n");
438       return false;
439    }
440    Dmsg1(150, "wrote vol label to block. Vol=%s\n", dcr->VolumeName);
441
442    dev->VolCatInfo.VolCatBytes = 0;        /* reset byte count */
443
444    /*
445     * If we are not dealing with a streaming device,
446     *  write the block now to ensure we have write permission.
447     *  It is better to find out now rather than later.
448     * We do not write the block now if this is an ANSI label. This
449     *  avoids re-writing the ANSI label, which we do not want to do.
450     */
451    if (!dev->has_cap(CAP_STREAM)) {
452       if (!dev->rewind(dcr)) {
453          Jmsg2(jcr, M_FATAL, 0, _("Rewind error on device %s: ERR=%s\n"),
454                dev->print_name(), dev->print_errmsg());
455          return false;
456       }
457       if (recycle) {
458          Dmsg1(150, "Doing recycle. Vol=%s\n", dcr->VolumeName);
459 //       volume_unused(dcr);             /* mark volume unused */
460          if (!dev->truncate(dcr)) {
461             Jmsg2(jcr, M_FATAL, 0, _("Truncate error on device %s: ERR=%s\n"),
462                   dev->print_name(), dev->print_errmsg());
463             return false;
464          }
465          if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
466             Jmsg2(jcr, M_FATAL, 0,
467                _("Failed to re-open DVD after truncate on device %s: ERR=%s\n"),
468                dev->print_name(), dev->print_errmsg());
469             return false;
470          }
471       }
472
473       /*
474        * If we have already detected an ANSI label, re-read it
475        *   to skip past it. Otherwise, we write a new one if 
476        *   so requested.  
477        */
478       if (dev->label_type != B_BACULA_LABEL) {
479          if (read_ansi_ibm_label(dcr) != VOL_OK) {
480             dev->rewind(dcr);
481             return false;
482          }
483       } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, dev->VolHdr.VolumeName)) {
484          return false;
485       }
486
487       /* Attempt write to check write permission */
488       Dmsg1(200, "Attempt to write to device fd=%d.\n", dev->fd());
489       if (!write_block_to_dev(dcr)) {
490          Jmsg2(jcr, M_ERROR, 0, _("Unable to write device %s: ERR=%s\n"),
491             dev->print_name(), dev->print_errmsg());
492          Dmsg0(200, "===ERROR write block to dev\n");
493          return false;
494       }
495    }
496    dev->set_labeled();
497    /* Set or reset Volume statistics */
498    dev->VolCatInfo.VolCatJobs = 0;
499    dev->VolCatInfo.VolCatFiles = 0;
500    dev->VolCatInfo.VolCatErrors = 0;
501    dev->VolCatInfo.VolCatBlocks = 0;
502    dev->VolCatInfo.VolCatRBytes = 0;
503    if (recycle) {
504       dev->VolCatInfo.VolCatMounts++;
505       dev->VolCatInfo.VolCatRecycles++;
506       dir_create_jobmedia_record(dcr, true);
507    } else {
508       dev->VolCatInfo.VolCatMounts = 1;
509       dev->VolCatInfo.VolCatRecycles = 0;
510       dev->VolCatInfo.VolCatWrites = 1;
511       dev->VolCatInfo.VolCatReads = 1;
512    }
513    Dmsg1(150, "dir_update_vol_info. Set Append vol=%s\n", dcr->VolumeName);
514    bstrncpy(dev->VolCatInfo.VolCatStatus, "Append", sizeof(dev->VolCatInfo.VolCatStatus));
515    bstrncpy(dev->VolCatInfo.VolCatName, dcr->VolumeName, sizeof(dev->VolCatInfo.VolCatName));
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    Dmsg1(150, "OK from rewrite vol label. Vol=%s\n", dcr->VolumeName);
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    bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName));
587    rec->data_len = ser_length(rec->data);
588    rec->FileIndex = dev->VolHdr.LabelType;
589    rec->VolSessionId = jcr->VolSessionId;
590    rec->VolSessionTime = jcr->VolSessionTime;
591    rec->Stream = jcr->NumWriteVolumes;
592    Dmsg2(150, "Created Vol label rec: FI=%s len=%d\n", FI_to_ascii(buf, rec->FileIndex),
593       rec->data_len);
594 }
595
596
597 /*
598  * Create a volume label in memory
599  */
600 void create_volume_label(DEVICE *dev, const char *VolName, 
601                          const char *PoolName, bool dvdnow)
602 {
603    DEVRES *device = (DEVRES *)dev->device;
604
605    Dmsg0(130, "Start create_volume_label()\n");
606
607    ASSERT(dev != NULL);
608
609    dev->clear_volhdr();          /* clear any old volume info */
610
611    bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
612    dev->VolHdr.VerNum = BaculaTapeVersion;
613    if (dev->is_dvd() && dvdnow) {
614       /* We do not want to re-label a DVD so write VOL_LABEL now */
615       dev->VolHdr.LabelType = VOL_LABEL;
616    } else {
617       dev->VolHdr.LabelType = PRE_LABEL;  /* Mark tape as unused */
618    }
619    bstrncpy(dev->VolHdr.VolumeName, VolName, sizeof(dev->VolHdr.VolumeName));
620    bstrncpy(dev->VolHdr.PoolName, PoolName, sizeof(dev->VolHdr.PoolName));
621    bstrncpy(dev->VolHdr.MediaType, device->media_type, sizeof(dev->VolHdr.MediaType));
622
623    bstrncpy(dev->VolHdr.PoolType, "Backup", sizeof(dev->VolHdr.PoolType));
624
625    dev->VolHdr.label_btime = get_current_btime();
626    dev->VolHdr.label_date = 0;
627    dev->VolHdr.label_time = 0;
628
629    if (gethostname(dev->VolHdr.HostName, sizeof(dev->VolHdr.HostName)) != 0) {
630       dev->VolHdr.HostName[0] = 0;
631    }
632    bstrncpy(dev->VolHdr.LabelProg, my_name, sizeof(dev->VolHdr.LabelProg));
633    sprintf(dev->VolHdr.ProgVersion, "Ver. %s %s", VERSION, BDATE);
634    sprintf(dev->VolHdr.ProgDate, "Build %s %s", __DATE__, __TIME__);
635    dev->set_labeled();               /* set has Bacula label */
636    if (debug_level >= 90) {
637       dump_volume_label(dev);
638    }
639 }
640
641 /*
642  * Create session label
643  *  The pool memory must be released by the calling program
644  */
645 void create_session_label(DCR *dcr, DEV_RECORD *rec, int label)
646 {
647    JCR *jcr = dcr->jcr;
648    ser_declare;
649
650    rec->VolSessionId   = jcr->VolSessionId;
651    rec->VolSessionTime = jcr->VolSessionTime;
652    rec->Stream         = jcr->JobId;
653
654    rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
655    ser_begin(rec->data, SER_LENGTH_Session_Label);
656    ser_string(BaculaId);
657    ser_uint32(BaculaTapeVersion);
658
659    ser_uint32(jcr->JobId);
660
661    /* Changed in VerNum 11 */
662    ser_btime(get_current_btime());
663    ser_float64(0);
664
665    ser_string(dcr->pool_name);
666    ser_string(dcr->pool_type);
667    ser_string(jcr->job_name);         /* base Job name */
668    ser_string(jcr->client_name);
669
670    /* Added in VerNum 10 */
671    ser_string(jcr->Job);              /* Unique name of this Job */
672    ser_string(jcr->fileset_name);
673    ser_uint32(jcr->get_JobType());
674    ser_uint32(jcr->get_JobLevel());
675    /* Added in VerNum 11 */
676    ser_string(jcr->fileset_md5);
677
678    if (label == EOS_LABEL) {
679       ser_uint32(jcr->JobFiles);
680       ser_uint64(jcr->JobBytes);
681       ser_uint32(dcr->StartBlock);
682       ser_uint32(dcr->EndBlock);
683       ser_uint32(dcr->StartFile);
684       ser_uint32(dcr->EndFile);
685       ser_uint32(jcr->JobErrors);
686
687       /* Added in VerNum 11 */
688       ser_uint32(jcr->JobStatus);
689    }
690    ser_end(rec->data, SER_LENGTH_Session_Label);
691    rec->data_len = ser_length(rec->data);
692 }
693
694 /* Write session label
695  *  Returns: false on failure
696  *           true  on success
697  */
698 bool write_session_label(DCR *dcr, int label)
699 {
700    JCR *jcr = dcr->jcr;
701    DEVICE *dev = dcr->dev;
702    DEV_RECORD *rec;
703    DEV_BLOCK *block = dcr->block;
704    char buf1[100], buf2[100];
705
706    rec = new_record();
707    Dmsg1(130, "session_label record=%x\n", rec);
708    switch (label) {
709    case SOS_LABEL:
710       set_start_vol_position(dcr);
711       break;
712    case EOS_LABEL:
713       if (dev->is_tape()) {
714          dcr->EndBlock = dev->EndBlock;
715          dcr->EndFile  = dev->EndFile;
716       } else {
717          dcr->EndBlock = (uint32_t)dev->file_addr;
718          dcr->EndFile = (uint32_t)(dev->file_addr >> 32);
719       }
720       break;
721    default:
722       Jmsg1(jcr, M_ABORT, 0, _("Bad Volume session label = %d\n"), label);
723       break;
724    }
725    create_session_label(dcr, rec, label);
726    rec->FileIndex = label;
727
728    /*
729     * We guarantee that the session record can totally fit
730     *  into a block. If not, write the block, and put it in
731     *  the next block. Having the sesssion record totally in
732     *  one block makes reading them much easier (no need to
733     *  read the next block).
734     */
735    if (!can_write_record_to_block(block, rec)) {
736       Dmsg0(150, "Cannot write session label to block.\n");
737       if (!write_block_to_device(dcr)) {
738          Dmsg0(130, "Got session label write_block_to_dev error.\n");
739          free_record(rec);
740          return false;
741       }
742    }
743    if (!write_record_to_block(block, rec)) {
744       free_record(rec);
745       return false;
746    }
747
748    Dmsg6(150, "Write sesson_label record JobId=%d FI=%s SessId=%d Strm=%s len=%d "
749              "remainder=%d\n", jcr->JobId,
750       FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
751       stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
752       rec->remainder);
753
754    free_record(rec);
755    Dmsg2(150, "Leave write_session_label Block=%ud File=%ud\n",
756       dev->get_block_num(), dev->get_file());
757    return true;
758 }
759
760 /*  unser_volume_label
761  *
762  * Unserialize the Bacula Volume label into the device Volume_Label
763  * structure.
764  *
765  * Assumes that the record is already read.
766  *
767  * Returns: false on error
768  *          true  on success
769 */
770
771 bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec)
772 {
773    ser_declare;
774    char buf1[100], buf2[100];
775
776    if (rec->FileIndex != VOL_LABEL && rec->FileIndex != PRE_LABEL) {
777       Mmsg3(dev->errmsg, _("Expecting Volume Label, got FI=%s Stream=%s len=%d\n"),
778               FI_to_ascii(buf1, rec->FileIndex),
779               stream_to_ascii(buf2, rec->Stream, rec->FileIndex),
780               rec->data_len);
781       if (!forge_on) {
782          return false;
783       }
784    }
785
786    dev->VolHdr.LabelType = rec->FileIndex;
787    dev->VolHdr.LabelSize = rec->data_len;
788
789
790    /* Unserialize the record into the Volume Header */
791    rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
792    ser_begin(rec->data, SER_LENGTH_Volume_Label);
793    unser_string(dev->VolHdr.Id);
794    unser_uint32(dev->VolHdr.VerNum);
795
796    if (dev->VolHdr.VerNum >= 11) {
797       unser_btime(dev->VolHdr.label_btime);
798       unser_btime(dev->VolHdr.write_btime);
799    } else { /* old way */
800       unser_float64(dev->VolHdr.label_date);
801       unser_float64(dev->VolHdr.label_time);
802    }
803    unser_float64(dev->VolHdr.write_date);    /* Unused with VerNum >= 11 */
804    unser_float64(dev->VolHdr.write_time);    /* Unused with VerNum >= 11 */
805
806    unser_string(dev->VolHdr.VolumeName);
807    unser_string(dev->VolHdr.PrevVolumeName);
808    unser_string(dev->VolHdr.PoolName);
809    unser_string(dev->VolHdr.PoolType);
810    unser_string(dev->VolHdr.MediaType);
811
812    unser_string(dev->VolHdr.HostName);
813    unser_string(dev->VolHdr.LabelProg);
814    unser_string(dev->VolHdr.ProgVersion);
815    unser_string(dev->VolHdr.ProgDate);
816
817    ser_end(rec->data, SER_LENGTH_Volume_Label);
818    Dmsg0(190, "unser_vol_label\n");
819    if (debug_level >= 190) {
820       dump_volume_label(dev);
821    }
822    return true;
823 }
824
825
826 bool unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec)
827 {
828    ser_declare;
829
830    rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
831    unser_begin(rec->data, SER_LENGTH_Session_Label);
832    unser_string(label->Id);
833    unser_uint32(label->VerNum);
834    unser_uint32(label->JobId);
835    if (label->VerNum >= 11) {
836       unser_btime(label->write_btime);
837    } else {
838       unser_float64(label->write_date);
839    }
840    unser_float64(label->write_time);
841    unser_string(label->PoolName);
842    unser_string(label->PoolType);
843    unser_string(label->JobName);
844    unser_string(label->ClientName);
845    if (label->VerNum >= 10) {
846       unser_string(label->Job);          /* Unique name of this Job */
847       unser_string(label->FileSetName);
848       unser_uint32(label->JobType);
849       unser_uint32(label->JobLevel);
850    }
851    if (label->VerNum >= 11) {
852       unser_string(label->FileSetMD5);
853    } else {
854       label->FileSetMD5[0] = 0;
855    }
856    if (rec->FileIndex == EOS_LABEL) {
857       unser_uint32(label->JobFiles);
858       unser_uint64(label->JobBytes);
859       unser_uint32(label->StartBlock);
860       unser_uint32(label->EndBlock);
861       unser_uint32(label->StartFile);
862       unser_uint32(label->EndFile);
863       unser_uint32(label->JobErrors);
864       if (label->VerNum >= 11) {
865          unser_uint32(label->JobStatus);
866       } else {
867          label->JobStatus = JS_Terminated; /* kludge */
868       }
869    }
870    return true;
871 }
872
873 void dump_volume_label(DEVICE *dev)
874 {
875    int dbl = debug_level;
876    uint32_t File;
877    const char *LabelType;
878    char buf[30];
879    struct tm tm;
880    struct date_time dt;
881
882    debug_level = 1;
883    File = dev->file;
884    switch (dev->VolHdr.LabelType) {
885    case PRE_LABEL:
886       LabelType = "PRE_LABEL";
887       break;
888    case VOL_LABEL:
889       LabelType = "VOL_LABEL";
890       break;
891    case EOM_LABEL:
892       LabelType = "EOM_LABEL";
893       break;
894    case SOS_LABEL:
895       LabelType = "SOS_LABEL";
896       break;
897    case EOS_LABEL:
898       LabelType = "EOS_LABEL";
899       break;
900    case EOT_LABEL:
901       goto bail_out;
902    default:
903       LabelType = buf;
904       sprintf(buf, _("Unknown %d"), dev->VolHdr.LabelType);
905       break;
906    }
907
908    Pmsg11(-1, _("\nVolume Label:\n"
909 "Id                : %s"
910 "VerNo             : %d\n"
911 "VolName           : %s\n"
912 "PrevVolName       : %s\n"
913 "VolFile           : %d\n"
914 "LabelType         : %s\n"
915 "LabelSize         : %d\n"
916 "PoolName          : %s\n"
917 "MediaType         : %s\n"
918 "PoolType          : %s\n"
919 "HostName          : %s\n"
920 ""),
921              dev->VolHdr.Id, dev->VolHdr.VerNum,
922              dev->VolHdr.VolumeName, dev->VolHdr.PrevVolumeName,
923              File, LabelType, dev->VolHdr.LabelSize,
924              dev->VolHdr.PoolName, dev->VolHdr.MediaType,
925              dev->VolHdr.PoolType, dev->VolHdr.HostName);
926
927    if (dev->VolHdr.VerNum >= 11) {
928       char dt[50];
929       bstrftime(dt, sizeof(dt), btime_to_utime(dev->VolHdr.label_btime));
930       Pmsg1(-1, _("Date label written: %s\n"), dt);
931    } else {
932       dt.julian_day_number   = dev->VolHdr.label_date;
933       dt.julian_day_fraction = dev->VolHdr.label_time;
934       tm_decode(&dt, &tm);
935       Pmsg5(-1,
936             _("Date label written: %04d-%02d-%02d at %02d:%02d\n"),
937               tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
938    }
939
940 bail_out:
941    debug_level = dbl;
942 }
943
944
945 static void dump_session_label(DEV_RECORD *rec, const char *type)
946 {
947    int dbl;
948    struct date_time dt;
949    struct tm tm;
950    SESSION_LABEL label;
951    char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], ec6[30], ec7[30];
952
953    unser_session_label(&label, rec);
954    dbl = debug_level;
955    debug_level = 1;
956    Pmsg7(-1, _("\n%s Record:\n"
957 "JobId             : %d\n"
958 "VerNum            : %d\n"
959 "PoolName          : %s\n"
960 "PoolType          : %s\n"
961 "JobName           : %s\n"
962 "ClientName        : %s\n"
963 ""),    type, label.JobId, label.VerNum,
964       label.PoolName, label.PoolType,
965       label.JobName, label.ClientName);
966
967    if (label.VerNum >= 10) {
968       Pmsg4(-1, _(
969 "Job (unique name) : %s\n"
970 "FileSet           : %s\n"
971 "JobType           : %c\n"
972 "JobLevel          : %c\n"
973 ""), label.Job, label.FileSetName, label.JobType, label.JobLevel);
974    }
975
976    if (rec->FileIndex == EOS_LABEL) {
977       Pmsg8(-1, _(
978 "JobFiles          : %s\n"
979 "JobBytes          : %s\n"
980 "StartBlock        : %s\n"
981 "EndBlock          : %s\n"
982 "StartFile         : %s\n"
983 "EndFile           : %s\n"
984 "JobErrors         : %s\n"
985 "JobStatus         : %c\n"
986 ""),
987          edit_uint64_with_commas(label.JobFiles, ec1),
988          edit_uint64_with_commas(label.JobBytes, ec2),
989          edit_uint64_with_commas(label.StartBlock, ec3),
990          edit_uint64_with_commas(label.EndBlock, ec4),
991          edit_uint64_with_commas(label.StartFile, ec5),
992          edit_uint64_with_commas(label.EndFile, ec6),
993          edit_uint64_with_commas(label.JobErrors, ec7),
994          label.JobStatus);
995    }
996    if (label.VerNum >= 11) {
997       char dt[50];
998       bstrftime(dt, sizeof(dt), btime_to_utime(label.write_btime));
999       Pmsg1(-1, _("Date written      : %s\n"), dt);
1000    } else {
1001       dt.julian_day_number   = label.write_date;
1002       dt.julian_day_fraction = label.write_time;
1003       tm_decode(&dt, &tm);
1004       Pmsg5(-1, _("Date written      : %04d-%02d-%02d at %02d:%02d\n"),
1005       tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
1006    }
1007
1008    debug_level = dbl;
1009 }
1010
1011 void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose)
1012 {
1013    const char *type;
1014    int dbl;
1015
1016    if (rec->FileIndex == 0 && rec->VolSessionId == 0 && rec->VolSessionTime == 0) {
1017       return;
1018    }
1019    dbl = debug_level;
1020    debug_level = 1;
1021    switch (rec->FileIndex) {
1022    case PRE_LABEL:
1023       type = _("Fresh Volume");
1024       break;
1025    case VOL_LABEL:
1026       type = _("Volume");
1027       break;
1028    case SOS_LABEL:
1029       type = _("Begin Job Session");
1030       break;
1031    case EOS_LABEL:
1032       type = _("End Job Session");
1033       break;
1034    case EOM_LABEL:
1035       type = _("End of Media");
1036       break;
1037    case EOT_LABEL:
1038       type = _("End of Tape");
1039       break;
1040    default:
1041       type = _("Unknown");
1042       break;
1043    }
1044    if (verbose) {
1045       switch (rec->FileIndex) {
1046       case PRE_LABEL:
1047       case VOL_LABEL:
1048          unser_volume_label(dev, rec);
1049          dump_volume_label(dev);
1050          break;
1051       case SOS_LABEL:
1052          dump_session_label(rec, type);
1053          break;
1054       case EOS_LABEL:
1055          dump_session_label(rec, type);
1056          break;
1057       case EOM_LABEL:
1058          Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1059             type, dev->file, dev->block_num, rec->VolSessionId, 
1060             rec->VolSessionTime, rec->Stream, rec->data_len);
1061          break;
1062       case EOT_LABEL:
1063          Pmsg0(-1, _("End of physical tape.\n"));
1064          break;
1065       default:
1066          Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1067             type, dev->file, dev->block_num, rec->VolSessionId, 
1068             rec->VolSessionTime, rec->Stream, rec->data_len);
1069          break;
1070       }
1071    } else {
1072       SESSION_LABEL label;
1073       char dt[50];
1074       switch (rec->FileIndex) {
1075       case SOS_LABEL:
1076          unser_session_label(&label, rec);
1077          bstrftimes(dt, sizeof(dt), btime_to_utime(label.write_btime));
1078          Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1079             type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1080          Pmsg4(-1, _("   Job=%s Date=%s Level=%c Type=%c\n"),
1081             label.Job, dt, label.JobLevel, label.JobType);
1082          break;
1083       case EOS_LABEL:
1084          char ed1[30], ed2[30];
1085          unser_session_label(&label, rec);
1086          bstrftimes(dt, sizeof(dt), btime_to_utime(label.write_btime));
1087          Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1088             type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1089          Pmsg7(-1, _("   Date=%s Level=%c Type=%c Files=%s Bytes=%s Errors=%d Status=%c\n"),
1090             dt, label.JobLevel, label.JobType,
1091             edit_uint64_with_commas(label.JobFiles, ed1),
1092             edit_uint64_with_commas(label.JobBytes, ed2),
1093             label.JobErrors, (char)label.JobStatus);
1094          break;
1095       case EOM_LABEL:
1096       case PRE_LABEL:
1097       case VOL_LABEL:
1098       default:
1099          Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1100             type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, 
1101             rec->Stream, rec->data_len);
1102          break;
1103       case EOT_LABEL:
1104          break;
1105       }
1106    }
1107    debug_level = dbl;
1108 }