]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/label.c
backport code from master
[bacula/bacula] / bacula / src / stored / label.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2012 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 three of the GNU Affero 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 Affero 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
36 #include "bacula.h"                   /* pull in global headers */
37 #include "stored.h"                   /* pull in Storage Deamon headers */
38
39 /* Forward referenced functions */
40 static void create_volume_label_record(DCR *dcr, DEVICE *dev, DEV_RECORD *rec);
41
42 /*
43  * Read the volume label
44  *
45  *  If dcr->VolumeName == NULL, we accept any Bacula Volume
46  *  If dcr->VolumeName[0] == 0, we accept any Bacula Volume
47  *  otherwise dcr->VolumeName must match the Volume.
48  *
49  *  If VolName given, ensure that it matches
50  *
51  *  Returns VOL_  code as defined in record.h
52  *    VOL_NOT_READ
53  *    VOL_OK                          good label found
54  *    VOL_NO_LABEL                    volume not labeled
55  *    VOL_IO_ERROR                    I/O error reading tape
56  *    VOL_NAME_ERROR                  label has wrong name
57  *    VOL_CREATE_ERROR                Error creating label
58  *    VOL_VERSION_ERROR               label has wrong version
59  *    VOL_LABEL_ERROR                 bad label type
60  *    VOL_NO_MEDIA                    no media in drive
61  *
62  *  The dcr block is emptied on return, and the Volume is
63  *    rewound.
64  */
65 int read_dev_volume_label(DCR *dcr)
66 {
67    JCR *jcr = dcr->jcr;
68    DEVICE * volatile dev = dcr->dev;
69    char *VolName = dcr->VolumeName;
70    DEV_RECORD *record;
71    bool ok = false;
72    DEV_BLOCK *block = dcr->block;
73    int stat;
74    bool want_ansi_label;
75    bool have_ansi_label = false;
76
77    Dmsg4(100, "Enter read_volume_label res=%d device=%s vol=%s dev_Vol=%s\n",
78       dev->num_reserved(), dev->print_name(), VolName, 
79       dev->VolHdr.VolumeName[0]?dev->VolHdr.VolumeName:"*NULL*");
80
81    if (!dev->is_open()) {
82       if (!dev->open(dcr, OPEN_READ_ONLY)) {
83          return VOL_IO_ERROR;
84       }
85    }
86
87    dev->clear_labeled();
88    dev->clear_append();
89    dev->clear_read();
90    dev->label_type = B_BACULA_LABEL;
91
92    if (!dev->rewind(dcr)) {
93       Mmsg(jcr->errmsg, _("Couldn't rewind device %s: ERR=%s\n"), 
94          dev->print_name(), dev->print_errmsg());
95       Dmsg1(130, "return VOL_NO_MEDIA: %s", jcr->errmsg);
96       return VOL_NO_MEDIA;
97    }
98    bstrncpy(dev->VolHdr.Id, "**error**", sizeof(dev->VolHdr.Id));
99
100   /* Read ANSI/IBM label if so requested */
101   want_ansi_label = dcr->VolCatInfo.LabelType != B_BACULA_LABEL ||
102                     dcr->device->label_type != B_BACULA_LABEL;
103   if (want_ansi_label || dev->has_cap(CAP_CHECKLABELS)) {
104       stat = read_ansi_ibm_label(dcr);            
105       /* If we want a label and didn't find it, return error */
106       if (want_ansi_label && stat != VOL_OK) {
107          goto bail_out;
108       }
109       if (stat == VOL_NAME_ERROR || stat == VOL_LABEL_ERROR) {
110          Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
111               dev->print_name(), VolName, dev->VolHdr.VolumeName);
112          if (!dev->poll && jcr->label_errors++ > 100) {
113             Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
114          }
115          goto bail_out;
116       }
117       if (stat != VOL_OK) {           /* Not an ANSI/IBM label, so re-read */
118          dev->rewind(dcr);
119       } else {
120          have_ansi_label = true;
121       }
122    }
123   
124    /* Read the Bacula Volume label block */
125    record = new_record();
126    empty_block(block);
127
128    Dmsg0(130, "Big if statement in read_volume_label\n");
129    if (!dcr->read_block_from_dev(NO_BLOCK_NUMBER_CHECK)) {
130       Mmsg(jcr->errmsg, _("Requested Volume \"%s\" on %s is not a Bacula "
131            "labeled Volume, because: ERR=%s"), NPRT(VolName), 
132            dev->print_name(), dev->print_errmsg());
133       Dmsg1(130, "%s", jcr->errmsg);
134    } else if (!read_record_from_block(dcr, block, record)) {
135       Mmsg(jcr->errmsg, _("Could not read Volume label from block.\n"));
136       Dmsg1(130, "%s", jcr->errmsg);
137    } else if (!unser_volume_label(dev, record)) {
138       Mmsg(jcr->errmsg, _("Could not unserialize Volume label: ERR=%s\n"),
139          dev->print_errmsg());
140       Dmsg1(130, "%s", jcr->errmsg);
141    } else if (strcmp(dev->VolHdr.Id, BaculaId) != 0 &&
142               strcmp(dev->VolHdr.Id, OldBaculaId) != 0) {
143       Mmsg(jcr->errmsg, _("Volume Header Id bad: %s\n"), dev->VolHdr.Id);
144       Dmsg1(130, "%s", jcr->errmsg);
145    } else {
146       ok = true;
147    }
148    free_record(record);               /* finished reading Volume record */
149
150    if (!dev->is_volume_to_unload()) {
151       dev->clear_unload();
152    }
153
154    if (!ok) {
155       if (forge_on || jcr->ignore_label_errors) {
156          dev->set_labeled();         /* set has Bacula label */
157          Jmsg(jcr, M_ERROR, 0, "%s", jcr->errmsg);
158          empty_block(block);
159          return VOL_OK;
160       }
161       Dmsg0(100, "No volume label - bailing out\n");
162       stat = VOL_NO_LABEL;
163       goto bail_out;
164    }
165
166    /* At this point, we have read the first Bacula block, and
167     * then read the Bacula Volume label. Now we need to
168     * make sure we have the right Volume.
169     */
170
171
172    if (dev->VolHdr.VerNum != BaculaTapeVersion &&
173        dev->VolHdr.VerNum != OldCompatibleBaculaTapeVersion1 &&
174        dev->VolHdr.VerNum != OldCompatibleBaculaTapeVersion2) {
175       Mmsg(jcr->errmsg, _("Volume on %s has wrong Bacula version. Wanted %d got %d\n"),
176          dev->print_name(), BaculaTapeVersion, dev->VolHdr.VerNum);
177       Dmsg1(130, "VOL_VERSION_ERROR: %s", jcr->errmsg);
178       stat = VOL_VERSION_ERROR;
179       goto bail_out;
180    }
181
182    /* We are looking for either an unused Bacula tape (PRE_LABEL) or
183     * a Bacula volume label (VOL_LABEL)
184     */
185    if (dev->VolHdr.LabelType != PRE_LABEL && dev->VolHdr.LabelType != VOL_LABEL) {
186       Mmsg(jcr->errmsg, _("Volume on %s has bad Bacula label type: %x\n"),
187           dev->print_name(), dev->VolHdr.LabelType);
188       Dmsg1(130, "%s", jcr->errmsg);
189       if (!dev->poll && jcr->label_errors++ > 100) {
190          Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
191       }
192       Dmsg0(150, "return VOL_LABEL_ERROR\n");
193       stat = VOL_LABEL_ERROR;
194       goto bail_out;
195    }
196
197    dev->set_labeled();               /* set has Bacula label */
198
199    /* Compare Volume Names */
200    Dmsg2(130, "Compare Vol names: VolName=%s hdr=%s\n", VolName?VolName:"*", dev->VolHdr.VolumeName);
201    if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolumeName, VolName) != 0) {
202       Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
203            dev->print_name(), VolName, dev->VolHdr.VolumeName);
204       Dmsg1(130, "%s", jcr->errmsg);
205       /*
206        * Cancel Job if too many label errors
207        *  => we are in a loop
208        */
209       if (!dev->poll && jcr->label_errors++ > 100) {
210          Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
211       }
212       Dmsg0(150, "return VOL_NAME_ERROR\n");
213       stat = VOL_NAME_ERROR;
214       goto bail_out;
215    }
216
217
218    if (debug_level >= 200) {
219       dump_volume_label(dev);
220    }
221    Dmsg0(130, "Leave read_volume_label() VOL_OK\n");
222    /* If we are a streaming device, we only get one chance to read */
223    if (!dev->has_cap(CAP_STREAM)) {
224       dev->rewind(dcr);
225       if (have_ansi_label) {
226          stat = read_ansi_ibm_label(dcr);            
227          /* If we want a label and didn't find it, return error */
228          if (stat != VOL_OK) {
229             goto bail_out;
230          }
231       }
232    }
233
234    Dmsg1(100, "Call reserve_volume=%s\n", dev->VolHdr.VolumeName);
235    if (reserve_volume(dcr, dev->VolHdr.VolumeName) == NULL) {
236       Mmsg2(jcr->errmsg, _("Could not reserve volume %s on %s\n"),
237            dev->VolHdr.VolumeName, dev->print_name());
238       Dmsg2(150, "Could not reserve volume %s on %s\n", dev->VolHdr.VolumeName, dev->print_name());
239       stat = VOL_NAME_ERROR;
240       goto bail_out;
241    }
242
243    empty_block(block);
244    return VOL_OK;
245
246 bail_out:
247    empty_block(block);
248    dev->rewind(dcr);
249    Dmsg1(150, "return %d\n", stat);
250    return stat;
251 }
252
253 /*
254  * Put a volume label into the block
255  *
256  *  Returns: false on failure
257  *           true  on success
258  */
259 static bool write_volume_label_to_block(DCR *dcr)
260 {
261    DEVICE *dev = dcr->dev;
262    DEV_BLOCK *block = dcr->block;
263    DEV_RECORD rec;
264    JCR *jcr = dcr->jcr;
265
266    Dmsg0(130, "write Label in write_volume_label_to_block()\n");
267
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, dev, &rec);
273
274    block->BlockNumber = 0;
275    if (!write_record_to_block(dcr, &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 *dev = dcr->dev;
302    DEV_BLOCK *block = dcr->block;
303
304    Dmsg0(150, "write_volume_label()\n");
305    if (*VolName == 0) {
306       Pmsg0(0, "=== ERROR: write_new_volume_label_to_dev called with NULL VolName\n");
307       goto bail_out;
308    }
309
310    if (relabel) {
311       volume_unused(dcr);             /* mark current volume unused */
312       /* Truncate device */
313       if (!dev->truncate(dcr)) {
314          goto bail_out;
315       }
316       if (!dev->is_tape()) {
317          dev->close_part(dcr);        /* make sure DVD/file closed for rename */
318       }
319    }
320
321    /* Set the new filename for open, ... */
322    dev->setVolCatName(VolName);
323    dcr->setVolCatName(VolName);
324    Dmsg1(150, "New VolName=%s\n", VolName);
325    if (!dev->open(dcr, OPEN_READ_WRITE)) {
326       /* If device is not tape, attempt to create it */
327       if (dev->is_tape() || !dev->open(dcr, CREATE_READ_WRITE)) {
328          Jmsg3(dcr->jcr, M_WARNING, 0, _("Open device %s Volume \"%s\" failed: ERR=%s\n"),
329                dev->print_name(), dcr->VolumeName, dev->bstrerror());
330          goto bail_out;
331       }
332    }
333    Dmsg1(150, "Label type=%d\n", dev->label_type);
334
335    for ( ;; ) {
336       empty_block(block);
337       if (!dev->rewind(dcr)) {
338          Dmsg2(130, "Bad status on %s from rewind: ERR=%s\n", dev->print_name(), dev->print_errmsg());
339          if (!forge_on) {
340             goto bail_out;
341          }
342       }
343
344       /* Temporarily mark in append state to enable writing */
345       dev->set_append();
346
347       /* Create PRE_LABEL or VOL_LABEL if DVD */
348       create_volume_label(dev, VolName, PoolName, dvdnow);
349
350       /*
351        * If we have already detected an ANSI label, re-read it
352        *   to skip past it. Otherwise, we write a new one if 
353        *   so requested.  
354        */
355       if (dev->label_type != B_BACULA_LABEL) {
356          if (read_ansi_ibm_label(dcr) != VOL_OK) {
357             dev->rewind(dcr);
358             goto bail_out;
359          }
360       } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, VolName)) {
361          goto bail_out;
362       }
363
364       create_volume_label_record(dcr, dev, dcr->rec);
365       dcr->rec->Stream = 0;
366       dcr->rec->maskedStream = 0;
367
368       if (!write_record_to_block(dcr, dcr->rec)) {
369          Dmsg2(130, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
370          goto bail_out;
371       } else {
372          Dmsg2(130, "Wrote label of %d bytes to %s\n", dcr->rec->data_len, dev->print_name());
373       }
374
375       Dmsg0(130, "Call write_block_to_dev()\n");
376       if (!dcr->write_block_to_dev()) {
377          Dmsg2(130, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
378          goto bail_out;
379       }
380       break;
381    }
382    dev = dcr->dev;
383
384
385    Dmsg0(130, " Wrote block to device\n");
386
387    if (dev->weof(1)) {
388       dev->set_labeled();
389       write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
390    }
391
392    if (debug_level >= 20)  {
393       dump_volume_label(dev);
394    }
395    Dmsg0(100, "Call reserve_volume\n");
396    if (reserve_volume(dcr, VolName) == NULL) {
397       Mmsg2(dcr->jcr->errmsg, _("Could not reserve volume %s on %s\n"),
398            dev->VolHdr.VolumeName, dev->print_name());
399       Dmsg1(100, "%s", dcr->jcr->errmsg);
400       goto bail_out;
401    }
402    dev = dcr->dev;                    /* may have changed in reserve_volume */
403
404    dev->clear_append();               /* remove append since this is PRE_LABEL */
405    return true;
406
407 bail_out:
408    volume_unused(dcr);
409    dev->clear_volhdr();
410    dev->clear_append();               /* remove append since this is PRE_LABEL */
411    return false;
412 }
413
414 /*
415  * Write a volume label. This is ONLY called if we have a valid Bacula
416  *   label of type PRE_LABEL or we are recyling an existing Volume.
417  *
418  *  Returns: true if OK
419  *           false if unable to write it
420  */
421 bool DCR::rewrite_volume_label(bool recycle)
422 {
423    DCR *dcr = this;
424
425    if (!dev->open(dcr, OPEN_READ_WRITE)) {
426        Jmsg3(jcr, M_WARNING, 0, _("Open device %s Volume \"%s\" failed: ERR=%s\n"),
427              dev->print_name(), dcr->VolumeName, dev->bstrerror());
428       return false;
429    }
430    Dmsg2(190, "set append found freshly labeled volume. fd=%d dev=%x\n", dev->fd(), dev);
431    dev->VolHdr.LabelType = VOL_LABEL; /* set Volume label */
432    dev->set_append();
433    if (!write_volume_label_to_block(dcr)) {
434       Dmsg0(200, "Error from write volume label.\n");
435       return false;
436    }
437    Dmsg1(150, "wrote vol label to block. Vol=%s\n", dcr->VolumeName);
438
439    dev->setVolCatInfo(false);
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          if (!dev->truncate(dcr)) {
458             Jmsg2(jcr, M_FATAL, 0, _("Truncate error on device %s: ERR=%s\n"),
459                   dev->print_name(), dev->print_errmsg());
460             return false;
461          }
462          if (!dev->open(dcr, OPEN_READ_WRITE)) {
463             Jmsg2(jcr, M_FATAL, 0,
464                _("Failed to re-open DVD after truncate on device %s: ERR=%s\n"),
465                dev->print_name(), dev->print_errmsg());
466             return false;
467          }
468       }
469
470       /*
471        * If we have already detected an ANSI label, re-read it
472        *   to skip past it. Otherwise, we write a new one if 
473        *   so requested.  
474        */
475       if (dev->label_type != B_BACULA_LABEL) {
476          if (read_ansi_ibm_label(dcr) != VOL_OK) {
477             dev->rewind(dcr);
478             return false;
479          }
480       } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, dev->VolHdr.VolumeName)) {
481          return false;
482       }
483
484       /* Attempt write to check write permission */
485       Dmsg1(200, "Attempt to write to device fd=%d.\n", dev->fd());
486       if (!dcr->write_block_to_dev()) {
487          Jmsg2(jcr, M_ERROR, 0, _("Unable to write device %s: ERR=%s\n"),
488             dev->print_name(), dev->print_errmsg());
489          Dmsg0(200, "===ERROR write block to dev\n");
490          return false;
491       }
492    }
493    dev->set_labeled();
494    /* Set or reset Volume statistics */
495    dev->VolCatInfo.VolCatJobs = 0;
496    dev->VolCatInfo.VolCatFiles = 0;
497    dev->VolCatInfo.VolCatErrors = 0;
498    dev->VolCatInfo.VolCatBlocks = 0;
499    dev->VolCatInfo.VolCatRBytes = 0;
500    if (recycle) {
501       dev->VolCatInfo.VolCatMounts++;
502       dev->VolCatInfo.VolCatRecycles++;
503       dir_create_jobmedia_record(dcr, true);
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    dev->VolCatInfo.VolFirstWritten = time(NULL);
512    bstrncpy(dev->VolCatInfo.VolCatStatus, "Append", sizeof(dev->VolCatInfo.VolCatStatus));
513    dev->setVolCatName(dcr->VolumeName);
514    if (!dir_update_volume_info(dcr, true, true)) {  /* indicate doing relabel */
515       return false;
516    }
517    if (recycle) {
518       Jmsg(jcr, M_INFO, 0, _("Recycled volume \"%s\" on device %s, all previous data lost.\n"),
519          dcr->VolumeName, dev->print_name());
520    } else {
521       Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume \"%s\" on device %s\n"),
522          dcr->VolumeName, dev->print_name());
523    }
524    /*
525     * End writing real Volume label (from pre-labeled tape), or recycling
526     *  the volume.
527     */
528    Dmsg1(150, "OK from rewrite vol label. Vol=%s\n", dcr->VolumeName);
529    return true;
530 }
531
532
533 /*
534  *  create_volume_label_record
535  *   Serialize label (from dev->VolHdr structure) into device record.
536  *   Assumes that the dev->VolHdr structure is properly
537  *   initialized.
538 */
539 static void create_volume_label_record(DCR *dcr, DEVICE *dev, DEV_RECORD *rec)
540 {
541    ser_declare;
542    struct date_time dt;
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    rec->maskedStream = jcr->NumWriteVolumes;
590    Dmsg2(150, "Created Vol label rec: FI=%s len=%d\n", FI_to_ascii(buf, rec->FileIndex),
591       rec->data_len);
592 }
593
594
595 /*
596  * Create a volume label in memory
597  */
598 void create_volume_label(DEVICE *dev, const char *VolName, 
599                          const char *PoolName, bool dvdnow)
600 {
601    DEVRES *device = (DEVRES *)dev->device;
602
603    Dmsg0(130, "Start create_volume_label()\n");
604
605    ASSERT(dev != NULL);
606
607    dev->clear_volhdr();          /* clear any old volume info */
608
609    bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
610    dev->VolHdr.VerNum = BaculaTapeVersion;
611    if (dev->is_dvd() && dvdnow) {
612       /* We do not want to re-label a DVD so write VOL_LABEL now */
613       dev->VolHdr.LabelType = VOL_LABEL;
614    } else {
615       dev->VolHdr.LabelType = PRE_LABEL;  /* Mark tape as unused */
616    }
617    bstrncpy(dev->VolHdr.VolumeName, VolName, sizeof(dev->VolHdr.VolumeName));
618    bstrncpy(dev->VolHdr.PoolName, PoolName, sizeof(dev->VolHdr.PoolName));
619    bstrncpy(dev->VolHdr.MediaType, device->media_type, sizeof(dev->VolHdr.MediaType));
620
621    bstrncpy(dev->VolHdr.PoolType, "Backup", sizeof(dev->VolHdr.PoolType));
622
623    dev->VolHdr.label_btime = get_current_btime();
624    dev->VolHdr.label_date = 0;
625    dev->VolHdr.label_time = 0;
626
627    if (gethostname(dev->VolHdr.HostName, sizeof(dev->VolHdr.HostName)) != 0) {
628       dev->VolHdr.HostName[0] = 0;
629    }
630    bstrncpy(dev->VolHdr.LabelProg, my_name, sizeof(dev->VolHdr.LabelProg));
631    sprintf(dev->VolHdr.ProgVersion, "Ver. %s %s", VERSION, BDATE);
632    sprintf(dev->VolHdr.ProgDate, "Build %s %s", __DATE__, __TIME__);
633    dev->set_labeled();               /* set has Bacula label */
634    if (debug_level >= 90) {
635       dump_volume_label(dev);
636    }
637 }
638
639 /*
640  * Create session label
641  *  The pool memory must be released by the calling program
642  */
643 void create_session_label(DCR *dcr, DEV_RECORD *rec, int label)
644 {
645    JCR *jcr = dcr->jcr;
646    ser_declare;
647
648    rec->VolSessionId   = jcr->VolSessionId;
649    rec->VolSessionTime = jcr->VolSessionTime;
650    rec->Stream         = jcr->JobId;
651    rec->maskedStream   = 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->getJobType());
673    ser_uint32(jcr->getJobLevel());
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 (!dcr->write_block_to_device()) {
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(dcr, 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_utime(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_utime(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_utime(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_utime(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 }