]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/stored/dev.c
Add address and socket for MySQL
[bacula/bacula] / bacula / src / stored / dev.c
index 32cd48dec7765391c802cc443cb0e59c13026101..e19032544d6251c6092e8edbf9a52f437bbdeef8 100644 (file)
  *
  *     Unfortunately, I have had to add more and more complication
  *     to this code. This was not foreseen as noted above, and as
- *     a consequence has lead to something more contored than is
+ *     a consequence has lead to something more contorted than is
  *     really necessary -- KES.  Note, this contortion has been
  *     corrected to a large extent by a rewrite (Apr MMI).
  *
  *   Version $Id$
  */
 /*
-   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+   Copyright (C) 2000-2003 Kern Sibbald and John Walker
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
@@ -49,7 +49,7 @@
  */
 
 /*
- * Handling I/O errors and end of tape conditions is a bit tricky.
+ * Handling I/O errors and end of tape conditions are a bit tricky.
  * This is how it is currently done when writting.
  * On either an I/O error or end of tape,
  * we will stop writing on the physical device (no I/O recovery is
@@ -95,36 +95,40 @@ extern int debug_level;
  * thus we neither allocate it nor free it. This allows
  * the caller to put the packet in shared memory.
  *
- *  Note, for a tape, the dev_name is the device name
+ *  Note, for a tape, the device->device_name is the device name
  *     (e.g. /dev/nst0), and for a file, the device name
  *     is the directory in which the file will be placed.
  *
  */
 DEVICE *
