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