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