]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/label.c
This commit was manufactured by cvs2svn to create tag
[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    Dmsg4(100, "Enter read_volume_label res=%d device=%s vol=%s dev_Vol=%s\n",
70       dev->reserved_device, dev->print_name(), VolName, 
71       dev->VolHdr.VolumeName[0]?dev->VolHdr.VolumeName:"*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(150, "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 (!dev->rewind(dcr)) {
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          dev->rewind(dcr);
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(150, "return VOL_LABEL_ERROR\n");
198       stat = VOL_LABEL_ERROR;
199       goto bail_out;
200    }
201
202    dev->set_labeled();               /* set has Bacula label */
203    new_volume(dcr, dev->VolHdr.VolumeName);
204
205    /* Compare Volume Names */
206    Dmsg2(30, "Compare Vol names: VolName=%s hdr=%s\n", VolName?VolName:"*", dev->VolHdr.VolumeName);
207    if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolumeName, VolName) != 0) {
208       Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
209            dev->print_name(), VolName, dev->VolHdr.VolumeName);
210       Dmsg1(30, "%s", jcr->errmsg);
211       /*
212        * Cancel Job if too many label errors
213        *  => we are in a loop
214        */
215       if (!dev->poll && jcr->label_errors++ > 100) {
216          Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
217       }
218       Dmsg0(150, "return VOL_NAME_ERROR\n");
219       stat = VOL_NAME_ERROR;
220       goto bail_out;
221    }
222    Dmsg1(30, "Copy vol_name=%s\n", dev->VolHdr.VolumeName);
223
224    if (debug_level >= 10) {
225       dump_volume_label(dev);
226    }
227    Dmsg0(30, "Leave read_volume_label() VOL_OK\n");
228    /* If we are a streaming device, we only get one chance to read */
229    if (!dev_cap(dev, CAP_STREAM)) {
230       dev->rewind(dcr);
231       if (have_ansi_label) {
232          stat = read_ansi_ibm_label(dcr);            
233          /* If we want a label and didn't find it, return error */
234          if (stat != VOL_OK) {
235             goto bail_out;
236          }
237       }
238    }
239    empty_block(block);
240    return VOL_OK;
241
242 bail_out:
243    empty_block(block);
244    dev->rewind(dcr);
245    Dmsg1(150, "return %d\n", stat);
246    return stat;
247 }
248
249 /*
250  * Put a volume label into the block
251  *
252  *  Returns: false on failure
253  *           true  on success
254  */
255 bool write_volume_label_to_block(DCR *dcr)
256 {
257    DEV_RECORD rec;
258    DEVICE *dev = dcr->dev;
259    JCR *jcr = dcr->jcr;
260    DEV_BLOCK *block = dcr->block;
261
262    Dmsg0(20, "write Label in write_volume_label_to_block()\n");
263    memset(&rec, 0, sizeof(rec));
264    rec.data = get_memory(SER_LENGTH_Volume_Label);
265    empty_block(block);                /* Volume label always at beginning */
266
267    create_volume_label_record(dcr, &rec);
268
269    block->BlockNumber = 0;
270    if (!write_record_to_block(block, &rec)) {
271       free_pool_memory(rec.data);
272       Jmsg1(jcr, M_FATAL, 0, _("Cannot write Volume label to block for device %s\n"),
273          dev->print_name());
274       return false;
275    } else {
276       Dmsg1(90, "Wrote label of %d bytes to block\n", rec.data_len);
277    }
278    free_pool_memory(rec.data);
279    return true;
280 }
281
282
283 /*
284  * Write a Volume Label
285  *  !!! Note, this is ONLY used for writing
286  *            a fresh volume label.  Any data
287  *            after the label will be destroyed,
288  *            in fact, we write the label 5 times !!!!
289  *
290  *  This routine 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(150, "Label type=%d\n", dev->label_type);
306    if (!dev->rewind(dcr)) {
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          dev->rewind(dcr);
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 (!dev->rewind(dcr)) {
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             dev->rewind(dcr);
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(150, "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    char buf[100];
483
484    /* Serialize the label into the device record. */
485
486    rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
487    ser_begin(rec->data, SER_LENGTH_Volume_Label);
488    ser_string(dev->VolHdr.Id);
489
490    ser_uint32(dev->VolHdr.VerNum);
491
492    if (dev->VolHdr.VerNum >= 11) {
493       ser_btime(dev->VolHdr.label_btime);
494       dev->VolHdr.write_btime = get_current_btime();
495       ser_btime(dev->VolHdr.write_btime);
496       dev->VolHdr.write_date = 0;
497       dev->VolHdr.write_time = 0;
498    } else {
499       /* OLD WAY DEPRECATED */
500       ser_float64(dev->VolHdr.label_date);
501       ser_float64(dev->VolHdr.label_time);
502       get_current_time(&dt);
503       dev->VolHdr.write_date = dt.julian_day_number;
504       dev->VolHdr.write_time = dt.julian_day_fraction;
505    }
506    ser_float64(dev->VolHdr.write_date);   /* 0 if VerNum >= 11 */
507    ser_float64(dev->VolHdr.write_time);   /* 0  if VerNum >= 11 */
508
509    ser_string(dev->VolHdr.VolumeName);
510    ser_string(dev->VolHdr.PrevVolumeName);
511    ser_string(dev->VolHdr.PoolName);
512    ser_string(dev->VolHdr.PoolType);
513    ser_string(dev->VolHdr.MediaType);
514
515    ser_string(dev->VolHdr.HostName);
516    ser_string(dev->VolHdr.LabelProg);
517    ser_string(dev->VolHdr.ProgVersion);
518    ser_string(dev->VolHdr.ProgDate);
519
520    ser_end(rec->data, SER_LENGTH_Volume_Label);
521    rec->data_len = ser_length(rec->data);
522    rec->FileIndex = dev->VolHdr.LabelType;
523    rec->VolSessionId = jcr->VolSessionId;
524    rec->VolSessionTime = jcr->VolSessionTime;
525    rec->Stream = jcr->NumVolumes;
526    Dmsg2(150, "Created Vol label rec: FI=%s len=%d\n", FI_to_ascii(buf, rec->FileIndex),
527       rec->data_len);
528 }
529
530
531 /*
532  * Create a volume label in memory
533  */
534 void create_volume_label(DEVICE *dev, const char *VolName, const char *PoolName)
535 {
536    DEVRES *device = (DEVRES *)dev->device;
537
538    Dmsg0(90, "Start create_volume_label()\n");
539
540    ASSERT(dev != NULL);
541
542    free_volume(dev);         /* release any old volume */
543    memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
544
545    bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
546    dev->VolHdr.VerNum = BaculaTapeVersion;
547    dev->VolHdr.LabelType = PRE_LABEL;  /* Mark tape as unused */
548    bstrncpy(dev->VolHdr.VolumeName, VolName, sizeof(dev->VolHdr.VolumeName));
549    bstrncpy(dev->VolHdr.PoolName, PoolName, sizeof(dev->VolHdr.PoolName));
550    bstrncpy(dev->VolHdr.MediaType, device->media_type, sizeof(dev->VolHdr.MediaType));
551
552    bstrncpy(dev->VolHdr.PoolType, "Backup", sizeof(dev->VolHdr.PoolType));
553
554    dev->VolHdr.label_btime = get_current_btime();
555    dev->VolHdr.label_date = 0;
556    dev->VolHdr.label_time = 0;
557
558    if (gethostname(dev->VolHdr.HostName, sizeof(dev->VolHdr.HostName)) != 0) {
559       dev->VolHdr.HostName[0] = 0;
560    }
561    bstrncpy(dev->VolHdr.LabelProg, my_name, sizeof(dev->VolHdr.LabelProg));
562    sprintf(dev->VolHdr.ProgVersion, "Ver. %s %s", VERSION, BDATE);
563    sprintf(dev->VolHdr.ProgDate, "Build %s %s", __DATE__, __TIME__);
564    dev->set_labeled();               /* set has Bacula label */
565    if (debug_level >= 90) {
566       dump_volume_label(dev);
567    }
568 }
569
570 /*
571  * Create session label
572  *  The pool memory must be released by the calling program
573  */
574 void create_session_label(DCR *dcr, DEV_RECORD *rec, int label)
575 {
576    JCR *jcr = dcr->jcr;
577    ser_declare;
578
579    rec->VolSessionId   = jcr->VolSessionId;
580    rec->VolSessionTime = jcr->VolSessionTime;
581    rec->Stream         = jcr->JobId;
582
583    rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
584    ser_begin(rec->data, SER_LENGTH_Session_Label);
585    ser_string(BaculaId);
586    ser_uint32(BaculaTapeVersion);
587
588    ser_uint32(jcr->JobId);
589
590    /* Changed in VerNum 11 */
591    ser_btime(get_current_btime());
592    ser_float64(0);
593
594    ser_string(dcr->pool_name);
595    ser_string(dcr->pool_type);
596    ser_string(jcr->job_name);         /* base Job name */
597    ser_string(jcr->client_name);
598
599    /* Added in VerNum 10 */
600    ser_string(jcr->Job);              /* Unique name of this Job */
601    ser_string(jcr->fileset_name);
602    ser_uint32(jcr->JobType);
603    ser_uint32(jcr->JobLevel);
604    /* Added in VerNum 11 */
605    ser_string(jcr->fileset_md5);
606
607    if (label == EOS_LABEL) {
608       ser_uint32(jcr->JobFiles);
609       ser_uint64(jcr->JobBytes);
610       ser_uint32(dcr->StartBlock);
611       ser_uint32(dcr->EndBlock);
612       ser_uint32(dcr->StartFile);
613       ser_uint32(dcr->EndFile);
614       ser_uint32(jcr->JobErrors);
615
616       /* Added in VerNum 11 */
617       ser_uint32(jcr->JobStatus);
618    }
619    ser_end(rec->data, SER_LENGTH_Session_Label);
620    rec->data_len = ser_length(rec->data);
621 }
622
623 /* Write session label
624  *  Returns: false on failure
625  *           true  on success
626  */
627 bool write_session_label(DCR *dcr, int label)
628 {
629    JCR *jcr = dcr->jcr;
630    DEVICE *dev = dcr->dev;
631    DEV_RECORD *rec;
632    DEV_BLOCK *block = dcr->block;
633    char buf1[100], buf2[100];
634
635    rec = new_record();
636    Dmsg1(90, "session_label record=%x\n", rec);
637    switch (label) {
638    case SOS_LABEL:
639       if (dev->is_tape()) {
640          dcr->StartBlock = dev->block_num;
641          dcr->StartFile  = dev->file;
642       } else {
643          dcr->StartBlock = (uint32_t)dev->file_addr;
644          dcr->StartFile = (uint32_t)(dev->file_addr >> 32);
645       }
646       break;
647    case EOS_LABEL:
648       if (dev->is_tape()) {
649          dcr->EndBlock = dev->EndBlock;
650          dcr->EndFile  = dev->EndFile;
651       } else {
652          dcr->EndBlock = (uint32_t)dev->file_addr;
653          dcr->EndFile = (uint32_t)(dev->file_addr >> 32);
654       }
655       break;
656    default:
657       Jmsg1(jcr, M_ABORT, 0, _("Bad session label = %d\n"), label);
658       break;
659    }
660    create_session_label(dcr, rec, label);
661    rec->FileIndex = label;
662
663    /*
664     * We guarantee that the session record can totally fit
665     *  into a block. If not, write the block, and put it in
666     *  the next block. Having the sesssion record totally in
667     *  one block makes reading them much easier (no need to
668     *  read the next block).
669     */
670    if (!can_write_record_to_block(block, rec)) {
671       Dmsg0(150, "Cannot write session label to block.\n");
672       if (!write_block_to_device(dcr)) {
673          Dmsg0(90, "Got session label write_block_to_dev error.\n");
674          /* ****FIXME***** errno is not set here */
675          Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"),
676                            dev_vol_name(dev), strerror(errno));
677          free_record(rec);
678          return false;
679       }
680    }
681    if (!write_record_to_block(block, rec)) {
682       Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"),
683                         dev_vol_name(dev), strerror(errno));
684       free_record(rec);
685       return false;
686    }
687
688    Dmsg6(20, "Write sesson_label record JobId=%d FI=%s SessId=%d Strm=%s len=%d "
689              "remainder=%d\n", jcr->JobId,
690       FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
691       stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
692       rec->remainder);
693
694    free_record(rec);
695    Dmsg2(20, "Leave write_session_label Block=%d File=%d\n",
696       dev->block_num, dev->file);
697    return true;
698 }
699
700 /*  unser_volume_label
701  *
702  * Unserialize the Bacula Volume label into the device Volume_Label
703  * structure.
704  *
705  * Assumes that the record is already read.
706  *
707  * Returns: false on error
708  *          true  on success
709 */
710
711 bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec)
712 {
713    ser_declare;
714    char buf1[100], buf2[100];
715
716    if (rec->FileIndex != VOL_LABEL && rec->FileIndex != PRE_LABEL) {
717       Mmsg3(dev->errmsg, _("Expecting Volume Label, got FI=%s Stream=%s len=%d\n"),
718               FI_to_ascii(buf1, rec->FileIndex),
719               stream_to_ascii(buf2, rec->Stream, rec->FileIndex),
720               rec->data_len);
721       if (!forge_on) {
722          return false;
723       }
724    }
725
726    dev->VolHdr.LabelType = rec->FileIndex;
727    dev->VolHdr.LabelSize = rec->data_len;
728
729
730    /* Unserialize the record into the Volume Header */
731    rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
732    ser_begin(rec->data, SER_LENGTH_Volume_Label);
733    unser_string(dev->VolHdr.Id);
734    unser_uint32(dev->VolHdr.VerNum);
735
736    if (dev->VolHdr.VerNum >= 11) {
737       unser_btime(dev->VolHdr.label_btime);
738       unser_btime(dev->VolHdr.write_btime);
739    } else { /* old way */
740       unser_float64(dev->VolHdr.label_date);
741       unser_float64(dev->VolHdr.label_time);
742    }
743    unser_float64(dev->VolHdr.write_date);    /* Unused with VerNum >= 11 */
744    unser_float64(dev->VolHdr.write_time);    /* Unused with VerNum >= 11 */
745
746    unser_string(dev->VolHdr.VolumeName);
747    unser_string(dev->VolHdr.PrevVolumeName);
748    unser_string(dev->VolHdr.PoolName);
749    unser_string(dev->VolHdr.PoolType);
750    unser_string(dev->VolHdr.MediaType);
751
752    unser_string(dev->VolHdr.HostName);
753    unser_string(dev->VolHdr.LabelProg);
754    unser_string(dev->VolHdr.ProgVersion);
755    unser_string(dev->VolHdr.ProgDate);
756
757    ser_end(rec->data, SER_LENGTH_Volume_Label);
758    Dmsg0(190, "unser_vol_label\n");
759    if (debug_level >= 190) {
760       dump_volume_label(dev);
761    }
762    return true;
763 }
764
765
766 bool unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec)
767 {
768    ser_declare;
769
770    rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
771    unser_begin(rec->data, SER_LENGTH_Session_Label);
772    unser_string(label->Id);
773    unser_uint32(label->VerNum);
774    unser_uint32(label->JobId);
775    if (label->VerNum >= 11) {
776       unser_btime(label->write_btime);
777    } else {
778       unser_float64(label->write_date);
779    }
780    unser_float64(label->write_time);
781    unser_string(label->PoolName);
782    unser_string(label->PoolType);
783    unser_string(label->JobName);
784    unser_string(label->ClientName);
785    if (label->VerNum >= 10) {
786       unser_string(label->Job);          /* Unique name of this Job */
787       unser_string(label->FileSetName);
788       unser_uint32(label->JobType);
789       unser_uint32(label->JobLevel);
790    }
791    if (label->VerNum >= 11) {
792       unser_string(label->FileSetMD5);
793    } else {
794       label->FileSetMD5[0] = 0;
795    }
796    if (rec->FileIndex == EOS_LABEL) {
797       unser_uint32(label->JobFiles);
798       unser_uint64(label->JobBytes);
799       unser_uint32(label->StartBlock);
800       unser_uint32(label->EndBlock);
801       unser_uint32(label->StartFile);
802       unser_uint32(label->EndFile);
803       unser_uint32(label->JobErrors);
804       if (label->VerNum >= 11) {
805          unser_uint32(label->JobStatus);
806       } else {
807          label->JobStatus = JS_Terminated; /* kludge */
808       }
809    }
810    return true;
811 }
812
813 void dump_volume_label(DEVICE *dev)
814 {
815    int dbl = debug_level;
816    uint32_t File;
817    const char *LabelType;
818    char buf[30];
819    struct tm tm;
820    struct date_time dt;
821
822    debug_level = 1;
823    File = dev->file;
824    switch (dev->VolHdr.LabelType) {
825    case PRE_LABEL:
826       LabelType = "PRE_LABEL";
827       break;
828    case VOL_LABEL:
829       LabelType = "VOL_LABEL";
830       break;
831    case EOM_LABEL:
832       LabelType = "EOM_LABEL";
833       break;
834    case SOS_LABEL:
835       LabelType = "SOS_LABEL";
836       break;
837    case EOS_LABEL:
838       LabelType = "EOS_LABEL";
839       break;
840    case EOT_LABEL:
841       goto bail_out;
842    default:
843       LabelType = buf;
844       sprintf(buf, _("Unknown %d"), dev->VolHdr.LabelType);
845       break;
846    }
847
848    Pmsg11(-1, _("\nVolume Label:\n"
849 "Id                : %s"
850 "VerNo             : %d\n"
851 "VolName           : %s\n"
852 "PrevVolName       : %s\n"
853 "VolFile           : %d\n"
854 "LabelType         : %s\n"
855 "LabelSize         : %d\n"
856 "PoolName          : %s\n"
857 "MediaType         : %s\n"
858 "PoolType          : %s\n"
859 "HostName          : %s\n"
860 ""),
861              dev->VolHdr.Id, dev->VolHdr.VerNum,
862              dev->VolHdr.VolumeName, dev->VolHdr.PrevVolumeName,
863              File, LabelType, dev->VolHdr.LabelSize,
864              dev->VolHdr.PoolName, dev->VolHdr.MediaType,
865              dev->VolHdr.PoolType, dev->VolHdr.HostName);
866
867    if (dev->VolHdr.VerNum >= 11) {
868       char dt[50];
869       bstrftime(dt, sizeof(dt), btime_to_unix(dev->VolHdr.label_btime));
870       Pmsg1(-1, _("Date label written: %s\n"), dt);
871    } else {
872    dt.julian_day_number   = dev->VolHdr.label_date;
873    dt.julian_day_fraction = dev->VolHdr.label_time;
874    tm_decode(&dt, &tm);
875    Pmsg5(-1,
876 _("Date label written: %04d-%02d-%02d at %02d:%02d\n"),
877       tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
878    }
879
880 bail_out:
881    debug_level = dbl;
882 }
883
884
885 static void dump_session_label(DEV_RECORD *rec, const char *type)
886 {
887    int dbl;
888    struct date_time dt;
889    struct tm tm;
890    SESSION_LABEL label;
891    char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], ec6[30], ec7[30];
892
893    unser_session_label(&label, rec);
894    dbl = debug_level;
895    debug_level = 1;
896    Pmsg7(-1, _("\n%s Record:\n"
897 "JobId             : %d\n"
898 "VerNum            : %d\n"
899 "PoolName          : %s\n"
900 "PoolType          : %s\n"
901 "JobName           : %s\n"
902 "ClientName        : %s\n"
903 ""),    type, label.JobId, label.VerNum,
904       label.PoolName, label.PoolType,
905       label.JobName, label.ClientName);
906
907    if (label.VerNum >= 10) {
908       Pmsg4(-1, _(
909 "Job (unique name) : %s\n"
910 "FileSet           : %s\n"
911 "JobType           : %c\n"
912 "JobLevel          : %c\n"
913 ""), label.Job, label.FileSetName, label.JobType, label.JobLevel);
914    }
915
916    if (rec->FileIndex == EOS_LABEL) {
917       Pmsg8(-1, _(
918 "JobFiles          : %s\n"
919 "JobBytes          : %s\n"
920 "StartBlock        : %s\n"
921 "EndBlock          : %s\n"
922 "StartFile         : %s\n"
923 "EndFile           : %s\n"
924 "JobErrors         : %s\n"
925 "JobStatus         : %c\n"
926 ""),
927          edit_uint64_with_commas(label.JobFiles, ec1),
928          edit_uint64_with_commas(label.JobBytes, ec2),
929          edit_uint64_with_commas(label.StartBlock, ec3),
930          edit_uint64_with_commas(label.EndBlock, ec4),
931          edit_uint64_with_commas(label.StartFile, ec5),
932          edit_uint64_with_commas(label.EndFile, ec6),
933          edit_uint64_with_commas(label.JobErrors, ec7),
934          label.JobStatus);
935    }
936    if (label.VerNum >= 11) {
937       char dt[50];
938       bstrftime(dt, sizeof(dt), btime_to_unix(label.write_btime));
939       Pmsg1(-1, _("Date written      : %s\n"), dt);
940    } else {
941       dt.julian_day_number   = label.write_date;
942       dt.julian_day_fraction = label.write_time;
943       tm_decode(&dt, &tm);
944       Pmsg5(-1, _("Date written      : %04d-%02d-%02d at %02d:%02d\n"),
945       tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
946    }
947
948    debug_level = dbl;
949 }
950
951 void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose)
952 {
953    const char *type;
954    int dbl;
955
956    if (rec->FileIndex == 0 && rec->VolSessionId == 0 && rec->VolSessionTime == 0) {
957       return;
958    }
959    dbl = debug_level;
960    debug_level = 1;
961    switch (rec->FileIndex) {
962    case PRE_LABEL:
963       type = _("Fresh Volume");
964       break;
965    case VOL_LABEL:
966       type = _("Volume");
967       break;
968    case SOS_LABEL:
969       type = _("Begin Job Session");
970       break;
971    case EOS_LABEL:
972       type = _("End Job Session");
973       break;
974    case EOM_LABEL:
975       type = _("End of Media");
976       break;
977    case EOT_LABEL:
978       type = _("End of Tape");
979       break;
980    default:
981       type = _("Unknown");
982       break;
983    }
984    if (verbose) {
985       switch (rec->FileIndex) {
986       case PRE_LABEL:
987       case VOL_LABEL:
988          unser_volume_label(dev, rec);
989          dump_volume_label(dev);
990          break;
991       case SOS_LABEL:
992          dump_session_label(rec, type);
993          break;
994       case EOS_LABEL:
995          dump_session_label(rec, type);
996          break;
997       case EOM_LABEL:
998          Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
999             type, dev->file, dev->block_num, rec->VolSessionId, 
1000             rec->VolSessionTime, rec->Stream, rec->data_len);
1001          break;
1002       case EOT_LABEL:
1003          Pmsg0(-1, _("End of physical tape.\n"));
1004          break;
1005       default:
1006          Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1007             type, dev->file, dev->block_num, rec->VolSessionId, 
1008             rec->VolSessionTime, rec->Stream, rec->data_len);
1009          break;
1010       }
1011    } else {
1012       SESSION_LABEL label;
1013       char dt[50];
1014       switch (rec->FileIndex) {
1015       case SOS_LABEL:
1016          unser_session_label(&label, rec);
1017          bstrftimes(dt, sizeof(dt), btime_to_unix(label.write_btime));
1018          Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1019             type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1020          Pmsg4(-1, _("   Job=%s Date=%s Level=%c Type=%c\n"),
1021             label.Job, dt, label.JobLevel, label.JobType);
1022          break;
1023       case EOS_LABEL:
1024          char ed1[30], ed2[30];
1025          unser_session_label(&label, rec);
1026          bstrftimes(dt, sizeof(dt), btime_to_unix(label.write_btime));
1027          Pmsg6(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d\n"),
1028             type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, label.JobId);
1029          Pmsg7(-1, _("   Date=%s Level=%c Type=%c Files=%s Bytes=%s Errors=%d Status=%c\n"),
1030             dt, label.JobLevel, label.JobType,
1031             edit_uint64_with_commas(label.JobFiles, ed1),
1032             edit_uint64_with_commas(label.JobBytes, ed2),
1033             label.JobErrors, (char)label.JobStatus);
1034          break;
1035       case EOM_LABEL:
1036       case PRE_LABEL:
1037       case VOL_LABEL:
1038       default:
1039          Pmsg7(-1, _("%s Record: File:blk=%u:%u SessId=%d SessTime=%d JobId=%d DataLen=%d\n"),
1040             type, dev->file, dev->block_num, rec->VolSessionId, rec->VolSessionTime, 
1041             rec->Stream, rec->data_len);
1042          break;
1043       case EOT_LABEL:
1044          break;
1045       }
1046    }
1047    debug_level = dbl;
1048 }