]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/label.c
- DVD writing/reading seems to be mostly working.
[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: 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 (!can_open_mounted_dev(dev)) {     
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       /* At this point, we are writing */
266       if (dev->free_space_errno < 0) {
267          Dmsg0(100, "Exit: read_dvd_volume_label !free_space VOL_NO_MEDIA\n");
268          Mmsg2(jcr->errmsg, _("free_space error on %s. The current medium is probably not writable: ERR=%s.\n"),
269                dev->print_name(), dev->errmsg);
270          return VOL_NO_MEDIA;
271       }
272       
273       /* 
274        * If we can't guess the name, and we are writing, 
275        * just reopen the right file with open_first_part.
276        */
277       if (open_first_part(dev, OPEN_READ_WRITE) < 0) {
278          berrno be;
279          Mmsg2(jcr->errmsg, _("open_first_part error on %s: ERR=%s.\n"),
280                dev->print_name(), be.strerror());
281          Dmsg0(100, "Leave read_dvd_volume_label VOL_IO_ERROR (!open_mounted_dev && !open_first_part)\n");
282          return VOL_IO_ERROR;
283       }
284       
285       Dmsg0(100, "Leave read_dvd_volume_label !open_mounted_dev\n");
286       return read_dev_volume_label(dcr);
287
288    } else {
289       /* 
290        * If we get here, we can open the mounted device
291        */
292       if (write && dcr->dev->free_space_errno < 0) {
293          Dmsg0(100, "Leave read_dvd_volume_label !free_space VOL_NO_MEDIA\n");
294          Mmsg2(jcr->errmsg, _("free_space error on %s. The current medium is probably not writable: ERR=%s.\n"),
295                dev->print_name(), dev->errmsg);
296          return VOL_NO_MEDIA;
297       }
298       
299       if (!write || dcr->VolCatInfo.VolCatParts > 0) {
300          Dmsg0(100, "Exit: read_dvd_volume_label (open_mounted_dev && (!write || dcr->VolCatInfo.VolCatParts > 0))\n");
301          return read_dev_volume_label(dcr);
302       }
303       
304       /* At this point, we are writing */
305       if (open_first_part(dcr->dev, OPEN_READ_WRITE) < 0) {
306          berrno be;
307          Mmsg2(jcr->errmsg, _("open_first_part error on %s: ERR=%s.\n"),
308                dev->print_name(), be.strerror());
309          Dmsg0(100, "Leave read_dvd_volume_label VOL_IO_ERROR (open_mounted_dev && !open_first_part)\n");
310          return VOL_IO_ERROR;
311       }
312       vol_label_status = read_dev_volume_label(dcr);
313       
314       /* When writing, if the guessed volume name is not the right volume name, 
315        * report the error, otherwise, just continue with the right file.
316        */
317       if (vol_label_status != VOL_NAME_ERROR) {
318          Dmsg0(100, "Leave read_dvd_volume_label (open_mounted_dev && !VOL_NAME_ERROR)\n");
319          dev->clear_labeled();   
320          return read_dev_volume_label(dcr);
321       } else {
322          Dmsg0(100, "Leave read_dvd_volume_label (open_mounted_dev && VOL_NAME_ERROR)\n");
323          return vol_label_status;
324       }
325    }
326 }
327
328 /*
329  * Put a volume label into the block
330  *
331  *  Returns: false on failure
332  *           true  on success
333  */
334 bool write_volume_label_to_block(DCR *dcr)
335 {
336    DEV_RECORD rec;
337    DEVICE *dev = dcr->dev;
338    JCR *jcr = dcr->jcr;
339    DEV_BLOCK *block = dcr->block;
340
341    Dmsg0(20, "write Label in write_volume_label_to_block()\n");
342    memset(&rec, 0, sizeof(rec));
343    rec.data = get_memory(SER_LENGTH_Volume_Label);
344    empty_block(block);                /* Volume label always at beginning */
345
346    create_volume_label_record(dcr, &rec);
347
348    block->BlockNumber = 0;
349    if (!write_record_to_block(block, &rec)) {
350       free_pool_memory(rec.data);
351       Jmsg1(jcr, M_FATAL, 0, _("Cannot write Volume label to block for device %s\n"),
352          dev->print_name());
353       return false;
354    } else {
355       Dmsg1(90, "Wrote label of %d bytes to block\n", rec.data_len);
356    }
357    free_pool_memory(rec.data);
358    return true;
359 }
360
361
362 /*
363  * Write a Volume Label
364  *  !!! Note, this is ONLY used for writing
365  *            a fresh volume label.  Any data
366  *            after the label will be destroyed,
367  *            in fact, we write the label 5 times !!!!
368  *
369  *  This routine expects that open_device() was previously called.
370  *
371  *  This routine should be used only when labeling a blank tape.
372  */
373 bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName, const char *PoolName)
374 {
375    DEVICE *dev = dcr->dev;
376
377
378    Dmsg0(99, "write_volume_label()\n");
379    empty_block(dcr->block);
380
381    Dmsg1(100, "Label type=%d\n", dev->label_type);
382    if (!rewind_dev(dev)) {
383       memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
384       Dmsg2(30, "Bad status on %s from rewind: ERR=%s\n", dev->print_name(), strerror_dev(dev));
385       if (!forge_on) {
386          goto bail_out;
387       }
388    }
389
390    /* Create PRE_LABEL */
391    create_volume_label(dev, VolName, PoolName);
392
393    /*
394     * If we have already detected an ANSI label, re-read it
395     *   to skip past it. Otherwise, we write a new one if 
396     *   so requested.  
397     */
398    if (dev->label_type != B_BACULA_LABEL) {
399       if (read_ansi_ibm_label(dcr) != VOL_OK) {
400          rewind_dev(dev);
401          goto bail_out;
402       }
403    } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, VolName)) {
404       goto bail_out;
405    }
406
407    create_volume_label_record(dcr, dcr->rec);
408    dcr->rec->Stream = 0;
409
410    /* Temporarily mark in append state to enable writing */
411    dev->set_append();
412    if (!write_record_to_block(dcr->block, dcr->rec)) {
413       Dmsg2(30, "Bad Label write on %s: ERR=%s\n", dev->print_name(), strerror_dev(dev));
414       goto bail_out;
415    } else {
416       Dmsg2(30, "Wrote label of %d bytes to %s\n", dcr->rec->data_len, dev->print_name());
417    }
418
419    Dmsg0(99, "Call write_block_to_dev()\n");
420    if (!write_block_to_dev(dcr)) {
421       Dmsg2(30, "Bad Label write on %s: ERR=%s\n", dev->print_name(), strerror_dev(dev));
422       goto bail_out;
423    }
424    Dmsg0(99, " Wrote block to device\n");
425
426    if (weof_dev(dev, 1) == 0) {
427       dev->set_labeled();
428       write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
429    }
430
431    if (debug_level >= 20)  {
432       dump_volume_label(dev);
433    }
434    dev->clear_append();               /* remove append since this is PRE_LABEL */
435    return true;
436
437 bail_out:
438    memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
439    dev->clear_append();               /* remove append since this is PRE_LABEL */
440    return false;
441 }
442
443 /*
444  * Write a volume label. This is ONLY called if we have a valid Bacula
445  *   label of type PRE_LABEL;
446  *  Returns: true if OK
447  *           false if unable to write it
448  */
449 bool rewrite_volume_label(DCR *dcr, bool recycle)
450 {
451    DEVICE *dev = dcr->dev;
452    JCR *jcr = dcr->jcr;
453
454    Dmsg1(190, "set append found freshly labeled volume. dev=%x\n", dev);
455    dev->VolHdr.LabelType = VOL_LABEL; /* set Volume label */
456    dev->set_append();
457    if (!write_volume_label_to_block(dcr)) {
458       Dmsg0(200, "Error from write volume label.\n");
459       return false;
460    }
461    /*
462     * If we are not dealing with a streaming device,
463     *  write the block now to ensure we have write permission.
464     *  It is better to find out now rather than later.
465     * We do not write the block now if this is an ANSI label. This
466     *  avoids re-writing the ANSI label, which we do not want to do.
467     */
468    if (!dev_cap(dev, CAP_STREAM)) {
469       if (!rewind_dev(dev)) {
470          Jmsg2(jcr, M_WARNING, 0, _("Rewind error on device %s: ERR=%s\n"),
471                dev->print_name(), strerror_dev(dev));
472       }
473       if (recycle) {
474          if (!truncate_dev(dev)) {
475             Jmsg2(jcr, M_WARNING, 0, _("Truncate error on device %s: ERR=%s\n"),
476                   dev->print_name(), strerror_dev(dev));
477          }
478       }
479
480       /*
481        * If we have already detected an ANSI label, re-read it
482        *   to skip past it. Otherwise, we write a new one if 
483        *   so requested.  
484        */
485       if (dev->label_type != B_BACULA_LABEL) {
486          if (read_ansi_ibm_label(dcr) != VOL_OK) {
487             rewind_dev(dev);
488             return false;
489          }
490       } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, dev->VolHdr.VolumeName)) {
491          return false;
492       }
493
494       /* Attempt write to check write permission */
495       Dmsg0(200, "Attempt to write to device.\n");
496       if (!write_block_to_dev(dcr)) {
497          Jmsg2(jcr, M_ERROR, 0, _("Unable to write device %s: ERR=%s\n"),
498             dev->print_name(), strerror_dev(dev));
499          Dmsg0(200, "===ERROR write block to dev\n");
500          return false;
501       }
502    }
503    /* Set or reset Volume statistics */
504    dev->VolCatInfo.VolCatJobs = 0;
505    dev->VolCatInfo.VolCatFiles = 0;
506    dev->VolCatInfo.VolCatBytes = 1;
507    dev->VolCatInfo.VolCatErrors = 0;
508    dev->VolCatInfo.VolCatBlocks = 0;
509    dev->VolCatInfo.VolCatRBytes = 0;
510    if (recycle) {
511       dev->VolCatInfo.VolCatMounts++;
512       dev->VolCatInfo.VolCatRecycles++;
513    } else {
514       dev->VolCatInfo.VolCatMounts = 1;
515       dev->VolCatInfo.VolCatRecycles = 0;
516       dev->VolCatInfo.VolCatWrites = 1;
517       dev->VolCatInfo.VolCatReads = 1;
518    }
519    Dmsg0(100, "dir_update_vol_info. Set Append\n");
520    bstrncpy(dev->VolCatInfo.VolCatStatus, "Append", sizeof(dev->VolCatInfo.VolCatStatus));
521    if (!dir_update_volume_info(dcr, true)) {  /* indicate doing relabel */
522       return false;
523    }
524    if (recycle) {
525       Jmsg(jcr, M_INFO, 0, _("Recycled volume \"%s\" on device %s, all previous data lost.\n"),
526          dcr->VolumeName, dev->print_name());
527    } else {
528       Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume \"%s\" on device %s\n"),
529          dcr->VolumeName, dev->print_name());
530    }
531    /*
532     * End writing real Volume label (from pre-labeled tape), or recycling
533     *  the volume.
534     */
535    Dmsg0(200, "OK from rewite vol label.\n");
536    return true;
537 }
538
539
540 /*
541  *  create_volume_label_record
542  *   Serialize label (from dev->VolHdr structure) into device record.
543  *   Assumes that the dev->VolHdr structure is properly
544  *   initialized.
545 */
546 static void create_volume_label_record(DCR *dcr, DEV_RECORD *rec)
547 {
548    ser_declare;
549    struct date_time dt;
550    DEVICE *dev = dcr->dev;
551    JCR *jcr = dcr->jcr;
552
553    /* Serialize the label into the device record. */
554
555    rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
556    ser_begin(rec->data, SER_LENGTH_Volume_Label);
557    ser_string(dev->VolHdr.Id);
558
559    ser_uint32(dev->VolHdr.VerNum);
560
561    if (dev->VolHdr.VerNum >= 11) {
562       ser_btime(dev->VolHdr.label_btime);
563       dev->VolHdr.write_btime = get_current_btime();
564       ser_btime(dev->VolHdr.write_btime);
565       dev->VolHdr.write_date = 0;
566       dev->VolHdr.write_time = 0;
567    } else {
568       /* OLD WAY DEPRECATED */
569       ser_float64(dev->VolHdr.label_date);
570       ser_float64(dev->VolHdr.label_time);
571       get_current_time(&dt);
572       dev->VolHdr.write_date = dt.julian_day_number;
573       dev->VolHdr.write_time = dt.julian_day_fraction;
574    }
575    ser_float64(dev->VolHdr.write_date);   /* 0 if VerNum >= 11 */
576    ser_float64(dev->VolHdr.write_time);   /* 0  if VerNum >= 11 */
577
578    ser_string(dev->VolHdr.VolumeName);
579    ser_string(dev->VolHdr.PrevVolumeName);
580    ser_string(dev->VolHdr.PoolName);
581    ser_string(dev->VolHdr.PoolType);
582    ser_string(dev->VolHdr.MediaType);
583
584    ser_string(dev->VolHdr.HostName);
585    ser_string(dev->VolHdr.LabelProg);
586    ser_string(dev->VolHdr.ProgVersion);
587    ser_string(dev->VolHdr.ProgDate);
588
589    ser_end(rec->data, SER_LENGTH_Volume_Label);
590    rec->data_len = ser_length(rec->data);
591    rec->FileIndex = dev->VolHdr.LabelType;
592    rec->VolSessionId = jcr->VolSessionId;
593    rec->VolSessionTime = jcr->VolSessionTime;
594    rec->Stream = jcr->NumVolumes;
595    Dmsg2(100, "Created Vol label rec: FI=%s len=%d\n", FI_to_ascii(rec->FileIndex),
596       rec->data_len);
597 }
598
599
600 /*
601  * Create a volume label in memory
602  */
603 void create_volume_label(DEVICE *dev, const char *VolName, const char *PoolName)
604 {
605    DEVRES *device = (DEVRES *)dev->device;
606
607    Dmsg0(90, "Start create_volume_label()\n");
608
609    ASSERT(dev != NULL);
610
611    memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
612
613    bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
614    dev->VolHdr.VerNum = BaculaTapeVersion;
615    dev->VolHdr.LabelType = PRE_LABEL;  /* Mark tape as unused */
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
702    rec = new_record();
703    Dmsg1(90, "session_label record=%x\n", rec);
704    switch (label) {
705    case SOS_LABEL:
706       if (dev->is_tape()) {
707          dcr->StartBlock = dev->block_num;
708          dcr->StartFile  = dev->file;
709       } else {
710          dcr->StartBlock = (uint32_t)dev->file_addr;
711          dcr->StartFile = (uint32_t)(dev->file_addr >> 32);
712       }
713       break;
714    case EOS_LABEL:
715       if (dev->is_tape()) {
716          dcr->EndBlock = dev->EndBlock;
717          dcr->EndFile  = dev->EndFile;
718       } else {
719          dcr->EndBlock = (uint32_t)dev->file_addr;
720          dcr->EndFile = (uint32_t)(dev->file_addr >> 32);
721       }
722       break;
723    default:
724       Jmsg1(jcr, M_ABORT, 0, _("Bad session label = %d\n"), label);
725       break;
726    }
727    create_session_label(dcr, rec, label);
728    rec->FileIndex = label;
729
730    /*
731     * We guarantee that the session record can totally fit
732     *  into a block. If not, write the block, and put it in
733     *  the next block. Having the sesssion record totally in
734     *  one block makes reading them much easier (no need to
735     *  read the next block).
736     */
737    if (!can_write_record_to_block(block, rec)) {
738       Dmsg0(100, "Cannot write session label to block.\n");
739       if (!write_block_to_device(dcr)) {
740          Dmsg0(90, "Got session label write_block_to_dev error.\n");
741          /* ****FIXME***** errno is not set here */
742          Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"),
743                            dev_vol_name(dev), strerror(errno));
744          free_record(rec);
745          return false;
746       }
747    }
748    if (!write_record_to_block(block, rec)) {
749       Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"),
750                         dev_vol_name(dev), strerror(errno));
751       free_record(rec);
752       return false;
753    }
754
755    Dmsg6(20, "Write sesson_label record JobId=%d FI=%s SessId=%d Strm=%s len=%d "
756              "remainder=%d\n", jcr->JobId,
757       FI_to_ascii(rec->FileIndex), rec->VolSessionId,
758       stream_to_ascii(rec->Stream, rec->FileIndex), rec->data_len,
759       rec->remainder);
760
761    free_record(rec);
762    Dmsg2(20, "Leave write_session_label Block=%d File=%d\n",
763       dev->block_num, dev->file);
764    return true;
765 }
766
767 /*  unser_volume_label
768  *
769  * Unserialize the Bacula Volume label into the device Volume_Label
770  * structure.
771  *
772  * Assumes that the record is already read.
773  *
774  * Returns: false on error
775  *          true  on success
776 */
777
778 bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec)
779 {
780    ser_declare;
781
782    if (rec->FileIndex != VOL_LABEL && rec->FileIndex != PRE_LABEL) {
783       Mmsg3(dev->errmsg, _("Expecting Volume Label, got FI=%s Stream=%s len=%d\n"),
784               FI_to_ascii(rec->FileIndex),
785               stream_to_ascii(rec->Stream, rec->FileIndex),
786               rec->data_len);
787       if (!forge_on) {
788          return false;
789       }
790    }
791
792    dev->VolHdr.LabelType = rec->FileIndex;
793    dev->VolHdr.LabelSize = rec->data_len;
794
795
796    /* Unserialize the record into the Volume Header */
797    rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
798    ser_begin(rec->data, SER_LENGTH_Volume_Label);
799    unser_string(dev->VolHdr.Id);
800    unser_uint32(dev->VolHdr.VerNum);
801
802    if (dev->VolHdr.VerNum >= 11) {
803       unser_btime(dev->VolHdr.label_btime);
804       unser_btime(dev->VolHdr.write_btime);
805    } else { /* old way */
806       unser_float64(dev->VolHdr.label_date);
807       unser_float64(dev->VolHdr.label_time);
808    }
809    unser_float64(dev->VolHdr.write_date);    /* Unused with VerNum >= 11 */
810    unser_float64(dev->VolHdr.write_time);    /* Unused with VerNum >= 11 */
811
812    unser_string(dev->VolHdr.VolumeName);
813    unser_string(dev->VolHdr.PrevVolumeName);
814    unser_string(dev->VolHdr.PoolName);
815    unser_string(dev->VolHdr.PoolType);
816    unser_string(dev->VolHdr.MediaType);
817
818    unser_string(dev->VolHdr.HostName);
819    unser_string(dev->VolHdr.LabelProg);
820    unser_string(dev->VolHdr.ProgVersion);
821    unser_string(dev->VolHdr.ProgDate);
822
823    ser_end(rec->data, SER_LENGTH_Volume_Label);
824    Dmsg0(90, "ser_read_vol\n");
825    if (debug_level >= 90) {
826       dump_volume_label(dev);
827    }
828    return true;
829 }
830
831
832 bool unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec)
833 {
834    ser_declare;
835
836    rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
837    unser_begin(rec->data, SER_LENGTH_Session_Label);
838    unser_string(label->Id);
839    unser_uint32(label->VerNum);
840    unser_uint32(label->JobId);
841    if (label->VerNum >= 11) {
842       unser_btime(label->write_btime);
843    } else {
844       unser_float64(label->write_date);
845    }
846    unser_float64(label->write_time);
847    unser_string(label->PoolName);
848    unser_string(label->PoolType);
849    unser_string(label->JobName);
850    unser_string(label->ClientName);
851    if (label->VerNum >= 10) {
852       unser_string(label->Job);          /* Unique name of this Job */
853       unser_string(label->FileSetName);
854       unser_uint32(label->JobType);
855       unser_uint32(label->JobLevel);
856    }
857    if (label->VerNum >= 11) {
858       unser_string(label->FileSetMD5);
859    } else {
860       label->FileSetMD5[0] = 0;
861    }
862    if (rec->FileIndex == EOS_LABEL) {
863       unser_uint32(label->JobFiles);
864       unser_uint64(label->JobBytes);
865       unser_uint32(label->StartBlock);
866       unser_uint32(label->EndBlock);
867       unser_uint32(label->StartFile);
868       unser_uint32(label->EndFile);
869       unser_uint32(label->JobErrors);
870       if (label->VerNum >= 11) {
871          unser_uint32(label->JobStatus);
872       } else {
873          label->JobStatus = JS_Terminated; /* kludge */
874       }
875    }
876    return true;
877 }
878
879 void dump_volume_label(DEVICE *dev)
880 {
881    int dbl = debug_level;
882    uint32_t File;
883    const char *LabelType;
884    char buf[30];
885    struct tm tm;
886    struct date_time dt;
887
888    debug_level = 1;
889    File = dev->file;
890    switch (dev->VolHdr.LabelType) {
891    case PRE_LABEL:
892       LabelType = "PRE_LABEL";
893       break;
894    case VOL_LABEL:
895       LabelType = "VOL_LABEL";
896       break;
897    case EOM_LABEL:
898       LabelType = "EOM_LABEL";
899       break;
900    case SOS_LABEL:
901       LabelType = "SOS_LABEL";
902       break;
903    case EOS_LABEL:
904       LabelType = "EOS_LABEL";
905       break;
906    case EOT_LABEL:
907       goto bail_out;
908    default:
909       LabelType = buf;
910       sprintf(buf, "Unknown %d", dev->VolHdr.LabelType);
911       break;
912    }
913
914    Pmsg11(-1, "\nVolume Label:\n"
915 "Id                : %s"
916 "VerNo             : %d\n"
917 "VolName           : %s\n"
918 "PrevVolName       : %s\n"
919 "VolFile           : %d\n"
920 "LabelType         : %s\n"
921 "LabelSize         : %d\n"
922 "PoolName          : %s\n"
923 "MediaType         : %s\n"
924 "PoolType          : %s\n"
925 "HostName          : %s\n"
926 "",
927              dev->VolHdr.Id, dev->VolHdr.VerNum,
928              dev->VolHdr.VolumeName, dev->VolHdr.PrevVolumeName,
929              File, LabelType, dev->VolHdr.LabelSize,
930              dev->VolHdr.PoolName, dev->VolHdr.MediaType,
931              dev->VolHdr.PoolType, dev->VolHdr.HostName);
932
933    if (dev->VolHdr.VerNum >= 11) {
934       char dt[50];
935       bstrftime(dt, sizeof(dt), btime_to_unix(dev->VolHdr.label_btime));
936       Pmsg1(-1, "Date label written: %s\n", dt);
937    } else {
938    dt.julian_day_number   = dev->VolHdr.label_date;
939    dt.julian_day_fraction = dev->VolHdr.label_time;
940    tm_decode(&dt, &tm);
941    Pmsg5(-1,
942 "Date label written: %04d-%02d-%02d at %02d:%02d\n",
943       tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
944    }
945
946 bail_out:
947    debug_level = dbl;
948 }
949
950
951 static void dump_session_label(DEV_RECORD *rec, const char *type)
952 {
953    int dbl;
954    struct date_time dt;
955    struct tm tm;
956    SESSION_LABEL label;
957    char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], ec6[30], ec7[30];
958
959    unser_session_label(&label, rec);
960    dbl = debug_level;
961    debug_level = 1;
962    Pmsg7(-1, "\n%s Record:\n"
963 "JobId             : %d\n"
964 "VerNum            : %d\n"
965 "PoolName          : %s\n"
966 "PoolType          : %s\n"
967 "JobName           : %s\n"
968 "ClientName        : %s\n"
969 "",    type, label.JobId, label.VerNum,
970       label.PoolName, label.PoolType,
971       label.JobName, label.ClientName);
972
973    if (label.VerNum >= 10) {
974       Pmsg4(-1, ""
975 "Job (unique name) : %s\n"
976 "FileSet           : %s\n"
977 "JobType           : %c\n"
978 "JobLevel          : %c\n"
979 "", label.Job, label.FileSetName, label.JobType, label.JobLevel);
980    }
981
982    if (rec->FileIndex == EOS_LABEL) {
983       Pmsg8(-1, ""
984 "JobFiles          : %s\n"
985 "JobBytes          : %s\n"
986 "StartBlock        : %s\n"
987 "EndBlock          : %s\n"
988 "StartFile         : %s\n"
989 "EndFile           : %s\n"
990 "JobErrors         : %s\n"
991 "JobStatus         : %c\n"
992 "",
993          edit_uint64_with_commas(label.JobFiles, ec1),
994          edit_uint64_with_commas(label.JobBytes, ec2),
995          edit_uint64_with_commas(label.StartBlock, ec3),
996          edit_uint64_with_commas(label.EndBlock, ec4),
997          edit_uint64_with_commas(label.StartFile, ec5),
998          edit_uint64_with_commas(label.EndFile, ec6),
999          edit_uint64_with_commas(label.JobErrors, ec7),
1000          label.JobStatus);
1001    }
1002    if (label.VerNum >= 11) {
1003       char dt[50];
1004       bstrftime(dt, sizeof(dt), btime_to_unix(label.write_btime));
1005       Pmsg1(-1, _("Date written      : %s\n"), dt);
1006    } else {
1007       dt.julian_day_number   = label.write_date;
1008       dt.julian_day_fraction = label.write_time;
1009       tm_decode(&dt, &tm);
1010       Pmsg5(-1, _(""
1011 "Date written      : %04d-%02d-%02d at %02d:%02d\n"),
1012       tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
1013    }
1014
1015    debug_level = dbl;
1016 }
1017
1018 void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose)
1019 {
1020    const char *type;
1021    int dbl;
1022
1023    dbl = debug_level;
1024    debug_level = 1;
1025    switch (rec->FileIndex) {
1026    case PRE_LABEL:
1027       type = _("Fresh Volume");
1028       break;
1029    case VOL_LABEL:
1030       type = _("Volume");
1031       break;
1032    case SOS_LABEL:
1033       type = _("Begin Job Session");
1034       break;
1035    case EOS_LABEL:
1036       type = _("End Job Session");
1037       break;
1038    case EOM_LABEL:
1039       type = _("End of Media");
1040       break;
1041    case EOT_LABEL:
1042       type = ("End of Tape");
1043       break;
1044    default:
1045       type = _("Unknown");
1046       break;
1047    }
1048    if (verbose) {
1049       switch (rec->FileIndex) {
1050       case PRE_LABEL:
1051       case VOL_LABEL:
1052          unser_volume_label(dev, rec);
1053          dump_volume_label(dev);
1054          break;
1055       case SOS_LABEL:
1056          dump_session_label(rec, type);
1057          break;
1058       case EOS_LABEL:
1059          dump_session_label(rec, type);
1060          break;
1061       case EOM_LABEL:
1062          Pmsg5(-1, "%s Record: SessId=%d SessTime=%d JobId=%d DataLen=%d\n",
1063             type, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
1064          break;
1065       case EOT_LABEL:
1066          Pmsg0(-1, _("End of physical tape.\n"));
1067          break;
1068       default:
1069          Pmsg5(-1, "%s Record: SessId=%d SessTime=%d JobId=%d DataLen=%d\n",
1070             type, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
1071          break;
1072       }
1073    } else {
1074       SESSION_LABEL label;
1075       switch (rec->FileIndex) {
1076       case SOS_LABEL:
1077          unser_session_label(&label, rec);
1078          Pmsg6(-1, "%s Record: SessId=%d SessTime=%d JobId=%d Level=%c Type=%c\n",
1079             type, rec->VolSessionId, rec->VolSessionTime, rec->Stream,
1080             label.JobLevel, label.JobType);
1081          break;
1082       case EOS_LABEL:
1083          char ed1[30], ed2[30];
1084          unser_session_label(&label, rec);
1085          Pmsg6(-1, "%s Record: SessId=%d SessTime=%d JobId=%d Level=%c Type=%c\n",
1086             type, rec->VolSessionId, rec->VolSessionTime, rec->Stream,
1087             label.JobLevel, label.JobType);
1088          Pmsg4(-1, "   Files=%s Bytes=%s Errors=%d Status=%c\n",
1089             edit_uint64_with_commas(label.JobFiles, ed1),
1090             edit_uint64_with_commas(label.JobBytes, ed2),
1091             label.JobErrors, (char)label.JobStatus);
1092          break;
1093       case EOM_LABEL:
1094       case PRE_LABEL:
1095       case VOL_LABEL:
1096       default:
1097          Pmsg5(-1, "%s Record: SessId=%d SessTime=%d JobId=%d DataLen=%d\n",
1098       type, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
1099          break;
1100       case EOT_LABEL:
1101          break;
1102       }
1103    }
1104    debug_level = dbl;
1105 }