General:
 
-Changes to 1.37.32:
+Changes to 1.37.34:
+03Aug03
+- Modify open() for tape so nonblocking really works.  
+- Use fcntl() to reset blocking status rather than close()
+  and reopen the drive.
+- Make sure dev->open() is always called so that any change
+  in read/write permissions will occur.
+- Open drives initially in daemon in read-only mode.
+- Ensure that each time the VolHdr.VolumeName is zapped
+  or changed that free_volume() is called on the old name.
+
+Changes to 1.37.33:
 03Aug03
 - Require 5 arguments to mtx-changer except list and slots
 - Turn -EPIPE status returns from bpipe to ETIME
 - Do not term_dev() during initialization in SD if the device
   could not be opened.  In the case of a tape drive, there may
   be no tape in the drive.
+
+Changes to 1.32.32:
 02Aug05
 - Correct PostgreSQL database scripts as suggested by a user.
 - Add additional info to FATAL message generated when a device
 
        * reading. If it is a file, it opens it.
        * If it is a tape, it checks the volume name
        */
-      for ( ; !dev->is_open(); ) {
-         Dmsg1(100, "bstored: open vol=%s\n", dcr->VolumeName);
-         if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
-            if (dev->dev_errno == EIO) {   /* no tape loaded */
-              Jmsg3(jcr, M_WARNING, 0, _("Open device %s Volume \"%s\" failed (EIO): ERR=%s\n"),
-                    dev->print_name(), dcr->VolumeName, strerror_dev(dev));
-               goto default_path;
-            }
-            
+      Dmsg1(100, "bstored: open vol=%s\n", dcr->VolumeName);
+      if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
+         if (dev->dev_errno == EIO) {   /* no tape loaded */
+           Jmsg3(jcr, M_WARNING, 0, _("Open device %s Volume \"%s\" failed (EIO): ERR=%s\n"),
+                 dev->print_name(), dcr->VolumeName, strerror_dev(dev));
+            goto default_path;
+         }
+         
 #ifdef xxx_needed
-            /* If we have a dvd that requires mount, 
-             * we need to try to open the label, so the info can be reported
-             * if a wrong volume has been mounted.   
-             */
-            if (dev->is_dvd() && (dcr->VolCatInfo.VolCatParts > 0)) {
-               break;
-            }  
+         /* If we have a dvd that requires mount, 
+          * we need to try to open the label, so the info can be reported
+          * if a wrong volume has been mounted.   
+          */
+         if (dev->is_dvd() && (dcr->VolCatInfo.VolCatParts > 0)) {
+            break;
+         }  
 #endif
-            
-            Jmsg3(jcr, M_FATAL, 0, _("Open device %s Volume \"%s\" failed: ERR=%s\n"),
-                dev->print_name(), dcr->VolumeName, strerror_dev(dev));
-            goto get_out;
-         }
-         Dmsg1(100, "opened dev %s OK\n", dev->print_name());
+         
+         Jmsg3(jcr, M_FATAL, 0, _("Open device %s Volume \"%s\" failed: ERR=%s\n"),
+             dev->print_name(), dcr->VolumeName, strerror_dev(dev));
+         goto get_out;
       }
