]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/label.c
Update new reservations changes
[bacula/bacula] / bacula / src / stored / label.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of John Walker.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  *
30  *  label.c  Bacula routines to handle labels
31  *
32  *   Kern Sibbald, MM
33  *
34  *
35  *   Version $Id$
36  */
37
38 #include "bacula.h"                   /* pull in global headers */
39 #include "stored.h"                   /* pull in Storage Deamon headers */
40
41 /* Forward referenced functions */
42 static void create_volume_label_record(DCR *dcr, DEV_RECORD *rec);
43
44 /*
45  * Read the volume label
46  *
47  *  If dcr->VolumeName == NULL, we accept any Bacula Volume
48  *  If dcr->VolumeName[0] == 0, we accept any Bacula Volume
49  *  otherwise dcr->VolumeName must match the Volume.
50  *
51  *  If VolName given, ensure that it matches
52  *
53  *  Returns VOL_  code as defined in record.h
54  *    VOL_NOT_READ
55  *    VOL_OK                          good label found
56  *    VOL_NO_LABEL                    volume not labeled
57  *    VOL_IO_ERROR                    I/O error reading tape
58  *    VOL_NAME_ERROR                  label has wrong name
59  *    VOL_CREATE_ERROR                Error creating label
60  *    VOL_VERSION_ERROR               label has wrong version
61  *    VOL_LABEL_ERROR                 bad label type
62  *    VOL_NO_MEDIA                    no media in drive
63  *
64  *  The dcr block is emptied on return, and the Volume is
65  *    rewound.
66  */
67 int read_dev_volume_label(DCR *dcr)
68 {
69    JCR *jcr = dcr->jcr;
70    DEVICE *dev = dcr->dev;
71    char *VolName = dcr->VolumeName;
72    DEV_RECORD *record;
73    bool ok = false;
74    DEV_BLOCK *block = dcr->block;
75    int stat;
76    bool want_ansi_label;
77    bool have_ansi_label = false;
78
79    Dmsg4(100, "Enter read_volume_label res=%d device=%s vol=%s dev_Vol=%s\n",
80       dev->reserved_device, dev->print_name(), VolName, 
81       dev->VolHdr.VolumeName[0]?dev->VolHdr.VolumeName:"*NULL*");
82
83    if (!dev->is_open()) {
84       if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
85          return VOL_IO_ERROR;
86       }
87    }
88    if (dev->is_labeled()) {              /* did we already read label? */
89       /* Compare Volume Names allow special wild card */
90       if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolumeName, VolName) != 0) {
91          Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
92             dev->print_name(), VolName, dev->VolHdr.VolumeName);
93          /*
94           * Cancel Job if too many label errors
95           *  => we are in a loop
96           */
97          if (!dev->poll && jcr->label_errors++ > 100) {
98             Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
99          }
100          Dmsg0(150, "return VOL_NAME_ERROR\n");
101          stat = VOL_NAME_ERROR;
102          goto bail_out;
103       }
104       Dmsg0(130, "Leave read_volume_label() VOL_OK\n");
105       return VOL_OK;       /* label already read */
106    }
107
108    dev->clear_labeled();
109    dev->clear_append();
110    dev->clear_read();
111    dev->label_type = B_BACULA_LABEL;
112
113    if (!dev->rewind(dcr)) {
114       Mmsg(jcr->errmsg, _("Couldn't rewind device %s: ERR=%s\n"), 
115          dev->print_name(), dev->print_errmsg());
116       Dmsg1(130, "return VOL_NO_MEDIA: %s", jcr->errmsg);
117       return VOL_NO_MEDIA;
118    }
119    bstrncpy(dev->VolHdr.Id, "**error**", sizeof(dev->VolHdr.Id));
120
121   /* Read ANSI/IBM label if so requested */
122   want_ansi_label = dcr->VolCatInfo.LabelType != B_BACULA_LABEL ||
123                     dcr->device->label_type != B_BACULA_LABEL;
124   if (want_ansi_label || dev->has_cap(CAP_CHECKLABELS)) {
125       stat = read_ansi_ibm_label(dcr);            
126       /* If we want a label and didn't find it, return error */
127       if (want_ansi_label && stat != VOL_OK) {
128          goto bail_out;
129       }
130       if (stat == VOL_NAME_ERROR || stat == VOL_LABEL_ERROR) {
131          Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
132               dev->print_name(), VolName, dev->VolHdr.VolumeName);
133          if (!dev->poll && jcr->label_errors++ > 100) {
134             Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
135          }
136          goto bail_out;
137       }
138       if (stat != VOL_OK) {           /* Not an ANSI/IBM label, so re-read */
139          dev->rewind(dcr);
140       } else {
141          have_ansi_label = true;
142       }
143    }
144   
145    /* Read the Bacula Volume label block */
146    record = new_record();
147    empty_block(block);
148
149    Dmsg0(130, "Big if statement in read_volume_label\n");
150    if (!read_block_from_dev(dcr, NO_BLOCK_NUMBER_CHECK)) {
151       Mmsg(jcr->errmsg, _("Requested Volume \"%s\" on %s is not a Bacula "
152            "labeled Volume, because: ERR=%s"), NPRT(VolName), 
153            dev->print_name(), dev->print_errmsg());
154       Dmsg1(130, "%s", jcr->errmsg);
155    } else if (!read_record_from_block(dcr, block, record)) {
156       Mmsg(jcr->errmsg, _("Could not read Volume label from block.\n"));
157       Dmsg1(130, "%s", jcr->errmsg);
158    } else if (!unser_volume_label(dev, record)) {
159       Mmsg(jcr->errmsg, _("Could not unserialize Volume label: ERR=%s\n"),
160          dev->print_errmsg());
161       Dmsg1(130, "%s", jcr->errmsg);
162    } else if (strcmp(dev->VolHdr.Id, BaculaId) != 0 &&
163               strcmp(dev->VolHdr.Id, OldBaculaId) != 0) {
164       Mmsg(jcr->errmsg, _("Volume Header Id bad: %s\n"), dev->VolHdr.Id);
165       Dmsg1(130, "%s", jcr->errmsg);
166    } else {
167       ok = true;
168    }
169    free_record(record);               /* finished reading Volume record */
170
171    if (!ok) {
172       if (forge_on || jcr->ignore_label_errors) {
173          dev->set_labeled();         /* set has Bacula label */
174          Jmsg(jcr, M_ERROR, 0, "%s", jcr->errmsg);
175          empty_block(block);
176          return VOL_OK;
177       }
178       Dmsg0(100, "No volume label - bailing out\n");
179       stat = VOL_NO_LABEL;
180       goto bail_out;
181    }
182
183    /* At this point, we have read the first Bacula block, and
184     * then read the Bacula Volume label. Now we need to
185     * make sure we have the right Volume.
186     */
187
188
189    if (dev->VolHdr.VerNum != BaculaTapeVersion &&
190        dev->VolHdr.VerNum != OldCompatibleBaculaTapeVersion1 &&
191        dev->VolHdr.VerNum != OldCompatibleBaculaTapeVersion2) {
192       Mmsg(jcr->errmsg, _("Volume on %s has wrong Bacula version. Wanted %d got %d\n"),
193          dev->print_name(), BaculaTapeVersion, dev->VolHdr.VerNum);
194       Dmsg1(130, "VOL_VERSION_ERROR: %s", jcr->errmsg);
195       stat = VOL_VERSION_ERROR;
196       goto bail_out;
197    }
198
199    /* We are looking for either an unused Bacula tape (PRE_LABEL) or
200     * a Bacula volume label (VOL_LABEL)
201     */
202    if (dev->VolHdr.LabelType != PRE_LABEL && dev->VolHdr.LabelType != VOL_LABEL) {
203       Mmsg(jcr->errmsg, _("Volume on %s has bad Bacula label type: %x\n"),
204           dev->print_name(), dev->VolHdr.LabelType);
205       Dmsg1(130, "%s", jcr->errmsg);
206       if (!dev->poll && jcr->label_errors++ > 100) {
207          Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
208       }
209       Dmsg0(150, "return VOL_LABEL_ERROR\n");
210       stat = VOL_LABEL_ERROR;
211       goto bail_out;
212    }
213
214    dev->set_labeled();               /* set has Bacula label */
215    if (reserve_volume(dcr, dev->VolHdr.VolumeName) == NULL) {
216       Mmsg2(jcr->errmsg, _("Could not reserve volume %s on %s\n"),
217            dev->VolHdr.VolumeName, dev->print_name());
218       stat = VOL_NAME_ERROR;
219       goto bail_out;
220    }
221
222    /* Compare Volume Names */
223    Dmsg2(130, "Compare Vol names: VolName=%s hdr=%s\n", VolName?VolName:"*", dev->VolHdr.VolumeName);
224    if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolumeName, VolName) != 0) {
225       Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
226            dev->print_name(), VolName, dev->VolHdr.VolumeName);
227       Dmsg1(130, "%s", jcr->errmsg);
228       /*
229        * Cancel Job if too many label errors
230        *  => we are in a loop
231        */
232       if (!dev->poll && jcr->label_errors++ > 100) {
233          Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
234       }
235       Dmsg0(150, "return VOL_NAME_ERROR\n");
236       stat = VOL_NAME_ERROR;
237       goto bail_out;
238    }
239    Dmsg1(130, "Copy vol_name=%s\n", dev->VolHdr.VolumeName);
240
241    if (debug_level >= 10) {
242       dump_volume_label(dev);
243    }
244    Dmsg0(130, "Leave read_volume_label() VOL_OK\n");
245    /* If we are a streaming device, we only get one chance to read */
246    if (!dev->has_cap(CAP_STREAM)) {
247       dev->rewind(dcr);
248       if (have_ansi_label) {
249          stat = read_ansi_ibm_label(dcr);            
250          /* If we want a label and didn't find it, return error */
251          if (stat != VOL_OK) {
252             goto bail_out;
253          }
254       }
255    }
256    empty_block(block);
257    return VOL_OK;
258
259 bail_out:
260    volume_unused(dcr);                /* mark volume "released" */
261    empty_block(block);
262    dev->rewind(dcr);
263    Dmsg1(150, "return %d\n", stat);
264    return stat;
265 }
266
267 /*
268  * Put a volume label into the block
269  *
270  *  Returns: false on failure
271  *           true  on success
272  */
273 bool write_volume_label_to_block(DCR *dcr)
274 {
275    DEV_RECORD rec;
276    DEVICE *dev = dcr->dev;
277    JCR *jcr = dcr->jcr;
278    DEV_BLOCK *block = dcr->block;
279
280    Dmsg0(130, "write Label in write_volume_label_to_block()\n");
281    memset(&rec, 0, sizeof(rec));
282    rec.data = get_memory(SER_LENGTH_Volume_Label);
283    empty_block(block);                /* Volume label always at beginning */
284
285    create_volume_label_record(dcr, &rec);
286
287    block->BlockNumber = 0;
288    if (!write_record_to_block(block, &rec)) {
289       free_pool_memory(rec.data);
290       Jmsg1(jcr, M_FATAL, 0, _("Cannot write Volume label to block for device %s\n"),
291          dev->print_name());
292       return false;
293    } else {
294       Dmsg1(130, "Wrote label of %d bytes to block\n", rec.data_len);
295    }
296    free_pool_memory(rec.data);
297    return true;
298 }
299
300
301 /*
302  * Write a Volume Label
303  *  !!! Note, this is ONLY used for writing
304  *            a fresh volume label.  Any data
305  *            after the label will be destroyed,
306  *            in fact, we write the label 5 times !!!!
307  *
308  *  This routine should be used only when labeling a blank tape.
309  */
310 bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName, 
311                                    const char *PoolName, bool relabel, bool dvdnow)
312 {
313    DEVICE *dev = dcr->dev;
314
315
316    Dmsg0(150, "write_volume_label()\n");
317    empty_block(dcr->block);
318
319    if (relabel) {
320       volume_unused(dcr);             /* mark current volume unused */
321       /* Truncate device */
322       if (!dev->truncate(dcr)) {
323          goto bail_out;
324       }
325       if (!dev->is_tape()) {
326          dev->close_part(dcr);        /* make sure DVD/file closed for rename */
327       }
328    }
329
330    /* Set the new filename for open, ... */
331    bstrncpy(dev->VolCatInfo.VolCatName, VolName, sizeof(dev->VolCatInfo.VolCatName));
332    bstrncpy(dcr->VolCatInfo.VolCatName, VolName, sizeof(dcr->VolCatInfo.VolCatName));
333    Dmsg1(150, "New VolName=%s\n", VolName);
334    if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
335       /* If device is not tape, attempt to create it */
336       if (dev->is_tape() || dev->open(dcr, CREATE_READ_WRITE) < 0) {
337          goto bail_out;
338       }
339    }
340    Dmsg1(150, "Label type=%d\n", dev->label_type);
341    if (!dev->rewind(dcr)) {
342       dev->clear_volhdr();
343       Dmsg2(130, "Bad status on %s from rewind: ERR=%s\n", dev->print_name(), dev->print_errmsg());
344       if (!forge_on) {
345          goto bail_out;
346       }
347    }
348
349    /* Temporarily mark in append state to enable writing */
350    dev->set_append();
351
352    /* Create PRE_LABEL or VOL_LABEL if DVD */
353    create_volume_label(dev, VolName, PoolName, dvdnow);
354
355    /*
356     * If we have already detected an ANSI label, re-read it
357     *   to skip past it. Otherwise, we write a new one if 
358     *   so requested.  
359     */
360    if (dev->label_type != B_BACULA_LABEL) {
361       if (read_ansi_ibm_label(dcr) != VOL_OK) {
362          dev->rewind(dcr);
363          goto bail_out;
364       }
365    } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, VolName)) {
366       goto bail_out;
367    }
368
369    create_volume_label_record(dcr, dcr->rec);
370    dcr->rec->Stream = 0;
371
372    if (!write_record_to_block(dcr->block, dcr->rec)) {
373       Dmsg2(130, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
374       goto bail_out;
375    } else {
376       Dmsg2(130, "Wrote label of %d bytes to %s\n", dcr->rec->data_len, dev->print_name());
377    }
378
379    Dmsg0(130, "Call write_block_to_dev()\n");
380    if (!write_block_to_dev(dcr)) {
381       Dmsg2(130, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
382       goto bail_out;
383    }
384
385    /* Now commit block to DVD if we should write now */
386    if (dev->is_dvd() && dvdnow) {
387       Dmsg1(150, "New VolName=%s\n", dev->VolCatInfo.VolCatName);
388       if (!dvd_write_part(dcr)) {
389          Dmsg2(130, "Bad DVD write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
390          goto bail_out;
391       }
392    }
393
394    Dmsg0(130, " Wrote block to device\n");
395
396    if (dev->weof(1)) {
397       dev->set_labeled();
398       write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
399    }
400
401    if (debug_level >= 20)  {
402       dump_volume_label(dev);
403    }
404    if (reserve_volume(dcr, VolName) == NULL) {
405       Mmsg2(dcr->jcr->errmsg, _("Could not reserve volume %s on %s\n"),
406            dev->VolHdr.VolumeName, dev->print_name());
407       goto bail_out;
408    }
409
410    dev->clear_append();               /* remove append since this is PRE_LABEL */
411    return true;
412
413 bail_out:
414    volume_unused(dcr);
415    dev->clear_volhdr();
416    dev->clear_append();               /* remove append since this is PRE_LABEL */
417    return false;
418 }
419
420 /*
421  * Write a volume label. This is ONLY called if we have a valid Bacula
422  *   label of type PRE_LABEL;
423  *  Returns: true if OK
424  *           false if unable to write it
425  */
426 bool rewrite_volume_label(DCR *dcr, bool recycle)
427 {
428    DEVICE *dev = dcr->dev;
429    JCR *jcr = dcr->jcr;
430
431    if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
432       return false;
433    }
434    Dmsg2(190, "set append found freshly labeled volume. fd=%d dev=%x\n", dev->fd(), dev);
435    dev->VolHdr.LabelType = VOL_LABEL; /* set Volume label */
436    dev->set_append();
437    if (!write_volume_label_to_block(dcr)) {
438       Dmsg0(200, "Error from write volume label.\n");
439       return false;
440    }
441
442    dev->VolCatInfo.VolCatBytes = 0;        /* reset byte count */
443
444    /*
445     * If we are not dealing with a streaming device,
446     *  write the block now to ensure we have write permission.
447     *  It is better to find out now rather than later.
448     * We do not write the block now if this is an ANSI label. This
449     *  avoids re-writing the ANSI label, which we do not want to do.
450     */
451    if (!dev->has_cap(CAP_STREAM)) {
452       if (!dev->rewind(dcr)) {
453          Jmsg2(jcr, M_FATAL, 0, _("Rewind error on device %s: ERR=%s\n"),
454                dev->print_name(), dev->print_errmsg());
455          return false;
456       }
457       if (recycle) {
458          volume_unused(dcr);             /* mark volume unused */
459          if (!dev->truncate(dcr)) {
460             Jmsg2(jcr, M_FATAL, 0, _("Truncate error on device %s: ERR=%s\n"),
461                   dev->print_name(), dev->print_errmsg());
462             return false;
463          }
464          if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
465             Jmsg2(jcr, M_FATAL, 0,
466                _("Failed to re-open DVD after truncate on device %s: ERR=%s\n"),
467                dev->print_name(), dev->print_errmsg());
468             return false;
469          }
470       }
471
472       /*
473        * If we have already detected an ANSI label, re-read it
474        *   to skip past it. Otherwise, we write a new one if 
475        *   so requested.  
476        */
477       if (dev->label_type != B_BACULA_LABEL) {
478          if (read_ansi_ibm_label(dcr) != VOL_OK) {
479             dev->rewind(dcr);
480             return false;
481          }
482       } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, dev->VolHdr.VolumeName)) {
483          return false;
484       }
485
486       /* Attempt write to check write permission */
487       Dmsg1(200, "Attempt to write to device fd=%d.\n", dev->fd());
488       if (!write_block_to_dev(dcr)) {
489          Jmsg2(jcr, M_ERROR, 0, _("Unable to write device %s: ERR=%s\n"),
490             dev->print_name(), dev->print_errmsg());
491          Dmsg0(200, "===ERROR write block to dev\n");
492          return false;
493       }
494    }
495    dev->set_labeled();
496    /* Set or reset Volume statistics */
497    dev->VolCatInfo.VolCatJobs = 0;
498    dev->VolCatInfo.VolCatFiles = 0;
499    dev->VolCatInfo.VolCatErrors = 0;
500    dev->VolCatInfo.VolCatBlocks = 0;
501    dev->VolCatInfo.VolCatRBytes = 0;
502    if (recycle) {
503       dev->VolCatInfo.VolCatMounts++;
504       dev->VolCatInfo.VolCatRecycles++;
505    } else {
506       dev->VolCatInfo.VolCatMounts = 1;
507       dev->VolCatInfo.VolCatRecycles = 0;
508       dev->VolCatInfo.VolCatWrites = 1;
509       dev->VolCatInfo.VolCatReads = 1;
510    }
511    Dmsg0(150, "dir_update_vol_info. Set Append\n");
512    bstrncpy(dev->VolCatInfo.VolCatStatus, "Append", sizeof(dev->VolCatInfo.VolCatStatus));
513    if (!dir_update_volume_info(dcr, true, true)) {  /* indicate doing relabel */
514       return false;
515    }
516    if (recycle) {
517       Jmsg(jcr, M_INFO, 0, _("Recycled volume \"%s\" on device %s, all previous data lost.\n"),
518          dcr->VolumeName, dev->print_name());
519    } else {
520       Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume \"%s\" on device %s\n"),
521          dcr->VolumeName, dev->print_name());
522    }
523    /*
524     * End writing real Volume label (from pre-labeled tape), or recycling
525     *  the volume.
526     */
527    Dmsg0(200, "OK from rewrite vol label.\n");
528    return true;
529 }
530
531
532 /*
533  *  create_volume_label_record
534  *   Serialize label (from dev->VolHdr structure) into device record.
535  *   Assumes that the dev->VolHdr structure is properly
536  *   initialized.
537 */
538 static void create_volume_label_record(DCR *dcr, DEV_RECORD *rec)
539 {
540    ser_declare;
541    struct date_time dt;
542    DEVICE *dev = dcr->dev;
543    JCR *jcr = dcr->jcr;
544    char buf[100];
545
546    /* Serialize the label into the device record. */
547
548    rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
549    ser_begin(rec->data, SER_LENGTH_Volume_Label);
550    ser_string(dev->VolHdr.Id);
551
552    ser_uint32(dev->VolHdr.VerNum);
553
554    if (dev->VolHdr.VerNum >= 11) {
555       ser_btime(dev->VolHdr.label_btime);
556       dev->VolHdr.write_btime = get_current_btime();
557       ser_btime(dev->VolHdr.write_btime);
558       dev->VolHdr.write_date = 0;
559       dev->VolHdr.write_time = 0;
560    } else {
561       /* OLD WAY DEPRECATED */
562       ser_float64(dev->VolHdr.label_date);
563       ser_float64(dev->VolHdr.label_time);
564       get_current_time(&dt);
565       dev->VolHdr.write_date = dt.julian_day_number;
566       dev->VolHdr.write_time = dt.julian_day_fraction;
567    }
568    ser_float64(dev->VolHdr.write_date);   /* 0 if VerNum >= 11 */
569    ser_float64(dev->VolHdr.write_time);   /* 0  if VerNum >= 11 */
570
571    ser_string(dev->VolHdr.VolumeName);
572    ser_string(dev->VolHdr.PrevVolumeName);
573    ser_string(dev->VolHdr.PoolName);
574    ser_string(dev->VolHdr.PoolType);
575    ser_string(dev->VolHdr.MediaType);
576
577    ser_string(dev->VolHdr.HostName);
578    ser_string(dev->VolHdr.LabelProg);
579    ser_string(dev->VolHdr.ProgVersion);
580    ser_string(dev->VolHdr.ProgDate);
581
582    ser_end(rec->data, SER_LENGTH_Volume_Label);
583    rec->data_len = ser_length(rec->data);
584    rec->FileIndex = dev->VolHdr.LabelType;
585    rec->VolSessionId = jcr->VolSessionId;
586    rec->VolSessionTime = jcr->VolSessionTime;
587    rec->Stream = jcr->NumWriteVolumes;
588    Dmsg2(150, "Created Vol label rec: FI=%s len=%d\n", FI_to_ascii(buf, rec->FileIndex),
589       rec->data_len);
590 }
591
592
593 /*
594  * Create a volume label in memory
595  */
596 void create_volume_label(DEVICE *dev, const char *VolName, 
597                          const char *PoolName, bool dvdnow)
598 {
599    DEVRES *device = (DEVRES *)dev->device;
600
601    Dmsg0(130, "Start create_volume_label()\n");
602
603    ASSERT(dev != NULL);
604
605    dev->clear_volhdr();          /* release any old volume */
606
607    bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
608    dev->VolHdr.VerNum = BaculaTapeVersion;
609    if (dev->is_dvd() && dvdnow) {
610       /* We do not want to re-label a DVD so write VOL_LABEL now */
611       dev->VolHdr.LabelType = VOL_LABEL;
612    } else {
613       dev->VolHdr.LabelType = PRE_LABEL;  /* Mark tape as unused */
614    }
615    bstrncpy(dev->VolHdr.VolumeName, VolName, sizeof(dev->VolHdr.VolumeName));
616    bstrncpy(dev->VolHdr.PoolName, PoolName, sizeof(dev->VolHdr.PoolName));
617    bstrncpy(dev->VolHdr.MediaType, device->media_type, sizeof(dev->VolHdr.MediaType));
618
619    bstrncpy(dev->VolHdr.PoolType, "Backup", sizeof(dev->VolHdr.PoolType));
620
621    dev->VolHdr.label_btime = get_current_btime();
622    dev->VolHdr.label_date = 0;
623    dev->VolHdr.label_time = 0;
624
625    if (gethostname(dev->VolHdr.HostName, sizeof(dev->VolHdr.HostName)) != 0) {
626       dev->VolHdr.HostName[0] = 0;
627    }
628    bstrncpy(dev->VolHdr.LabelProg, my_name, sizeof(dev->VolHdr.LabelProg));
629    sprintf(dev->VolHdr.ProgVersion, "Ver. %s %s", VERSION, BDATE);
630    sprintf(dev->VolHdr.ProgDate, "Build %s %s", __DATE__, __TIME__);
631    dev->set_labeled();               /* set has Bacula label */
632    if (debug_level >= 90) {
633       dump_volume_label(dev);
634    }
635 }
636
637 /*
638  * Create session label
639  *  The pool memory must be released by the calling program
640  */
641 void create_session_label(DCR *dcr, DEV_RECORD *rec, int label)
642 {
643    JCR *jcr = dcr->jcr;
644    ser_declare;
645
646    rec->VolSessionId   = jcr->VolSessionId;
647    rec->VolSessionTime = jcr->VolSessionTime;
648    rec->Stream         = jcr->JobId;
649
650    rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
651    ser_begin(rec->data, SER_LENGTH_Session_Label);
652    ser_string(BaculaId);
653    ser_uint32(BaculaTapeVersion);
654
655    ser_uint32(jcr->JobId);
656
657    /* Changed in VerNum 11 */
658    ser_btime(get_current_btime());
659    ser_float64(0);
660
661    ser_string(dcr->pool_name);
662    ser_string(dcr->pool_type);
663    ser_string(jcr->job_name);         /* base Job name */
664    ser_string(jcr->client_name);
665
666    /* Added in VerNum 10 */
667    ser_string(jcr->Job);              /* Unique name of this Job */
668    ser_string(jcr->fileset_name);
669    ser_uint32(jcr->JobType);
670    ser_uint32(jcr->JobLevel);
671    /* Added in VerNum 11 */
672    ser_string(jcr->fileset_md5);
673
674    if (label == EOS_LABEL) {
675       ser_uint32(jcr->JobFiles);
676       ser_uint64(jcr->JobBytes);
677       ser_uint32(dcr->StartBlock);
678       ser_uint32(dcr->EndBlock);
679       ser_uint32(dcr->StartFile);
680       ser_uint32(dcr->EndFile);
681       ser_uint32(jcr->JobErrors);
682
683       /* Added in VerNum 11 */
684       ser_uint32(jcr->JobStatus);
685    }
686    ser_end(rec->data, SER_LENGTH_Session_Label);
687    rec->data_len = ser_length(rec->data);
688 }
689
690 /* Write session label
691  *  Returns: false on failure
692  *           true  on success
693  */
694 bool write_session_label(DCR *dcr, int label)
695 {
696    JCR *jcr = dcr->jcr;
697    DEVICE *dev = dcr->dev;
698    DEV_RECORD *rec;
699    DEV_BLOCK *block = dcr->block;
700    char buf1[100], buf2[100];
701
702    rec = new_record();
703    Dmsg1(130, "session_label record=%x\n", rec);
704    switch (label) {
705    case SOS_LABEL:
706       if (dev->is_tape()) {
707          dcr->StartBlock = dev->block_num;
708          dcr->StartFile  = dev->file;
709       } else {
710          dcr->StartBlock = (uint32_t)dev->file_addr;
711          dcr->StartFile = (uint32_t)(dev->file_addr >> 32);
712       }
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 }