]> git.sur5r.net Git - bacula/bacula/commitdiff
- Modified ANSI label code to preserve any ANSI label
authorKern Sibbald <kern@sibbald.com>
Wed, 9 Feb 2005 14:40:03 +0000 (14:40 +0000)
committerKern Sibbald <kern@sibbald.com>
Wed, 9 Feb 2005 14:40:03 +0000 (14:40 +0000)
  already found by skipping over it rather than rewriting
  it.
- Split the ANSI label code into ansi_label.c
- Do not let user relabel an ANSI labeled tape.
- Applied a patch for the console help command supplied
  in a bug report.
- Added some new dev methods. Most notably was
  set_eof(), which handles setting all the dev variables
  when an EOF is just read. This is now used most everywhere
  in the code.

git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@1820 91ce42f0-d328-0410-95d8-f526ca767f89

17 files changed:
bacula/examples/python/NewVolume.py
bacula/kernstodo
bacula/src/.cvsignore
bacula/src/cats/cats.h
bacula/src/dird/ua_cmds.c
bacula/src/stored/Makefile.in
bacula/src/stored/ansi_label.c [new file with mode: 0644]
bacula/src/stored/block.c
bacula/src/stored/bscan.c
bacula/src/stored/dev.c
bacula/src/stored/dev.h
bacula/src/stored/dircmd.c
bacula/src/stored/label.c
bacula/src/stored/mount.c
bacula/src/stored/protos.h
bacula/src/stored/record.h
bacula/src/version.h

index b6df07e6f55ccf5273120fceef897ca75c4f4a16..3a1df0cf4f59f118d431f7a17281d0397945a5ae 100644 (file)
@@ -7,6 +7,6 @@ def NewVolume(j):
     print "Client=" + client
     numvol = bacula.get(j, "NumVols");
     print "NumVols=", numvol
-    bacula.set(jcr=j, JobReport="Python New Volume set for Job.\n") 
-    bacula.set(jcr=j, VolumeName="TestA-001")
+#   bacula.set(jcr=j, JobReport="Python New Volume set for Job.\n") 
+#   bacula.set(jcr=j, VolumeName="TestA-001")
     return 1
index 13d63158269dfe9a2782b817e937f12056e2c4c4..dade3954dd6a91b7cf24a2c7347b2af7d374473a 100644 (file)
@@ -30,6 +30,11 @@ Suggestions for Preben:
 - Optimized bootstrap.
 
 For 1.37:
+- Make sure SD deletes spool files on error exit.
+- Delete old spool files when SD starts.
+- When Python creates a new label, the tape is immediately
+  recycled and no label created. This happens when using   
+  autolabeling -- even when Python doesn't generate the name.
 - Add a restore directory-x
 - When labeling tapes, if you enter 000026, Bacula uses
   the tape index rather than the Volume name 000026.
@@ -360,6 +365,10 @@ For 1.37 Testing/Documentation:
 - any actions should be interuptable with STRG+C
 - command-expansion would be pretty cool
 ====
