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