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