+- When the replace Never option is set, new directory permissions
+  are not restored. See bug 213. To fix this requires creating a
+  list of newly restored directories so that those directory 
+  permissions *can* be restored.
 - Compaction of Disk space by "migrating" Volumes that have pruned
   Jobs (what criteria? size, #jobs, time).
 - Add prune all command
index a9c61f762d0a9e958a41436a5b89b36b88fe9448..463e48169ea2f63ef07126327b955f3af717cc27 100644 (file)
@@ -6,3 +6,4 @@ config.h
 testprogs
 host.h
 perlgui
+python
index c2d2637b38e62dd39b3d208bdbba535028f2b5b0..a912098ce67f0cbd5d1f8544f8a48bfe9d2b0c60 100644 (file)
 
  */
 
+/*
+   Here is how database versions work. 
+
+   While I am working on a new release with database changes, the
+   update scripts are in the src/cats directory under the names
+   update_xxx_tables.in.  Most of the time, I make database updates
+   in one go and immediately update the version, but not always.  If
+   there are going to be several updates as is the case with version
+   1.37, then I will often forgo changing the version until the last
+   update otherwise I will end up with too many versions and a lot
+   of confusion.
+
+   When I am pretty sure there will be no more updates, I will
+   change the version from 8 to 9 (in the present case), and when I
+   am 100% sure there will be no more changes, the update script
+   will be copied to the updatedb directory with the correct name
+   (in the present case 8 to 9).
+
+   Now, in principle, each of the different DB implementations 
+   can have a different version, but in practice they are all
+   the same (simplifies things). The exception is the internal
+   database, which is no longer used, and hence, no longer changes.
+ */
+
+
 #ifndef __SQL_H_
 #define __SQL_H_ 1
 
index 0c0644488ab84c8b7074a56f8e0c99f58fe287f7..273d1500e880e11f21babc615bc7bbb4f2e90f32 100644 (file)
@@ -97,16 +97,16 @@ int quit_cmd(UAContext *ua, const char *cmd);
 struct cmdstruct { const char *key; int (*func)(UAContext *ua, const char *cmd); const char *help; };
 static struct cmdstruct commands[] = {
  { N_("add"),        add_cmd,         _("add media to a pool")},
- { N_("autodisplay"), autodisplay_cmd, _("autodisplay [on/off] -- console messages")},
- { N_("automount"),   automount_cmd,  _("automount [on/off] -- after label")},
- { N_("cancel"),     cancel_cmd,    _("cancel job=nnn -- cancel a job")},
+ { N_("autodisplay"), autodisplay_cmd, _("autodisplay [on|off] -- console messages")},
+ { N_("automount"),   automount_cmd,  _("automount [on|off] -- after label")},
+ { N_("cancel"),     cancel_cmd,    _("cancel <job=nnn> -- cancel a job")},
  { N_("create"),     create_cmd,    _("create DB Pool from resource")},
  { N_("delete"),     delete_cmd,    _("delete [pool=<pool-name> | media volume=<volume-name>]")},
  { N_("estimate"),   estimate_cmd,  _("performs FileSet estimate, listing gives full listing")},
  { N_("exit"),       quit_cmd,      _("exit = quit")},
- { N_("gui"),        gui_cmd,       _("gui [on/off] -- non-interactive gui mode")},
+ { N_("gui"),        gui_cmd,       _("gui [on|off] -- non-interactive gui mode")},
  { N_("help"),       help_cmd,      _("print this command")},
- { N_("list"),       list_cmd,      _("list [pools | jobs | jobtotals | media <pool> | files jobid=<nn>]; from catalog")},
+ { N_("list"),       list_cmd,      _("list [pools | jobs | jobtotals | media <pool=pool-name> | files <jobid=nn>]; from catalog")},
  { N_("label"),      label_cmd,     _("label a tape")},
  { N_("llist"),      llist_cmd,     _("full or long list like list command")},
  { N_("messages"),   messagescmd,   _("messages")},
index cbdfa2292fd014ac6d3ee1cf8d6d814fc93e72ab..782721c1f8ac54a73e7772a2249f297f8c417668 100644 (file)
@@ -18,7 +18,8 @@ first_rule: all
 dummy:
 
 # bacula-sd
-SVRSRCS = stored.c autochanger.c acquire.c append.c \
+SVRSRCS = stored.c ansi_label.c \
+         autochanger.c acquire.c append.c \
          askdir.c authenticate.c \
          block.c butil.c dev.c \
          device.c dircmd.c fd_cmds.c job.c \
@@ -26,7 +27,8 @@ SVRSRCS = stored.c autochanger.c acquire.c append.c \
          python.c \
          read.c read_record.c record.c \
          spool.c status.c stored_conf.c
-SVROBJS = stored.o autochanger.o acquire.o append.o \
+SVROBJS = stored.o ansi_label.o \
+         autochanger.o acquire.o append.o \
          askdir.o authenticate.o \
          block.o butil.o dev.o \
          device.o dircmd.o fd_cmds.o job.o \
@@ -37,29 +39,35 @@ SVROBJS = stored.o autochanger.o acquire.o append.o \
 
 # btape
 TAPESRCS = btape.c block.c butil.c dev.c device.c label.c \
+          ansi_label.c \
           acquire.c mount.c record.c read_record.c \
           stored_conf.c match_bsr.c parse_bsr.c spool.c
 TAPEOBJS = btape.o block.o butil.o dev.o device.o label.o \
+          ansi_label.o \
           autochanger.o acquire.o mount.o record.o read_record.o \
           stored_conf.o match_bsr.o parse_bsr.o spool.o
 
 # bls
 BLSOBJS = bls.o block.o butil.o device.o dev.o label.o match_bsr.o \
+         ansi_label.o \
          autochanger.o acquire.o mount.o parse_bsr.o record.o  \
          read_record.o stored_conf.o spool.o
 
 # bextract
 BEXTOBJS = bextract.o block.o device.o dev.o label.o record.o \
+          ansi_label.o \
           autochanger.o acquire.o mount.o match_bsr.o parse_bsr.o butil.o \
           read_record.o stored_conf.o spool.o
 
 # bscan
 SCNOBJS = bscan.o block.o device.o dev.o label.o \
+         ansi_label.o \
          autochanger.o acquire.o mount.o record.o match_bsr.o parse_bsr.o \
          butil.o read_record.o stored_conf.o spool.o
 
 # bcopy
 COPYOBJS = bcopy.o block.o device.o dev.o label.o \
+          ansi_label.o \
           autochanger.o acquire.o mount.o record.o match_bsr.o parse_bsr.o \
           butil.o read_record.o stored_conf.o spool.o
 
diff --git a/bacula/src/stored/ansi_label.c b/bacula/src/stored/ansi_label.c
new file mode 100644 (file)
index 0000000..0ee7ad0
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+ *
+ *  ansi_label.c routines to handle ANSI (and perhaps one day IBM)
+ *   tape labels.
+ *
+ *   Kern Sibbald, MMV
+ *
+ *
+ *
+ *   Version $Id$
+ */
+/*
+   Copyright (C) 2005 Kern Sibbald
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public
+   License along with this program; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+   MA 02111-1307, USA.
+
+ */
+
+#include "bacula.h"                   /* pull in global headers */
+#include "stored.h"                   /* pull in Storage Deamon headers */
+
+/* Forward referenced functions */
+static char *ansi_date(time_t td, char *buf);
+static bool same_label_names(char *bacula_name, char *ansi_name);
+
+/*
+ * We read an ANSI label and compare the Volume name. We require
+ * a VOL1 record of 80 characters followed by a HDR1 record containing
+ * BACULA.DATA in the filename field. We then read up to 3 more 
+ * header records (they are not required) and an EOF, at which
+ * point, all is good.
+ *
+ * Returns:
+ *    VOL_OK           Volume name OK
+ *    VOL_NO_LABEL     No ANSI label on Volume
+ *    VOL_IO_ERROR     I/O error on read
+ *    VOL_NAME_ERROR   Wrong name in VOL1 record
+ *    VOL_LABEL_ERROR  Probably an ANSI label, but something wrong
+ *     
+ */ 
+int read_ansi_ibm_label(DCR *dcr) 
+{
+   DEVICE *dev = dcr->dev;
+   JCR *jcr = dcr->jcr;
+   char label[80];                   /* tape label */
+   int stat, i;
+   char *VolName = dcr->VolumeName;
+
+   /*
+    * Read VOL1, HDR1, HDR2 labels, but ignore the data
+    *  If tape read the following EOF mark, on disk do
+    *  not read.
+    */
+   Dmsg0(000, "Read ansi label.\n");
+   if (!dev->is_tape()) {
+      return VOL_OK;
+   }
+
+   dev->label_type = B_BACULA_LABEL;  /* assume Bacula label */
+
+   /* Read a maximum of 5 records VOL1, HDR1, ... HDR4 */
+   for (i=0; i < 6; i++) {
+      do {
+        stat = read(dev->fd, label, sizeof(label));
+      } while (stat == -1 && errno == EINTR);
+      if (stat < 0) {
+        berrno be;
+        clrerror_dev(dev, -1);
+         Dmsg1(000, "Read device got: ERR=%s\n", be.strerror());
+         Mmsg2(dev->errmsg, _("Read error on device %s in ANSI/IBM label. ERR=%s\n"),
+           dev->dev_name, be.strerror());
+         Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
+        dev->VolCatInfo.VolCatErrors++;
+        return VOL_IO_ERROR;
+      }
+      if (stat == 0) {
+        if (dev->at_eof()) {
+           dev->state |= ST_EOT;
+            Dmsg0(000, "EOM on ANSI label\n");
+            return VOL_LABEL_ERROR;   /* at EOM this shouldn't happen */
+        } else {
+           dev->set_eof();
+        }
+      }
+      switch (i) {
+      case 0:                        /* Want VOL1 label */
+         if (stat != 80 || strncmp("VOL1", label, 4) != 0) {
+            Dmsg0(000, "No VOL1 label\n");
+           return VOL_NO_LABEL;   /* No ANSI label */
+        }
+
+        dev->label_type = B_ANSI_LABEL;
+
+        /* Compare Volume Names allow special wild card */
+         if (VolName && *VolName && *VolName != '*') { 
+           if (!same_label_names(VolName, &label[4])) {
+              char *p = &label[4];
+              char *q = dev->VolHdr.VolName;
+               for (int i=0; *p != ' ' && i < 6; i++) {
+                 *q++ = *p++;
+              }
+              *q = 0;
+               Dmsg2(000, "Wanted ANSI Vol %s got %6s\n", VolName, dev->VolHdr.VolName);
+              return VOL_NAME_ERROR;
+           }
+        }
+        break;
+      case 1:
+         if (stat != 80 || strncmp("HDR1", label, 4) != 0) {
+            Dmsg0(000, "No HDR1 label\n");
+           return VOL_LABEL_ERROR;
+        }
+         if (strncmp("BACULA.DATA", &label[4], 11) != 0) {
+            Dmsg1(000, "HD1 not Bacula label. Wanted  BACULA.DATA got %11s\n",
+              &label[4]);
+           return VOL_NAME_ERROR;     /* Not a Bacula label */
+        }
+        break;
+      case 2:
+         if (stat != 80 || strncmp("HDR2", label, 4) != 0) {
+            Dmsg0(000, "No HDR2 label\n");
+           return VOL_LABEL_ERROR;
+        }
+        break;
+      default:
+        if (stat == 0) {
+            Dmsg0(000, "ANSI label OK\n");
+           return VOL_OK;
+        }
+         if (stat != 80 || strncmp("HDR", label, 3) != 0) {
+            Dmsg0(000, "Unknown or bad ANSI label record.\n");
+           return VOL_LABEL_ERROR;
+        }
+        break;
+      }
+   }
+   Dmsg0(000, "Too many records in ANSI label.\n");
+   return VOL_LABEL_ERROR;
+}  
+
+/*
+ * Write an ANSI or IBM 80 character tape label
+ *   Assume we are positioned at the beginning of the tape.
+ *   Returns:  true of OK
+ *            false if error
+ */
+bool write_ansi_ibm_label(DCR *dcr, const char *VolName)
+{
+   DEVICE *dev = dcr->dev;
+   JCR *jcr = dcr->jcr;
+   char label[80];                   /* tape label */
+   char date[20];                    /* ansi date buffer */
+   time_t now;
+   int len, stat, label_type;
+
+   /*
+    * If the Device requires a specific label type use it,
+    * otherwise, use the type requested by the Director
+    */
+   if (dcr->device->label_type != B_BACULA_LABEL) {
+      label_type = dcr->device->label_type;   /* force label type */
+   } else {
+      label_type = dcr->VolCatInfo.LabelType; /* accept Dir type */
+   }
+
+   switch (label_type) {
+   case B_BACULA_LABEL:
+      return true;
+   case B_ANSI_LABEL:
+   case B_IBM_LABEL:
+      ser_declare;
+      Dmsg1(000, "Write ANSI label type=%d\n", label_type);
+      len = strlen(VolName);
+      if (len > 6) {
+         Jmsg1(jcr, M_FATAL, 0, _("ANSI Volume label name \"%s\" longer than 6 chars.\n"),
+           VolName);
+        return false;
+      }
+      memset(label, ' ', sizeof(label));
+      ser_begin(label, sizeof(label));
+      ser_bytes("VOL1", 4);
+      ser_bytes(VolName, len);
+      label[79] = '3';                /* ANSI label flag */
+      /* Write VOL1 label */
+      stat = write(dev->fd, label, sizeof(label));
+      if (stat != sizeof(label)) {
+        berrno be;
+         Jmsg1(jcr, M_FATAL, 0,  _("Could not write ANSI VOL1 label. ERR=%s\n"),
+           be.strerror());
+        return false;
+      }
+      /* Now construct HDR1 label */
+      ser_begin(label, sizeof(label));
+      ser_bytes("HDR1", 4);
+      ser_bytes("BACULA.DATA", 11);            /* Filename field */
+      ser_begin(&label[21], sizeof(label)-21); /* fileset field */
+      ser_bytes(VolName, len);       /* write Vol Ser No. */
+      ser_begin(&label[27], sizeof(label)-27);
+      ser_bytes("00010001000100", 14);  /* File section, File seq no, Generation no */
+      now = time(NULL);
+      ser_bytes(ansi_date(now, date), 6); /* current date */
+      ser_bytes(ansi_date(now - 24 * 3600, date), 6); /* created yesterday */
+      ser_bytes(" 000000Bacula              ", 27);
+      /* Write HDR1 label */
+      stat = write(dev->fd, label, sizeof(label));
+      if (stat != sizeof(label)) {
+        berrno be;
+         Jmsg1(jcr, M_FATAL, 0, _("Could not write ANSI HDR1 label. ERR=%s\n"),
+           be.strerror());
+        return false;
+      }
+      /* Now construct HDR2 label */
+      memset(label, ' ', sizeof(label));
+      ser_begin(label, sizeof(label));
+      ser_bytes("HDR2F3200032000", 15);
+      /* Write HDR1 label */
+      stat = write(dev->fd, label, sizeof(label));
+      if (stat != sizeof(label)) {
+        berrno be;
+         Jmsg1(jcr, M_FATAL, 0, _("Could not write ANSI HDR1 label. ERR=%s\n"),
+           be.strerror());
+        return false;
+      }
+      if (weof_dev(dev, 1) < 0) {
+         Jmsg(jcr, M_FATAL, 0, _("Error writing EOF to tape. ERR=%s"), dev->errmsg);
+        return false;
+      }
+      return true;
+   default:
+      Jmsg0(jcr, M_ABORT, 0, _("write_ansi_ibm_label called for non-ANSI/IBM type\n"));
+      return false; /* should not get here */
+   }
+}
+
+/* Check a Bacula Volume name against an ANSI Volume name */
+static bool same_label_names(char *bacula_name, char *ansi_name)
+{
+   char *a = ansi_name;
+   char *b = bacula_name;
+   /* Six characters max */
+   for (int i=0; i < 6; i++) {
+      if (*a == *b) {
+        a++;
+        b++;
+        continue;
+      }
+      /* ANSI labels are blank filled, Bacula's are zero terminated */
+      if (*a == ' ' && *b == 0) {
+        return true;
+      }
+      return false;
+   }
+   /* Reached 6 characters */
+   b++;
+   if (*b == 0) {
+      return true;
+   }
+   return false;
+}
+
+
+static char *ansi_date(time_t td, char *buf)
+{
+   struct tm *tm;
+
+   if (td == 0) {
+      td = time(NULL);
+   }
+   tm = gmtime(&td);
+   bsnprintf(buf, 10, " %05d ", 1000 * (tm->tm_year + 1900 - 2000) + tm->tm_yday);
+   return buf;
+}
index cc88da62ec194fd6349361db591cbc40b9a7abd9..c1317da712b4ca0f6f8ada930c98b29be855cd25 100644 (file)
@@ -477,7 +477,7 @@ bool write_block_to_dev(DCR *dcr)
        (dev->file_size+block->binbuf) >= dev->max_file_size) {
       dev->file_size = 0;            /* reset file size */
 
-      if (dev_state(dev, ST_TAPE) && weof_dev(dev, 1) != 0) {           /* write eof */
+      if (dev->is_tape() && weof_dev(dev, 1) != 0) {           /* write eof */
          Dmsg0(190, "WEOF error in max file size.\n");
         terminate_writing_volume(dcr);
         dev->dev_errno = ENOSPC;
@@ -870,17 +870,15 @@ reread:
    Dmsg3(200, "Read device got %d bytes at %u:%u\n", stat,
       dev->file, dev->block_num);
    if (stat == 0) {            /* Got EOF ! */
-      dev->block_num = block->read_len = 0;
+      dev->block_num = 0;
+      block->read_len = 0;
       Mmsg3(dev->errmsg, _("Read zero bytes at %u:%u on device %s.\n"),
         dev->file, dev->block_num, dev->dev_name);
       if (dev->at_eof()) {      /* EOF already read? */
         dev->state |= ST_EOT;  /* yes, 2 EOFs => EOT */
-        block->read_len = 0;
         return 0;
       }
-      dev->file++;             /* increment file */
-      dev->state |= ST_EOF;    /* set EOF read */
-      block->read_len = 0;
+      dev->set_eof();
       return false;            /* return eof */
    }
    /* Continue here for successful read */
index 291c3d5ba901249444c21ddcc0b959e758c800fb..574c74091689a8432d1e0342b44b616d92bd176c 100644 (file)
@@ -367,7 +367,6 @@ static bool record_cb(DCR *dcr, DEV_RECORD *rec)
    if (rec->data_len > 0) {
       mr.VolBytes += rec->data_len + WRITE_RECHDR_LENGTH; /* Accumulate Volume bytes */
       if (showProgress) {
-        char ed1[50];
         int pct = (mr.VolBytes * 100) / currentVolumeSize;
         if (pct != last_pct) {
             fprintf(stdout, "done: %d%%\n", pct);
index 666b86b426846c09ff7d463ebb1eabe9212fee4b..6397ba74513ab152927a066b70cc2566f018df2d 100644 (file)
@@ -159,7 +159,6 @@ init_dev(DEVICE *dev, DEVRES *device)
    dev->vol_poll_interval = device->vol_poll_interval;
    dev->max_spool_size = device->max_spool_size;
    dev->drive_index = device->drive_index;
-   dev->label_type = device->label_type;
    if (tape) { /* No parts on tapes */
       dev->max_part_size = 0;
    }
@@ -328,6 +327,7 @@ open_dev(DEVICE *dev, char *VolName, int mode)
    Dmsg3(29, "open_dev: tape=%d dev_name=%s vol=%s\n", dev_is_tape(dev),
         dev->dev_name, dev->VolCatInfo.VolCatName);
    dev->state &= ~(ST_LABEL|ST_APPEND|ST_READ|ST_EOT|ST_WEOT|ST_EOF);
+   dev->label_type = B_BACULA_LABEL;
    if (dev->is_tape() || dev->is_fifo()) {
       dev->file_size = 0;
       int timeout;
@@ -921,14 +921,6 @@ int open_first_part(DEVICE *dev) {
    }
 }
 
-#ifdef debug_tracing
-#undef rewind_dev
-bool _rewind_dev(char *file, int line, DEVICE *dev)
-{
-   Dmsg2(100, "rewind_dev called from %s:%d\n", file, line);
-   return rewind_dev(dev);
-}
-#endif
 
 /* Protected version of lseek, which opens the right part if necessary */
 off_t lseek_dev(DEVICE *dev, off_t offset, int whence)
@@ -1029,6 +1021,15 @@ off_t lseek_dev(DEVICE *dev, off_t offset, int whence)
    }
 }
 
+#ifdef debug_tracing
+#undef rewind_dev
+bool _rewind_dev(char *file, int line, DEVICE *dev)
+{
+   Dmsg2(100, "rewind_dev called from %s:%d\n", file, line);
+   return rewind_dev(dev);
+}
+#endif
+
 /*
  * Rewind the device.
  *  Returns: true  on success
@@ -1088,6 +1089,19 @@ bool rewind_dev(DEVICE *dev)
    return true;
 }
 
+/*
+ * Called to indicate that we have just read an
+ *  EOF from the device.
+ */
+void DEVICE::set_eof() 
+{ 
+   state |= ST_EOF;
+   file++;
+   file_addr = 0;
+   file_size = 0;
+   block_num = 0;
+}
+
 /*
  * Position device to end of medium (end of data)
  *  Returns: 1 on succes
@@ -1102,7 +1116,7 @@ eod_dev(DEVICE *dev)
    off_t pos;
 
    Dmsg0(29, "eod_dev\n");
-   if (dev->state & ST_EOT) {
+   if (dev->at_eot()) {
       return 1;
    }
    dev->state &= ~(ST_EOF);  /* remove EOF flags */
@@ -1112,7 +1126,7 @@ eod_dev(DEVICE *dev)
    if (dev->state & (ST_FIFO | ST_PROG)) {
       return 1;
    }
-   if (!(dev->is_tape())) {
+   if (!dev->is_tape()) {
       pos = lseek_dev(dev, (off_t)0, SEEK_END);
 //    Dmsg1(100, "====== Seek to %lld\n", pos);
       if (pos >= 0) {
@@ -1173,6 +1187,7 @@ eod_dev(DEVICE *dev)
         return 0;
       }
       Dmsg2(100, "EOD file=%d block=%d\n", mt_stat.mt_fileno, mt_stat.mt_blkno);
+      dev->set_eof();
       dev->file = mt_stat.mt_fileno;
 
    /*
@@ -1189,7 +1204,7 @@ eod_dev(DEVICE *dev)
        * Move file by file to the end of the tape
        */
       int file_num;
-      for (file_num=dev->file; !(dev->state & ST_EOT); file_num++) {
+      for (file_num=dev->file; !dev->at_eot(); file_num++) {
          Dmsg0(200, "eod_dev: doing fsf 1\n");
         if (!fsf_dev(dev, 1)) {
             Dmsg0(200, "fsf_dev error.\n");
@@ -1205,6 +1220,7 @@ eod_dev(DEVICE *dev)
            if (dev_cap(dev, CAP_MTIOCGET) && ioctl(dev->fd, MTIOCGET, (char *)&mt_stat) == 0 &&
                      mt_stat.mt_fileno >= 0) {
                Dmsg2(100, "Adjust file from %d to %d\n", dev->file , mt_stat.mt_fileno);
+              dev->set_eof();
               dev->file = mt_stat.mt_fileno;
            }
            stat = 0;
@@ -1521,10 +1537,8 @@ fsf_dev(DEVICE *dev, int num)
         return false;
       }
       Dmsg2(200, "fsf file=%d block=%d\n", mt_stat.mt_fileno, mt_stat.mt_blkno);
+      dev->set_eof();
       dev->file = mt_stat.mt_fileno;
-      dev->state |= ST_EOF;    /* just read EOF */
-      dev->file_addr = 0;
-      dev->file_size = 0;
       return true;
 
    /*
@@ -1572,10 +1586,7 @@ fsf_dev(DEVICE *dev, int num)
                Dmsg0(100, "Set ST_EOT\n");
               break;
            } else {
-              dev->state |= ST_EOF;
-              dev->file++;
-              dev->file_addr = 0;
-              dev->file_size = 0;
+              dev->set_eof();
               continue;
            }
         } else {                        /* Got data */
@@ -1594,10 +1605,7 @@ fsf_dev(DEVICE *dev, int num)
             Dmsg0(100, "Got < 0 for MTFSF\n");
             Dmsg1(100, "%s", dev->errmsg);
         } else {
-           dev->state |= ST_EOF;     /* just read EOF */
-           dev->file++;
-           dev->file_addr = 0;
-           dev->file_size = 0;
+           dev->set_eof();
         }
       }
       free_memory(rbuf);
@@ -1717,11 +1725,7 @@ fsr_dev(DEVICE *dev, int num)
         if (dev->state & ST_EOF) {
            dev->state |= ST_EOT;
         } else {
-           dev->state |= ST_EOF;           /* assume EOF */
-           dev->file++;
-           dev->block_num = 0;
-           dev->file_addr = 0;
-           dev->file_size = 0;
+           dev->set_eof();
         }
       }
       Mmsg2(dev->errmsg, _("ioctl MTFSR error on %s. ERR=%s.\n"),
@@ -1861,6 +1865,12 @@ weof_dev(DEVICE *dev, int num)
    if (!dev->is_tape()) {
       return 0;
    }
+   if (!dev->can_append()) {
+      Mmsg0(dev->errmsg, _("Attempt to WEOF on non-appendable Volume\n"));
+      Emsg0(M_FATAL, 0, dev->errmsg);
+      return -1;
+   }
+      
    dev->state &= ~(ST_EOT | ST_EOF);  /* remove EOF/EOT flags */
    mt_com.mt_op = MTWEOF;
    mt_com.mt_count = num;
@@ -2048,6 +2058,7 @@ static void do_close(DEVICE *dev)
    /* Clean up device packet so it can be reused */
    dev->fd = -1;
    dev->state &= ~(ST_OPENED|ST_LABEL|ST_READ|ST_APPEND|ST_EOT|ST_WEOT|ST_EOF);
+   dev->label_type = B_BACULA_LABEL;
    dev->file = dev->block_num = 0;
    dev->file_size = 0;
    dev->file_addr = 0;
index d63bf4cde0eb4f225b2bd91e34a33089f9ed8087..abf48beb3f6d285e68217fac91d77e567046ddc9 100644 (file)
@@ -248,6 +248,7 @@ public:
    int is_dvd() const;
    int is_open() const;
    int is_labeled() const;
+   int is_busy() const;               /* either reading or writing */
    int at_eof() const;
    int at_eom() const;
    int at_eot() const;
@@ -255,6 +256,7 @@ public:
    int can_read() const;
    const char *strerror() const;
    const char *archive_name() const;
+   void set_eof();
 };
 
 /* Note, these return int not bool! */
@@ -264,6 +266,7 @@ inline int DEVICE::is_fifo() const { return state & ST_FIFO; }
 inline int DEVICE::is_dvd()  const { return state & ST_DVD; }
 inline int DEVICE::is_open() const { return state & ST_OPENED; }
 inline int DEVICE::is_labeled() const { return state & ST_LABEL; }
+inline int DEVICE::is_busy() const { return state & ST_READ || num_writers; }
 inline int DEVICE::at_eof() const { return state & ST_EOF; }
 inline int DEVICE::at_eom() const { return state & ST_EOT; }
 inline int DEVICE::at_eot() const { return state & ST_EOT; }
@@ -272,9 +275,6 @@ inline int DEVICE::can_read() const { return state & ST_READ; }
 inline const char *DEVICE::strerror() const { return errmsg; }
 inline const char *DEVICE::archive_name() const { return dev_name; }
 
-
-
 /*
  * Device Context (or Control) Record.
  *  There is one of these records for each Job that is using
index c4a97757251f903215fba78e9f462bea17663643..4026e1c737441c2438ffe5e84e9b2938586f39b8 100644 (file)
@@ -82,6 +82,7 @@ static void label_volume_if_ok(JCR *jcr, DEVICE *dev, char *oldname,
                               char *newname, char *poolname,
                               int Slot, int relabel);
 static bool try_autoload_device(JCR *jcr, int slot, const char *VolName);
+static void send_dir_busy_message(BSOCK *dir, DEVICE *dev);
 
 struct s_cmds {
    const char *cmd;
@@ -338,14 +339,8 @@ static bool do_label(JCR *jcr, int relabel)
                     dev->dev_blocked == BST_WAITING_FOR_SYSOP ||
                     dev->dev_blocked == BST_UNMOUNTED_WAITING_FOR_SYSOP)) {
            label_volume_if_ok(jcr, dev, oldname, newname, poolname, slot, relabel);
-        } else if (dev_state(dev, ST_READ) || dev->num_writers) {
-           if (dev_state(dev, ST_READ)) {
-                bnet_fsend(dir, _("3911 Device %s is busy with 1 reader.\n"),
-                  dev_name(dev));
-           } else {
-                bnet_fsend(dir, _("3912 Device %s is busy with %d writer(s).\n"),
-                  dev_name(dev), dev->num_writers);
-           }
+        } else if (dev->is_busy()) {
+           send_dir_busy_message(dir, dev);
         } else {                     /* device not being used */
            label_volume_if_ok(jcr, dev, oldname, newname, poolname, slot, relabel);
         }
@@ -402,13 +397,17 @@ static void label_volume_if_ok(JCR *jcr, DEVICE *dev, char *oldname,
    case VOL_OK:
       if (!relabel) {
         bnet_fsend(dir, _(
-            "3911 Cannot label Volume because it is already labeled: \"%s\"\n"),
+            "3920 Cannot label Volume because it is already labeled: \"%s\"\n"),
             dev->VolHdr.VolName);
         break;
       }
       /* Relabel request. If oldname matches, continue */
       if (strcmp(oldname, dev->VolHdr.VolName) != 0) {
-         bnet_fsend(dir, _("Wrong volume mounted.\n"));
+         bnet_fsend(dir, _("3921 Wrong volume mounted.\n"));
+        break;
+      }
+      if (dev->label_type != B_BACULA_LABEL) {
+         bnet_fsend(dir, _("3922 Cannot relabel an ANSI/IBM labeled Volume.\n"));
         break;
       }
       /* Fall through wanted! */
@@ -643,16 +642,8 @@ static bool unmount_cmd(JCR *jcr)
         } else if (dev->dev_blocked == BST_WRITING_LABEL) {
             bnet_fsend(dir, _("3903 Device \"%s\" is being labeled.\n"), dev_name(dev));
 
-        } else if (dev_state(dev, ST_READ) || dev->num_writers) {
-           if (dev_state(dev, ST_READ)) {
-                Dmsg0(90, "Device in read mode\n");
-                bnet_fsend(dir, _("3904 Device \"%s\" is busy reading.\n"), dev_name(dev));
-           } else {
-                Dmsg1(90, "Device busy with %d writers\n", dev->num_writers);
-                bnet_fsend(dir, _("3905 Device %s is busy with %d writer(s).\n"),
-                  dev_name(dev), dev->num_writers);
-           }
-
+        } else if (dev->is_busy()) {
+           send_dir_busy_message(dir, dev);
         } else {                     /* device not being used */
             Dmsg0(90, "Device not in use, unmounting\n");
            /* On FreeBSD, I am having ASSERT() failures in block_device()
@@ -714,16 +705,8 @@ static bool release_cmd(JCR *jcr)
         } else if (dev->dev_blocked == BST_WRITING_LABEL) {
             bnet_fsend(dir, _("3914 Device %s is being labeled.\n"), dev_name(dev));
 
-        } else if (dev_state(dev, ST_READ) || dev->num_writers) {
-           if (dev_state(dev, ST_READ)) {
-                Dmsg0(90, "Device in read mode\n");
-                bnet_fsend(dir, _("3915 Device %s is busy with 1 reader.\n"), dev_name(dev));
-           } else {
-                Dmsg1(90, "Device busy with %d writers\n", dev->num_writers);
-                bnet_fsend(dir, _("3916 Device %s is busy with %d writer(s).\n"),
-                  dev_name(dev), dev->num_writers);
-           }
-
+        } else if (dev->is_busy()) {
+           send_dir_busy_message(dir, dev);
         } else {                     /* device not being used */
             Dmsg0(90, "Device not in use, unmounting\n");
            release_volume(jcr->dcr);
@@ -769,13 +752,8 @@ static bool autochanger_cmd(JCR *jcr)
                     dev->dev_blocked == BST_WAITING_FOR_SYSOP ||
                     dev->dev_blocked == BST_UNMOUNTED_WAITING_FOR_SYSOP)) {
            autochanger_list(dcr, dir);
-        } else if (dev_state(dev, ST_READ) || dev->num_writers) {
-           if (dev_state(dev, ST_READ)) {
-                bnet_fsend(dir, _("3901 Device %s is busy with 1 reader.\n"), dev_name(dev));
-           } else {
-                bnet_fsend(dir, _("3902 Device %s is busy with %d writer(s).\n"),
-                  dev_name(dev), dev->num_writers);
-           }
+        } else if (dev->is_busy()) {
+           send_dir_busy_message(dir, dev);
         } else {                     /* device not being used */
            autochanger_list(dcr, dir);
         }
@@ -815,14 +793,8 @@ static bool readlabel_cmd(JCR *jcr)
                     dev->dev_blocked == BST_WAITING_FOR_SYSOP ||
                     dev->dev_blocked == BST_UNMOUNTED_WAITING_FOR_SYSOP)) {
            read_volume_label(jcr, dev, Slot);
-        } else if (dev_state(dev, ST_READ) || dev->num_writers) {
-           if (dev_state(dev, ST_READ)) {
-                bnet_fsend(dir, _("3911 Device %s is busy with 1 reader.\n"),
-                           dev_name(dev));
-           } else {
-                bnet_fsend(dir, _("3912 Device %s is busy with %d writer(s).\n"),
-                  dev_name(dev), dev->num_writers);
-           }
+        } else if (dev->is_busy()) {
+           send_dir_busy_message(dir, dev);
         } else {                     /* device not being used */
            read_volume_label(jcr, dev, Slot);
         }
@@ -897,3 +869,14 @@ static bool try_autoload_device(JCR *jcr, int slot, const char *VolName)
    }
    return true;
 }
