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