Document:
+- Does ClientRunAfterJob fail the job on a bad return code?
 - datadir for po files.
 - AM_GNU_GETTEXT finds the library if you specify 
   --with-libintl-prefix
 - Does WildFile match against full name?  Doc.
 
 For 1.39:
+- Add a recursive mark command (rmark) to restore.
 - "Minimum Job Interval = nnn" sets minimum interval between Jobs
   of the same level and does not permit multiple simultaneous
   running of that Job (i.e. lets any previous invocation finish
 
 
 General:
 
+Changes to 1.37.40:
+24Sep05
+- Fix mode change open in btape.c
+- Use nonblocking opens on Linux only.
+- Move set_blocking code for tapes into method to
+  simplify main line code.
+- Cleanup the code for ensuring we advance tape on fsf.
+  This should fix IBM problems -- patch from Adam Thorton
+  was very helpful.
+- Remove test for BMT_EOD in fixup_device... this eliminates
+  need for status_dev() routine.
+- Before doing label ensure device is in read-write mode.
+
 Changes to 1.37.39:
 20Sep05
 - Tweak daemon.c berrno, copyright.
 
  *
  */
 /*
-   Copyright (C) 2002-2005 Kern Sibbald
+   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
-   published by the Free Software Foundation; either version 2 of
-   the License, or (at your option) any later version.
+   modify it under the terms of the GNU General Public License
+   version 2 as amended with additional clauses defined in the
+   file LICENSE in the main source directory.
 
    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.
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
+   the file LICENSE for additional details.
 
  */
 
 
  *
  *   Version $Id$
  */
-
 /*
-   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
-   published by the Free Software Foundation; either version 2 of
-   the License, or (at your option) any later version.
+   modify it under the terms of the GNU General Public License
+   version 2 as amended with additional clauses defined in the
+   file LICENSE in the main source directory.
 
    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.
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
+   the file LICENSE for additional details.
 
  */
 
  * buf as base64 characters.
  *
  *  Returns: the number of characters stored not
- *          including the EOS
+ *           including the EOS
  */
 int
 bin_to_base64(char *buf, char *bin, int len)
    rem = 0;
    for (i=0; i<len; ) {
       if (rem < 6) {
-        reg <<= 8;
-        reg |= (int8_t)bin[i++];
-        rem += 8;
+         reg <<= 8;
+         reg |= (int8_t)bin[i++];
+         rem += 8;
       }
       save = reg;
       reg >>= (rem - 6);
    if (rem) {
       mask = 1;
       for (i=1; i<rem; i++) {
-        mask = (mask << 1) | 1;
+         mask = (mask << 1) | 1;
       }
       buf[j++] = base64_digits[reg & mask];
    }
    for (i=0; my_glob.gl_pathv[i]; i++) {
       fname = my_glob.gl_pathv[i];
       if (lstat(fname, &statp) < 0) {
-        printf("Cannot stat %s: %s\n", fname, strerror(errno));
-        continue;
+         printf("Cannot stat %s: %s\n", fname, strerror(errno));
+         continue;
       }
       encode_stat(where, &statp);
 
 #endif
 
       if (debug_level)
-        printf("%s: len=%d val=%s\n", fname, strlen(where), where);
+         printf("%s: len=%d val=%s\n", fname, strlen(where), where);
 
       decode_stat(where, &statn);
 
       if (statp.st_dev != statn.st_dev ||
-         statp.st_ino != statn.st_ino ||
-         statp.st_mode != statn.st_mode ||
-         statp.st_nlink != statn.st_nlink ||
-         statp.st_uid != statn.st_uid ||
-         statp.st_gid != statn.st_gid ||
-         statp.st_rdev != statn.st_rdev ||
-         statp.st_size != statn.st_size ||
-         statp.st_blksize != statn.st_blksize ||
-         statp.st_blocks != statn.st_blocks ||
-         statp.st_atime != statn.st_atime ||
-         statp.st_mtime != statn.st_mtime ||
-         statp.st_ctime != statn.st_ctime) {
-
-        printf("%s: %s\n", fname, where);
-        encode_stat(where, &statn);
-        printf("%s: %s\n", fname, where);
-        printf("NOT EQAL\n");
+          statp.st_ino != statn.st_ino ||
+          statp.st_mode != statn.st_mode ||
+          statp.st_nlink != statn.st_nlink ||
+          statp.st_uid != statn.st_uid ||
+          statp.st_gid != statn.st_gid ||
+          statp.st_rdev != statn.st_rdev ||
+          statp.st_size != statn.st_size ||
+          statp.st_blksize != statn.st_blksize ||
+          statp.st_blocks != statn.st_blocks ||
+          statp.st_atime != statn.st_atime ||
+          statp.st_mtime != statn.st_mtime ||
+          statp.st_ctime != statn.st_ctime) {
+
+         printf("%s: %s\n", fname, where);
+         encode_stat(where, &statn);
+         printf("%s: %s\n", fname, where);
+         printf("NOT EQAL\n");
       }
 
    }
 
 
    block = new_block(dev);
    lock_device(dev);
-   if (!dev->is_open()) {
-      Dmsg1(200, "Opening device %s\n", dcr->VolumeName);
-      if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
-         Emsg1(M_FATAL, 0, _("dev open failed: %s\n"), dev->errmsg);
-         unlock_device(dev);
-         free_block(block);
-         return false;
-      }
+   Dmsg1(200, "Opening device %s\n", dcr->VolumeName);
+   if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
+      Emsg1(M_FATAL, 0, _("dev open failed: %s\n"), dev->errmsg);
+      unlock_device(dev);
+      free_block(block);
+      return false;
    }
    Pmsg1(000, _("open device %s: OK\n"), dev->print_name());
    dev->set_append();                 /* put volume in append mode */
 
    bool found = false;
    DEVRES *device;
 
+   Dmsg0(900, "Enter find_device_res\n");
    LockRes();
    foreach_res(device, R_DEVICE) {
+      Dmsg2(900, "Compare %s and %s\n", device->device_name, device_name);
       if (strcmp(device->device_name, device_name) == 0) {
          found = true;
          break;
          }
       }
       foreach_res(device, R_DEVICE) {
+         Dmsg2(900, "Compare %s and %s\n", device->hdr.name, device_name);
          if (strcmp(device->hdr.name, device_name) == 0) {
             found = true;
             break;
 
          return fd;
       } else {
         ::close(fd); /* use system close so correct mode will be used on open */
+        fd = -1;
+        Dmsg0(100, "Close fd for mode change.\n");
       }
    }
-  if (dcr) {
-     bstrncpy(VolCatInfo.VolCatName, dcr->VolumeName, sizeof(VolCatInfo.VolCatName));
-  }
+   if (dcr) {
+      bstrncpy(VolCatInfo.VolCatName, dcr->VolumeName, sizeof(VolCatInfo.VolCatName));
+   }
 
    Dmsg4(29, "open dev: tape=%d dev_name=%s vol=%s mode=%s\n", is_tape(),
          print_name(), VolCatInfo.VolCatName, mode_to_str(omode));
  */
 void DEVICE::open_tape_device(DCR *dcr, int omode) 
 {
-   int nonblocking = 0;;
+   int nonblocking = 0;
    file_size = 0;
    int timeout;
    int ioerrcnt = 10;
    set_mode(omode);
    timeout = max_open_wait;
    errno = 0;
+#ifdef HAVE_LINUX_OS
    if (open_nowait) {
        /* Set wait counters to zero for no wait */
        timeout = ioerrcnt = 0;
        /* Open drive in non-block mode */
        nonblocking = O_NONBLOCK;
    }
+#endif
    if (is_fifo() && timeout) {
       /* Set open timer */
       tid = start_thread_timer(pthread_self(), timeout);
          stop_thread_timer(tid);
          tid = 0;
       }
-      Emsg0(M_FATAL, 0, errmsg);
+      Jmsg0(dcr->jcr, M_FATAL, 0, errmsg);
       break;
    }
-   /* 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;
-         /* 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;
-         }
-      }
+
+   if (nonblocking) {
+      set_blocking();
+   }
+
+   if (fd >= 0) {
       openmode = omode;              /* save open mode */
       Dmsg2(100, "openmode=%d %s\n", openmode, mode_to_str(openmode));
       dev_errno = 0;
       use_count = 1;
       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) {
       stop_thread_timer(tid);
    Dmsg1(29, "open dev: tape %d opened\n", fd);
 }
 
