]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/label.c
- Fix mode change open in btape.c
[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 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 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    bool have_ansi_label = false;
68
69    Dmsg3(100, "Enter read_volume_label device=%s vol=%s dev_Vol=%s\n",
70       dev->print_name(), VolName, dev->VolHdr.VolumeName[0]?dev->VolHdr.VolumeName:
71       "*NULL*");
72
73    if (!dev->is_open()) {
74       Emsg0(M_ABORT, 0, _("BAD call to read_dev_volume_label\n"));
75    }
76    if (dev->is_labeled()) {              /* did we already read label? */
77       /* Compare Volume Names allow special wild card */
78       if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolumeName, VolName) != 0) {
79          Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
80             dev->print_name(), VolName, dev->VolHdr.VolumeName);
81          /*
82           * Cancel Job if too many label errors
83           *  => we are in a loop
84           */
85          if (!dev->poll && jcr->label_errors++ > 100) {
86             Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
87          }
88          Dmsg0(100, "return VOL_NAME_ERROR\n");
89          stat = VOL_NAME_ERROR;
90          goto bail_out;
91       }
92       Dmsg0(30, "Leave read_volume_label() VOL_OK\n");
93       return VOL_OK;       /* label already read */
94    }
95
96    dev->clear_labeled();
97    dev->clear_append();
98    dev->clear_read();
99    dev->label_type = B_BACULA_LABEL;
100
101    if (!rewind_dev(dev)) {
102       Mmsg(jcr->errmsg, _("Couldn't rewind device %s: ERR=%s\n"), 
103          dev->print_name(), strerror_dev(dev));
104       Dmsg1(30, "return VOL_NO_MEDIA: %s", jcr->errmsg);
105       return VOL_NO_MEDIA;
106    }
107    bstrncpy(dev->VolHdr.Id, "**error**", sizeof(dev->VolHdr.Id));
108
109   /* Read ANSI/IBM label if so requested */
110   
111   want_ansi_label = dcr->VolCatInfo.LabelType != B_BACULA_LABEL ||
112                     dcr->device->label_type != B_BACULA_LABEL;
113   if (want_ansi_label || dev_cap(dev, CAP_CHECKLABELS)) {
114       stat = read_ansi_ibm_label(dcr);            
115       /* If we want a label and didn't find it, return error */
116       if (want_ansi_label && stat != VOL_OK) {
117          goto bail_out;
118       }
119       if (stat == VOL_NAME_ERROR || stat == VOL_LABEL_ERROR) {
120          Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
121               dev->print_name(), VolName, dev->VolHdr.VolumeName);
122          if (!dev->poll && jcr->label_errors++ > 100) {
123             Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg);
124          }
125          goto bail_out;
126       }
127       if (stat != VOL_OK) {           /* Not an ANSI/IBM label, so re-read */
128          rewind_dev(dev);
129       } else {
130          have_ansi_label = true;
131       }
132    }
133   
134    /* Read the Bacula Volume label block */
135    record = new_record();
136    empty_block(block);
137
138    Dmsg0(90, "Big if statement in read_volume_label\n");
139    if (!read_block_from_dev(dcr, NO_BLOCK_NUMBER_CHECK)) {
140       Mmsg(jcr->errmsg, _("Requested Volume \"%s\" on %s is not a Bacula "
141            "labeled Volume, because: ERR=%s"), NPRT(VolName), 
142            dev->print_name(), strerror_dev(dev));
143       Dmsg1(30, "%s", jcr->errmsg);
144    } else if (!read_record_from_block(block, record)) {
145       Mmsg(jcr->errmsg, _("Could not read Volume label from block.\n"));
146       Dmsg1(30, "%s", jcr->errmsg);
147    } else if (!unser_volume_label(dev, record)) {
148       Mmsg(jcr->errmsg, _("Could not unserialize Volume label: ERR=%s\n"),
149          strerror_dev(dev));
150       Dmsg1(30, "%s", jcr->errmsg);
151    } else if (strcmp(dev->VolHdr.Id, BaculaId) != 0 &&
152               strcmp(dev->VolHdr.Id, OldBaculaId) != 0) {
153       Mmsg(jcr->errmsg, _("Volume Header Id bad: %s\n"), dev->VolHdr.Id);
154       Dmsg1(30, "%s", jcr->errmsg);
155    } else {
156       ok = true;
157    }
158    free_record(record);               /* finished reading Volume record */
159
160    if (!ok) {
161       if (forge_on || jcr->ignore_label_errors) {
162          dev->set_labeled();         /* set has Bacula label */
163          Jmsg(jcr, M_ERROR, 0, "%s", jcr->errmsg);
164          empty_block(block);
165          return VOL_OK;
166       }
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(100, "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(100, "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       rewind_dev(dev);
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    rewind_dev(dev);
245    Dmsg1(100, "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 expects that open_device() was previously called.
291  *
292  *  This routine should be used only when labeling a blank tape.
293  */
294 bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName, const char *PoolName)
295 {
296    DEVICE *dev = dcr->dev;
297
298
299    Dmsg0(99, "write_volume_label()\n");
300    empty_block(dcr->block);
301
302    if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
303       goto bail_out;
304    }
305    Dmsg1(100, "Label type=%d\n", dev->label_type);
306    if (!rewind_dev(dev)) {
307       free_volume(dev);
308       memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
309       Dmsg2(30, "Bad status on %s from rewind: ERR=%s\n", dev->print_name(), strerror_dev(dev));
310       if (!forge_on) {
311          goto bail_out;
312       }
313    }
314
315    /* Create PRE_LABEL */
316    create_volume_label(dev, VolName, PoolName);
317
318    /*
319     * If we have already detected an ANSI label, re-read it
320     *   to skip past it. Otherwise, we write a new one if 
321     *   so requested.  
322     */
323    if (dev->label_type != B_BACULA_LABEL) {
324       if (read_ansi_ibm_label(dcr) != VOL_OK) {
325          rewind_dev(dev);
326          goto bail_out;
327       }
328    } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, VolName)) {
329       goto bail_out;
330    }
331
332    create_volume_label_record(dcr, dcr->rec);
333    dcr->rec->Stream = 0;
334
335    /* Temporarily mark in append state to enable writing */
336    dev->set_append();
337    if (!write_record_to_block(dcr->block, dcr->rec)) {
338       Dmsg2(30, "Bad Label write on %s: ERR=%s\n", dev->print_name(), strerror_dev(dev));
339       goto bail_out;
340    } else {
341       Dmsg2(30, "Wrote label of %d bytes to %s\n", dcr->rec->data_len, dev->print_name());
342    }
343
344    Dmsg0(99, "Call write_block_to_dev()\n");
345    if (!write_block_to_dev(dcr)) {
346       Dmsg2(30, "Bad Label write on %s: ERR=%s\n", dev->print_name(), strerror_dev(dev));
347       goto bail_out;
348    }
349    Dmsg0(99, " Wrote block to device\n");
350
351    if (weof_dev(dev, 1) == 0) {
352       dev->set_labeled();
353       write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
354    }
355
356    if (debug_level >= 20)  {
357       dump_volume_label(dev);
358    }
359    new_volume(dcr, VolName);
360    dev->clear_append();               /* remove append since this is PRE_LABEL */
361    return true;
362
363 bail_out:
364    free_volume(dev);
365    memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
366    dev->clear_append();               /* remove append since this is PRE_LABEL */
367    return false;
368 }
369
370 /*
371  * Write a volume label. This is ONLY called if we have a valid Bacula
372  *   label of type PRE_LABEL;
373  *  Returns: true if OK
374  *           false if unable to write it
375  */
376 bool rewrite_volume_label(DCR *dcr, bool recycle)
377 {
378    DEVICE *dev = dcr->dev;
379    JCR *jcr = dcr->jcr;
380
381    if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
382       return false;
383    }
384    Dmsg2(190, "set append found freshly labeled volume. fd=%d dev=%x\n", dev->fd, dev);
385    dev->VolHdr.LabelType = VOL_LABEL; /* set Volume label */
386    dev->set_append();
387    if (!write_volume_label_to_block(dcr)) {
388       Dmsg0(200, "Error from write volume label.\n");
389       return false;
390    }
391    /*
392     * If we are not dealing with a streaming device,
393     *  write the block now to ensure we have write permission.
394     *  It is better to find out now rather than later.
395     * We do not write the block now if this is an ANSI label. This
396     *  avoids re-writing the ANSI label, which we do not want to do.
397     */
398    if (!dev_cap(dev, CAP_STREAM)) {
399       if (!rewind_dev(dev)) {
400          Jmsg2(jcr, M_WARNING, 0, _("Rewind error on device %s: ERR=%s\n"),
401                dev->print_name(), strerror_dev(dev));
402       }
403       if (recycle) {
404          if (!truncate_dev(dcr)) {
405             Jmsg2(jcr, M_WARNING, 0, _("Truncate error on device %s: ERR=%s\n"),
406                   dev->print_name(), strerror_dev(dev));
407          }
408       }
409
410       /*
411        * If we have already detected an ANSI label, re-read it
412        *   to skip past it. Otherwise, we write a new one if 
413        *   so requested.  
414        */
415       if (dev->label_type != B_BACULA_LABEL) {
416          if (read_ansi_ibm_label(dcr) != VOL_OK) {
417             rewind_dev(dev);
418             return false;
419          }
420       } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, dev->VolHdr.VolumeName)) {
421          return false;
422       }
423
424       /* Attempt write to check write permission */
425       Dmsg1(200, "Attempt to write to device fd=%d.\n", dev->fd);
426       if (!write_block_to_dev(dcr)) {
427          Jmsg2(jcr, M_ERROR, 0, _("Unable to write device %s: ERR=%s\n"),
428             dev->print_name(), strerror_dev(dev));
429          Dmsg0(200, "===ERROR write block to dev\n");
430          return false;
431       }
432    }
433    /* Set or reset Volume statistics */
434    dev->VolCatInfo.VolCatJobs = 0;
435    dev->VolCatInfo.VolCatFiles = 0;
436    dev->VolCatInfo.VolCatBytes = 1;
437    dev->VolCatInfo.VolCatErrors = 0;
438    dev->VolCatInfo.VolCatBlocks = 0;
439    dev->VolCatInfo.VolCatRBytes = 0;
440    if (recycle) {
441       dev->VolCatInfo.VolCatMounts++;
442       dev->VolCatInfo.VolCatRecycles++;
443    } else {
444       dev->VolCatInfo.VolCatMounts = 1;
445       dev->VolCatInfo.VolCatRecycles = 0;
446       dev->VolCatInfo.VolCatWrites = 1;
447       dev->VolCatInfo.VolCatReads = 1;
448    }
449    Dmsg0(100, "dir_update_vol_info. Set Append\n");
450    bstrncpy(dev->VolCatInfo.VolCatStatus, "Append", sizeof(dev->VolCatInfo.VolCatStatus));
451    if (!dir_update_volume_info(dcr, true)) {  /* indicate doing relabel */
452       return false;
453    }
454    if (recycle) {
455       Jmsg(jcr, M_INFO, 0, _("Recycled volume \"%s\" on device %s, all previous data lost.\n"),
456          dcr->VolumeName, dev->print_name());
457    } else {
458       Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume \"%s\" on device %s\n"),
459          dcr->VolumeName, dev->print_name());
460    }
461    /*
462     * End writing real Volume label (from pre-labeled tape), or recycling
463     *  the volume.
464     */
465    Dmsg0(200, "OK from rewite vol label.\n");
466    return true;
467 }
468
469
470 /*
471  *  create_volume_label_record
472  *   Serialize label (from dev->VolHdr structure) into device record.
473  *   Assumes that the dev->VolHdr structure is properly
474  *   initialized.
475 */
476 static void create_volume_label_record(DCR *dcr, DEV_RECORD *rec)
477 {
478    ser_declare;
479    struct date_time dt;
480    DEVICE *dev = dcr->dev;
481    JCR *jcr = dcr->jcr;
482
483    /* Serialize the label into the device record. */
484
485    rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
486    ser_begin(rec->data, SER_LENGTH_Volume_Label);
487    ser_string(dev->VolHdr.Id);
488
489    ser_uint32(dev->VolHdr.VerNum);
490
491    if (dev->VolHdr.VerNum >= 11) {
492       ser_btime(dev->VolHdr.label_btime);
493       dev->VolHdr.write_btime = get_current_btime();
494       ser_btime(dev->VolHdr.write_btime);
495       dev->VolHdr.write_date = 0;
496       dev->VolHdr.write_time = 0;
497    } else {
498       /* OLD WAY DEPRECATED */
499       ser_float64(dev->VolHdr.label_date);
500       ser_float64(dev->VolHdr.label_time);
501       get_current_time(&dt);
502       dev->VolHdr.write_date = dt.julian_day_number;
503       dev->VolHdr.write_time = dt.julian_day_fraction;
504    }
505    ser_float64(dev->VolHdr.write_date);   /* 0 if VerNum >= 11 */
506    ser_float64(dev->VolHdr.write_time);   /* 0  if VerNum >= 11 */
507
508    ser_string(dev->VolHdr.VolumeName);
509    ser_string(dev->VolHdr.PrevVolumeName);
510    ser_string(dev->VolHdr.PoolName);
511    ser_string(dev->VolHdr.PoolType);
512    ser_string(dev->VolHdr.MediaType);
513
514    ser_string(dev->VolHdr.HostName);
515    ser_string(dev->VolHdr.LabelProg);
516    ser_string(dev->VolHdr.ProgVersion);
517    ser_string(dev->VolHdr.ProgDate);
518
519    ser_end(rec->data, SER_LENGTH_Volume_Label);
520    rec->data_len = ser_length(rec->data);
521    rec->FileIndex = dev->VolHdr.LabelType;
522    rec->VolSessionId = jcr->VolSessionId;
523    rec->VolSessionTime = jcr->VolSessionTime;
524    rec->Stream = jcr->NumVolumes;
525    Dmsg2(100, "Created Vol label rec: FI=%s len=%d\n", FI_to_ascii(rec->FileIndex),
526       rec->data_len);
527 }
528
529
530 /*
531  * Create a volume label in memory
532  */
533 void create_volume_label(DEVICE *dev, const char *VolName, const char *PoolName)
534 {
535    DEVRES *device = (DEVRES *)dev->device;
536
537    Dmsg0(90, "Start create_volume_label()\n");
538
539    ASSERT(dev != NULL);
540
541    free_volume(dev);         /* release any old volume */
542    memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
543
544    bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
545    dev->VolHdr.VerNum = BaculaTapeVersion;
546    dev->VolHdr.LabelType = PRE_LABEL;  /* Mark tape as unused */
547    bstrncpy(dev->VolHdr.VolumeName, VolName, sizeof(dev->VolHdr.VolumeName));
548    bstrncpy(dev->VolHdr.PoolName, PoolName, sizeof(dev->VolHdr.PoolName));
549    bstrncpy(dev->VolHdr.MediaType, device->media_type, sizeof(dev->VolHdr.MediaType));
550
551    bstrncpy(dev->VolHdr.PoolType, "Backup", sizeof(dev->VolHdr.PoolType));
552
553    dev->VolHdr.label_btime = get_current_btime();
554    dev->VolHdr.label_date = 0;
555    dev->VolHdr.label_time = 0;
556
557    if (gethostname(dev->VolHdr.HostName, sizeof(dev->VolHdr.HostName)) != 0) {
558       dev->VolHdr.HostName[0] = 0;
559    }
560    bstrncpy(dev->VolHdr.LabelProg, my_name, sizeof(dev->VolHdr.LabelProg));
561    sprintf(dev->VolHdr.ProgVersion, "Ver. %s %s", VERSION, BDATE);
562    sprintf(dev->VolHdr.ProgDate, "Build %s %s", __DATE__, __TIME__);
563    dev->set_labeled();               /* set has Bacula label */
564    if (debug_level >= 90) {
565       dump_volume_label(dev);
566    }
567 }
568
569 /*
570  * Create session label
571  *  The pool memory must be released by the calling program
572  */
573 void create_session_label(DCR *dcr, DEV_RECORD *rec, int label)
574 {
575    JCR *jcr = dcr->jcr;
576    ser_declare;
577
578    rec->VolSessionId   = jcr->VolSessionId;
579    rec->VolSessionTime = jcr->VolSessionTime;
580    rec->Stream         = jcr->JobId;
581
582    rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
583    ser_begin(rec->data, SER_LENGTH_Session_Label);
584    ser_string(BaculaId);
585    ser_uint32(BaculaTapeVersion);
586
587    ser_uint32(jcr->JobId);
588
589    /* Changed in VerNum 11 */
590    ser_btime(get_current_btime());
591    ser_float64(0);
592
593    ser_string(dcr->pool_name);
594    ser_string(dcr->pool_type);
595    ser_string(jcr->job_name);         /* base Job name */
596    ser_string(jcr->client_name);
597
598    /* Added in VerNum 10 */
599    ser_string(jcr->Job);              /* Unique name of this Job */
600    ser_string(jcr->fileset_name);
601    ser_uint32(jcr->JobType);
602    ser_uint32(jcr->JobLevel);
603    /* Added in VerNum 11 */
604    ser_string(jcr->fileset_md5);
605
606    if (label == EOS_LABEL) {
607       ser_uint32(jcr->JobFiles);
608       ser_uint64(jcr->JobBytes);
609       ser_uint32(dcr->StartBlock);
610       ser_uint32(dcr->EndBlock);
611       ser_uint32(dcr->StartFile);
612       ser_uint32(dcr->EndFile);
613       ser_uint32(jcr->JobErrors);
614
615       /* Added in VerNum 11 */
616       ser_uint32(jcr->JobStatus);
617    }
618    ser_end(rec->data, SER_LENGTH_Session_Label);
619    rec->data_len = ser_length(rec->data);
620 }
621
622 /* Write session label
623  *  Returns: false on failure
624  *           true  on success
625  */
626 bool write_session_label(DCR *dcr, int label)
627 {
628    JCR *jcr = dcr->jcr;
629    DEVICE *dev = dcr->dev;
630    DEV_RECORD *rec;
631    DEV_BLOCK *block = dcr->block;
632
633    rec = new_record();
634    Dmsg1(90, "session_label record=%x\n", rec);
635    switch (label) {
636    case SOS_LABEL:
637       if (dev->is_tape()) {
638          dcr->StartBlock = dev->block_num;
639          dcr->StartFile  = dev->file;
640       } else {
641          dcr->StartBlock = (uint32_t)dev->file_addr;
642          dcr->StartFile = (uint32_t)(dev->file_addr >> 32);
643       }
644       break;
645    case EOS_LABEL:
646       if (dev->is_tape()) {
647          dcr->EndBlock = dev->EndBlock;
648          dcr->EndFile  = dev->EndFile;
649       } else {
650          dcr->EndBlock = (uint32_t)dev->file_addr;
651          dcr->EndFile = (uint32_t)(dev->file_addr >> 32);
652       }
653       break;
654    default:
655       Jmsg1(jcr, M_ABORT, 0, _("Bad session label = %d\n"), label);
656       break;
657    }
658    create_session_label(dcr, rec, label);
659    rec->FileIndex = label;
660
661    /*
662     * We guarantee that the session record can totally fit
663     *  into a block. If not, write the block, and put it in
664     *  the next block. Having the sesssion record totally in
665     *  one block makes reading them much easier (no need to
666     *  read the next block).
667     */
668    if (!can_write_record_to_block(block, rec)) {
669       Dmsg0(100, "Cannot write session label to block.\n");
670       if (!write_block_to_device(dcr)) {
671          Dmsg0(90, "Got session label write_block_to_dev error.\n");
672          /* ****FIXME***** errno is not set here */
673          Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"),
674                            dev_vol_name(dev), strerror(errno));
675          free_record(rec);
676          return false;
677       }
678    }
679    if (!write_record_to_block(block, rec)) {
680       Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"),
681                         dev_vol_name(dev), strerror(errno));
682       free_record(rec);
683       return false;
684    }
685
686    Dmsg6(20, "Write sesson_label record JobId=%d FI=%s SessId=%d Strm=%s len=%d "
687              "remainder=%d\n", jcr->JobId,
688       FI_to_ascii(rec->FileIndex), rec->VolSessionId,
689       stream_to_ascii(rec->Stream, rec->FileIndex), rec->data_len,
690       rec->remainder);
691
692    free_record(rec);
693    Dmsg2(20, "Leave write_session_label Block=%d File=%d\n",
694       dev->block_num, dev->file);
695    return true;
696 }
697
698 /*  unser_volume_label
699  *
700  * Unserialize the Bacula Volume label into the device Volume_Label
701  * structure.
702  *
703  * Assumes that the record is already read.
704  *
705  * Returns: false on error
706  *          true  on success
707 */
708
709 bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec)
710 {
711    ser_declare;
712
713    if (rec->FileIndex != VOL_LABEL && rec->FileIndex != PRE_LABEL) {
714       Mmsg3(dev->errmsg, _("Expecting Volume Label, got FI=%s Stream=%s len=%d\n"),
715               FI_to_ascii(rec->FileIndex),
716               stream_to_ascii(rec->Stream, rec->FileIndex),
717               rec->data_len);
718       if (!forge_on) {
719          return false;
720       }
721    }
722
723    dev->VolHdr.LabelType = rec->FileIndex;
724    dev->VolHdr.LabelSize = rec->data_len;
725
726
727    /* Unserialize the record into the Volume Header */
728    rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
729    ser_begin(rec->data, SER_LENGTH_Volume_Label);
730    unser_string(dev->VolHdr.Id);
731    unser_uint32(dev->VolHdr.VerNum);
732
733    if (dev->VolHdr.VerNum >= 11) {
734       unser_btime(dev->VolHdr.label_btime);
735       unser_btime(dev->VolHdr.write_btime);
736    } else { /* old way */
737       unser_float64(dev->VolHdr.label_date);
738       unser_float64(dev->VolHdr.label_time);
739    }
740    unser_float64(dev->VolHdr.write_date);    /* Unused with VerNum >= 11 */
741    unser_float64(dev->VolHdr.write_time);    /* Unused with VerNum >= 11 */
742
743    unser_string(dev->VolHdr.VolumeName);
744    unser_string(dev->VolHdr.PrevVolumeName);
745    unser_string(dev->VolHdr.PoolName);
746    unser_string(dev->VolHdr.PoolType);
747    unser_string(dev->VolHdr.MediaType);
748
749    unser_string(dev->VolHdr.HostName);
750    unser_string(dev->VolHdr.LabelProg);
751    unser_string(dev->VolHdr.ProgVersion);
752    unser_string(dev->VolHdr.ProgDate);
753
754    ser_end(rec->data, SER_LENGTH_Volume_Label);
755    Dmsg0(90, "unser_vol_label\n");
756    if (debug_level >= 90) {
757       dump_volume_label(dev);
758    }
759    return true;
760 }
761
762
763 bool unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec)
764 {
765    ser_declare;
766
767    rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
768    unser_begin(rec->data, SER_LENGTH_Session_Label);
769    unser_string(label->Id);
770    unser_uint32(label->VerNum);
771    unser_uint32(label->JobId);
772    if (label->VerNum >= 11) {
773       unser_btime(label->write_btime);
774    } else {
775       unser_float64(label->write_date);
776    }
777    unser_float64(label->write_time);
778    unser_string(label->PoolName);
779    unser_string(label->PoolType);
780    unser_string(label->JobName);
781    unser_string(label->ClientName);
782    if (label->VerNum >= 10) {
783       unser_string(label->Job);          /* Unique name of this Job */
784       unser_string(label->FileSetName);
785       unser_uint32(label->JobType);
786       unser_uint32(label->JobLevel);
787    }
788    if (label->VerNum >= 11) {
789       unser_string(label->FileSetMD5);
790    } else {
791       label->FileSetMD5[0] = 0;
792    }
793    if (rec->FileIndex == EOS_LABEL) {
794       unser_uint32(label->JobFiles);
795       unser_uint64(label->JobBytes);
796       unser_uint32(label->StartBlock);
797       unser_uint32(label->EndBlock);
798       unser_uint32(label->StartFile);
799       unser_uint32(label->EndFile);
800       unser_uint32(label->JobErrors);
801       if (label->VerNum >= 11) {
802          unser_uint32(label->JobStatus);
803       } else {
804          label->JobStatus = JS_Terminated; /* kludge */
805       }
806    }
807    return true;
808 }
809
810 void dump_volume_label(DEVICE *dev)
811 {
812    int dbl = debug_level;
813    uint32_t File;
814    const char *LabelType;
815    char buf[30];
816    struct tm tm;
817    struct date_time dt;
818
819    debug_level = 1;
820    File = dev->file;
821    switch (dev->VolHdr.LabelType) {
822    case PRE_LABEL:
823       LabelType = "PRE_LABEL";
824       break;
825    case VOL_LABEL:
826       LabelType = "VOL_LABEL";
827       break;
828    case EOM_LABEL:
829       LabelType = "EOM_LABEL";
830       break;
831    case SOS_LABEL:
832       LabelType = "SOS_LABEL";
833       break;
834    case EOS_LABEL:
835       LabelType = "EOS_LABEL";
836       break;
837    case EOT_LABEL:
838       goto bail_out;
839    default:
840       LabelType = buf;
841       sprintf(buf, _("Unknown %d"), dev->VolHdr.LabelType);
842       break;
843    }
844
845    Pmsg11(-1, _("\nVolume Label:\n"
846 "Id                : %s"
847 "VerNo             : %d\n"
848 "VolName           : %s\n"
849 "PrevVolName       : %s\n"
850 "VolFile           : %d\n"
851 "LabelType         : %s\n"
852 "LabelSize         : %d\n"
853 "PoolName          : %s\n"
854 "MediaType         : %s\n"
855 "PoolType          : %s\n"
856 "HostName          : %s\n"
857 ""),
858              dev->VolHdr.Id, dev->VolHdr.VerNum,
859              dev->VolHdr.VolumeName, dev->VolHdr.PrevVolumeName,
860              File, LabelType, dev->VolHdr.LabelSize,
861              dev->VolHdr.PoolName, dev->VolHdr.MediaType,
862              dev->VolHdr.PoolType, dev->VolHdr.HostName);
863
864    if (dev->VolHdr.VerNum >= 11) {
865       char dt[50];
866       bstrftime(dt, sizeof(dt), btime_to_unix(dev->VolHdr.label_btime));
867       Pmsg1(-1, _("Date label written: %s\n"), dt);
868    } else {
869    dt.julian_day_number   = dev->VolHdr.label_date;
870    dt.julian_day_fraction = dev->VolHdr.label_time;
871    tm_decode(&dt, &tm);
872    Pmsg5(-1,
873 _("Date label written: %04d-%02d-%02d at %02d:%02d\n"),
874       tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
875    }
876
877 bail_out:
878    debug_level = dbl;
879 }
880
881
882 static void dump_session_label(DEV_RECORD *rec, const char *type)
883 {
884    int dbl;
885    struct date_time dt;
886    struct tm tm;
887    SESSION_LABEL label;
888    char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], ec6[30], ec7[30];
889
890    unser_session_label(&label, rec);
891    dbl = debug_level;
892    debug_level = 1;
893    Pmsg7(-1, _("\n%s Record:\n"
894 "JobId             : %d\n"
895 "VerNum            : %d\n"
896 "PoolName          : %s\n"
897 "PoolType          : %s\n"
898 "JobName           : %s\n"
899 "ClientName        : %s\n"
900 ""),    type, label.JobId, label.VerNum,
901       label.PoolName, label.PoolType,
902       label.JobName, label.ClientName);
903
904    if (label.VerNum >= 10) {
905       Pmsg4(-1, _(
906 "Job (unique name) : %s\n"
907 "FileSet           : %s\n"
908 "JobType           : %c\n"
909 "JobLevel          : %c\n"
910 ""), label.Job, label.FileSetName, label.JobType, label.JobLevel);
911    }
912
913    if (rec->FileIndex == EOS_LABEL) {
914       Pmsg8(-1, _(
915 "JobFiles          : %s\n"
916 "JobBytes          : %s\n"
917 "StartBlock        : %s\n"
918 "EndBlock          : %s\n"
919 "StartFile         : %s\n"
920 "EndFile           : %s\n"
921 "JobErrors         : %s\n"
922 "JobStatus         : %c\n"
923 ""),
924          edit_uint64_with_commas(label.JobFiles, ec1),
925          edit_uint64_with_commas(label.JobBytes, ec2),
926          edit_uint64_with_commas(label.StartBlock, ec3),
927          edit_uint64_with_commas(label.EndBlock, ec4),
928          edit_uint64_with_commas(label.StartFile, ec5),
929          edit_uint64_with_commas(label.EndFile, ec6),
930          edit_uint64_with_commas(label.JobErrors, ec7),
931          label.JobStatus);
932    }
933    if (label.VerNum >= 11) {
934       char dt[50];
935       bstrftime(dt, sizeof(dt), btime_to_unix(label.write_btime));
936       Pmsg1(-1, _("Date written      : %s\n"), dt);
937    } else {
938       dt.julian_day_number   = label.write_date;
939       dt.julian_day_fraction = label.write_time;
940       tm_decode(&dt, &tm);
941       Pmsg5(-1, _("Date written      : %04d-%02d-%02d at %02d:%02d\n"),
942       tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
943    }
944
945    debug_level = dbl;
946 }
947
948 void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose)
949 {
950    const char *type;
951    int dbl;
952
953    if (rec->FileIndex == 0 && rec->VolSessionId == 0 && rec->VolSessionTime == 0) {
954       return;
955    }
956    dbl = debug_level;
957    debug_level = 1;
958    switch (rec->FileIndex) {
959    case PRE_LABEL:
960       type = _("Fresh Volume");
961       break;
962    case VOL_LABEL:
963       type = _("Volume");
964       break;
965    case SOS_LABEL:
966       type = _("Begin Job Session");
967       break;
968    case EOS_LABEL:
969       type = _("End Job Session");
970       break;
971    case EOM_LABEL:
972       type = _("End of Media");
973       break;
974    case EOT_LABEL:
975       type = _("End of Tape");
976       break;
977    default:
978       type = _("Unknown");
979       break;
980    }
981    if (verbose) {
982       switch (rec->FileIndex) {
983       case PRE_LABEL:
984       case VOL_LABEL:
985          unser_volume_label(dev, rec);
986          dump_volume_label(dev);
987          break;
988       case SOS_LABEL:
989          dump_session_label(rec, type);
990          break;
991       case EOS_LABEL:
992          dump_session_label(rec, type);
993          break;
994       case EOM_LABEL:
995          Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
996             type, dev->file, dev->block_num, rec->VolSessionId, 
997             rec->VolSessionTime, rec->Stream, rec->data_len);
998          break;
999       case EOT_LABEL:
1000          Pmsg0(-1, _("End of physical tape.\n"));
1001          break;
1002       default:
1003          Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1004             type, dev->file, dev->block_num, rec->VolSessionId, 
1005             rec->VolSessionTime, rec->Stream, rec->data_len);
1006          break;
1007       }
1008    } else {
1009       SESSION_LABEL label;
1010       char dt[50];
1011       switch (rec->FileIndex) {
1012       case SOS_LABEL:
1013          unser_session_label(&label, rec);
1014          bstrftimes(dt, sizeof(dt), btime_to_unix(label.write_btime));
1015          Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1016             type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1017          Pmsg4(-1, _("   Job=%s Date=%s Level=%c Type=%c\n"),
1018             label.Job, dt, label.JobLevel, label.JobType);
1019          break;
1020       case EOS_LABEL:
1021          char ed1[30], ed2[30];
1022          unser_session_label(&label, rec);
1023          bstrftimes(dt, sizeof(dt), btime_to_unix(label.write_btime));
1024          Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1025             type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1026          Pmsg7(-1, _("   Date=%s Level=%c Type=%c Files=%s Bytes=%s Errors=%d Status=%c\n"),
1027             dt, label.JobLevel, label.JobType,
1028             edit_uint64_with_commas(label.JobFiles, ed1),
1029             edit_uint64_with_commas(label.JobBytes, ed2),
1030             label.JobErrors, (char)label.JobStatus);
1031          break;
1032       case EOM_LABEL:
1033       case PRE_LABEL:
1034       case VOL_LABEL:
1035       default:
1036          Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1037             type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, 
1038             rec->Stream, rec->data_len);
1039          break;
1040       case EOT_LABEL:
1041          break;
1042       }
1043    }
1044    debug_level = dbl;
1045 }