-init_dev(DEVICE *dev, char *dev_name)
+init_dev(DEVICE *dev, DEVRES *device)
 {
    struct stat statp;
-   int tape;
+   int tape, fifo;
    int errstat;
 
    /* Check that device is available */
-   if (stat(dev_name, &statp) < 0) {
+   if (stat(device->device_name, &statp) < 0) {
       if (dev) {
         dev->dev_errno = errno;
       } 
-      Emsg2(M_FATAL, 0, "Unable to stat device %s : %s\n", dev_name, strerror(errno));
+      Emsg2(M_FATAL, 0, "Unable to stat device %s : %s\n", device->device_name, 
+           strerror(errno));
       return NULL;
    }
    tape = FALSE;
+   fifo = FALSE;
    if (S_ISDIR(statp.st_mode)) {
       tape = FALSE;
    } else if (S_ISCHR(statp.st_mode)) {
       tape = TRUE;
+   } else if (S_ISFIFO(statp.st_mode)) {
+      fifo = TRUE;
    } else {
       if (dev) {
         dev->dev_errno = ENODEV;
       }
-      Emsg2(M_FATAL, 0, "%s is an unknown device type. Must be tape or directory. st_mode=%x\n", 
+      Emsg2(M_FATAL, 0, _("%s is an unknown device type. Must be tape or directory. st_mode=%x\n"),
         dev_name, statp.st_mode);
       return NULL;
    }
@@ -135,28 +139,58 @@ init_dev(DEVICE *dev, char *dev_name)
    } else {
       memset(dev, 0, sizeof(DEVICE));
    }
+
+   /* Copy user supplied device parameters from Resource */
+   dev->dev_name = get_memory(strlen(device->device_name)+1);
+   strcpy(dev->dev_name, device->device_name);
+   dev->capabilities = device->cap_bits;
+   dev->min_block_size = device->min_block_size;
+   dev->max_block_size = device->max_block_size;
+   dev->max_volume_jobs = device->max_volume_jobs;
+   dev->max_volume_files = device->max_volume_files;
+   dev->max_volume_size = device->max_volume_size;
+   dev->max_file_size = device->max_file_size;
+   dev->volume_capacity = device->volume_capacity;
+   dev->max_rewind_wait = device->max_rewind_wait;
+   dev->max_open_wait = device->max_open_wait;
+   dev->max_open_vols = device->max_open_vols;
+   dev->device = device;
+
    if (tape) {
       dev->state |= ST_TAPE;
+   } else if (fifo) {
+      dev->state |= ST_FIFO;
+      dev->capabilities |= CAP_STREAM; /* set stream device */
+   } else {
+      dev->state |= ST_FILE;
    }
-   dev->dev_name = (char *) get_memory(strlen(dev_name)+1);
-   strcpy(dev->dev_name, dev_name);
 
-   dev->errmsg = (char *) get_pool_memory(PM_EMSG);
+   if (dev->max_block_size > 1000000) {
+      Emsg3(M_ERROR, 0, _("Block size %u on device %s is too large, using default %u\n"), 
+        dev->max_block_size, dev->dev_name, DEFAULT_BLOCK_SIZE);
+      dev->max_block_size = 0;
+   }
+   if (dev->max_block_size % TAPE_BSIZE != 0) {
+      Emsg2(M_WARNING, 0, _("Max block size %u not multiple of device %s block size.\n"),
+        dev->max_block_size, dev->dev_name);
+   }   
+        
+   dev->errmsg = get_pool_memory(PM_EMSG);
    *dev->errmsg = 0;
 
    if ((errstat = pthread_mutex_init(&dev->mutex, NULL)) != 0) {
       dev->dev_errno = errstat;
-      Mmsg1(&dev->errmsg, "Unable to init mutex: ERR=%s\n", strerror(errstat));
+      Mmsg1(&dev->errmsg, _("Unable to init mutex: ERR=%s\n"), strerror(errstat));
       Emsg0(M_FATAL, 0, dev->errmsg);
    }
    if ((errstat = pthread_cond_init(&dev->wait, NULL)) != 0) {
       dev->dev_errno = errstat;
-      Mmsg1(&dev->errmsg, "Unable to init cond variable: ERR=%s\n", strerror(errstat));
+      Mmsg1(&dev->errmsg, _("Unable to init cond variable: ERR=%s\n"), strerror(errstat));
       Emsg0(M_FATAL, 0, dev->errmsg);
    }
    if ((errstat = pthread_cond_init(&dev->wait_next_vol, NULL)) != 0) {
       dev->dev_errno = errstat;
-      Mmsg1(&dev->errmsg, "Unable to init cond variable: ERR=%s\n", strerror(errstat));
+      Mmsg1(&dev->errmsg, _("Unable to init cond variable: ERR=%s\n"), strerror(errstat));
       Emsg0(M_FATAL, 0, dev->errmsg);
    }
    dev->fd = -1;
@@ -176,7 +210,7 @@ init_dev(DEVICE *dev, char *dev_name)
 int
 open_dev(DEVICE *dev, char *VolName, int mode)
 {
-   char *archive_name;
+   POOLMEM *archive_name;
 
    if (dev->state & ST_OPENED) {
       /*
@@ -189,9 +223,9 @@ open_dev(DEVICE *dev, char *VolName, int mode)
         return -1;
       }
       dev->use_count++;
-      Mmsg2(&dev->errmsg, "WARNING!!!! device %s opened %d times!!!\n"
+      Mmsg2(&dev->errmsg, _("WARNING!!!! device %s opened %d times!!!\n")
            dev->dev_name, dev->use_count);
-      Emsg0(M_WARNING, 0, dev->errmsg);
+      Emsg1(M_WARNING, 0, "%s", dev->errmsg);
       return dev->fd;
    }
    if (VolName) {
@@ -201,41 +235,81 @@ 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);
-   if (dev->state & ST_TAPE) {
+   if (dev->state & (ST_TAPE|ST_FIFO)) {
+      int timeout;
       Dmsg0(29, "open_dev: device is tape\n");
-      if (mode == READ_WRITE) {
+      if (mode == OPEN_READ_WRITE) {
         dev->mode = O_RDWR | O_BINARY;
-      } else {
+      } else if (mode == OPEN_READ_ONLY) {
         dev->mode = O_RDONLY | O_BINARY;
+      } else if (mode == OPEN_WRITE_ONLY) {
+        dev->mode = O_WRONLY | O_BINARY;
+      } else {
+         Emsg0(M_ABORT, 0, _("Illegal mode given to open_dev.\n")); 
+      }
+      timeout = dev->max_open_wait;
+      errno = 0;
+      if (dev->state & ST_FIFO && timeout) {
+        /* Set open timer */
+        dev->tid = start_thread_timer(pthread_self(), timeout);
       }
-      if ((dev->fd = open(dev->dev_name, dev->mode, MODE_RW)) < 0) {
+      /* If busy retry each second for max_open_wait seconds */
+      while ((dev->fd = open(dev->dev_name, dev->mode, MODE_RW)) < 0) {
+        if (errno == EAGAIN) {
+           continue;
+        }
+        if (errno == EBUSY && timeout-- > 0) {
+            Dmsg2(100, "Device %s busy. ERR=%s\n", dev->dev_name, strerror(errno));
+           sleep(1);
+           continue;
+        }
         dev->dev_errno = errno;
-         Mmsg2(&dev->errmsg, "stored: unable to open device %s: ERR=%s\n"
+         Mmsg2(&dev->errmsg, _("stored: unable to open device %s: ERR=%s\n")
               dev->dev_name, strerror(dev->dev_errno));
+        /* Stop any open timer we set */
+        if (dev->tid) {
+           stop_thread_timer(dev->tid);
+           dev->tid = 0;
+        }
         Emsg0(M_FATAL, 0, dev->errmsg);
-      } else {
+        break;
+      }
+      if (dev->fd >= 0) {
         dev->dev_errno = 0;
         dev->state |= ST_OPENED;
         dev->use_count++;
         update_pos_dev(dev);             /* update position */
       }
+      /* Stop any open() timer we started */
+      if (dev->tid) {
+        stop_thread_timer(dev->tid);
+        dev->tid = 0;
+      }
       Dmsg1(29, "open_dev: tape %d opened\n", dev->fd);
    } else {
-      archive_name = (char *) get_pool_memory(PM_FNAME);
-      strcpy(archive_name, dev->dev_name);
+      /*
+       * Handle opening of file
+       */
+      archive_name = get_pool_memory(PM_FNAME);
+      pm_strcpy(&archive_name, dev->dev_name);
       if (archive_name[strlen(archive_name)] != '/') {
-         strcat(archive_name, "/");
+         pm_strcat(&archive_name, "/");
       }
-      strcat(archive_name, VolName);
+      pm_strcat(&archive_name, VolName);
       Dmsg1(29, "open_dev: device is disk %s\n", archive_name);
-      if (mode == READ_WRITE) {
+      if (mode == OPEN_READ_WRITE) {
         dev->mode = O_CREAT | O_RDWR | O_BINARY;
-      } else {
+      } else if (mode == OPEN_READ_ONLY) {
         dev->mode = O_RDONLY | O_BINARY;
+      } else if (mode == OPEN_WRITE_ONLY) {
+        dev->mode = O_WRONLY | O_BINARY;
+      } else {
+         Emsg0(M_ABORT, 0, _("Illegal mode given to open_dev.\n")); 
       }
-      if ((dev->fd = open(archive_name, dev->mode, MODE_RW)) < 0) {
+      /* If creating file, give 0640 permissions */
+      if ((dev->fd = open(archive_name, dev->mode, 0640)) < 0) {
         dev->dev_errno = errno;
-         Mmsg2(&dev->errmsg, "Could not open: %s, ERR=%s\n", archive_name, strerror(dev->dev_errno));
+         Mmsg2(&dev->errmsg, _("Could not open: %s, ERR=%s\n"), archive_name, strerror(dev->dev_errno));
         Emsg0(M_FATAL, 0, dev->errmsg);
       } else {
         dev->dev_errno = 0;
@@ -262,13 +336,14 @@ int rewind_dev(DEVICE *dev)
    Dmsg0(29, "rewind_dev\n");
    if (dev->fd < 0) {
       dev->dev_errno = EBADF;
-      Mmsg1(&dev->errmsg, "Bad call to rewind_dev. Device %s not open\n",
+      Mmsg1(&dev->errmsg, _("Bad call to rewind_dev. Device %s not open\n"),
            dev->dev_name);
-      Emsg0(M_ABORT, 0, dev->errmsg);
+      Emsg0(M_FATAL, 0, dev->errmsg);
       return 0;
    }
    dev->state &= ~(ST_APPEND|ST_READ|ST_EOT | ST_EOF | ST_WEOT);  /* remove EOF/EOT flags */
    dev->block_num = dev->file = 0;
+   dev->file_addr = 0;
    if (dev->state & ST_TAPE) {
       mt_com.mt_op = MTREW;
       mt_com.mt_count = 1;
@@ -287,16 +362,16 @@ int rewind_dev(DEVICE *dev)
               sleep(5);
               continue;
            }
-            Mmsg2(&dev->errmsg, "Rewind error on %s. ERR=%s.\n",
+            Mmsg2(&dev->errmsg, _("Rewind error on %s. ERR=%s.\n"),
               dev->dev_name, strerror(dev->dev_errno));
            return 0;
         }
         break;
       }
-   } else {
-      if (lseek(dev->fd, 0, SEEK_SET) < 0) {
+   } else if (dev->state & ST_FILE) {
+      if (lseek(dev->fd, (off_t)0, SEEK_SET) < 0) {
         dev->dev_errno = errno;
-         Mmsg2(&dev->errmsg, "lseek error on %s. ERR=%s.\n",
+         Mmsg2(&dev->errmsg, _("lseek error on %s. ERR=%s.\n"),
            dev->dev_name, strerror(dev->dev_errno));
         return 0;
       }
@@ -315,7 +390,7 @@ eod_dev(DEVICE *dev)
    struct mtop mt_com;
    struct mtget mt_stat;
    int stat = 0;
-   int32_t pos;
+   off_t pos;
 
    Dmsg0(29, "eod_dev\n");
    if (dev->state & ST_EOT) {
@@ -323,9 +398,14 @@ eod_dev(DEVICE *dev)
    }
    dev->state &= ~(ST_EOF);  /* remove EOF flags */
    dev->block_num = dev->file = 0;
+   dev->file_addr = 0;
+   if (dev->state & (ST_FIFO | ST_PROG)) {
+      return 1;
+   }
    if (!(dev->state & ST_TAPE)) {
-      pos = lseek(dev->fd, 0, SEEK_END);
-      if (pos > 0) {
+      pos = lseek(dev->fd, (off_t)0, SEEK_END);
+//    Dmsg1(000, "====== Seek to %lld\n", pos);
+      if (pos >= 0) {
         update_pos_dev(dev);
         dev->state |= ST_EOT;
         return 1;
@@ -339,13 +419,13 @@ eod_dev(DEVICE *dev)
          Dmsg1(50, "ioctl error: %s\n", strerror(dev->dev_errno));
         clrerror_dev(dev, mt_com.mt_op);
         update_pos_dev(dev);
-         Mmsg2(&dev->errmsg, "ioctl MTEOM error on %s. ERR=%s.\n",
+         Mmsg2(&dev->errmsg, _("ioctl MTEOM error on %s. ERR=%s.\n"),
            dev->dev_name, strerror(dev->dev_errno));
         return 0;
       }
       if (ioctl(dev->fd, MTIOCGET, (char *)&mt_stat) < 0) {
         dev->dev_errno = errno;
-         Mmsg2(&dev->errmsg, "ioctl MTIOCGET error on %s. ERR=%s.\n",
+         Mmsg2(&dev->errmsg, _("ioctl MTIOCGET error on %s. ERR=%s.\n"),
            dev->dev_name, strerror(dev->dev_errno));
         return 0;
       }
@@ -361,8 +441,8 @@ eod_dev(DEVICE *dev)
       }
       while (!(dev->state & ST_EOT)) {
          Dmsg0(200, "Do fsf 1\n");
-        if (fsf_dev(dev, 1) < 0) {
-            Dmsg0(200, "fsf_dev return < 0\n");
+        if (!fsf_dev(dev, 1)) {
+            Dmsg0(200, "fsf_dev error.\n");
            return 0;
         }
       }
@@ -373,52 +453,39 @@ eod_dev(DEVICE *dev)
 }
 
 /*
- * Set the position of the device.
+ * Set the position of the device -- only for files
+ *   For other devices, there is no generic way to do it.
  *  Returns: 1 on succes
  *          0 on error
  */
 int update_pos_dev(DEVICE *dev)
 {
-#ifdef xxxx
-   struct mtget mt_stat;
-#endif
-   int32_t pos;
+   off_t pos;
    int stat = 0;
 
    if (dev->fd < 0) {
       dev->dev_errno = EBADF;
-      Mmsg0(&dev->errmsg, "Bad device call. Archive not open\n");
+      Mmsg0(&dev->errmsg, _("Bad device call. Archive not open\n"));
       Emsg0(M_FATAL, 0, dev->errmsg);
       return 0;
    }
 
    /* Find out where we are */
-   if (!(dev->state & ST_TAPE)) {
+   if (dev->state & ST_FILE) {
       dev->file = 0;
-      pos = lseek(dev->fd, 0, SEEK_CUR);
+      dev->file_addr = 0;
+      pos = lseek(dev->fd, (off_t)0, SEEK_CUR);
       if (pos < 0) {
-         Dmsg1(200, "Seek error: ERR=%s\n", strerror(dev->dev_errno));
-        pos = 0;
+         Dmsg1(000, "Seek error: ERR=%s\n", strerror(dev->dev_errno));
         dev->dev_errno = errno;
-         Mmsg2(&dev->errmsg, "lseek error on %s. ERR=%s.\n",
+         Mmsg2(&dev->errmsg, _("lseek error on %s. ERR=%s.\n"),
            dev->dev_name, strerror(dev->dev_errno));
       } else {
         stat = 1;
+        dev->file_addr = pos;
       }
       return stat;
    }
-
-#ifdef REALLY_IMPLEMENTED
-   if (ioctl(dev->fd, MTIOCGET, (char *)&mt_stat) < 0) {
-      Dmsg1(50, "MTIOCGET error: %s\n", strerror(dev->dev_errno));
-      dev->dev_errno = errno;
-      Mmsg2(&dev->errmsg, "ioctl MTIOCGET error on %s. ERR=%s.\n",
-        dev->dev_name, strerror(dev->dev_errno));
-   } else {
-      stat = 1;
-   }
-   return stat;
-#endif
    return 1;
 }
 
@@ -453,7 +520,7 @@ status_dev(DEVICE *dev, uint32_t *status)
       Dmsg2(-20," file=%d block=%d\n", dev->file, dev->block_num);
       if (ioctl(dev->fd, MTIOCGET, (char *)&mt_stat) < 0) {
         dev->dev_errno = errno;
-         Mmsg2(&dev->errmsg, "ioctl MTIOCGET error on %s. ERR=%s.\n",
+         Mmsg2(&dev->errmsg, _("ioctl MTIOCGET error on %s. ERR=%s.\n"),
            dev->dev_name, strerror(dev->dev_errno));
         return 0;
       }
@@ -519,7 +586,7 @@ int load_dev(DEVICE *dev)
 
    if (dev->fd < 0) {
       dev->dev_errno = EBADF;
-      Mmsg0(&dev->errmsg, "Bad call to load_dev. Archive not open\n");
+      Mmsg0(&dev->errmsg, _("Bad call to load_dev. Archive not open\n"));
       Emsg0(M_FATAL, 0, dev->errmsg);
       return 0;
    }
@@ -529,17 +596,18 @@ int load_dev(DEVICE *dev)
 #ifndef MTLOAD
    Dmsg0(200, "stored: MTLOAD command not available\n");
    dev->dev_errno = ENOTTY;          /* function not available */
-   Mmsg2(&dev->errmsg, "ioctl MTLOAD error on %s. ERR=%s.\n",
+   Mmsg2(&dev->errmsg, _("ioctl MTLOAD error on %s. ERR=%s.\n"),
         dev->dev_name, strerror(dev->dev_errno));      return 0;
    return 0;
 #else
 
    dev->block_num = dev->file = 0;
+   dev->file_addr = 0;
    mt_com.mt_op = MTLOAD;
    mt_com.mt_count = 1;
    if (ioctl(dev->fd, MTIOCTOP, (char *)&mt_com) < 0) {
       dev->dev_errno = errno;
-      Mmsg2(&dev->errmsg, "ioctl MTLOAD error on %s. ERR=%s.\n",
+      Mmsg2(&dev->errmsg, _("ioctl MTLOAD error on %s. ERR=%s.\n"),
         dev->dev_name, strerror(dev->dev_errno));      return 0;
    }
    return 1;
@@ -557,7 +625,7 @@ int offline_dev(DEVICE *dev)
 
    if (dev->fd < 0) {
       dev->dev_errno = EBADF;
-      Mmsg0(&dev->errmsg, "Bad call to load_dev. Archive not open\n");
+      Mmsg0(&dev->errmsg, _("Bad call to load_dev. Archive not open\n"));
       Emsg0(M_FATAL, 0, dev->errmsg);
       return 0;
    }
@@ -566,42 +634,51 @@ int offline_dev(DEVICE *dev)
    }
 
    dev->block_num = dev->file = 0;
+   dev->file_addr = 0;
+#ifdef MTUNLOCK
+   mt_com.mt_op = MTUNLOCK;
+   mt_com.mt_count = 1;
+   ioctl(dev->fd, MTIOCTOP, (char *)&mt_com);
+#endif
    mt_com.mt_op = MTOFFL;
    mt_com.mt_count = 1;
    if (ioctl(dev->fd, MTIOCTOP, (char *)&mt_com) < 0) {
       dev->dev_errno = errno;
-      Mmsg2(&dev->errmsg, "ioctl MTOFFL error on %s. ERR=%s.\n",
+      Mmsg2(&dev->errmsg, _("ioctl MTOFFL error on %s. ERR=%s.\n"),
         dev->dev_name, strerror(dev->dev_errno));
       return 0;
    }
+   Dmsg1(100, "Offlined device %s\n", dev->dev_name);
    return 1;
 }
 
 
 /* 
  * Foward space a file 
+ *   Returns: 1 on success
+ *           0 on failure
  */
 int
 fsf_dev(DEVICE *dev, int num)
 { 
    struct mtop mt_com;
-   int stat;
+   int stat = 0;
    char rbuf[1024];
 
    if (dev->fd < 0) {
       dev->dev_errno = EBADF;
-      Mmsg0(&dev->errmsg, "Bad call to fsf_dev. Archive not open\n");
+      Mmsg0(&dev->errmsg, _("Bad call to fsf_dev. Archive not open\n"));
       Emsg0(M_FATAL, 0, dev->errmsg);
-      return -1;
+      return 0;
    }
 
    if (!(dev->state & ST_TAPE)) {
-      return 0;
+      return 1;
    }
    if (dev->state & ST_EOT) {
       dev->dev_errno = 0;
-      Mmsg1(&dev->errmsg, "Device %s at End of Tape.\n", dev->dev_name);
-      return -1;
+      Mmsg1(&dev->errmsg, _("Device %s at End of Tape.\n"), dev->dev_name);
+      return 0;
    }
    if (dev->state & ST_EOF)
       Dmsg0(200, "ST_EOF set on entry to FSF\n");
@@ -623,7 +700,7 @@ fsf_dev(DEVICE *dev, int num)
               dev->state |= ST_EOT;
               clrerror_dev(dev, -1);
                Dmsg1(200, "Set ST_EOT read error %d\n", dev->dev_errno);
-               Mmsg2(&dev->errmsg, "read error on %s. ERR=%s.\n",
+               Mmsg2(&dev->errmsg, _("read error on %s. ERR=%s.\n"),
                  dev->dev_name, strerror(dev->dev_errno));
                Dmsg1(200, "%s", dev->errmsg);
               break;
@@ -640,6 +717,7 @@ fsf_dev(DEVICE *dev, int num)
            } else {
               dev->state |= ST_EOF;
               dev->file++;
+              dev->file_addr = 0;
               continue;
            }
         } else {                        /* Got data */
@@ -652,13 +730,14 @@ fsf_dev(DEVICE *dev, int num)
            dev->state |= ST_EOT;
             Dmsg0(200, "Set ST_EOT\n");
            clrerror_dev(dev, MTFSF);
-            Mmsg2(&dev->errmsg, "ioctl MTFSF error on %s. ERR=%s.\n",
+            Mmsg2(&dev->errmsg, _("ioctl MTFSF error on %s. ERR=%s.\n"),
               dev->dev_name, strerror(dev->dev_errno));
             Dmsg0(200, "Got < 0 for MT_FSF\n");
             Dmsg1(200, "%s", dev->errmsg);
         } else {
            dev->state |= ST_EOF;     /* just read EOF */
            dev->file++;
+           dev->file_addr = 0;
         }   
       }
    
@@ -672,7 +751,7 @@ fsf_dev(DEVICE *dev, int num)
       }
       if (dev->state & ST_EOT) {
         dev->dev_errno = 0;
-         Mmsg1(&dev->errmsg, "Device %s at End of Tape.\n", dev->dev_name);
+         Mmsg1(&dev->errmsg, _("Device %s at End of Tape.\n"), dev->dev_name);
         stat = -1;
       } else {
         stat = 0;
@@ -685,7 +764,7 @@ fsf_dev(DEVICE *dev, int num)
    if (dev->state & ST_EOT)
       Dmsg0(200, "ST_EOT set on exit FSF\n");
    Dmsg1(200, "Return from FSF file=%d\n", dev->file);
-   return stat;
+   return stat == 0 ? 1 : 0;
 }
 
 /* 
@@ -699,7 +778,7 @@ bsf_dev(DEVICE *dev, int num)
 
    if (dev->fd < 0) {
       dev->dev_errno = EBADF;
-      Mmsg0(&dev->errmsg, "Bad call to fsf_dev. Archive not open\n");
+      Mmsg0(&dev->errmsg, _("Bad call to fsf_dev. Archive not open\n"));
       Emsg0(M_FATAL, 0, dev->errmsg);
       return -1;
    }
@@ -710,12 +789,13 @@ bsf_dev(DEVICE *dev, int num)
    Dmsg0(29, "bsf_dev\n");
    dev->state &= ~(ST_EOT|ST_EOF);
    dev->file -= num;
+   dev->file_addr = 0;
    mt_com.mt_op = MTBSF;
    mt_com.mt_count = num;
    stat = ioctl(dev->fd, MTIOCTOP, (char *)&mt_com);
    if (stat < 0) {
       clrerror_dev(dev, MTBSF);
-      Mmsg2(&dev->errmsg, "ioctl MTBSF error on %s. ERR=%s.\n",
+      Mmsg2(&dev->errmsg, _("ioctl MTBSF error on %s. ERR=%s.\n"),
         dev->dev_name, strerror(dev->dev_errno));
    }
    update_pos_dev(dev);
@@ -734,7 +814,7 @@ fsr_dev(DEVICE *dev, int num)
 
    if (dev->fd < 0) {
       dev->dev_errno = EBADF;
-      Mmsg0(&dev->errmsg, "Bad call to fsf_dev. Archive not open\n");
+      Mmsg0(&dev->errmsg, _("Bad call to fsf_dev. Archive not open\n"));
       Emsg0(M_FATAL, 0, dev->errmsg);
       return -1;
    }
@@ -755,9 +835,10 @@ fsr_dev(DEVICE *dev, int num)
       } else {
         dev->state |= ST_EOF;           /* assume EOF */
         dev->file++;
+        dev->file_addr = 0;
       }
       clrerror_dev(dev, MTFSR);
-      Mmsg2(&dev->errmsg, "ioctl MTFSR error on %s. ERR=%s.\n",
+      Mmsg2(&dev->errmsg, _("ioctl MTFSR error on %s. ERR=%s.\n"),
         dev->dev_name, strerror(dev->dev_errno));
    }
    update_pos_dev(dev);
@@ -766,6 +847,8 @@ fsr_dev(DEVICE *dev, int num)
 
 /* 
  * Backward space a record
+ *   Returns:  0 on success
+ *           -1 on failure
  */
 int
 bsr_dev(DEVICE *dev, int num)
@@ -775,7 +858,7 @@ bsr_dev(DEVICE *dev, int num)
 
    if (dev->fd < 0) {
       dev->dev_errno = EBADF;
-      Mmsg0(&dev->errmsg, "Bad call to fsf_dev. Archive not open\n");
+      Mmsg0(&dev->errmsg, _("Bad call to fsf_dev. Archive not open\n"));
       Emsg0(M_FATAL, 0, dev->errmsg);
       return -1;
    }
@@ -791,7 +874,7 @@ bsr_dev(DEVICE *dev, int num)
    stat = ioctl(dev->fd, MTIOCTOP, (char *)&mt_com);
    if (stat < 0) {
       clrerror_dev(dev, MTBSR);
-      Mmsg2(&dev->errmsg, "ioctl MTBSR error on %s. ERR=%s.\n",
+      Mmsg2(&dev->errmsg, _("ioctl MTBSR error on %s. ERR=%s.\n"),
         dev->dev_name, strerror(dev->dev_errno));
    }
    update_pos_dev(dev);
@@ -811,7 +894,7 @@ weof_dev(DEVICE *dev, int num)
 
    if (dev->fd < 0) {
       dev->dev_errno = EBADF;
-      Mmsg0(&dev->errmsg, "Bad call to fsf_dev. Archive not open\n");
+      Mmsg0(&dev->errmsg, _("Bad call to fsf_dev. Archive not open\n"));
       Emsg0(M_FATAL, 0, dev->errmsg);
       return -1;
    }
@@ -827,9 +910,10 @@ weof_dev(DEVICE *dev, int num)
    stat = ioctl(dev->fd, MTIOCTOP, (char *)&mt_com);
    if (stat == 0) {
       dev->file++;
+      dev->file_addr = 0;
    } else {
       clrerror_dev(dev, MTWEOF);
-      Mmsg2(&dev->errmsg, "ioctl MTWEOF error on %s. ERR=%s.\n",
+      Mmsg2(&dev->errmsg, _("ioctl MTWEOF error on %s. ERR=%s.\n"),
         dev->dev_name, strerror(dev->dev_errno));
    }
    return stat;
@@ -900,7 +984,7 @@ clrerror_dev(DEVICE *dev, int func)
       }
       if (msg != NULL) {
         dev->dev_errno = ENOSYS;
-         Mmsg1(&dev->errmsg, "This device does not support %s.\n", msg);
+         Mmsg1(&dev->errmsg, _("This device does not support %s.\n"), msg);
         Emsg0(M_ERROR, 0, dev->errmsg);
       }
    }
@@ -927,16 +1011,22 @@ int flush_dev(DEVICE *dev)
 
 static void do_close(DEVICE *dev)
 {
+
    Dmsg0(29, "really close_dev\n");
    close(dev->fd);
    /* 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->block_num = 0;
-   dev->file = 0;
-   dev->LastBlockNumWritten = 0;
+   dev->file = dev->block_num = 0;
+   dev->file_addr = 0;
+   dev->EndFile = dev->EndBlock = 0;
    memset(&dev->VolCatInfo, 0, sizeof(dev->VolCatInfo));
    memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
+   dev->use_count--;
+   if (dev->tid) {
+      stop_thread_timer(dev->tid);
+      dev->tid = 0;
+   }
 }
 
 /* 
@@ -946,7 +1036,7 @@ void
 close_dev(DEVICE *dev)
 {
    if (!dev) {
-      Mmsg0(&dev->errmsg, "Bad call to fsf_dev. Archive not open\n");
+      Mmsg0(&dev->errmsg, _("Bad call to fsf_dev. Archive not open\n"));
       Emsg0(M_FATAL, 0, dev->errmsg);
       return;
    }
@@ -954,20 +1044,34 @@ close_dev(DEVICE *dev)
       do_close(dev);
    } else {    
       Dmsg0(29, "close_dev but in use so leave open.\n");
+      dev->use_count--;
    }
-   dev->use_count--;
 }
 
+/*
+ * Used when unmounting the device
+ */
 void force_close_dev(DEVICE *dev)
 {
    if (!dev) {
-      Mmsg0(&dev->errmsg, "Bad call to fsf_dev. Archive not open\n");
+      Mmsg0(&dev->errmsg, _("Bad call to fsf_dev. Archive not open\n"));
       Emsg0(M_FATAL, 0, dev->errmsg);
       return;
    }
    Dmsg0(29, "really close_dev\n");
    do_close(dev);
-   dev->use_count--;
+}
+
+int truncate_dev(DEVICE *dev)
+{
+   if (dev->state & ST_TAPE) {
+      return 1;
+   }
+   if (ftruncate(dev->fd, 0) != 0) {
+      Mmsg1(&dev->errmsg, _("Unable to truncate device. ERR=%s\n"), strerror(errno));
+      return 0;
+   }
+   return 1;
 }
 
 int 
@@ -1008,11 +1112,11 @@ term_dev(DEVICE *dev)
 {
    if (!dev) {
       dev->dev_errno = EBADF;
-      Mmsg0(&dev->errmsg, "Bad call to fsf_dev. Archive not open\n");
+      Mmsg0(&dev->errmsg, _("Bad call to fsf_dev. Archive not open\n"));
       Emsg0(M_FATAL, 0, dev->errmsg);
       return;
    }
-   close_dev(dev);
+   do_close(dev);
    Dmsg0(29, "term_dev\n");
    if (dev->dev_name) {
       free_memory(dev->dev_name);
@@ -1029,3 +1133,41 @@ term_dev(DEVICE *dev)
       free_pool_memory((POOLMEM *)dev);
    }
 }
+
+
+/* To make following two functions more readable */
+
+#define attached_jcrs ((JCR *)(dev->attached_jcrs))
+
+void attach_jcr_to_device(DEVICE *dev, JCR *jcr)
+{
+   jcr->prev_dev = NULL;
+   jcr->next_dev = attached_jcrs;
+   if (attached_jcrs) {
+      attached_jcrs->prev_dev = jcr;
+   }
+   attached_jcrs = jcr;
+   Dmsg1(100, "Attached Job %s\n", jcr->Job);
+}
+
+void detach_jcr_from_device(DEVICE *dev, JCR *jcr)
+{
+   if (!jcr->prev_dev) {
+      attached_jcrs = jcr->next_dev;
+   } else {
+      jcr->prev_dev->next_dev = jcr->next_dev;
+   }
+   if (jcr->next_dev) {
+      jcr->next_dev->prev_dev = jcr->prev_dev; 
+   }
+   jcr->next_dev = jcr->prev_dev = NULL;
+   Dmsg1(100, "Detached Job %s\n", jcr->Job);
+}
+
+JCR *next_attached_jcr(DEVICE *dev, JCR *jcr)
+{
+   if (jcr == NULL) {
+      return attached_jcrs;
+   }
+   return jcr->next_dev;
+}