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