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