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