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