+void DEVICE::set_blocking()
+{
+   int oflags;
+   /* Try to reset blocking */
+   if ((oflags = fcntl(fd, F_GETFL, 0)) < 0 ||
+       fcntl(fd, F_SETFL, oflags & ~O_NONBLOCK) < 0) {
+      berrno be;
+      ::close(fd);                   /* use system close() */
+      fd = ::open(dev_name, mode, MODE_RW);       
+      Dmsg2(100, "fcntl error. ERR=%s. Close-reopen fd=%d\n", be.strerror(), fd);
+   }
+}
+
 /*
  * Open a file device
  */
             return false;
          }
          /*
-          * Avoid infinite loop. ***FIXME*** possibly add code
-          *   to set EOD or to turn off CAP_FASTFSF if on.
+          * Avoid infinite loop by ensuring we advance.
           */
          if (file_num == (int)dev->file) {
             struct mtget mt_stat;
             Dmsg1(100, "fsf did not advance from file %d\n", file_num);
+            dev->set_ateof();
             if (dev_get_os_pos(dev, &mt_stat)) {
                Dmsg2(100, "Adjust file from %d to %d\n", dev->file , mt_stat.mt_fileno);
-               dev->set_ateof();
                dev->file = mt_stat.mt_fileno;
-            }
-            return false;
+            }       
+            break;
          }
       }
    }
 
    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 */
