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