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