* On either an I/O error or end of tape,
  * we will stop writing on the physical device (no I/O recovery is
  * attempted at least in this daemon). The state flag will be sent
- * to include ST_EOT, which is ephimeral, and ST_WEOT, which is
+ * to include ST_EOT, which is ephemeral, and ST_WEOT, which is
  * persistent. Lots of routines clear ST_EOT, but ST_WEOT is
  * cleared only when the problem goes away.  Now when ST_WEOT
  * is set all calls to write_block_to_device() call the fix_up
    /*
     * Handle opening of DVD Volume
     */     
-   Dmsg3(29, "Enter: open_dvd_dev: %s dev=%s mode=%s\n", is_dvd()?"DVD":"disk",
-         archive_name.c_str(), mode_to_str(omode));
+   Dmsg2(29, "Enter: open_dvd_dev: DVD vol=%s mode=%s\n", 
+         &dcr->VolCatInfo, mode_to_str(omode));
 
    /*
     * For a DVD we must always pull the state info from dcr->VolCatInfo
     *   OPEN_READ_ONLY as writing would be an error.
     */
    Dmsg2(29, "open DVD part=%d num_dvd_parts=%d\n", part, num_dvd_parts);
+   /* Now find the name of the part that we want to access */
    if (part <= num_dvd_parts) {
       omode = OPEN_READ_ONLY;
       make_mounted_dvd_filename(this, archive_name);
    Dmsg3(99, "open_dvd_device: part=%d num_dvd_parts=%d, VolCatInfo.VolCatParts=%d\n",
       part, num_dvd_parts, dcr->VolCatInfo.VolCatParts);
      
-   if (mount_dvd(this, 1)) {
+   if (mount(1)) {
       Dmsg0(99, "DVD device mounted.\n");
       if (num_dvd_parts == 0 && !truncating) {
          /*
          if (!check_can_write_on_non_blank_dvd(dcr)) {
             Mmsg(errmsg, _("The DVD in device %s contains data, please blank it before writing.\n"), print_name());
             Emsg0(M_FATAL, 0, errmsg);
-            unmount_dvd(this, 1); /* Unmount the device, so the operator can change it. */
+            unmount(1); /* Unmount the device, so the operator can change it. */
             clear_opened();
             return;
          }
          blank_dvd = true;
+      } else {
+         /*
+          * Ensure that we have the correct DVD loaded by looking for part1.
+          * We only succeed the open if it exists. Failure to do this could
+          * leave us trying to add a part to a different DVD!
+          */
+         uint32_t oldpart = part;
+         struct stat statp;
+         POOL_MEM part1_name(PM_FNAME);
+         part = 1;
+         make_mounted_dvd_filename(this, part1_name);
+         part = oldpart;
+         if (stat(part1_name.c_str(), &statp) < 0) {
+            berrno be;
+            Mmsg(errmsg, _("Unable to stat DVD part 1 file %s: ERR=%s\n"),
+               part1_name.c_str(), be.strerror());
+            Emsg0(M_FATAL, 0, errmsg);
+            clear_opened();
+            return;
+         }
+         if (!S_ISREG(statp.st_mode)) {
+            /* It is not a regular file */
+            Mmsg(errmsg, _("DVD part 1 is not a regular file %s.\n"),
+               part1_name.c_str());
+            Emsg0(M_FATAL, 0, errmsg);
+            clear_opened();
+            return;
+         }
       }
    } else {
       Dmsg0(99, "DVD device mount failed.\n");
       /* We cannot mount the device */
       if (num_dvd_parts == 0) {
          /* Run free space, check there is a media. */
-         if (!update_free_space_dev(this)) {
+         if (!update_freespace()) {
             Emsg0(M_FATAL, 0, errmsg);
             clear_opened();
             return;
  */
 bool DEVICE::unmount(int timeout) 
 {
-   Dmsg0(90, "Enter unmount_dvd\n");
+   Dmsg0(90, "Enter unmount\n");
    if (is_mounted()) {
       return do_mount(0, timeout);
    }
       icmd = device->unmount_command;
    }
    
+   clear_freespace_ok();
    edit_mount_codes(ocmd, icmd);
    
-   Dmsg2(100, "do_mount_dvd: cmd=%s mounted=%d\n", ocmd.c_str(), !!is_mounted());
+   Dmsg2(100, "do_mount: cmd=%s mounted=%d\n", ocmd.c_str(), !!is_mounted());
 
    if (dotimeout) {
       /* Try at most 1 time to (un)mount the device. This should perhaps be configurable. */
    } else {
       timeout = 0;
    }
-   results = get_memory(2000);
+   results = get_memory(4000);
    results[0] = 0;
 
    /* If busy retry each second */
    while ((status = run_program_full_output(ocmd.c_str(), 
                        max_open_wait/2, results)) != 0) {
       /* Doesn't work with internationalization (This is not a problem) */
-      if (fnmatch("*is already mounted on", results, 0) == 0) {
+      if (mount && fnmatch("*is already mounted on*", results, 0) == 0) {
+         break;
+      }
+      if (!mount && fnmatch("* not mounted*", results, 0) == 0) {
          break;
       }
       if (timeout-- > 0) {
          bmicrosleep(1, 0);
          continue;
       }
-      Dmsg2(40, "Device %s cannot be mounted. ERR=%s\n", print_name(), results);
-      Mmsg(errmsg, _("Device %s cannot be mounted. ERR=%s\n"), 
-           print_name(), results);
+      if (status != 0) {
+         berrno be;
+         Dmsg5(40, "Device %s cannot be %smounted. stat=%d result=%s ERR=%s\n", print_name(),
+              (mount ? "" : "un"), status, results, be.strerror(status));
+         Mmsg(errmsg, _("Device %s cannot be %smounted. ERR=%s\n"), 
+              print_name(), (mount ? "" : "un"), be.strerror(status));
+      } else {
+         Dmsg4(40, "Device %s cannot be %smounted. stat=%d ERR=%s\n", print_name(),
+              (mount ? "" : "un"), status, results);
+         Mmsg(errmsg, _("Device %s cannot be %smounted. ERR=%s\n"), 
+              print_name(), (mount ? "" : "un"), results);
+      }
       /*
        * Now, just to be sure it is not mounted, try to read the
        *  filesystem.
       Dmsg1(29, "do_mount: got %d files in the mount point (not counting ., .. and .keep)\n", count);
       
       if (count > 0) {
-         mount = 1;                      /* If we got more than ., .. and .keep */
-         break;                          /*   there must be something mounted */
+         /* If we got more than ., .. and .keep */
+         /*   there must be something mounted */
+         if (mount) {
+            Dmsg1(100, "Did Mount by count=%d\n", count);
+            break;
+         } else {
+            /* An unmount request. We failed to unmount - report an error */
+            set_mounted(true);
+            free_pool_memory(results);
+            Dmsg0(200, "== error mount=1 wanted unmount\n");
+            return false;
+         }
       }
 get_out:
       set_mounted(false);
    
    set_mounted(mount);              /* set/clear mounted flag */
    free_pool_memory(results);
+   /* Do not check free space when unmounting */
+   if (mount && !update_freespace()) {
+      return false;
+   }
    Dmsg1(200, "============ mount=%d\n", mount);
    return true;
 }
 
 #include "stored.h"
 
 /* Forward referenced functions */
-static bool do_mount_dvd(DEVICE* dev, int mount, int dotimeout);
 static void add_file_and_part_name(DEVICE *dev, POOL_MEM &archive_name);
 
 /* 
                   archive_name.c_str(), dev->part);
 }  
 
-/* Mount the device.
- * If timeout, wait until the mount command returns 0.
- * If !timeout, try to mount the device only once.
- */
-bool mount_dvd(DEVICE* dev, int timeout) 
-{
-   Dmsg0(90, "Enter mount_dvd\n");
-   if (dev->is_mounted()) {
-      return true;
-   } else if (dev->requires_mount()) {
-      return do_mount_dvd(dev, 1, timeout);
-   }       
-   return true;
-}
-
-/* Unmount the device
- * If timeout, wait until the unmount command returns 0.
- * If !timeout, try to unmount the device only once.
- */
-bool unmount_dvd(DEVICE *dev, int timeout) 
-{
-   if (!dev->is_dvd()) {
-      return true;
-   }
-   Dmsg0(90, "Enter unmount_dvd\n");
-   if (dev->is_mounted()) {
-      return do_mount_dvd(dev, 0, timeout);
-   }
-   return true;
-}
-
-/* (Un)mount the device */
-static bool do_mount_dvd(DEVICE* dev, int mount, int dotimeout) 
-{
-   POOL_MEM ocmd(PM_FNAME);
-   POOLMEM *results;
-   char *icmd;
-   int status, timeout;
-   
-   sm_check(__FILE__, __LINE__, false);
-   if (mount) {
-      if (dev->is_mounted()) {
-         Dmsg0(200, "======= DVD mount=1\n");
-         return true;
-      }
-      icmd = dev->device->mount_command;
-   } else {
-      if (!dev->is_mounted()) {
-         Dmsg0(200, "======= DVD mount=0\n");
-         return true;
-      }
-      icmd = dev->device->unmount_command;
-   }
-   
-   dev->clear_freespace_ok();
-   dev->edit_mount_codes(ocmd, icmd);
-   
-   Dmsg2(200, "do_mount_dvd: cmd=%s mounted=%d\n", ocmd.c_str(), !!dev->is_mounted());
-
-   if (dotimeout) {
-      /* Try at most 1 time to (un)mount the device. This should perhaps be configurable. */
-      timeout = 1;
-   } else {
-      timeout = 0;
-   }
-   results = get_memory(2000);
-   results[0] = 0;
-   /* If busy retry each second */
-   Dmsg1(20, "Run mount prog=%s\n", ocmd.c_str());
-   while ((status = run_program_full_output(ocmd.c_str(), 
-                       dev->max_open_wait/2, results)) != 0) {
-      Dmsg2(20, "Mount status=%d result=%s\n", status, results);
-      /* Doesn't work with internationalization (This is not a problem) */
-      if (mount && fnmatch("*is already mounted on*", results, 0) == 0) {
-         break;
-      }
-      if (!mount && fnmatch("* not mounted*", results, 0) == 0) {
-         break;
-      }
-      if (timeout-- > 0) {
-         /* Sometimes the device cannot be mounted because it is already mounted.
-          * Try to unmount it, then remount it */
-         if (mount) {
-            Dmsg1(400, "Trying to unmount the device %s...\n", dev->print_name());
-            do_mount_dvd(dev, 0, 0);
-         }
-         bmicrosleep(1, 0);
-         continue;
-      }
-      if (status != 0) {
-         berrno be;
-         Dmsg5(40, "Device %s cannot be %smounted. stat=%d result=%s ERR=%s\n", dev->print_name(),
-              (mount ? "" : "un"), status, results, be.strerror(status));
-         Mmsg(dev->errmsg, _("Device %s cannot be %smounted. ERR=%s\n"), 
-              dev->print_name(), (mount ? "" : "un"), be.strerror(status));
-      } else {
-         Dmsg4(40, "Device %s cannot be %smounted. stat=%d ERR=%s\n", dev->print_name(),
-              (mount ? "" : "un"), status, results);
-         Mmsg(dev->errmsg, _("Device %s cannot be %smounted. ERR=%s\n"), 
-              dev->print_name(), (mount ? "" : "un"), results);
-      }
-      /*
-       * Now, just to be sure it is not mounted, try to read the
-       *  filesystem.
-       */
-      DIR* dp;
-      struct dirent *entry, *result;
-      int name_max;
-      int count;
-      
-      name_max = pathconf(".", _PC_NAME_MAX);
-      if (name_max < 1024) {
-         name_max = 1024;
-      }
-         
-      if (!(dp = opendir(dev->device->mount_point))) {
-         berrno be;
-         dev->dev_errno = errno;
-         Dmsg3(29, "do_mount_dvd: failed to open dir %s (dev=%s), ERR=%s\n", 
-               dev->device->mount_point, dev->print_name(), be.strerror());
-         goto get_out;
-      }
-      
-      entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
-      count = 0;
-      while (1) {
-         if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
-            dev->dev_errno = EIO;
-            Dmsg2(129, "do_mount_dvd: failed to find suitable file in dir %s (dev=%s)\n", 
-                  dev->device->mount_point, dev->print_name());
-            break;
-         }
-         if (strcmp(result->d_name, ".") && strcmp(result->d_name, "..") && 
-             strcmp(result->d_name, ".keep")) {
-            count++; /* result->d_name != ., .. or .keep (Gentoo-specific) */
-            Dmsg1(100, "Inc count=%d\n", count);
-            break;
-         } else {
-            Dmsg2(129, "do_mount_dvd: ignoring %s in %s\n", 
-                  result->d_name, dev->device->mount_point);
-         }
-      }
-      free(entry);
-      closedir(dp);
-      
-      Dmsg1(29, "do_mount_dvd: got %d files in the mount point (not counting ., .. and .keep)\n", count);
-      
-      if (count > 0) {
-         /* If we got more than ., .. and .keep */
-         /*   there must be something mounted */
-         if (mount) {
-            Dmsg1(100, "Did Mount by count=%d\n", count);
-            break;
-         } else {
-            /* An unmount request. We failed to unmount - report an error */
-            dev->set_mounted(true);
-            free_pool_memory(results);
-            Dmsg0(200, "== DVD mount=1\n");
-            return false;
-         }
-      }
-get_out:
-      dev->set_mounted(false);
-      sm_check(__FILE__, __LINE__, false);
-      free_pool_memory(results);
-      Dmsg0(200, "== DVD mount=0\n");
-      return false;
-   }
-   Dmsg0(100, "Out of mount/umount loop\n");
-   
-   dev->set_mounted(mount);              /* set/clear mounted flag */
-   free_pool_memory(results);
-   /* Do not check free space when unmounting */
-   if (mount) {
-      Dmsg0(100, "Calling update_free_space\n");
-      if (!update_free_space_dev(dev)) {
-         return false;
-      }
-   }
-   Dmsg1(200, "== DVD mount=%d\n", mount);
-   return true;
-}
-
 /* Update the free space on the device */
-bool update_free_space_dev(DEVICE* dev) 
+bool DEVICE::update_freespace() 
 {
    POOL_MEM ocmd(PM_FNAME);
    POOLMEM* results;
    bool ok = false;
    int status;
 
-   if (!dev->is_dvd() || dev->is_freespace_ok()) {
+   if (!is_dvd() || is_freespace_ok()) {
       return true;
    }
    
    /* The device must be mounted in order to dvd-freespace to work */
-   mount_dvd(dev, 1);
+   mount(1);
    
    sm_check(__FILE__, __LINE__, false);
-   icmd = dev->device->free_space_command;
+   icmd = device->free_space_command;
    
    if (!icmd) {
-      dev->free_space = 0;
-      dev->free_space_errno = 0;
-      dev->clear_freespace_ok();              /* No valid freespace */
-      dev->clear_media();
+      free_space = 0;
+      free_space_errno = 0;
+      clear_freespace_ok();              /* No valid freespace */
+      clear_media();
       Dmsg2(29, "ERROR: update_free_space_dev: free_space=%s, free_space_errno=%d (!icmd)\n", 
-            edit_uint64(dev->free_space, ed1), dev->free_space_errno);
-      Mmsg(dev->errmsg, _("No FreeSpace command defined.\n"));
+            edit_uint64(free_space, ed1), free_space_errno);
+      Mmsg(errmsg, _("No FreeSpace command defined.\n"));
       return false;
    }
    
-   dev->edit_mount_codes(ocmd, icmd);
+   edit_mount_codes(ocmd, icmd);
    
-   Dmsg1(29, "update_free_space_dev: cmd=%s\n", ocmd.c_str());
+   Dmsg1(29, "update_freespace: cmd=%s\n", ocmd.c_str());
 
    results = get_pool_memory(PM_MESSAGE);
    
    while (1) {
       berrno be;
       Dmsg1(20, "Run freespace prog=%s\n", ocmd.c_str());
-      status = run_program_full_output(ocmd.c_str(), dev->max_open_wait/2, results);
+      status = run_program_full_output(ocmd.c_str(), max_open_wait/2, results);
       Dmsg2(500, "Freespace status=%d result=%s\n", status, results);
       if (status == 0) {
          free = str_to_int64(results);
          Dmsg1(400, "Free space program run: Freespace=%s\n", results);
          if (free >= 0) {
-            dev->free_space = free;
-            dev->free_space_errno = 0;
-            dev->set_freespace_ok();     /* have valid freespace */
-            dev->set_media();
-            Mmsg(dev->errmsg, "");
+            free_space = free;
+            free_space_errno = 0;
+            set_freespace_ok();     /* have valid freespace */
+            set_media();
+            Mmsg(errmsg, "");
             ok = true;
             break;
          }
       }
-      dev->free_space = 0;
-      dev->free_space_errno = EPIPE;
-      dev->clear_freespace_ok();         /* no valid freespace */
-      Mmsg2(dev->errmsg, _("Cannot run free space command. Results=%s ERR=%s\n"), 
+      free_space = 0;
+      free_space_errno = EPIPE;
+      clear_freespace_ok();         /* no valid freespace */
+      Mmsg2(errmsg, _("Cannot run free space command. Results=%s ERR=%s\n"), 
             results, be.strerror(status));
       
       if (--timeout > 0) {
          Dmsg4(40, "Cannot get free space on device %s. free_space=%s, "
-            "free_space_errno=%d ERR=%s\n", dev->print_name(), 
-               edit_uint64(dev->free_space, ed1), dev->free_space_errno, 
-               dev->errmsg);
+            "free_space_errno=%d ERR=%s\n", print_name(), 
+               edit_uint64(free_space, ed1), free_space_errno, 
+               errmsg);
          bmicrosleep(1, 0);
          continue;
       }
 
-      dev->dev_errno = dev->free_space_errno;
+      dev_errno = free_space_errno;
       Dmsg4(40, "Cannot get free space on device %s. free_space=%s, "
          "free_space_errno=%d ERR=%s\n",
-            dev->print_name(), edit_uint64(dev->free_space, ed1),
-            dev->free_space_errno, dev->errmsg);
+            print_name(), edit_uint64(free_space, ed1),
+            free_space_errno, errmsg);
       break;
    }
    
    free_pool_memory(results);
-   Dmsg4(29, "leave update_free_space_dev: free_space=%s freespace_ok=%d free_space_errno=%d have_media=%d\n", 
-      edit_uint64(dev->free_space, ed1), !!dev->is_freespace_ok(), dev->free_space_errno, !!dev->have_media());
+   Dmsg4(29, "leave update_freespace: free_space=%s freespace_ok=%d free_space_errno=%d have_media=%d\n", 
+      edit_uint64(free_space, ed1), !!is_freespace_ok(), free_space_errno, !!have_media());
    sm_check(__FILE__, __LINE__, false);
    return ok;
 }
    
    /* growisofs umounted the device, so remount it (it will update the free space) */
    dev->clear_mounted();
-   mount_dvd(dev, 1);
+   dev->mount(1);
    Jmsg(dcr->jcr, M_INFO, 0, _("Remaining free space %s on %s\n"), 
       edit_uint64_with_commas(dev->free_space, ed1), dev->print_name());
    sm_check(__FILE__, __LINE__, false);
    dev->clear_freespace_ok();             /* need to update freespace */
    dev->close_part(dcr);
 
-   if (!unmount_dvd(dev, 1)) {
+   if (!dev->unmount(1)) {
       Dmsg0(400, "truncate_dvd: Failed to unmount DVD\n");
       return false;
    }