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