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