+
+static void send_dir_busy_message(BSOCK *dir, DEVICE *dev)
+{
+   if (dev->can_read()) {
+       bnet_fsend(dir, _("3911 Device \"%s\" is busy reading.\n"),
+                  dev_name(dev));
+   } else {
+       bnet_fsend(dir, _("3912 Device \"%s\" is busy with %d writer(s).\n"),
+         dev_name(dev), dev->num_writers);
+   }
+}
index cfda892467d4d119f9739a26f714b243aa3f00e1..1ae87ff3aa6068cc2808bae05f8ce00c529df6f9 100644 (file)
@@ -32,8 +32,6 @@
 
 /* Forward referenced functions */
 static void create_volume_label_record(DCR *dcr, DEV_RECORD *rec);
-static int read_ansi_ibm_label(DCR *dcr);
-static char *ansi_date(time_t td, char *buf);
 
 extern char my_name[];
 extern int debug_level;
@@ -49,14 +47,17 @@ extern int debug_level;
  *
  *  Returns VOL_  code as defined in record.h
  *    VOL_NOT_READ
- *    VOL_OK
- *    VOL_NO_LABEL
- *    VOL_IO_ERROR
- *    VOL_NAME_ERROR
- *    VOL_CREATE_ERROR
- *    VOL_VERSION_ERROR
- *    VOL_LABEL_ERROR
- *    VOL_NO_MEDIA
+ *    VOL_OK                         good label found
+ *    VOL_NO_LABEL                   volume not labeled
+ *    VOL_IO_ERROR                   I/O error reading tape
+ *    VOL_NAME_ERROR                 label has wrong name
+ *    VOL_CREATE_ERROR               Error creating label
+ *    VOL_VERSION_ERROR              label has wrong version
+ *    VOL_LABEL_ERROR                bad label type
+ *    VOL_NO_MEDIA                   no media in drive
+ *
+ *  The dcr block is emptied on return, and the Volume is
+ *    rewound.
  */
 int read_dev_volume_label(DCR *dcr)
 {
@@ -67,7 +68,7 @@ int read_dev_volume_label(DCR *dcr)
    bool ok = false;
    DEV_BLOCK *block = dcr->block;
    int stat;
-   bool want_ansi_ibm_label;
+   bool want_ansi_label;
 
    Dmsg3(100, "Enter read_volume_label device=%s vol=%s dev_Vol=%s\n",
       dev_name(dev), VolName, dev->VolHdr.VolName);
@@ -94,6 +95,7 @@ int read_dev_volume_label(DCR *dcr)
    }
 
    dev->state &= ~(ST_LABEL|ST_APPEND|ST_READ);  /* set no label, no append */
