]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/label.c
- Add Date, Job, level to updates to .bsr file in
[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-2005 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 ammended 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 extern char my_name[];
32 extern int debug_level;
33
34 /*
35  * Read the volume label
36  *
37  *  If dcr->VolumeName == NULL, we accept any Bacula Volume
38  *  If dcr->VolumeName[0] == 0, we accept any Bacula Volume
39  *  otherwise dcr->VolumeName must match the Volume.
40  *
41  *  If VolName given, ensure that it matches
42  *
43  *  Returns VOL_  code as defined in record.h
44  *    VOL_NOT_READ
45  *    VOL_OK                          good label found
46  *    VOL_NO_LABEL                    volume not labeled
47  *    VOL_IO_ERROR                    I/O error reading tape
48  *    VOL_NAME_ERROR                  label has wrong name
49  *    VOL_CREATE_ERROR                Error creating label
50  *    VOL_VERSION_ERROR               label has wrong version
51  *    VOL_LABEL_ERROR                 bad label type
52  *    VOL_NO_MEDIA                    no media in drive
53  *
54  *  The dcr block is emptied on return, and the Volume is
55  *    rewound.
56  */
57 int read_dev_volume_label(DCR *dcr)
58 {
59    JCR *jcr = dcr->jcr;
60    DEVICE *dev = dcr->dev;
61    char *VolName = dcr->VolumeName;
62    DEV_RECORD *record;
63    bool ok = false;
64    DEV_BLOCK *block = dcr->block;
65    int stat;
66    bool want_ansi_label;
67
68    Dmsg3(100, "Enter read_volume_label device=%s vol=%s dev_Vol=%s\n",
69       dev->name(), VolName, dev->VolHdr.VolumeName);
70
71    if (!dev->is_open()) {
72       Emsg0(M_ABORT, 0, _("BAD call to read_dev_volume_label\n"));
73    }
74    if (dev->is_labeled()) {              /* did we already read label? */
75       /* Compare Volume Names allow special wild card */
76       if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolumeName, VolName) != 0) {
77          Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
78             dev->print_name(), VolName, dev->VolHdr.VolumeName);
79          /*
80           * Cancel Job if too many label errors
81           *  => we are in a loop
82           */
83          if (!dev->poll && jcr->label_errors++ > 100) {
84             Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
85          }
86          return VOL_NAME_ERROR;
87       }
88       Dmsg0(30, "Leave read_volume_label() VOL_OK\n");
89       return VOL_OK;       /* label already read */
90    }
91
92    dev->clear_labeled();
93    dev->clear_append();
94    dev->clear_read();
95    dev->label_type = B_BACULA_LABEL;
96
97    if (!rewind_dev(dev)) {
98       Mmsg(jcr->errmsg, _("Couldn't rewind device %s: ERR=%s\n"), 
99          dev->print_name(), strerror_dev(dev));
100       Dmsg1(30, "%s", jcr->errmsg);
101       return VOL_NO_MEDIA;
102    }
103    bstrncpy(dev->VolHdr.Id, "**error**", sizeof(dev->VolHdr.Id));
104
105   /* Read ANSI/IBM label if so requested */
106   
107   want_ansi_label = dcr->VolCatInfo.LabelType != B_BACULA_LABEL ||
108                     dcr->device->label_type != B_BACULA_LABEL;
109   if (want_ansi_label || dev_cap(dev, CAP_CHECKLABELS)) {
110       stat = read_ansi_ibm_label(dcr);            
111       /* If we want a label and didn't find it, return error */
112       if (want_ansi_label && stat != VOL_OK) {
113          empty_block(block);
114          rewind_dev(dev);
115          return stat;
116       }
117       if (stat == VOL_NAME_ERROR || stat == VOL_LABEL_ERROR) {
118          Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
119               dev->print_name(), VolName, dev->VolHdr.VolumeName);
120          if (!dev->poll && jcr->label_errors++ > 100) {
121             Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
122          }
123          empty_block(block);
124          rewind_dev(dev);
125          return stat;
126       }
127       if (stat != VOL_OK) {           /* Not an ANSI/IBM label, so re-read */
128          rewind_dev(dev);
129       }
130    }
131   
132    /* Read the Bacula Volume label block */
133    record = new_record();
134    empty_block(block);
135
136    Dmsg0(90, "Big if statement in read_volume_label\n");
137    if (!read_block_from_dev(dcr, NO_BLOCK_NUMBER_CHECK)) {
138       Mmsg(jcr->errmsg, _("Requested Volume \"%s\" on %s is not a Bacula "
139            "labeled Volume, because: ERR=%s"), NPRT(VolName), 
140            dev->print_name(), strerror_dev(dev));
141       Dmsg1(30, "%s", jcr->errmsg);
142    } else if (!read_record_from_block(block, record)) {
143       Mmsg(jcr->errmsg, _("Could not read Volume label from block.\n"));
144       Dmsg1(30, "%s", jcr->errmsg);
145    } else if (!unser_volume_label(dev, record)) {
146       Mmsg(jcr->errmsg, _("Could not unserialize Volume label: ERR=%s\n"),
147          strerror_dev(dev));
148       Dmsg1(30, "%s", jcr->errmsg);
149    } else if (strcmp(dev->VolHdr.Id, BaculaId) != 0 &&
150               strcmp(dev->VolHdr.Id, OldBaculaId) != 0) {
151       Mmsg(jcr->errmsg, _("Volume Header Id bad: %s\n"), dev->VolHdr.Id);
152       Dmsg1(30, "%s", jcr->errmsg);
153    } else {
154       ok = true;
155    }
156    free_record(record);               /* finished reading Volume record */
157    empty_block(block);                /* done with block */
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          return VOL_OK;
164       }
165       rewind_dev(dev);
166       return VOL_NO_LABEL;
167    }
168
169    /* At this point, we have read the first Bacula block, and
170     * then read the Bacula Volume label. Now we need to
171     * make sure we have the right Volume.
172     */
173
174    /* If we are a streaming device, we only get one chance to read */
175    if (!dev_cap(dev, CAP_STREAM)) {
176       rewind_dev(dev);
177    }
178
179    if (dev->VolHdr.VerNum != BaculaTapeVersion &&
180        dev->VolHdr.VerNum != OldCompatibleBaculaTapeVersion1 &&
181        dev->VolHdr.VerNum != OldCompatibleBaculaTapeVersion2) {
182       Mmsg(jcr->errmsg, _("Volume on %s has wrong Bacula version. Wanted %d got %d\n"),
183          dev->print_name(), BaculaTapeVersion, dev->VolHdr.VerNum);
184       Dmsg1(30, "%s", jcr->errmsg);
185       return VOL_VERSION_ERROR;
186    }
187
188    /* We are looking for either an unused Bacula tape (PRE_LABEL) or
189     * a Bacula volume label (VOL_LABEL)
190     */
191    if (dev->VolHdr.LabelType != PRE_LABEL && dev->VolHdr.LabelType != VOL_LABEL) {
192       Mmsg(jcr->errmsg, _("Volume on %s has bad Bacula label type: %x\n"),
193           dev->print_name(), dev->VolHdr.LabelType);
194       Dmsg1(30, "%s", jcr->errmsg);
195       if (!dev->poll && jcr->label_errors++ > 100) {
196          Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
197       }
198       return VOL_LABEL_ERROR;
199    }
200
201    dev->set_labeled();               /* set has Bacula label */
202    new_volume(dev->VolHdr.VolumeName, dev);
203
204    /* Compare Volume Names */
205    Dmsg2(30, "Compare Vol names: VolName=%s hdr=%s\n", VolName?VolName:"*", dev->VolHdr.VolumeName);
206    if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolumeName, VolName) != 0) {
207       Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
208            dev->print_name(), VolName, dev->VolHdr.VolumeName);
209       Dmsg1(30, "%s", jcr->errmsg);
210       /*
211        * Cancel Job if too many label errors
212        *  => we are in a loop
213        */
214       if (!dev->poll && jcr->label_errors++ > 100) {
215          Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
216       }
217       return VOL_NAME_ERROR;
218    }
219    Dmsg1(30, "Copy vol_name=%s\n", dev->VolHdr.VolumeName);
220
221    if (debug_level >= 10) {
222       dump_volume_label(dev);
223    }
224    Dmsg0(30, "Leave read_volume_label() VOL_OK\n");
225    return VOL_OK;
226 }
227
228 /* Read the volume label by guessing the volume name. (only for DVD devices)
229  * write is true if we are reading the label before writing to the device.
230  *
231  * If the volume name cannot be guessed :
232  *  Writing : returns the label of the current file (on the harddisk).
233  *  Reading : returns an error
234  */
235 int read_dvd_volume_label(DCR *dcr, bool write) 
236 {
237    int vol_label_status;
238    DEVICE *dev = dcr->dev;
239    JCR *jcr = dcr->jcr;
240    Dmsg3(100, "Enter read_dvd_volume_label device=%s vol=%s dev_Vol=%s\n",
241          dev->print_name(), dcr->VolumeName, dev->VolHdr.VolumeName);
242    
243    if (!dev->is_dvd()) {  
244       Jmsg1(jcr, M_ABORT, 0, _("Device %s is not a DVD.\n"), dev->print_name());
245       return -1;    /* for compiler, won't get here */
246    }
247    
248    if (!write && (dcr->VolCatInfo.VolCatParts == 0)) {
249       Dmsg0(100, "Leave read_dvd_volume_label !writing, and VolCatParts == 0\n");
250       return read_dev_volume_label(dcr);
251    }
252    
253    /*
254     * For mounted devices, try to guess the Volume name
255     * and read the label if possible.
256     */
257    if (open_mounted_dev(dev) < 0) {     
258       if (!write || dcr->VolCatInfo.VolCatParts > 0) {
259          Mmsg2(jcr->errmsg, _("Requested Volume \"%s\" on %s is not a Bacula labeled Volume."),
260                dev->print_name(), dcr->VolumeName);
261          Dmsg0(100, "Leave read_dvd_volume_label VOL_NO_LABEL (!open_mounted_dev)\n");
262          return VOL_NO_LABEL;
263       }
264       
265       if (write && dev->free_space_errno < 0) {
266          Dmsg0(100, "Leave read_dvd_volume_label !free_space VOL_NO_MEDIA\n");
267          Mmsg2(jcr->errmsg, _("free_space error on %s. The current medium is probably not writable: ERR=%s.\n"),
268                dev->print_name(), dev->errmsg);
269          return VOL_NO_MEDIA;
270       }
271       
272       /* 
273        * If we can't guess the name, and we are writing, 
274        * just reopen the right file with open_first_part.
275        */
276       if (open_first_part(dev) < 0) {
277          berrno be;
278          Mmsg2(jcr->errmsg, _("open_first_part error on %s: ERR=%s.\n"),
279                dev->print_name(), be.strerror());
280          Dmsg0(100, "Leave read_dvd_volume_label VOL_IO_ERROR (!open_mounted_dev && !open_first_part)\n");
281          return VOL_IO_ERROR;
282       }
283       
284       Dmsg0(100, "Leave read_dvd_volume_label !open_mounted_dev\n");
285       return read_dev_volume_label(dcr);
286    } else {
287       if (write && dcr->dev->free_space_errno < 0) {
288          Dmsg0(100, "Leave read_dvd_volume_label !free_space VOL_NO_MEDIA\n");
289          Mmsg2(jcr->errmsg, _("free_space error on %s. The current medium is probably not writable: ERR=%s.\n"),
290                dev->print_name(), dev->errmsg);
291          return VOL_NO_MEDIA;
292       }
293       
294       vol_label_status = read_dev_volume_label(dcr);
295
296       if (!write || dcr->VolCatInfo.VolCatParts > 0) {
297          Dmsg0(100, "Leave read_dvd_volume_label (open_mounted_dev && (!write || dcr->VolCatInfo.VolCatParts > 0))\n");
298          return vol_label_status;
299       }
300       
301       if (open_first_part(dcr->dev) < 0) {
302          berrno be;
303          Mmsg2(jcr->errmsg, _("open_first_part error on %s: ERR=%s.\n"),
304                dev->print_name(), be.strerror());
305          Dmsg0(100, "Leave read_dvd_volume_label VOL_IO_ERROR (open_mounted_dev && !open_first_part)\n");
306          return VOL_IO_ERROR;
307       }
308       
309       /* When writing, if the guessed volume name is not the right volume name, 
310        * report the error, otherwise, just continue with the right file.
311        */
312       if (vol_label_status != VOL_NAME_ERROR) {
313          Dmsg0(100, "Leave read_dvd_volume_label (open_mounted_dev && !VOL_NAME_ERROR)\n");
314          dev->clear_labeled();   
315          return read_dev_volume_label(dcr);
316       } else {
317          Dmsg0(100, "Leave read_dvd_volume_label (open_mounted_dev && VOL_NAME_ERROR)\n");
318          return vol_label_status;
319       }
320    }
321 }
322
323 /*
324  * Put a volume label into the block
325  *
326  *  Returns: false on failure
327  *           true  on success
328  */
329 bool write_volume_label_to_block(DCR *dcr)
330 {
331    DEV_RECORD rec;
332    DEVICE *dev = dcr->dev;
333    JCR *jcr = dcr->jcr;
334    DEV_BLOCK *block = dcr->block;
335
336    Dmsg0(20, "write Label in write_volume_label_to_block()\n");
337    memset(&rec, 0, sizeof(rec));
338    rec.data = get_memory(SER_LENGTH_Volume_Label);
339    empty_block(block);                /* Volume label always at beginning */
340
341    create_volume_label_record(dcr, &rec);
342
343    block->BlockNumber = 0;
344    if (!write_record_to_block(block, &rec)) {
345       free_pool_memory(rec.data);
346       Jmsg1(jcr, M_FATAL, 0, _("Cannot write Volume label to block for device %s\n"),
347          dev->print_name());
348       return false;
349    } else {
350       Dmsg1(90, "Wrote label of %d bytes to block\n", rec.data_len);
351    }
352    free_pool_memory(rec.data);
353    return true;
354 }
355
356
357 /*
358  * Write a Volume Label
359  *  !!! Note, this is ONLY used for writing
360  *            a fresh volume label.  Any data
361  *            after the label will be destroyed,
362  *            in fact, we write the label 5 times !!!!
363  *
364  *  This routine expects that open_device() was previously called.
365  *
366  *  This routine should be used only when labeling a blank tape.
367  */
368 bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName, const char *PoolName)
369 {
370    DEVICE *dev = dcr->dev;
371
372
373    Dmsg0(99, "write_volume_label()\n");
374    empty_block(dcr->block);
375
376    Dmsg1(100, "Label type=%d\n", dev->label_type);
377    if (!rewind_dev(dev)) {
378       memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
379       Dmsg2(30, "Bad status on %s from rewind: ERR=%s\n", dev->print_name(), strerror_dev(dev));
380       if (!forge_on) {
381          goto bail_out;
382       }
383    }
384
385    /* Create PRE_LABEL */
386    create_volume_label(dev, VolName, PoolName);
387
388    /*
389     * If we have already detected an ANSI label, re-read it
390     *   to skip past it. Otherwise, we write a new one if 
391     *   so requested.  
392     */
393    if (dev->label_type != B_BACULA_LABEL) {
394       if (read_ansi_ibm_label(dcr) != VOL_OK) {
395          rewind_dev(dev);
396          goto bail_out;
397       }
398    } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, VolName)) {
399       goto bail_out;
400    }
401
402    create_volume_label_record(dcr, dcr->rec);
403    dcr->rec->Stream = 0;
404
405    /* Temporarily mark in append state to enable writing */
406    dev->set_append();
407    if (!write_record_to_block(dcr->block, dcr->rec)) {
408       Dmsg2(30, "Bad Label write on %s: ERR=%s\n", dev->print_name(), strerror_dev(dev));
409       goto bail_out;
410    } else {
411       Dmsg2(30, "Wrote label of %d bytes to %s\n", dcr->rec->data_len, dev->print_name());
412    }
413
414    Dmsg0(99, "Call write_block_to_dev()\n");
415    if (!write_block_to_dev(dcr)) {
416       Dmsg2(30, "Bad Label write on %s: ERR=%s\n", dev->print_name(), strerror_dev(dev));
417       goto bail_out;
418    }
419    Dmsg0(99, " Wrote block to device\n");
420
421    if (weof_dev(dev, 1) == 0) {
422       dev->set_labeled();
423       write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
424    }
425
426    if (debug_level >= 20)  {
427       dump_volume_label(dev);
428    }
429    dev->clear_append();               /* remove append since this is PRE_LABEL */
430    return true;
431
432 bail_out:
433    memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
434    dev->clear_append();               /* remove append since this is PRE_LABEL */
435    return false;
436 }
437
438 /*
439  * Write a volume label. This is ONLY called if we have a valid Bacula
440  *   label of type PRE_LABEL;
441  *  Returns: true if OK
442  *           false if unable to write it
443  */
444 bool rewrite_volume_label(DCR *dcr, bool recycle)
445 {
446    DEVICE *dev = dcr->dev;
447    JCR *jcr = dcr->jcr;
448
449    Dmsg1(190, "set append found freshly labeled volume. dev=%x\n", dev);
450    dev->VolHdr.LabelType = VOL_LABEL; /* set Volume label */
451    dev->set_append();
452    if (!write_volume_label_to_block(dcr)) {
453       Dmsg0(200, "Error from write volume label.\n");
454       return false;
455    }
456    /*
457     * If we are not dealing with a streaming device,
458     *  write the block now to ensure we have write permission.
459     *  It is better to find out now rather than later.
460     * We do not write the block now if this is an ANSI label. This
461     *  avoids re-writing the ANSI label, which we do not want to do.
462     */
463    if (!dev_cap(dev, CAP_STREAM)) {
464       if (!rewind_dev(dev)) {
465          Jmsg2(jcr, M_WARNING, 0, _("Rewind error on device %s: ERR=%s\n"),
466                dev->print_name(), strerror_dev(dev));
467       }
468       if (recycle) {
469          if (!truncate_dev(dev)) {
470             Jmsg2(jcr, M_WARNING, 0, _("Truncate error on device %s: ERR=%s\n"),
471                   dev->print_name(), strerror_dev(dev));
472          }
473       }
474
475       /*
476        * If we have already detected an ANSI label, re-read it
477        *   to skip past it. Otherwise, we write a new one if 
478        *   so requested.  
479        */
480       if (dev->label_type != B_BACULA_LABEL) {
481          if (read_ansi_ibm_label(dcr) != VOL_OK) {
482             rewind_dev(dev);
483             return false;
484          }
485       } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, dev->VolHdr.VolumeName)) {
486          return false;
487       }
488
489       /* Attempt write to check write permission */
490       Dmsg0(200, "Attempt to write to device.\n");
491       if (!write_block_to_dev(dcr)) {
492          Jmsg2(jcr, M_ERROR, 0, _("Unable to write device %s: ERR=%s\n"),
493             dev->print_name(), strerror_dev(dev));
494          Dmsg0(200, "===ERROR write block to dev\n");
495          return false;
496       }
497    }
498    /* Set or reset Volume statistics */
499    dev->VolCatInfo.VolCatJobs = 0;
500    dev->VolCatInfo.VolCatFiles = 0;
501    dev->VolCatInfo.VolCatBytes = 1;
502    dev->VolCatInfo.VolCatErrors = 0;
503    dev->VolCatInfo.VolCatBlocks = 0;
504    dev->VolCatInfo.VolCatRBytes = 0;
505    if (recycle) {
506       dev->VolCatInfo.VolCatMounts++;
507       dev->VolCatInfo.VolCatRecycles++;
508    } else {
509       dev->VolCatInfo.VolCatMounts = 1;
510       dev->VolCatInfo.VolCatRecycles = 0;
511       dev->VolCatInfo.VolCatWrites = 1;
512       dev->VolCatInfo.VolCatReads = 1;
513    }
514    Dmsg0(100, "dir_update_vol_info. Set Append\n");
515    bstrncpy(dev->VolCatInfo.VolCatStatus, "Append", sizeof(dev->VolCatInfo.VolCatStatus));
516    if (!dir_update_volume_info(dcr, true)) {  /* indicate doing relabel */
517       return false;
518    }
519    if (recycle) {
520       Jmsg(jcr, M_INFO, 0, _("Recycled volume \"%s\" on device %s, all previous data lost.\n"),
521          dcr->VolumeName, dev->print_name());
522    } else {
523       Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume \"%s\" on device %s\n"),
524          dcr->VolumeName, dev->print_name());
525    }
526    /*
527     * End writing real Volume label (from pre-labeled tape), or recycling
528     *  the volume.
529     */
530    Dmsg0(200, "OK from rewite vol label.\n");
531    return true;
532 }
533
534
535 /*
536  *  create_volume_label_record
537  *   Serialize label (from dev->VolHdr structure) into device record.
538  *   Assumes that the dev->VolHdr structure is properly
539  *   initialized.
540 */
541 static void create_volume_label_record(DCR *dcr, DEV_RECORD *rec)
542 {
543    ser_declare;
544    struct date_time dt;
545    DEVICE *dev = dcr->dev;
546    JCR *jcr = dcr->jcr;
547
548    /* Serialize the label into the device record. */
549
550    rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
551    ser_begin(rec->data, SER_LENGTH_Volume_Label);
552    ser_string(dev->VolHdr.Id);
553
554    ser_uint32(dev->VolHdr.VerNum);
555
556    if (dev->VolHdr.VerNum >= 11) {
557       ser_btime(dev->VolHdr.label_btime);
558       dev->VolHdr.write_btime = get_current_btime();
559       ser_btime(dev->VolHdr.write_btime);
560       dev->VolHdr.write_date = 0;
561       dev->VolHdr.write_time = 0;
562    } else {
563       /* OLD WAY DEPRECATED */
564       ser_float64(dev->VolHdr.label_date);
565       ser_float64(dev->VolHdr.label_time);
566       get_current_time(&dt);
567       dev->VolHdr.write_date = dt.julian_day_number;
568       dev->VolHdr.write_time = dt.julian_day_fraction;
569    }
570    ser_float64(dev->VolHdr.write_date);   /* 0 if VerNum >= 11 */
571    ser_float64(dev->VolHdr.write_time);   /* 0  if VerNum >= 11 */
572
573    ser_string(dev->VolHdr.VolumeName);
574    ser_string(dev->VolHdr.PrevVolumeName);
575    ser_string(dev->VolHdr.PoolName);
576    ser_string(dev->VolHdr.PoolType);
577    ser_string(dev->VolHdr.MediaType);
578
579    ser_string(dev->VolHdr.HostName);
580    ser_string(dev->VolHdr.LabelProg);
581    ser_string(dev->VolHdr.ProgVersion);
582    ser_string(dev->VolHdr.ProgDate);
583
584    ser_end(rec->data, SER_LENGTH_Volume_Label);
585    rec->data_len = ser_length(rec->data);
586    rec->FileIndex = dev->VolHdr.LabelType;
587    rec->VolSessionId = jcr->VolSessionId;
588    rec->VolSessionTime = jcr->VolSessionTime;
589    rec->Stream = jcr->NumVolumes;
590    Dmsg2(100, "Created Vol label rec: FI=%s len=%d\n", FI_to_ascii(rec->FileIndex),
591       rec->data_len);
592 }
593
594
595 /*
596  * Create a volume label in memory
597  */
598 void create_volume_label(DEVICE *dev, const char *VolName, const char *PoolName)
599 {
600    DEVRES *device = (DEVRES *)dev->device;
601
602    Dmsg0(90, "Start create_volume_label()\n");
603
604    ASSERT(dev != NULL);
605
606    memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
607
608    bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
609    dev->VolHdr.VerNum = BaculaTapeVersion;
610    dev->VolHdr.LabelType = PRE_LABEL;  /* Mark tape as unused */
611    bstrncpy(dev->VolHdr.VolumeName, VolName, sizeof(dev->VolHdr.VolumeName));
612    bstrncpy(dev->VolHdr.PoolName, PoolName, sizeof(dev->VolHdr.PoolName));
613    bstrncpy(dev->VolHdr.MediaType, device->media_type, sizeof(dev->VolHdr.MediaType));
614
615    bstrncpy(dev->VolHdr.PoolType, "Backup", sizeof(dev->VolHdr.PoolType));
616
617    dev->VolHdr.label_btime = get_current_btime();
618    dev->VolHdr.label_date = 0;
619    dev->VolHdr.label_time = 0;
620
621    if (gethostname(dev->VolHdr.HostName, sizeof(dev->VolHdr.HostName)) != 0) {
622       dev->VolHdr.HostName[0] = 0;
623    }
624    bstrncpy(dev->VolHdr.LabelProg, my_name, sizeof(dev->VolHdr.LabelProg));
625    sprintf(dev->VolHdr.ProgVersion, "Ver. %s %s", VERSION, BDATE);
626    sprintf(dev->VolHdr.ProgDate, "Build %s %s", __DATE__, __TIME__);
627    dev->set_labeled();               /* set has Bacula label */
628    if (debug_level >= 90) {
629       dump_volume_label(dev);
630    }
631 }
632
633 /*
634  * Create session label
635  *  The pool memory must be released by the calling program
636  */
637 void create_session_label(DCR *dcr, DEV_RECORD *rec, int label)
638 {
639    JCR *jcr = dcr->jcr;
640    ser_declare;
641
642    rec->VolSessionId   = jcr->VolSessionId;
643    rec->VolSessionTime = jcr->VolSessionTime;
644    rec->Stream         = jcr->JobId;
645
646    rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
647    ser_begin(rec->data, SER_LENGTH_Session_Label);
648    ser_string(BaculaId);
649    ser_uint32(BaculaTapeVersion);
650
651    ser_uint32(jcr->JobId);
652
653    /* Changed in VerNum 11 */
654    ser_btime(get_current_btime());
655    ser_float64(0);
656
657    ser_string(dcr->pool_name);
658    ser_string(dcr->pool_type);
659    ser_string(jcr->job_name);         /* base Job name */
660    ser_string(jcr->client_name);
661
662    /* Added in VerNum 10 */
663    ser_string(jcr->Job);              /* Unique name of this Job */
664    ser_string(jcr->fileset_name);
665    ser_uint32(jcr->JobType);
666    ser_uint32(jcr->JobLevel);
667    /* Added in VerNum 11 */
668    ser_string(jcr->fileset_md5);
669
670    if (label == EOS_LABEL) {
671       ser_uint32(jcr->JobFiles);
672       ser_uint64(jcr->JobBytes);
673       ser_uint32(dcr->StartBlock);
674       ser_uint32(dcr->EndBlock);
675       ser_uint32(dcr->StartFile);
676       ser_uint32(dcr->EndFile);
677       ser_uint32(jcr->JobErrors);
678
679       /* Added in VerNum 11 */
680       ser_uint32(jcr->JobStatus);
681    }
682    ser_end(rec->data, SER_LENGTH_Session_Label);
683    rec->data_len = ser_length(rec->data);
684 }
685
686 /* Write session label
687  *  Returns: false on failure
688  *           true  on success
689  */
690 bool write_session_label(DCR *dcr, int label)
691 {
692    JCR *jcr = dcr->jcr;
693    DEVICE *dev = dcr->dev;
694    DEV_RECORD *rec;
695    DEV_BLOCK *block = dcr->block;
696
697    rec = new_record();
698    Dmsg1(90, "session_label record=%x\n", rec);
699    switch (label) {
700    case SOS_LABEL:
701       if (dev->is_tape()) {
702          dcr->StartBlock = dev->block_num;
703          dcr->StartFile  = dev->file;
704       } else {
705          dcr->StartBlock = (uint32_t)dev->file_addr;
706          dcr->StartFile = (uint32_t)(dev->file_addr >> 32);
707       }
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 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(100, "Cannot write session label to block.\n");
734       if (!write_block_to_device(dcr)) {
735          Dmsg0(90, "Got session label write_block_to_dev error.\n");
736          /* ****FIXME***** errno is not set here */
737          Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"),
738                            dev_vol_name(dev), strerror(errno));
739          free_record(rec);
740          return false;
741       }
742    }
743    if (!write_record_to_block(block, rec)) {
744       Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"),
745                         dev_vol_name(dev), strerror(errno));
746       free_record(rec);
747       return false;
748    }
749
750    Dmsg6(20, "Write sesson_label record JobId=%d FI=%s SessId=%d Strm=%s len=%d "
751              "remainder=%d\n", jcr->JobId,
752       FI_to_ascii(rec->FileIndex), rec->VolSessionId,
753       stream_to_ascii(rec->Stream, rec->FileIndex), rec->data_len,
754       rec->remainder);
755
756    free_record(rec);
757    Dmsg2(20, "Leave write_session_label Block=%d File=%d\n",
758       dev->block_num, dev->file);
759    return true;
760 }
761
762 /*  unser_volume_label
763  *
764  * Unserialize the Bacula Volume label into the device Volume_Label
765  * structure.
766  *
767  * Assumes that the record is already read.
768  *
769  * Returns: false on error
770  *          true  on success
771 */
772
773 bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec)
774 {
775    ser_declare;
776
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(rec->FileIndex),
780               stream_to_ascii(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(90, "ser_read_vol\n");
820    if (debug_level >= 90) {
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, _(""
1006 "Date written      : %04d-%02d-%02d at %02d:%02d\n"),
1007       tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
1008    }
1009
1010    debug_level = dbl;
1011 }
1012
1013 void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose)
1014 {
1015    const char *type;
1016    int dbl;
1017
1018    dbl = debug_level;
1019    debug_level = 1;
1020    switch (rec->FileIndex) {
1021    case PRE_LABEL:
1022       type = _("Fresh Volume");
1023       break;
1024    case VOL_LABEL:
1025       type = _("Volume");
1026       break;
1027    case SOS_LABEL:
1028       type = _("Begin Job Session");
1029       break;
1030    case EOS_LABEL:
1031       type = _("End Job Session");
1032       break;
1033    case EOM_LABEL:
1034       type = _("End of Media");
1035       break;
1036    case EOT_LABEL:
1037       type = ("End of Tape");
1038       break;
1039    default:
1040       type = _("Unknown");
1041       break;
1042    }
1043    if (verbose) {
1044       switch (rec->FileIndex) {
1045       case PRE_LABEL:
1046       case VOL_LABEL:
1047          unser_volume_label(dev, rec);
1048          dump_volume_label(dev);
1049          break;
1050       case SOS_LABEL:
1051          dump_session_label(rec, type);
1052          break;
1053       case EOS_LABEL:
1054          dump_session_label(rec, type);
1055          break;
1056       case EOM_LABEL:
1057          Pmsg5(-1, "%s Record: SessId=%d SessTime=%d JobId=%d DataLen=%d\n",
1058             type, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
1059          break;
1060       case EOT_LABEL:
1061          Pmsg0(-1, _("End of physical tape.\n"));
1062          break;
1063       default:
1064          Pmsg5(-1, "%s Record: SessId=%d SessTime=%d JobId=%d DataLen=%d\n",
1065             type, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
1066          break;
1067       }
1068    } else {
1069       SESSION_LABEL label;
1070       switch (rec->FileIndex) {
1071       case SOS_LABEL:
1072          unser_session_label(&label, rec);
1073          Pmsg6(-1, "%s Record: SessId=%d SessTime=%d JobId=%d Level=%c Type=%c\n",
1074             type, rec->VolSessionId, rec->VolSessionTime, rec->Stream,
1075             label.JobLevel, label.JobType);
1076          break;
1077       case EOS_LABEL:
1078          char ed1[30], ed2[30];
1079          unser_session_label(&label, rec);
1080          Pmsg6(-1, "%s Record: SessId=%d SessTime=%d JobId=%d Level=%c Type=%c\n",
1081             type, rec->VolSessionId, rec->VolSessionTime, rec->Stream,
1082             label.JobLevel, label.JobType);
1083          Pmsg4(-1, "   Files=%s Bytes=%s Errors=%d Status=%c\n",
1084             edit_uint64_with_commas(label.JobFiles, ed1),
1085             edit_uint64_with_commas(label.JobBytes, ed2),
1086             label.JobErrors, (char)label.JobStatus);
1087          break;
1088       case EOM_LABEL:
1089       case PRE_LABEL:
1090       case VOL_LABEL:
1091       default:
1092          Pmsg5(-1, "%s Record: SessId=%d SessTime=%d JobId=%d DataLen=%d\n",
1093       type, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
1094          break;
1095       case EOT_LABEL:
1096          break;
1097       }
1098    }
1099    debug_level = dbl;
1100 }