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