+   dev->label_type = B_BACULA_LABEL;
 
    if (!rewind_dev(dev)) {
       Mmsg(jcr->errmsg, _("Couldn't rewind device %s ERR=%s\n"), dev_name(dev),
@@ -105,12 +107,22 @@ int read_dev_volume_label(DCR *dcr)
 
   /* Read ANSI/IBM label if so requested */
   
-  want_ansi_ibm_label = dcr->VolCatInfo.LabelType != B_BACULA_LABEL ||
-                       dcr->device->label_type != B_BACULA_LABEL;
-  if (want_ansi_ibm_label || dev_cap(dev, CAP_CHECKLABELS)) {
+  want_ansi_label = dcr->VolCatInfo.LabelType != B_BACULA_LABEL ||
+                   dcr->device->label_type != B_BACULA_LABEL;
+  if (want_ansi_label || dev_cap(dev, CAP_CHECKLABELS)) {
       stat = read_ansi_ibm_label(dcr);           
       /* If we want a label and didn't find it, return error */
-      if (want_ansi_ibm_label && stat != VOL_OK) {
+      if (want_ansi_label && stat != VOL_OK) {
+        empty_block(block);
+        rewind_dev(dev);
+        return stat;
+      }
+      if (stat == VOL_NAME_ERROR || stat == VOL_LABEL_ERROR) {
+         Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"),
+             dev_name(dev), VolName, dev->VolHdr.VolName);
+        if (!dev->poll && jcr->label_errors++ > 100) {
+            Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
+        }
         empty_block(block);
         rewind_dev(dev);
         return stat;
@@ -123,6 +135,7 @@ int read_dev_volume_label(DCR *dcr)
    /* Read the Bacula Volume label block */
    record = new_record();
    empty_block(block);
+
    Dmsg0(90, "Big if statement in read_volume_label\n");
    if (!read_block_from_dev(dcr, NO_BLOCK_NUMBER_CHECK)) {
       Mmsg(jcr->errmsg, _("Requested Volume \"%s\" on %s is not a Bacula "
@@ -143,22 +156,26 @@ int read_dev_volume_label(DCR *dcr)
    } else {
       ok = true;
    }
+   free_record(record);              /* finished reading Volume record */
+   empty_block(block);               /* done with block */
+
    if (!ok) {
-      free_record(record);
       if (forge_on || jcr->ignore_label_errors) {
         dev->state |= ST_LABEL;      /* set has Bacula label */
          Jmsg(jcr, M_ERROR, 0, "%s", jcr->errmsg);
         return VOL_OK;
       }
-      empty_block(block);
       rewind_dev(dev);
       return VOL_NO_LABEL;
    }
 
-   free_record(record);
+   /* At this point, we have read the first Bacula block, and
+    * then read the Bacula Volume label. Now we need to
+    * make sure we have the right Volume.
+    */
+
    /* If we are a streaming device, we only get one chance to read */
    if (!dev_cap(dev, CAP_STREAM)) {
-      empty_block(block);
       rewind_dev(dev);
    }
 
@@ -178,6 +195,9 @@ int read_dev_volume_label(DCR *dcr)
       Mmsg(jcr->errmsg, _("Volume on %s has bad Bacula label type: %x\n"),
          dev_name(dev), dev->VolHdr.LabelType);
       Dmsg1(30, "%s", jcr->errmsg);
+      if (!dev->poll && jcr->label_errors++ > 100) {
+         Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg);
+      }
       return VOL_LABEL_ERROR;
    }
 
@@ -207,7 +227,7 @@ int read_dev_volume_label(DCR *dcr)
    return VOL_OK;
 }
 
-/* Read the volume label by guessing the volume name. (only for mounted devices)
+/* Read the volume label by guessing the volume name. (only for DVD devices)
  * write is true if we are reading the label before writing to the device.
  *
  * If the volume name cannot be guessed :
@@ -235,14 +255,14 @@ int read_dev_volume_label_guess(DCR *dcr, bool write)
    /* For mounted devices, tries to guess the volume name, and read the label if possible.
    */
    if (open_guess_name_dev(dev) < 0) {    
-      if ((!write) || (dcr->VolCatInfo.VolCatParts > 0)) {
+      if (!write || dcr->VolCatInfo.VolCatParts > 0) {
          Mmsg2(jcr->errmsg, _("Requested Volume \"%s\" on %s is not a Bacula labeled Volume."),
               dev_name(dev), dcr->VolumeName);
          Dmsg0(100, "Leave read_dev_volume_label_guess VOL_IO_ERROR (!open_guess_name_dev)\n");
         return VOL_NO_LABEL;
       }
       
-      if (write && (dev->free_space_errno < 0)) {
+      if (write && dev->free_space_errno < 0) {
          Dmsg0(100, "Leave read_dev_volume_label_guess !free_space VOL_NO_MEDIA\n");
          Mmsg2(jcr->errmsg, _("free_space error on %s. The current medium is probably not writable. ERR=%s.\n"),
               dev->dev_name, dev->errmsg);
@@ -261,7 +281,7 @@ int read_dev_volume_label_guess(DCR *dcr, bool write)
       Dmsg0(100, "Leave read_dev_volume_label_guess !open_guess_name_dev\n");
       return read_dev_volume_label(dcr);
    } else {
-      if (write && (dcr->dev->free_space_errno < 0)) {
+      if (write && dcr->dev->free_space_errno < 0) {
          Dmsg0(100, "Leave read_dev_volume_label_guess !free_space VOL_NO_MEDIA\n");
          Mmsg2(jcr->errmsg, _("free_space error on %s. The current medium is probably not writable. ERR=%s.\n"),
               dev->dev_name, dev->errmsg);
@@ -270,7 +290,7 @@ int read_dev_volume_label_guess(DCR *dcr, bool write)
       
       vol_label_status = read_dev_volume_label(dcr);
 
-      if ((!write) || (dcr->VolCatInfo.VolCatParts > 0)) {
+      if (!write || dcr->VolCatInfo.VolCatParts > 0) {
          Dmsg0(100, "Leave read_dev_volume_label_guess (open_guess_name_dev && (!write || dcr->VolCatInfo.VolCatParts > 0))\n");
         return vol_label_status;
       }
@@ -290,111 +310,224 @@ int read_dev_volume_label_guess(DCR *dcr, bool write)
          Dmsg0(100, "Leave read_dev_volume_label_guess (open_guess_name_dev && !VOL_NAME_ERROR)\n");
         dev->state &= ~ST_LABEL;
         return read_dev_volume_label(dcr);
-      }
-      else {
+      } else {
          Dmsg0(100, "Leave read_dev_volume_label_guess (open_guess_name_dev && VOL_NAME_ERROR)\n");
         return vol_label_status;
       }
    }
 }
 
-/*  unser_volume_label
+/*
+ * Put a volume label into the block
  *
- * Unserialize the Bacula Volume label into the device Volume_Label
- * structure.
+ *  Returns: false on failure
+ *          true  on success
+ */
+bool write_volume_label_to_block(DCR *dcr)
+{
+   DEV_RECORD rec;
+   DEVICE *dev = dcr->dev;
+   JCR *jcr = dcr->jcr;
+   DEV_BLOCK *block = dcr->block;
+
+   Dmsg0(20, "write Label in write_volume_label_to_block()\n");
+   memset(&rec, 0, sizeof(rec));
+   rec.data = get_memory(SER_LENGTH_Volume_Label);
+   empty_block(block);               /* Volume label always at beginning */
+
+   create_volume_label_record(dcr, &rec);
+
+   block->BlockNumber = 0;
+   if (!write_record_to_block(block, &rec)) {
+      free_pool_memory(rec.data);
+      Jmsg1(jcr, M_FATAL, 0, _("Cannot write Volume label to block for device %s\n"),
+        dev_name(dev));
+      return false;
+   } else {
+      Dmsg1(90, "Wrote label of %d bytes to block\n", rec.data_len);
+   }
+   free_pool_memory(rec.data);
+   return true;
+}
+
+
+/*
+ * Write a Volume Label
+ *  !!! Note, this is ONLY used for writing
+ *           a fresh volume label.  Any data
+ *           after the label will be destroyed,
+ *           in fact, we write the label 5 times !!!!
  *
- * Assumes that the record is already read.
+ *  This routine expects that open_device() was previously called.
  *
- * Returns: false on error
- *         true  on success
-*/
-
-bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec)
+ *  This routine should be used only when labeling a blank tape.
+ */
+bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName, const char *PoolName)
 {
-   ser_declare;
+   DEVICE *dev = dcr->dev;
 
-   if (rec->FileIndex != VOL_LABEL && rec->FileIndex != PRE_LABEL) {
-      Mmsg3(dev->errmsg, _("Expecting Volume Label, got FI=%s Stream=%s len=%d\n"),
-             FI_to_ascii(rec->FileIndex),
-             stream_to_ascii(rec->Stream, rec->FileIndex),
-             rec->data_len);
+
+   Dmsg0(99, "write_volume_label()\n");
+   empty_block(dcr->block);
+
+   Dmsg1(000, "Label type=%d\n", dev->label_type);
+   if (!rewind_dev(dev)) {
+      memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
+      Dmsg2(30, "Bad status on %s from rewind. ERR=%s\n", dev_name(dev), strerror_dev(dev));
       if (!forge_on) {
-        return false;
+        goto bail_out;
       }
    }
 
-   dev->VolHdr.LabelType = rec->FileIndex;
-   dev->VolHdr.LabelSize = rec->data_len;
+   /* Create PRE_LABEL */
+   create_volume_label(dev, VolName, PoolName);
 
+   /*
+    * If we have already detected an ANSI label, re-read it
+    *  to skip past it. Otherwise, we write a new one if 
+    *  so requested.  
+    */
+   if (dev->label_type != B_BACULA_LABEL) {
+      if (read_ansi_ibm_label(dcr) != VOL_OK) {
+        rewind_dev(dev);
+        goto bail_out;
+      }
+   } else if (!write_ansi_ibm_label(dcr, VolName)) {
+      goto bail_out;
+   }
 
-   /* Unserialize the record into the Volume Header */
-   rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
-   ser_begin(rec->data, SER_LENGTH_Volume_Label);
-   unser_string(dev->VolHdr.Id);
-   unser_uint32(dev->VolHdr.VerNum);
+   create_volume_label_record(dcr, dcr->rec);
+   dcr->rec->Stream = 0;
 
-   if (dev->VolHdr.VerNum >= 11) {
-      unser_btime(dev->VolHdr.label_btime);
-      unser_btime(dev->VolHdr.write_btime);
-   } else { /* old way */
-      unser_float64(dev->VolHdr.label_date);
-      unser_float64(dev->VolHdr.label_time);
+   /* Temporarily mark in append state to enable writing */
+   dev->state |= ST_APPEND;
+   if (!write_record_to_block(dcr->block, dcr->rec)) {
+      Dmsg2(30, "Bad Label write on %s. ERR=%s\n", dev_name(dev), strerror_dev(dev));
+      goto bail_out;
+   } else {
+      Dmsg2(30, "Wrote label of %d bytes to %s\n", dcr->rec->data_len, dev_name(dev));
    }
-   unser_float64(dev->VolHdr.write_date);    /* Unused with VerNum >= 11 */
-   unser_float64(dev->VolHdr.write_time);    /* Unused with VerNum >= 11 */
 
-   unser_string(dev->VolHdr.VolName);
-   unser_string(dev->VolHdr.PrevVolName);
-   unser_string(dev->VolHdr.PoolName);
-   unser_string(dev->VolHdr.PoolType);
-   unser_string(dev->VolHdr.MediaType);
+   Dmsg0(99, "Call write_block_to_dev()\n");
+   if (!write_block_to_dev(dcr)) {
+      Dmsg2(30, "Bad Label write on %s. ERR=%s\n", dev_name(dev), strerror_dev(dev));
+      goto bail_out;
+   }
+   Dmsg0(99, " Wrote block to device\n");
 
-   unser_string(dev->VolHdr.HostName);
-   unser_string(dev->VolHdr.LabelProg);
-   unser_string(dev->VolHdr.ProgVersion);
-   unser_string(dev->VolHdr.ProgDate);
+   if (weof_dev(dev, 1) == 0) {
+      dev->state |= ST_LABEL;
+   }
 
-   ser_end(rec->data, SER_LENGTH_Volume_Label);
-   Dmsg0(90, "ser_read_vol\n");
-   if (debug_level >= 90) {
+   if (debug_level >= 20)  {
       dump_volume_label(dev);
    }
+   dev->state &= ~ST_APPEND;         /* remove append since this is PRE_LABEL */
    return true;
+
+bail_out:
+   memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
+   dev->state &= ~ST_APPEND;         /* remove append since this is PRE_LABEL */
+   return false;
 }
 
 /*
- * Put a volume label into the block
- *
- *  Returns: false on failure
- *          true  on success
+ * Write a volume label. This is ONLY called if we have a valid Bacula
+ *   label of type PRE_LABEL;
+ *  Returns: true if OK
+ *          false if unable to write it
  */
-bool write_volume_label_to_block(DCR *dcr)
+bool rewrite_volume_label(DCR *dcr, bool recycle)
 {
-   DEV_RECORD rec;
    DEVICE *dev = dcr->dev;
    JCR *jcr = dcr->jcr;
-   DEV_BLOCK *block = dcr->block;
 
-   Dmsg0(20, "write Label in write_volume_label_to_block()\n");
-   memset(&rec, 0, sizeof(rec));
-   rec.data = get_memory(SER_LENGTH_Volume_Label);
-   empty_block(block);               /* Volume label always at beginning */
+   Dmsg1(190, "set append found freshly labeled volume. dev=%x\n", dev);
+   dev->VolHdr.LabelType = VOL_LABEL; /* set Volume label */
+   dev->state |= ST_APPEND;
+   if (!write_volume_label_to_block(dcr)) {
+      Dmsg0(200, "Error from write volume label.\n");
+      return false;
+   }
+   /*
+    * If we are not dealing with a streaming device,
+    *  write the block now to ensure we have write permission.
+    *  It is better to find out now rather than later.
+    * We do not write the block now if this is an ANSI label. This
+    *  avoids re-writing the ANSI label, which we do not want to do.
+    */
+   if (!dev_cap(dev, CAP_STREAM)) {
+      if (!rewind_dev(dev)) {
+         Jmsg2(jcr, M_WARNING, 0, _("Rewind error on device \"%s\". ERR=%s\n"),
+              dev_name(dev), strerror_dev(dev));
+      }
+      if (recycle) {
+        if (!truncate_dev(dev)) {
+            Jmsg2(jcr, M_WARNING, 0, _("Truncate error on device \"%s\". ERR=%s\n"),
+                 dev_name(dev), strerror_dev(dev));
+        }
+      }
 
-   create_volume_label_record(dcr, &rec);
+      /*
+       * If we have already detected an ANSI label, re-read it
+       *   to skip past it. Otherwise, we write a new one if 
+       *   so requested.  
+       */
+      if (dev->label_type != B_BACULA_LABEL) {
+        if (read_ansi_ibm_label(dcr) != VOL_OK) {
+           rewind_dev(dev);
+           return false;
+        }
+      } else if (!write_ansi_ibm_label(dcr, dev->VolHdr.VolName)) {
+        return false;
+      }
 
-   block->BlockNumber = 0;
-   if (!write_record_to_block(block, &rec)) {
-      free_pool_memory(rec.data);
-      Jmsg1(jcr, M_FATAL, 0, _("Cannot write Volume label to block for device %s\n"),
-        dev_name(dev));
+      /* Attempt write to check write permission */
+      Dmsg0(200, "Attempt to write to device.\n");
+      if (!write_block_to_dev(dcr)) {
+         Jmsg2(jcr, M_ERROR, 0, _("Unable to write device \"%s\". ERR=%s\n"),
+           dev_name(dev), strerror_dev(dev));
+         Dmsg0(200, "===ERROR write block to dev\n");
+        return false;
+      }
+   }
+   /* Set or reset Volume statistics */
+   dev->VolCatInfo.VolCatJobs = 0;
+   dev->VolCatInfo.VolCatFiles = 0;
+   dev->VolCatInfo.VolCatBytes = 1;
+   dev->VolCatInfo.VolCatErrors = 0;
+   dev->VolCatInfo.VolCatBlocks = 0;
+   dev->VolCatInfo.VolCatRBytes = 0;
+   if (recycle) {
+      dev->VolCatInfo.VolCatMounts++;
+      dev->VolCatInfo.VolCatRecycles++;
+   } else {
+      dev->VolCatInfo.VolCatMounts = 1;
+      dev->VolCatInfo.VolCatRecycles = 0;
+      dev->VolCatInfo.VolCatWrites = 1;
+      dev->VolCatInfo.VolCatReads = 1;
+   }
+   Dmsg0(100, "dir_update_vol_info. Set Append\n");
+   bstrncpy(dev->VolCatInfo.VolCatStatus, "Append", sizeof(dev->VolCatInfo.VolCatStatus));
+   if (!dir_update_volume_info(dcr, true)) {  /* indicate doing relabel */
       return false;
+   }
+   if (recycle) {
+      Jmsg(jcr, M_INFO, 0, _("Recycled volume \"%s\" on device \"%s\", all previous data lost.\n"),
+        dcr->VolumeName, dev_name(dev));
    } else {
-      Dmsg1(90, "Wrote label of %d bytes to block\n", rec.data_len);
+      Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume \"%s\" on device \"%s\"\n"),
+        dcr->VolumeName, dev_name(dev));
    }
-   free_pool_memory(rec.data);
+   /*
+    * End writing real Volume label (from pre-labeled tape), or recycling
+    *  the volume.
+    */
+   Dmsg0(200, "OK from rewite vol label.\n");
    return true;
 }
 
+
 /*
  *  create_volume_label_record
  *   Serialize label (from dev->VolHdr structure) into device record.
@@ -493,78 +626,6 @@ void create_volume_label(DEVICE *dev, const char *VolName, const char *PoolName)
    }
 }
 
-/*
- * Write a Volume Label
- *  !!! Note, this is ONLY used for writing
- *           a fresh volume label.  Any data
- *           after the label will be destroyed,
- *           in fact, we write the label 5 times !!!!
- *
- *  This routine expects that open_device() was previously called.
- *
- *  This routine should be used only when labeling a blank tape.
- */
-bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName, const char *PoolName)
-{
-   bool ok = false;
-   DEVICE *dev = dcr->dev;
-
-
-   Dmsg0(99, "write_volume_label()\n");
-   empty_block(dcr->block);
-   /* Create PRE_LABEL */
-   create_volume_label(dev, VolName, PoolName);
-
-   if (!rewind_dev(dev)) {
-      memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
-      Dmsg2(30, "Bad status on %s from rewind. ERR=%s\n", dev_name(dev), strerror_dev(dev));
-      if (!forge_on) {
-        return false;
-      }
-   }
-
-   /* Write ANSI/IBM label if so requested */
-   if (!write_ansi_ibm_label(dcr, VolName)) {
-      memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
-      goto bail_out;
-   }
-
-   create_volume_label_record(dcr, dcr->rec);
-   dcr->rec->Stream = 0;
-
-   /* Temporarily mark in append state to enable writing */
-   dev->state |= ST_APPEND;
-   if (!write_record_to_block(dcr->block, dcr->rec)) {
-      Dmsg2(30, "Bad Label write on %s. ERR=%s\n", dev_name(dev), strerror_dev(dev));
-      memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
-      goto bail_out;
-   } else {
-      Dmsg2(30, "Wrote label of %d bytes to %s\n", dcr->rec->data_len, dev_name(dev));
-   }
-
-   Dmsg0(99, "Call write_block_to_dev()\n");
-   if (!write_block_to_dev(dcr)) {
-      memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
-      Dmsg2(30, "Bad Label write on %s. ERR=%s\n", dev_name(dev), strerror_dev(dev));
-      goto bail_out;
-   }
-   Dmsg0(99, " Wrote block to device\n");
-
-   if (weof_dev(dev, 1) == 0) {
-      dev->state |= ST_LABEL;
-      ok = true;
-   }
-
-   if (debug_level >= 20)  {
-      dump_volume_label(dev);
-   }
-
-bail_out:
-   dev->state &= ~ST_APPEND;         /* remove append since this is PRE_LABEL */
-   return ok;
-}
-
-
 /*
  * Create session label
  *  The pool memory must be released by the calling program
@@ -694,6 +755,118 @@ bool write_session_label(DCR *dcr, int label)
    return true;
 }
 
+/*  unser_volume_label
+ *
+ * Unserialize the Bacula Volume label into the device Volume_Label
+ * structure.
+ *
+ * Assumes that the record is already read.
+ *
+ * Returns: false on error
+ *         true  on success
+*/
+
+bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec)
+{
+   ser_declare;
+
+   if (rec->FileIndex != VOL_LABEL && rec->FileIndex != PRE_LABEL) {
+      Mmsg3(dev->errmsg, _("Expecting Volume Label, got FI=%s Stream=%s len=%d\n"),
+             FI_to_ascii(rec->FileIndex),
+             stream_to_ascii(rec->Stream, rec->FileIndex),
+             rec->data_len);
+      if (!forge_on) {
+        return false;
+      }
+   }
+
+   dev->VolHdr.LabelType = rec->FileIndex;
+   dev->VolHdr.LabelSize = rec->data_len;
+
+
+   /* Unserialize the record into the Volume Header */
+   rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
+   ser_begin(rec->data, SER_LENGTH_Volume_Label);
+   unser_string(dev->VolHdr.Id);
+   unser_uint32(dev->VolHdr.VerNum);
+
+   if (dev->VolHdr.VerNum >= 11) {
+      unser_btime(dev->VolHdr.label_btime);
+      unser_btime(dev->VolHdr.write_btime);
+   } else { /* old way */
+      unser_float64(dev->VolHdr.label_date);
+      unser_float64(dev->VolHdr.label_time);
+   }
+   unser_float64(dev->VolHdr.write_date);    /* Unused with VerNum >= 11 */
+   unser_float64(dev->VolHdr.write_time);    /* Unused with VerNum >= 11 */
+
+   unser_string(dev->VolHdr.VolName);
+   unser_string(dev->VolHdr.PrevVolName);
+   unser_string(dev->VolHdr.PoolName);
+   unser_string(dev->VolHdr.PoolType);
+   unser_string(dev->VolHdr.MediaType);
+
+   unser_string(dev->VolHdr.HostName);
+   unser_string(dev->VolHdr.LabelProg);
+   unser_string(dev->VolHdr.ProgVersion);
+   unser_string(dev->VolHdr.ProgDate);
+
+   ser_end(rec->data, SER_LENGTH_Volume_Label);
+   Dmsg0(90, "ser_read_vol\n");
+   if (debug_level >= 90) {
+      dump_volume_label(dev);
+   }
+   return true;
+}
+
+
+bool unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec)
+{
+   ser_declare;
+
+   rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
+   unser_begin(rec->data, SER_LENGTH_Session_Label);
+   unser_string(label->Id);
+   unser_uint32(label->VerNum);
+   unser_uint32(label->JobId);
+   if (label->VerNum >= 11) {
+      unser_btime(label->write_btime);
+   } else {
+      unser_float64(label->write_date);
+   }
+   unser_float64(label->write_time);
+   unser_string(label->PoolName);
+   unser_string(label->PoolType);
+   unser_string(label->JobName);
+   unser_string(label->ClientName);
+   if (label->VerNum >= 10) {
+      unser_string(label->Job);         /* Unique name of this Job */
+      unser_string(label->FileSetName);
+      unser_uint32(label->JobType);
+      unser_uint32(label->JobLevel);
+   }
+   if (label->VerNum >= 11) {
+      unser_string(label->FileSetMD5);
+   } else {
+      label->FileSetMD5[0] = 0;
+   }
+   if (rec->FileIndex == EOS_LABEL) {
+      unser_uint32(label->JobFiles);
+      unser_uint64(label->JobBytes);
+      unser_uint32(label->StartBlock);
+      unser_uint32(label->EndBlock);
+      unser_uint32(label->StartFile);
+      unser_uint32(label->EndFile);
+      unser_uint32(label->JobErrors);
+      if (label->VerNum >= 11) {
+        unser_uint32(label->JobStatus);
+      } else {
+        label->JobStatus = JS_Terminated; /* kludge */
+      }
+   }
+   return true;
+}
+
 void dump_volume_label(DEVICE *dev)
 {
    int dbl = debug_level;
@@ -765,53 +938,6 @@ bail_out:
    debug_level = dbl;
 }
 
-bool unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec)
-{
-   ser_declare;
-
-   rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
-   unser_begin(rec->data, SER_LENGTH_Session_Label);
-   unser_string(label->Id);
-   unser_uint32(label->VerNum);
-   unser_uint32(label->JobId);
-   if (label->VerNum >= 11) {
-      unser_btime(label->write_btime);
-   } else {
-      unser_float64(label->write_date);
-   }
-   unser_float64(label->write_time);
-   unser_string(label->PoolName);
-   unser_string(label->PoolType);
-   unser_string(label->JobName);
-   unser_string(label->ClientName);
-   if (label->VerNum >= 10) {
-      unser_string(label->Job);         /* Unique name of this Job */
-      unser_string(label->FileSetName);
-      unser_uint32(label->JobType);
-      unser_uint32(label->JobLevel);
-   }
-   if (label->VerNum >= 11) {
-      unser_string(label->FileSetMD5);
-   } else {
-      label->FileSetMD5[0] = 0;
-   }
-   if (rec->FileIndex == EOS_LABEL) {
-      unser_uint32(label->JobFiles);
-      unser_uint64(label->JobBytes);
-      unser_uint32(label->StartBlock);
-      unser_uint32(label->EndBlock);
-      unser_uint32(label->StartFile);
-      unser_uint32(label->EndFile);
-      unser_uint32(label->JobErrors);
-      if (label->VerNum >= 11) {
-        unser_uint32(label->JobStatus);
-      } else {
-        label->JobStatus = JS_Terminated; /* kludge */
-      }
-   }
-   return true;
-}
-
 
 static void dump_session_label(DEV_RECORD *rec, const char *type)
 {
@@ -968,187 +1094,3 @@ void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose)
    }
    debug_level = dbl;
 }
-
-/*
- * Write an ANSI or IBM 80 character tape label
- *   Assume we are positioned at the beginning of the tape.
- *   Returns:  true of OK
- *            false if error
- */
-bool write_ansi_ibm_label(DCR *dcr, const char *VolName)
-{
-   DEVICE *dev = dcr->dev;
-   JCR *jcr = dcr->jcr;
-   char label[80];                   /* tape label */
-   char date[20];                    /* ansi date buffer */
-   time_t now;
-   int len, stat, label_type;
-
-   /*
-    * If the Device requires a specific label type use it,
-    * otherwise, use the type requested by the Director
-    */
-   if (dcr->device->label_type != B_BACULA_LABEL) {
-      label_type = dcr->device->label_type;   /* force label type */
-   } else {
-      label_type = dcr->VolCatInfo.LabelType; /* accept Dir type */
-   }
-
-   switch (label_type) {
-   case B_BACULA_LABEL:
-      return true;
-   case B_ANSI_LABEL:
-   case B_IBM_LABEL:
-      ser_declare;
-      Dmsg1(000, "Write ANSI label type=%d\n", label_type);
-      len = strlen(VolName);
-      if (len > 6) {
-         Jmsg1(jcr, M_FATAL, 0, _("ANSI Volume label name \"%s\" longer than 6 chars.\n"),
-           VolName);
-        return false;
-      }
-      memset(label, ' ', sizeof(label));
-      ser_begin(label, sizeof(label));
-      ser_bytes("VOL1", 4);
-      ser_bytes(VolName, len);
-      label[79] = '3';                /* ANSI label flag */
-      /* Write VOL1 label */
-      stat = write(dev->fd, label, sizeof(label));
-      if (stat != sizeof(label)) {
-        berrno be;
-         Jmsg1(jcr, M_FATAL, 0,  _("Could not write ANSI VOL1 label. ERR=%s\n"),
-           be.strerror());
-        return false;
-      }
-      /* Now construct HDR1 label */
-      ser_begin(label, sizeof(label));
-      ser_bytes("HDR1", 4);
-      ser_bytes("BACULA.DATA", 11);            /* Filename field */
-      ser_begin(&label[21], sizeof(label)-21); /* fileset field */
-      ser_bytes(VolName, len);       /* write Vol Ser No. */
-      ser_begin(&label[27], sizeof(label)-27);
-      ser_bytes("00010001000100", 14);  /* File section, File seq no, Generation no */
-      now = time(NULL);
-      ser_bytes(ansi_date(now, date), 6); /* current date */
-      ser_bytes(ansi_date(now - 24 * 3600, date), 6); /* created yesterday */
-      ser_bytes(" 000000Bacula              ", 27);
-      /* Write HDR1 label */
-      stat = write(dev->fd, label, sizeof(label));
-      if (stat != sizeof(label)) {
-        berrno be;
-         Jmsg1(jcr, M_FATAL, 0, _("Could not write ANSI HDR1 label. ERR=%s\n"),
-           be.strerror());
-        return false;
-      }
-      /* Now construct HDR2 label */
-      memset(label, ' ', sizeof(label));
-      ser_begin(label, sizeof(label));
-      ser_bytes("HDR2F3200032000", 15);
-      /* Write HDR1 label */
-      stat = write(dev->fd, label, sizeof(label));
-      if (stat != sizeof(label)) {
-        berrno be;
-         Jmsg1(jcr, M_FATAL, 0, _("Could not write ANSI HDR1 label. ERR=%s\n"),
-           be.strerror());
-        return false;
-      }
-      if (weof_dev(dev, 1) < 0) {
-         Jmsg(jcr, M_FATAL, 0, _("Error writing EOF to tape. ERR=%s"), dev->errmsg);
-        return false;
-      }
-      return true;
-   default:
-      Jmsg0(jcr, M_ABORT, 0, _("write_ansi_ibm_label called for non-ANSI/IBM type\n"));
-      return false; /* should not get here */
-   }
-}
-
-static int read_ansi_ibm_label(DCR *dcr) 
-{
-   DEVICE *dev = dcr->dev;
-   JCR *jcr = dcr->jcr;
-   char label[80];                   /* tape label */
-   int stat, i, num_rec;
-
-   /*
-    * Read VOL1, HDR1, HDR2 labels, but ignore the data
-    *  If tape read the following EOF mark, on disk do
-    *  not read.
-    */
-   Dmsg0(000, "Read ansi label.\n");
-   if (dev->is_tape()) {
-      num_rec = 4;
-   } else {
-      num_rec = 3;
-   }
-   for (i=0; i < num_rec; i++) {
-      do {
-        stat = read(dev->fd, label, sizeof(label));
-      } while (stat == -1 && errno == EINTR);
-      if (stat < 0) {
-        berrno be;
-        clrerror_dev(dev, -1);
-         Dmsg1(000, "Read device got: ERR=%s\n", be.strerror());
-         Mmsg2(dev->errmsg, _("Read error on device %s in ANSI/IBM label. ERR=%s\n"),
-           dev->dev_name, be.strerror());
-         Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
-        dev->VolCatInfo.VolCatErrors++;
-        return VOL_IO_ERROR;
-      }
-      if (stat == 0) {
-        if (dev->at_eof()) {
-           dev->state |= ST_EOT;
-           return VOL_NO_LABEL;
-        } else {
-           dev->state |= ST_EOF;
-        }
-      }
-      switch (i) {
-      case 0:                        /* Want VOL1 label */
-         if (stat != 80 || strncmp("VOL1", label, 4) != 0) {
-            Dmsg0(000, "No VOL1 label\n");
-           return VOL_NO_LABEL;
-        }
-        break;
-      case 1:
-         if (stat != 80 || strncmp("HDR1", label, 4) != 0) {
-            Dmsg0(000, "No HDR1 label\n");
-           return VOL_NO_LABEL;
-        }
-         if (strncmp("BACULA.DATA", &label[4], 11) != 0) {
-            Dmsg0(000, "HD1 not Bacula label\n");
-           return VOL_NAME_ERROR;
-        }
-        break;
-      case 2:
-         if (stat != 80 || strncmp("HDR2", label, 4) != 0) {
-            Dmsg0(000, "No HDR2 label\n");
-           return VOL_NO_LABEL;
-        }
-        break;
-      case 3:                        /* Should get EOF here */
-        if (stat != 0) {
-            Dmsg0(000, "No EOF\n");
-           return VOL_IO_ERROR;
-        }
-        break;
-      }
-   }
-   /* ***FIXME*** add detection of IBM labels */
-   dev->label_type = B_ANSI_LABEL;
-   Dmsg0(000, "ANSI label OK\n");
-   return VOL_OK;
-}  
-
-
-static char *ansi_date(time_t td, char *buf)
-{
-   struct tm *tm;
-
-   if (td == 0) {
-      td = time(NULL);
-   }
-   tm = gmtime(&td);
-   bsnprintf(buf, 10, " %05d ", 1000 * (tm->tm_year + 1900 - 2000) + tm->tm_yday);
-   return buf;
-}
index cf678ae0a61827d74d0e39d9505be7adb26e7c53..fdda8d2f011d134f122057c8a1cc408e60a40498 100644 (file)
@@ -30,8 +30,6 @@
 #include "bacula.h"                   /* pull in global headers */
 #include "stored.h"                   /* pull in Storage Deamon headers */
 
-static bool rewrite_volume_label(DCR *dcr, bool recycle);
-
 
 /*
  * If release is set, we rewind the current volume,
@@ -375,86 +373,6 @@ read_volume:
    return true;
 }
 
-/*
- * Write a volume label.
- *  Returns: true if OK
- *          false if unable to write it
- */
-static bool rewrite_volume_label(DCR *dcr, bool recycle)
-{
-   DEVICE *dev = dcr->dev;
-   JCR *jcr = dcr->jcr;
-
-   Dmsg1(190, "set append found freshly labeled volume. dev=%x\n", dev);
-   dev->VolHdr.LabelType = VOL_LABEL; /* set Volume label */
-   dev->state |= ST_APPEND;
-   if (!write_volume_label_to_block(dcr)) {
-      Dmsg0(200, "Error from write volume label.\n");
-      return false;
-   }
-   /*
-    * If we are not dealing with a streaming device,
-    *  write the block now to ensure we have write permission.
-    *  It is better to find out now rather than later.
-    */
-   if (!dev_cap(dev, CAP_STREAM)) {
-      if (!rewind_dev(dev)) {
-         Jmsg2(jcr, M_WARNING, 0, _("Rewind error on device \"%s\". ERR=%s\n"),
-              dev_name(dev), strerror_dev(dev));
-      }
-      if (recycle) {
-        if (!truncate_dev(dev)) {
-            Jmsg2(jcr, M_WARNING, 0, _("Truncate error on device \"%s\". ERR=%s\n"),
-                 dev_name(dev), strerror_dev(dev));
-        }
-      }
-      /* Attempt write to check write permission */
-      Dmsg0(200, "Attempt to write to device.\n");
-      if (!write_ansi_ibm_label(dcr, dev->VolHdr.VolName)) {
-        return false;
-      }
-      if (!write_block_to_dev(dcr)) {
-         Jmsg2(jcr, M_ERROR, 0, _("Unable to write device \"%s\". ERR=%s\n"),
-           dev_name(dev), strerror_dev(dev));
-         Dmsg0(200, "===ERROR write block to dev\n");
-        return false;
-      }
-   }
-   /* Set or reset Volume statistics */
-   dev->VolCatInfo.VolCatJobs = 0;
-   dev->VolCatInfo.VolCatFiles = 0;
-   dev->VolCatInfo.VolCatBytes = 1;
-   dev->VolCatInfo.VolCatErrors = 0;
-   dev->VolCatInfo.VolCatBlocks = 0;
-   dev->VolCatInfo.VolCatRBytes = 0;
-   if (recycle) {
-      dev->VolCatInfo.VolCatMounts++;
-      dev->VolCatInfo.VolCatRecycles++;
-   } else {
-      dev->VolCatInfo.VolCatMounts = 1;
-      dev->VolCatInfo.VolCatRecycles = 0;
-      dev->VolCatInfo.VolCatWrites = 1;
-      dev->VolCatInfo.VolCatReads = 1;
-   }
-   Dmsg0(100, "dir_update_vol_info. Set Append\n");
-   bstrncpy(dev->VolCatInfo.VolCatStatus, "Append", sizeof(dev->VolCatInfo.VolCatStatus));
-   if (!dir_update_volume_info(dcr, true)) {  /* indicate doing relabel */
-      return false;
-   }
-   if (recycle) {
-      Jmsg(jcr, M_INFO, 0, _("Recycled volume \"%s\" on device \"%s\", all previous data lost.\n"),
-        dcr->VolumeName, dev_name(dev));
-   } else {
-      Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume \"%s\" on device \"%s\"\n"),
-        dcr->VolumeName, dev_name(dev));
-   }
-   /*
-    * End writing real Volume label (from pre-labeled tape), or recycling
-    *  the volume.
-    */
-   Dmsg0(200, "OK from rewite vol label.\n");
-   return true;
-}
 
 
 /*
@@ -518,6 +436,7 @@ void release_volume(DCR *dcr)
    memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
    /* Force re-read of label */
    dev->state &= ~(ST_LABEL|ST_READ|ST_APPEND);
