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