+   void set_blocking(); /* in dev.c */
 
 };
 
 
  */
 bool fixup_device_block_write_error(DCR *dcr)
 {
-   uint32_t stat;
    char PrevVolName[MAX_NAME_LENGTH];
    DEV_BLOCK *label_blk;
    DEV_BLOCK *block = dcr->block;
    DEVICE *dev = dcr->dev;
 
    wait_time = time(NULL);
-   stat = status_dev(dev);
-   if (!(stat & BMT_EOD)) {
-      return false;                    /* this really shouldn't happen */
-   }
 
-   Dmsg0(100, "======= Got EOD ========\n");
+   Dmsg0(100, "Enter fixup_device_block_write_error\n");
 
    block_device(dev, BST_DOING_ACQUIRE);
    /* Unlock, but leave BLOCKED */
 
    Dmsg0(99, "write_volume_label()\n");
    empty_block(dcr->block);
 
+   if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
+      goto bail_out;
+   }
    Dmsg1(100, "Label type=%d\n", dev->label_type);
    if (!rewind_dev(dev)) {
       free_volume(dev);
    DEVICE *dev = dcr->dev;
    JCR *jcr = dcr->jcr;
 
+   if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
+      return false;
+   }
    Dmsg2(190, "set append found freshly labeled volume. fd=%d dev=%x\n", dev->fd, dev);
    dev->VolHdr.LabelType = VOL_LABEL; /* set Volume label */
    dev->set_append();
 
  */
 
 #undef  VERSION
-#define VERSION "1.37.39"
-#define BDATE   "20 September 2005"
-#define LSMDATE "20Sep05"
+#define VERSION "1.37.40"
+#define BDATE   "24 September 2005"
+#define LSMDATE "24Sep05"
 
 /* Debug flags */
 #undef  DEBUG