+      Dmsg1(100, "opened dev %s OK\n", dev->print_name());
       
       /* Read Volume Label */
       
 
          if (VolName && *VolName && *VolName != '*') { 
             if (!same_label_names(VolName, &label[4])) {
                char *p = &label[4];
-               char *q = dev->VolHdr.VolumeName;
+               char *q;  
+
+               free_volume(dev);
+               /* Store new Volume name */
+               q = dev->VolHdr.VolumeName;
                for (int i=0; *p != ' ' && i < 6; i++) {
                   *q++ = *p++;
                }
 
    state &= ~(ST_LABEL|ST_APPEND|ST_READ|ST_EOT|ST_WEOT|ST_EOF);
    label_type = B_BACULA_LABEL;
    if (is_tape() || is_fifo()) {
-      open_tape_device(omode);
+      open_tape_device(dcr, omode);
    } else if (is_dvd()) {
       Dmsg1(100, "call open_dvd_device mode=%s\n", mode_to_str(omode));
       open_dvd_device(dcr, omode);
    }
 }
 
-void DEVICE::open_tape_device(int omode) 
+/*
+ * If the flage open_nowait is set, which is the case
+ *   when the daemon is initially trying to open the device,
+ *   we open it with O_NONBLOCK set and O_RONLY, which will
+ *   allow us to open normal Linux tape drives with no tape
+ *   in the drive without blocking.  We then immediately
+ *   set blocking status so that if we read from the device they
+ *   will be normal blocking reads.
+ *
+ * If later, we want to write on the device, it will be freed and
+ *   reopened, but hopefully there will be a tape in the drive so
+ *   we will not block.
+ */
+void DEVICE::open_tape_device(DCR *dcr, int omode) 
 {
    int nonblocking = 0;;
    file_size = 0;
       tid = start_thread_timer(pthread_self(), timeout);
    }
    /* If busy retry each second for max_open_wait seconds */
-open_again:
-   Dmsg1(500, "Try open %s\n", print_name());
+   Dmsg3(100, "Try open %s mode=%s nonblocking=%d\n", print_name(),
+      mode_to_str(omode), nonblocking);
    /* Use system open() */
-   while ((fd = ::open(dev_name, mode, MODE_RW+nonblocking)) < 0) {
+   while ((fd = ::open(dev_name, mode+nonblocking, MODE_RW)) < 0) {
       berrno be;
-      Dmsg2(500, "Open error errno=%d ERR=%s\n", errno, be.strerror());
+      Dmsg2(100, "Open error errno=%d ERR=%s\n", errno, be.strerror());
       if (errno == EINTR || errno == EAGAIN) {
-         Dmsg0(500, "Continue open\n");
+         Dmsg0(100, "Continue open\n");
          continue;
       }
       /* Busy wait for specified time (default = 5 mins) */
       /* IO error (no volume) try 10 times every 6 seconds */
       if (errno == EIO && ioerrcnt-- > 0) {
          bmicrosleep(5, 0);
-         Dmsg0(500, "Continue open\n");
+         Dmsg0(100, "Continue open\n");
          continue;
       }
       dev_errno = errno;
       Emsg0(M_FATAL, 0, errmsg);
       break;
    }
-   if (fd >= 0) {
-      /* If opened in non-block mode, close it an open it normally */
+   /* Really an if, but we use a break for an error exit */
+   while (fd >= 0) {
+      /* If opened in non-block mode, make it block now */
       if (nonblocking) {
+         int oflags;
          nonblocking = 0;
-         ::close(fd);                /* use system close() */
-         goto open_again;
+         /* Try to reset blocking */
+         if ((oflags = fcntl(fd, F_GETFL, 0)) < 0 ||
+             fcntl(fd, F_SETFL, oflags & ~O_NONBLOCK) < 0) {
+            berrno be;
+            Jmsg1(dcr->jcr, M_ERROR, 0, "fcntl error. ERR=%s\n", be.strerror());
+            ::close(fd);                   /* use system close() */
+            fd = -1;
+            break;
+         }
       }
       openmode = omode;              /* save open mode */
       Dmsg2(100, "openmode=%d %s\n", openmode, mode_to_str(openmode));
       update_pos_dev(this);                /* update position */
       set_os_device_parameters(this);      /* do system dependent stuff */
       Dmsg0(500, "Open OK\n");
+      break;
    }
    /* Stop any open() timer we started */
    if (tid) {
    dev->part_start = 0;
    dev->EndFile = dev->EndBlock = 0;
    memset(&dev->VolCatInfo, 0, sizeof(dev->VolCatInfo));
+   free_volume(dev);
    memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
    if (dev->tid) {
       stop_thread_timer(dev->tid);
 
    int mode;                          /* read/write modes */
    int openmode;                      /* parameter passed to open_dev (useful to reopen the device) */
    bool autoselect;                   /* Autoselect in autochanger */
-   bool open_nowait;                  /* If set, don t wait on open */
+   bool open_nowait;                  /* If set, don't wait on open */
    int label_type;                    /* Bacula/ANSI/IBM label types */
    uint32_t drive_index;              /* Autochanger drive index (base 0) */
    int32_t  Slot;                     /* Slot currently in drive (base 1) */
 
 private:
    void set_mode(int omode); /* in dev.c */
-   void open_tape_device(int omode); /* in dev.c */
+   void open_tape_device(DCR *dcr, int omode); /* in dev.c */
    void open_file_device(int omode); /* in dev.c */
    void open_dvd_device(DCR *dcr, int omode); /* in dev.c */
 
 
     if (dev_cap(dev, CAP_STREAM)) {
        mode = OPEN_WRITE_ONLY;
     } else {
-       mode = OPEN_READ_WRITE;
+       mode = OPEN_READ_ONLY;
     }
    Dmsg0(129, "Opening device.\n");
    dev->open_nowait = true;
 
    }
 
    /* Ensure that the device is open -- autoload_device() closes it */
-   for ( ; !dev->is_open(); ) {
-      if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
-         bnet_fsend(dir, _("3910 Unable to open device %s: ERR=%s\n"),
-            dev->print_name(), dev->strerror());
-         return false;
-      }
+   if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
+      bnet_fsend(dir, _("3910 Unable to open device %s: ERR=%s\n"),
+         dev->print_name(), dev->strerror());
+      return false;
    }
    return true;
 }
 
 
    Dmsg1(100, "Label type=%d\n", dev->label_type);
    if (!rewind_dev(dev)) {
+      free_volume(dev);
       memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
       Dmsg2(30, "Bad status on %s from rewind: ERR=%s\n", dev->print_name(), strerror_dev(dev));
       if (!forge_on) {
    return true;
 
 bail_out:
+   free_volume(dev);
    memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
    dev->clear_append();               /* remove append since this is PRE_LABEL */
    return false;
 
    ASSERT(dev != NULL);
 
+   free_volume(dev);         /* release any old volume */
    memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
 
    bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
 
 /* */
 #undef  VERSION
-#define VERSION "1.37.33"
+#define VERSION "1.37.34"
 #define BDATE   "03 August 2005"
 #define LSMDATE "03Aug05"