+   dev->label_type = B_BACULA_LABEL;
    dcr->VolumeName[0] = 0;
 
    if (dev->is_open() && (!dev->is_tape() || !dev_cap(dev, CAP_ALWAYSOPEN))) {
index f5ab5defe5521a9656e3b3c6347a3799730e38d6..b94363a825192c7dff2ceb4226230b8cb13316a2 100644 (file)
@@ -163,8 +163,10 @@ void     create_session_label(DCR *dcr, DEV_RECORD *rec, int label);
 void     create_volume_label(DEVICE *dev, const char *VolName, const char *PoolName);
 bool     write_new_volume_label_to_dev(DCR *dcr, const char *VolName, const char *PoolName);
 bool     write_ansi_ibm_label(DCR *dcr, const char *VolName);
+int      read_ansi_ibm_label(DCR *dcr);
 bool     write_session_label(DCR *dcr, int label);
 bool     write_volume_label_to_block(DCR *dcr);
+bool     rewrite_volume_label(DCR *dcr, bool recycle);
 void     dump_volume_label(DEVICE *dev);
 void     dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose);
 bool     unser_volume_label(DEVICE *dev, DEV_RECORD *rec);
index 2d6f5a4dc59cf188f6e23d3b1d2fd8dfce00b343..b586a7635e1a3c6b8d12bb237a8f4d31bea22647 100644 (file)
@@ -8,7 +8,7 @@
  *
  */
 /*
-   Copyright (C) 2000-2004 Kern Sibbald and John Walker
+   Copyright (C) 2000-2005 Kern Sibbald
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
index 6175c6a35ef0941a4c202f568b1034355bd23d62..bbde218477be5b1fcab509d951757b1cb6c5912e 100644 (file)
@@ -1,8 +1,8 @@
 /* */
 #undef  VERSION
 #define VERSION "1.37.3"
-#define BDATE   "07 February 2005"
-#define LSMDATE "07Feb05"
+#define BDATE   "09 February 2005"
+#define LSMDATE "09Feb05"
 
 /* Debug flags */
 #undef  DEBUG