]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/stored/dircmd.c
kes Apply the recycle patch from Richard Mortimer.
[bacula/bacula] / bacula / src / stored / dircmd.c
index 762e54ab49d1c13f891b370925a0f6454c15f8b9..f83263105b618a22451ed0ca75751f3ab17213d0 100644 (file)
@@ -8,7 +8,8 @@
  *
  *    N.B. in this file, in general we must use P(dev->mutex) rather
  *      than lock_device(dev) so that we can examine the blocked
  *
  *    N.B. in this file, in general we must use P(dev->mutex) rather
  *      than lock_device(dev) so that we can examine the blocked
- *      state rather than blocking ourselves. In some "safe" cases,
+ *      state rather than blocking ourselves because a Job
+ *      thread has the device blocked. In some "safe" cases,
  *      we can do things to a blocked device. CAREFUL!!!!
  *
  *    File daemon commands are handled in fdcmd.c
  *      we can do things to a blocked device. CAREFUL!!!!
  *
  *    File daemon commands are handled in fdcmd.c
  *
  */
 /*
  *
  */
 /*
-   Copyright (C) 2001-2005 Kern Sibbald
+   Copyright (C) 2001-2006 Kern Sibbald
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
-   version 2 as ammended with additional clauses defined in the
+   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,
    file LICENSE in the main source directory.
 
    This program is distributed in the hope that it will be useful,
@@ -42,9 +43,8 @@
 extern BSOCK *filed_chan;
 extern int r_first, r_last;
 extern struct s_res resources[];
 extern BSOCK *filed_chan;
 extern int r_first, r_last;
 extern struct s_res resources[];
-extern char my_name[];
-extern time_t daemon_start_time;
 extern struct s_last_job last_job;
 extern struct s_last_job last_job;
+extern bool init_done;
 
 /* Static variables */
 static char derrmsg[]     = "3900 Invalid command\n";
 
 /* Static variables */
 static char derrmsg[]     = "3900 Invalid command\n";
@@ -69,11 +69,12 @@ static bool setdebug_cmd(JCR *jcr);
 static bool cancel_cmd(JCR *cjcr);
 static bool mount_cmd(JCR *jcr);
 static bool unmount_cmd(JCR *jcr);
 static bool cancel_cmd(JCR *cjcr);
 static bool mount_cmd(JCR *jcr);
 static bool unmount_cmd(JCR *jcr);
-static bool autochanger_cmd(JCR *sjcr);
+static bool bootstrap_cmd(JCR *jcr);
+static bool changer_cmd(JCR *sjcr);
 static bool do_label(JCR *jcr, int relabel);
 static bool do_label(JCR *jcr, int relabel);
-static DEVICE *find_device(JCR *jcr, POOL_MEM &dev_name);
+static DCR *find_device(JCR *jcr, POOL_MEM &dev_name, int drive);
 static void read_volume_label(JCR *jcr, DEVICE *dev, int Slot);
 static void read_volume_label(JCR *jcr, DEVICE *dev, int Slot);
-static void label_volume_if_ok(JCR *jcr, DEVICE *dev, char *oldname,
+static void label_volume_if_ok(DCR *dcr, char *oldname,
                                char *newname, char *poolname,
                                int Slot, int relabel);
 static bool try_autoload_device(JCR *jcr, int slot, const char *VolName);
                                char *newname, char *poolname,
                                int Slot, int relabel);
 static bool try_autoload_device(JCR *jcr, int slot, const char *VolName);
@@ -90,7 +91,7 @@ struct s_cmds {
  */
 static struct s_cmds cmds[] = {
    {"JobId=",      job_cmd,         0},     /* start Job */
  */
 static struct s_cmds cmds[] = {
    {"JobId=",      job_cmd,         0},     /* start Job */
-   {"autochanger", autochanger_cmd, 0},
+   {"autochanger", changer_cmd,     0},
    {"bootstrap",   bootstrap_cmd,   0},
    {"cancel",      cancel_cmd,      0},
    {"label",       label_cmd,       0},     /* label a tape */
    {"bootstrap",   bootstrap_cmd,   0},
    {"cancel",      cancel_cmd,      0},
    {"label",       label_cmd,       0},     /* label a tape */
@@ -190,6 +191,10 @@ void *handle_connection_request(void *arg)
          break;               /* connection terminated */
       }
       Dmsg1(199, "<dird: %s\n", bs->msg);
          break;               /* connection terminated */
       }
       Dmsg1(199, "<dird: %s\n", bs->msg);
+      /* Ensure that device initialization is complete */
+      while (!init_done) {
+         bmicrosleep(1, 0);
+      }
       found = false;
       for (i=0; cmds[i].cmd; i++) {
         if (strncmp(cmds[i].cmd, bs->msg, strlen(cmds[i].cmd)) == 0) {
       found = false;
       for (i=0; cmds[i].cmd; i++) {
         if (strncmp(cmds[i].cmd, bs->msg, strlen(cmds[i].cmd)) == 0) {
@@ -202,7 +207,7 @@ void *handle_connection_request(void *arg)
            Dmsg1(200, "Do command: %s\n", cmds[i].cmd);
            if (!cmds[i].func(jcr)) { /* do command */
               quit = true; /* error, get out */
            Dmsg1(200, "Do command: %s\n", cmds[i].cmd);
            if (!cmds[i].func(jcr)) { /* do command */
               quit = true; /* error, get out */
-              Dmsg1(190, "Command %s requsts quit\n", cmds[i].cmd);
+              Dmsg1(190, "Command %s reqeusts quit\n", cmds[i].cmd);
            }
            found = true;             /* indicate command found */
            break;
            }
            found = true;             /* indicate command found */
            break;
@@ -232,7 +237,7 @@ static bool setdebug_cmd(JCR *jcr)
 
    Dmsg1(10, "setdebug_cmd: %s", dir->msg);
    if (sscanf(dir->msg, "setdebug=%d trace=%d", &level, &trace_flag) != 2 || level < 0) {
 
    Dmsg1(10, "setdebug_cmd: %s", dir->msg);
    if (sscanf(dir->msg, "setdebug=%d trace=%d", &level, &trace_flag) != 2 || level < 0) {
-      bnet_fsend(dir, "3991 Bad setdebug command: %s\n", dir->msg);
+      bnet_fsend(dir, _("3991 Bad setdebug command: %s\n"), dir->msg);
       return 0;
    }
    debug_level = level;
       return 0;
    }
    debug_level = level;
@@ -253,23 +258,28 @@ static bool cancel_cmd(JCR *cjcr)
 
    if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
       if (!(jcr=get_jcr_by_full_name(Job))) {
 
    if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
       if (!(jcr=get_jcr_by_full_name(Job))) {
-         bnet_fsend(dir, _("3902 Job %s not found.\n"), Job);
+         bnet_fsend(dir, _("3904 Job %s not found.\n"), Job);
       } else {
       } else {
-         P(jcr->mutex);
+         jcr->lock();
          oldStatus = jcr->JobStatus;
          set_jcr_job_status(jcr, JS_Canceled);
          if (!jcr->authenticated && oldStatus == JS_WaitFD) {
             pthread_cond_signal(&jcr->job_start_wait); /* wake waiting thread */
          }
          oldStatus = jcr->JobStatus;
          set_jcr_job_status(jcr, JS_Canceled);
          if (!jcr->authenticated && oldStatus == JS_WaitFD) {
             pthread_cond_signal(&jcr->job_start_wait); /* wake waiting thread */
          }
-         V(jcr->mutex);
+         jcr->unlock();
          if (jcr->file_bsock) {
             bnet_sig(jcr->file_bsock, BNET_TERMINATE);
          }
          /* If thread waiting on mount, wake him */
          if (jcr->dcr && jcr->dcr->dev && jcr->dcr->dev->waiting_for_mount()) {
          if (jcr->file_bsock) {
             bnet_sig(jcr->file_bsock, BNET_TERMINATE);
          }
          /* If thread waiting on mount, wake him */
          if (jcr->dcr && jcr->dcr->dev && jcr->dcr->dev->waiting_for_mount()) {
-             pthread_cond_signal(&jcr->dcr->dev->wait_next_vol);
-             pthread_cond_broadcast(&wait_device_release);
+            pthread_cond_broadcast(&jcr->dcr->dev->wait_next_vol);
+            pthread_cond_broadcast(&wait_device_release);
+         }
+         if (jcr->read_dcr && jcr->read_dcr->dev && jcr->read_dcr->dev->waiting_for_mount()) {
+            pthread_cond_broadcast(&jcr->read_dcr->dev->wait_next_vol);
+            pthread_cond_broadcast(&wait_device_release);
          }
          }
+         Jmsg(jcr, M_INFO, 0, _("Job marked to be canceled.\n"));
          bnet_fsend(dir, _("3000 Job %s marked to be canceled.\n"), jcr->Job);
          free_jcr(jcr);
       }
          bnet_fsend(dir, _("3000 Job %s marked to be canceled.\n"), jcr->Job);
          free_jcr(jcr);
       }
@@ -281,7 +291,7 @@ static bool cancel_cmd(JCR *cjcr)
 }
 
 /*
 }
 
 /*
- * Label a tape
+ * Label a Volume
  *
  */
 static bool label_cmd(JCR *jcr)
  *
  */
 static bool label_cmd(JCR *jcr)
@@ -299,23 +309,28 @@ static bool do_label(JCR *jcr, int relabel)
    POOLMEM *newname, *oldname, *poolname, *mtype;
    POOL_MEM dev_name;
    BSOCK *dir = jcr->dir_bsock;
    POOLMEM *newname, *oldname, *poolname, *mtype;
    POOL_MEM dev_name;
    BSOCK *dir = jcr->dir_bsock;
+   DCR *dcr;
    DEVICE *dev;
    bool ok = false;
    int slot;
    DEVICE *dev;
    bool ok = false;
    int slot;
+   int drive;
 
    newname = get_memory(dir->msglen+1);
    oldname = get_memory(dir->msglen+1);
    poolname = get_memory(dir->msglen+1);
    mtype = get_memory(dir->msglen+1);
    if (relabel) {
 
    newname = get_memory(dir->msglen+1);
    oldname = get_memory(dir->msglen+1);
    poolname = get_memory(dir->msglen+1);
    mtype = get_memory(dir->msglen+1);
    if (relabel) {
-      if (sscanf(dir->msg, "relabel %127s OldName=%127s NewName=%127s PoolName=%127s MediaType=%127s Slot=%d",
-          dev_name.c_str(), oldname, newname, poolname, mtype, &slot) == 6) {
+      if (sscanf(dir->msg, "relabel %127s OldName=%127s NewName=%127s PoolName=%127s "
+                 "MediaType=%127s Slot=%d drive=%d",
+                  dev_name.c_str(), oldname, newname, poolname, mtype, 
+                  &slot, &drive) == 7) {
          ok = true;
       }
    } else {
       *oldname = 0;
          ok = true;
       }
    } else {
       *oldname = 0;
-      if (sscanf(dir->msg, "label %127s VolumeName=%127s PoolName=%127s MediaType=%127s Slot=%d",
-          dev_name.c_str(), newname, poolname, mtype, &slot) == 5) {
+      if (sscanf(dir->msg, "label %127s VolumeName=%127s PoolName=%127s "
+                 "MediaType=%127s Slot=%d drive=%d", 
+          dev_name.c_str(), newname, poolname, mtype, &slot, &drive) == 6) {
          ok = true;
       }
    }
          ok = true;
       }
    }
@@ -324,24 +339,29 @@ static bool do_label(JCR *jcr, int relabel)
       unbash_spaces(oldname);
       unbash_spaces(poolname);
       unbash_spaces(mtype);
       unbash_spaces(oldname);
       unbash_spaces(poolname);
       unbash_spaces(mtype);
-      dev = find_device(jcr, dev_name);
-      if (dev) {
-         /******FIXME**** compare MediaTypes */
+      dcr = find_device(jcr, dev_name, drive);
+      if (dcr) {
+         dev = dcr->dev;
          P(dev->mutex);               /* Use P to avoid indefinite block */
          if (!dev->is_open()) {
          P(dev->mutex);               /* Use P to avoid indefinite block */
          if (!dev->is_open()) {
-            label_volume_if_ok(jcr, dev, oldname, newname, poolname, slot, relabel);
-            force_close_device(dev);
+            Dmsg1(400, "Can %slabel. Device is not open\n", relabel?"re":"");
+            label_volume_if_ok(dcr, oldname, newname, poolname, slot, relabel);
+            dev->close();
          /* Under certain "safe" conditions, we can steal the lock */
          } else if (dev->can_steal_lock()) {
          /* Under certain "safe" conditions, we can steal the lock */
          } else if (dev->can_steal_lock()) {
-            label_volume_if_ok(jcr, dev, oldname, newname, poolname, slot, relabel);
-         } else if (dev->is_busy()) {
+            Dmsg0(400, "Can relabel. can_steal_lock\n");
+            label_volume_if_ok(dcr, oldname, newname, poolname, slot, relabel);
+         } else if (dev->is_busy() || dev->is_blocked()) {
             send_dir_busy_message(dir, dev);
          } else {                     /* device not being used */
             send_dir_busy_message(dir, dev);
          } else {                     /* device not being used */
-            label_volume_if_ok(jcr, dev, oldname, newname, poolname, slot, relabel);
+            Dmsg0(400, "Can relabel. device not used\n");
+            label_volume_if_ok(dcr, oldname, newname, poolname, slot, relabel);
          }
          V(dev->mutex);
          }
          V(dev->mutex);
+         free_dcr(dcr);
+         jcr->dcr = NULL;
       } else {
       } else {
-         bnet_fsend(dir, _("3999 Device \"%s\" not found\n"), dev_name.c_str());
+         bnet_fsend(dir, _("3999 Device \"%s\" not found or could not be opened.\n"), dev_name.c_str());
       }
    } else {
       /* NB dir->msg gets clobbered in bnet_fsend, so save command */
       }
    } else {
       /* NB dir->msg gets clobbered in bnet_fsend, so save command */
@@ -362,29 +382,50 @@ static bool do_label(JCR *jcr, int relabel)
  *
  *  Enter with the mutex set
  */
  *
  *  Enter with the mutex set
  */
-static void label_volume_if_ok(JCR *jcr, DEVICE *dev, char *oldname,
+static void label_volume_if_ok(DCR *dcr, char *oldname,
                                char *newname, char *poolname,
                                int slot, int relabel)
 {
                                char *newname, char *poolname,
                                int slot, int relabel)
 {
-   BSOCK *dir = jcr->dir_bsock;
+   BSOCK *dir = dcr->jcr->dir_bsock;
    bsteal_lock_t hold;
    bsteal_lock_t hold;
-   DCR *dcr = jcr->dcr;
+   DEVICE *dev = dcr->dev;
    int label_status;
    int label_status;
+   int mode;
+   const char *volname = (relabel == 1) ? oldname : newname;
+   char ed1[50];
 
 
-   dcr->dev = dev;
    steal_device_lock(dev, &hold, BST_WRITING_LABEL);
    steal_device_lock(dev, &hold, BST_WRITING_LABEL);
+   Dmsg1(100, "Stole device %s lock, writing label.\n", dev->print_name());
+
 
 
-   if (!try_autoload_device(jcr, slot, newname)) {
+   Dmsg0(90, "try_autoload_device - looking for volume_info\n");
+   if (!try_autoload_device(dcr->jcr, slot, volname)) {
       goto bail_out;                  /* error */
    }
 
       goto bail_out;                  /* error */
    }
 
-   /* See what we have for a Volume */
-   if (dev->is_dvd()) {
-      label_status = read_dvd_volume_label(dcr, /*write*/true);
+   /* Ensure that the device is open -- autoload_device() closes it */
+   if (dev->is_tape()) {
+      mode = OPEN_READ_WRITE;
    } else {
    } else {
-      label_status = read_dev_volume_label(dcr);
+      mode = CREATE_READ_WRITE;
+   }
+
+   if (relabel) {
+      dev->truncating = true;         /* let open() know we will truncate it */
    }
    }
+   /* Set old volume name for open if relabeling */
+   bstrncpy(dcr->VolCatInfo.VolCatName, volname, sizeof(dcr->VolCatInfo.VolCatName));
+   if (dev->open(dcr, mode) < 0) {
+      bnet_fsend(dir, _("3910 Unable to open device %s: ERR=%s\n"),
+         dev->print_name(), dev->strerror());
+      goto bail_out;      
+   }
+
+   /* See what we have for a Volume */
+   label_status = read_dev_volume_label(dcr);
    
    
+   /* Set new volume name */
+   bstrncpy(dcr->VolCatInfo.VolCatName, newname, sizeof(dcr->VolCatInfo.VolCatName));
    switch(label_status) {
    case VOL_NAME_ERROR:
    case VOL_VERSION_ERROR:
    switch(label_status) {
    case VOL_NAME_ERROR:
    case VOL_VERSION_ERROR:
@@ -393,11 +434,12 @@ static void label_volume_if_ok(JCR *jcr, DEVICE *dev, char *oldname,
       if (!relabel) {
          bnet_fsend(dir, _(
             "3920 Cannot label Volume because it is already labeled: \"%s\"\n"),
       if (!relabel) {
          bnet_fsend(dir, _(
             "3920 Cannot label Volume because it is already labeled: \"%s\"\n"),
-             dev->VolHdr.VolName);
+             dev->VolHdr.VolumeName);
          break;
       }
          break;
       }
+
       /* Relabel request. If oldname matches, continue */
       /* Relabel request. If oldname matches, continue */
-      if (strcmp(oldname, dev->VolHdr.VolName) != 0) {
+      if (strcmp(oldname, dev->VolHdr.VolumeName) != 0) {
          bnet_fsend(dir, _("3921 Wrong volume mounted.\n"));
          break;
       }
          bnet_fsend(dir, _("3921 Wrong volume mounted.\n"));
          break;
       }
@@ -408,17 +450,19 @@ static void label_volume_if_ok(JCR *jcr, DEVICE *dev, char *oldname,
       /* Fall through wanted! */
    case VOL_IO_ERROR:
    case VOL_NO_LABEL:
       /* Fall through wanted! */
    case VOL_IO_ERROR:
    case VOL_NO_LABEL:
-      if (!write_new_volume_label_to_dev(dcr, newname, poolname)) {
-         bnet_fsend(dir, _("3912 Failed to label Volume: ERR=%s\n"), strerror_dev(dev));
+      if (!write_new_volume_label_to_dev(dcr, newname, poolname, 
+           relabel, true /* write dvd now */)) {
+         bnet_fsend(dir, _("3912 Failed to label Volume: ERR=%s\n"), dev->bstrerror());
          break;
       }
       bstrncpy(dcr->VolumeName, newname, sizeof(dcr->VolumeName));
       /* The following 3000 OK label. string is scanned in ua_label.c */
          break;
       }
       bstrncpy(dcr->VolumeName, newname, sizeof(dcr->VolumeName));
       /* The following 3000 OK label. string is scanned in ua_label.c */
-      bnet_fsend(dir, "3000 OK label. Volume=%s Device=%s\n",
-         newname, dev->print_name());
+      bnet_fsend(dir, "3000 OK label. VolBytes=%s DVD=%d Volume=\"%s\" Device=%s\n",
+                 edit_uint64(dev->VolCatInfo.VolCatBytes, ed1),
+                 dev->is_dvd()?1:0, newname, dev->print_name());
       break;
    case VOL_NO_MEDIA:
       break;
    case VOL_NO_MEDIA:
-      bnet_fsend(dir, _("3912 Failed to label Volume: ERR=%s\n"), strerror_dev(dev));
+      bnet_fsend(dir, _("3912 Failed to label Volume: ERR=%s\n"), dev->bstrerror());
       break;
    default:
       bnet_fsend(dir, _("3913 Cannot label Volume. "
       break;
    default:
       bnet_fsend(dir, _("3913 Cannot label Volume. "
@@ -427,6 +471,9 @@ static void label_volume_if_ok(JCR *jcr, DEVICE *dev, char *oldname,
    }
 
 bail_out:
    }
 
 bail_out:
+   if (!dev->is_open()) {
+      free_volume(dev);
+   }
    give_back_device_lock(dev, &hold);
    return;
 }
    give_back_device_lock(dev, &hold);
    return;
 }
@@ -451,7 +498,7 @@ static bool read_label(DCR *dcr)
    dev->clear_labeled();              /* force read of label */
    switch (read_dev_volume_label(dcr)) {
    case VOL_OK:
    dev->clear_labeled();              /* force read of label */
    switch (read_dev_volume_label(dcr)) {
    case VOL_OK:
-      bnet_fsend(dir, _("3001 Mounted Volume: %s\n"), dev->VolHdr.VolName);
+      bnet_fsend(dir, _("3001 Mounted Volume: %s\n"), dev->VolHdr.VolumeName);
       ok = true;
       break;
    default:
       ok = true;
       break;
    default:
@@ -464,14 +511,18 @@ static bool read_label(DCR *dcr)
    return ok;
 }
 
    return ok;
 }
 
-static DEVICE *find_device(JCR *jcr, POOL_MEM &devname)
+/* 
+ * Searches for device by name, and if found, creates a dcr and
+ *  returns it.
+ */
+static DCR *find_device(JCR *jcr, POOL_MEM &devname, int drive)
 {
    DEVRES *device;
    AUTOCHANGER *changer;
    bool found = false;
 {
    DEVRES *device;
    AUTOCHANGER *changer;
    bool found = false;
+   DCR *dcr = NULL;
 
    unbash_spaces(devname);
 
    unbash_spaces(devname);
-// LockRes();
    foreach_res(device, R_DEVICE) {
       /* Find resource, and make sure we were able to open it */
       if (fnmatch(device->hdr.name, devname.c_str(), 0) == 0) {
    foreach_res(device, R_DEVICE) {
       /* Find resource, and make sure we were able to open it */
       if (fnmatch(device->hdr.name, devname.c_str(), 0) == 0) {
@@ -489,41 +540,47 @@ static DEVICE *find_device(JCR *jcr, POOL_MEM &devname)
          break;
       }
    }
          break;
       }
    }
-   foreach_res(changer, R_AUTOCHANGER) {
-      /* Find resource, and make sure we were able to open it */
-      if (fnmatch(devname.c_str(), changer->hdr.name, 0) == 0) {
-         /* Try each device in this AutoChanger */
-         foreach_alist(device, changer->device) {
-            Dmsg1(100, "Try changer device %s\n", device->hdr.name);
-            if (!device->dev) {
-               device->dev = init_dev(jcr, device);
-            }
-            if (!device->dev) {
-               Dmsg1(100, "Device %s could not be opened. Skipped\n", devname.c_str());
-               Jmsg(jcr, M_WARNING, 0, _("\n"
-                  "     Device \"%s\" in changer \"%s\" requested by DIR could not be opened or does not exist.\n"),
-                    device->hdr.name, devname.c_str());
-               continue;
-            }
-            if (!device->dev->autoselect) {
-               continue;              /* device is not available */
+   if (!found) {
+      foreach_res(changer, R_AUTOCHANGER) {
+         /* Find resource, and make sure we were able to open it */
+         if (fnmatch(devname.c_str(), changer->hdr.name, 0) == 0) {
+            /* Try each device in this AutoChanger */
+            foreach_alist(device, changer->device) {
+               Dmsg1(100, "Try changer device %s\n", device->hdr.name);
+               if (!device->dev) {
+                  device->dev = init_dev(jcr, device);
+               }
+               if (!device->dev) {
+                  Dmsg1(100, "Device %s could not be opened. Skipped\n", devname.c_str());
+                  Jmsg(jcr, M_WARNING, 0, _("\n"
+                     "     Device \"%s\" in changer \"%s\" requested by DIR could not be opened or does not exist.\n"),
+                       device->hdr.name, devname.c_str());
+                  continue;
+               }
+               if (!device->dev->autoselect) {
+                  Dmsg1(100, "Device %s not autoselect skipped.\n", devname.c_str());
+                  continue;              /* device is not available */
+               }
+               if (drive < 0 || drive == (int)device->dev->drive_index) {
+                  Dmsg1(20, "Found changer device %s\n", device->hdr.name);
+                  found = true;
+                  break;
+               }
+               Dmsg3(100, "Device %s drive wrong: want=%d got=%d skipping\n",
+                  devname.c_str(), drive, (int)device->dev->drive_index);
             }
             }
-            Dmsg1(20, "Found changer device %s\n", device->hdr.name);
-            found = true;
-            break;
+            break;                    /* we found it but could not open a device */
          }
          }
-         break;                    /* we found it but could not open a device */
       }
    }
 
    if (found) {
       }
    }
 
    if (found) {
-      jcr->dcr = new_dcr(jcr, device->dev);
-//    UnlockRes();
-      jcr->dcr->device = device;
-      return jcr->dcr->dev;
+      Dmsg1(100, "Found device %s\n", device->hdr.name);
+      dcr = new_dcr(jcr, device->dev);
+      dcr->device = device;
+      jcr->dcr = dcr;
    }
    }
-// UnlockRes();
-   return NULL;
+   return dcr;
 }
 
 
 }
 
 
@@ -536,12 +593,21 @@ static bool mount_cmd(JCR *jcr)
    BSOCK *dir = jcr->dir_bsock;
    DEVICE *dev;
    DCR *dcr;
    BSOCK *dir = jcr->dir_bsock;
    DEVICE *dev;
    DCR *dcr;
-
-   if (sscanf(dir->msg, "mount %127s", devname.c_str()) == 1) {
-      dev = find_device(jcr, devname);
-      dcr = jcr->dcr;
-      if (dev) {
+   int drive;
+   int slot = 0;
+   bool ok;
+
+   ok = sscanf(dir->msg, "mount %127s drive=%d slot=%d", devname.c_str(), 
+               &drive, &slot) == 3;
+   if (!ok) {
+      ok = sscanf(dir->msg, "mount %127s drive=%d", devname.c_str(), &drive) == 2;
+   }
+   if (ok) {
+      dcr = find_device(jcr, devname, drive);
+      if (dcr) {
+         dev = dcr->dev;
          P(dev->mutex);               /* Use P to avoid indefinite block */
          P(dev->mutex);               /* Use P to avoid indefinite block */
+         Dmsg1(100, "mount cmd blocked=%d\n", dev->dev_blocked);
          switch (dev->dev_blocked) {         /* device blocked? */
          case BST_WAITING_FOR_SYSOP:
             /* Someone is waiting, wake him */
          switch (dev->dev_blocked) {         /* device blocked? */
          case BST_WAITING_FOR_SYSOP:
             /* Someone is waiting, wake him */
@@ -556,10 +622,18 @@ static bool mount_cmd(JCR *jcr)
          /* In both of these two cases, we (the user) unmounted the Volume */
          case BST_UNMOUNTED_WAITING_FOR_SYSOP:
          case BST_UNMOUNTED:
          /* In both of these two cases, we (the user) unmounted the Volume */
          case BST_UNMOUNTED_WAITING_FOR_SYSOP:
          case BST_UNMOUNTED:
+            if (dev->is_autochanger() && slot > 0) {
+               try_autoload_device(jcr, slot, "");
+            }
             /* We freed the device, so reopen it and wake any waiting threads */
             /* We freed the device, so reopen it and wake any waiting threads */
-            if (open_dev(dev, NULL, OPEN_READ_WRITE) < 0) {
+            if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
                bnet_fsend(dir, _("3901 open device failed: ERR=%s\n"),
                bnet_fsend(dir, _("3901 open device failed: ERR=%s\n"),
-                  strerror_dev(dev));
+                  dev->bstrerror());
+               if (dev->dev_blocked == BST_UNMOUNTED) {
+                  /* We blocked the device, so unblock it */
+                  Dmsg0(100, "Unmounted. Unblocking device\n");
+                  unblock_device(dev);
+               }
                break;
             }
             read_dev_volume_label(dcr);
                break;
             }
             read_dev_volume_label(dcr);
@@ -574,7 +648,7 @@ static bool mount_cmd(JCR *jcr)
             }
             if (dev->is_labeled()) {
                bnet_fsend(dir, _("3001 Device %s is mounted with Volume \"%s\"\n"),
             }
             if (dev->is_labeled()) {
                bnet_fsend(dir, _("3001 Device %s is mounted with Volume \"%s\"\n"),
-                  dev->print_name(), dev->VolHdr.VolName);
+                  dev->print_name(), dev->VolHdr.VolumeName);
             } else {
                bnet_fsend(dir, _("3905 Device %s open but no Bacula volume is mounted.\n"
                                  "If this is not a blank tape, try unmounting and remounting the Volume.\n"),
             } else {
                bnet_fsend(dir, _("3905 Device %s open but no Bacula volume is mounted.\n"
                                  "If this is not a blank tape, try unmounting and remounting the Volume.\n"),
@@ -585,7 +659,7 @@ static bool mount_cmd(JCR *jcr)
             break;
 
          case BST_DOING_ACQUIRE:
             break;
 
          case BST_DOING_ACQUIRE:
-            bnet_fsend(dir, _("3001 Device %s is mounted; doing acquire.\n"),
+            bnet_fsend(dir, _("3001 Device %s is doing acquire.\n"),
                        dev->print_name());
             break;
 
                        dev->print_name());
             break;
 
@@ -595,34 +669,43 @@ static bool mount_cmd(JCR *jcr)
             break;
 
          case BST_NOT_BLOCKED:
             break;
 
          case BST_NOT_BLOCKED:
+            if (dev->is_autochanger() && slot > 0) {
+               try_autoload_device(jcr, slot, "");
+            }
             if (dev->is_open()) {
                if (dev->is_labeled()) {
                   bnet_fsend(dir, _("3001 Device %s is mounted with Volume \"%s\"\n"),
             if (dev->is_open()) {
                if (dev->is_labeled()) {
                   bnet_fsend(dir, _("3001 Device %s is mounted with Volume \"%s\"\n"),
-                     dev->print_name(), dev->VolHdr.VolName);
+                     dev->print_name(), dev->VolHdr.VolumeName);
                } else {
                   bnet_fsend(dir, _("3905 Device %s open but no Bacula volume is mounted.\n"
                                  "If this is not a blank tape, try unmounting and remounting the Volume.\n"),
                              dev->print_name());
                }
                } else {
                   bnet_fsend(dir, _("3905 Device %s open but no Bacula volume is mounted.\n"
                                  "If this is not a blank tape, try unmounting and remounting the Volume.\n"),
                              dev->print_name());
                }
-            } else {
-               if (!dev->is_tape()) {
-                  /* Nothing to do */
-                  break;
-               }
-               if (open_dev(dev, NULL, OPEN_READ_WRITE) < 0) {
+            } else if (dev->is_tape()) {
+               if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
                   bnet_fsend(dir, _("3901 open device failed: ERR=%s\n"),
                   bnet_fsend(dir, _("3901 open device failed: ERR=%s\n"),
-                     strerror_dev(dev));
+                     dev->bstrerror());
                   break;
                }
                read_label(dcr);
                if (dev->is_labeled()) {
                   bnet_fsend(dir, _("3001 Device %s is already mounted with Volume \"%s\"\n"),
                   break;
                }
                read_label(dcr);
                if (dev->is_labeled()) {
                   bnet_fsend(dir, _("3001 Device %s is already mounted with Volume \"%s\"\n"),
-                     dev->print_name(), dev->VolHdr.VolName);
+                     dev->print_name(), dev->VolHdr.VolumeName);
                } else {
                   bnet_fsend(dir, _("3905 Device %s open but no Bacula volume is mounted.\n"
                                     "If this is not a blank tape, try unmounting and remounting the Volume.\n"),
                              dev->print_name());
                }
                } else {
                   bnet_fsend(dir, _("3905 Device %s open but no Bacula volume is mounted.\n"
                                     "If this is not a blank tape, try unmounting and remounting the Volume.\n"),
                              dev->print_name());
                }
+            } else if (dev->is_dvd()) {
+               if (mount_dvd(dev, 1)) {
+                  bnet_fsend(dir, _("3002 Device %s is mounted.\n"), 
+                     dev->print_name());
+               } else {
+                  bnet_fsend(dir, _("3907 %s"), dev->bstrerror());
+               } 
+            } else { /* must be file */
+               bnet_fsend(dir, _("3906 File device %s is always mounted.\n"),
+                  dev->print_name());
             }
             break;
 
             }
             break;
 
@@ -631,8 +714,10 @@ static bool mount_cmd(JCR *jcr)
             break;
          }
          V(dev->mutex);
             break;
          }
          V(dev->mutex);
+         free_dcr(dcr);
+         jcr->dcr = NULL;
       } else {
       } else {
-         bnet_fsend(dir, _("3999 Device \"%s\" not found\n"), devname.c_str());
+         bnet_fsend(dir, _("3999 Device \"%s\" not found or could not be opened.\n"), devname.c_str());
       }
    } else {
       pm_strcpy(jcr->errmsg, dir->msg);
       }
    } else {
       pm_strcpy(jcr->errmsg, dir->msg);
@@ -650,24 +735,43 @@ static bool unmount_cmd(JCR *jcr)
    POOL_MEM devname;
    BSOCK *dir = jcr->dir_bsock;
    DEVICE *dev;
    POOL_MEM devname;
    BSOCK *dir = jcr->dir_bsock;
    DEVICE *dev;
+   DCR *dcr;
+   int drive;
 
 
-   if (sscanf(dir->msg, "unmount %127s", devname.c_str()) == 1) {
-      dev = find_device(jcr, devname);
-      if (dev) {
+   if (sscanf(dir->msg, "unmount %127s drive=%d", devname.c_str(), &drive) == 2) {
+      dcr = find_device(jcr, devname, drive);
+      if (dcr) {
+         dev = dcr->dev;
          P(dev->mutex);               /* Use P to avoid indefinite block */
          if (!dev->is_open()) {
          P(dev->mutex);               /* Use P to avoid indefinite block */
          if (!dev->is_open()) {
-            Dmsg0(90, "Device already unmounted\n");
-            bnet_fsend(dir, _("3901 Device %s is already unmounted.\n"), 
-               dev->print_name());
-
+            if (!dev->is_busy()) {
+               unload_autochanger(jcr->dcr, -1);          
+            }
+            if (dev->is_dvd()) {
+               if (unmount_dvd(dev, 0)) {
+                  bnet_fsend(dir, _("3002 Device %s unmounted.\n"), 
+                     dev->print_name());
+               } else {
+                  bnet_fsend(dir, _("3907 %s"), dev->bstrerror());
+               } 
+            } else {
+               Dmsg0(90, "Device already unmounted\n");
+               bnet_fsend(dir, _("3901 Device %s is already unmounted.\n"), 
+                  dev->print_name());
+            }
          } else if (dev->dev_blocked == BST_WAITING_FOR_SYSOP) {
             Dmsg2(90, "%d waiter dev_block=%d. doing unmount\n", dev->num_waiting,
                dev->dev_blocked);
          } else if (dev->dev_blocked == BST_WAITING_FOR_SYSOP) {
             Dmsg2(90, "%d waiter dev_block=%d. doing unmount\n", dev->num_waiting,
                dev->dev_blocked);
-            offline_or_rewind_dev(dev);
-            force_close_device(dev);
-            dev->dev_blocked = BST_UNMOUNTED_WAITING_FOR_SYSOP;
-            bnet_fsend(dir, _("3001 Device %s unmounted.\n"), 
-               dev->print_name());
+            if (!unload_autochanger(jcr->dcr, -1)) {
+               dev->close();
+            }
+            if (dev->is_dvd() && !unmount_dvd(dev, 0)) {
+               bnet_fsend(dir, _("3907 %s"), dev->bstrerror());
+            } else {
+               dev->dev_blocked = BST_UNMOUNTED_WAITING_FOR_SYSOP;
+               bnet_fsend(dir, _("3001 Device %s unmounted.\n"), 
+                  dev->print_name());
+            }
 
          } else if (dev->dev_blocked == BST_DOING_ACQUIRE) {
             bnet_fsend(dir, _("3902 Device %s is busy in acquire.\n"), 
 
          } else if (dev->dev_blocked == BST_DOING_ACQUIRE) {
             bnet_fsend(dir, _("3902 Device %s is busy in acquire.\n"), 
@@ -689,14 +793,21 @@ static bool unmount_cmd(JCR *jcr)
             /*  block_device(dev, BST_UNMOUNTED); replace with 2 lines below */
             dev->dev_blocked = BST_UNMOUNTED;
             dev->no_wait_id = 0;
             /*  block_device(dev, BST_UNMOUNTED); replace with 2 lines below */
             dev->dev_blocked = BST_UNMOUNTED;
             dev->no_wait_id = 0;
-            offline_or_rewind_dev(dev);
-            force_close_device(dev);
-            bnet_fsend(dir, _("3002 Device %s unmounted.\n"), 
-               dev->print_name());
+            if (!unload_autochanger(jcr->dcr, -1)) {
+               dev->close();
+            }
+            if (dev->is_dvd() && !unmount_dvd(dev, 0)) {
+               bnet_fsend(dir, _("3907 %s"), dev->bstrerror());
+            } else {
+               bnet_fsend(dir, _("3002 Device %s unmounted.\n"), 
+                  dev->print_name());
+            }
          }
          V(dev->mutex);
          }
          V(dev->mutex);
+         free_dcr(dcr);
+         jcr->dcr = NULL;
       } else {
       } else {
-         bnet_fsend(dir, _("3999 Device \"%s\" not found\n"), devname.c_str());
+         bnet_fsend(dir, _("3999 Device \"%s\" not found or could not be opened.\n"), devname.c_str());
       }
    } else {
       /* NB dir->msg gets clobbered in bnet_fsend, so save command */
       }
    } else {
       /* NB dir->msg gets clobbered in bnet_fsend, so save command */
@@ -719,25 +830,28 @@ static bool release_cmd(JCR *jcr)
    POOL_MEM devname;
    BSOCK *dir = jcr->dir_bsock;
    DEVICE *dev;
    POOL_MEM devname;
    BSOCK *dir = jcr->dir_bsock;
    DEVICE *dev;
+   DCR *dcr;
+   int drive;
 
 
-   if (sscanf(dir->msg, "release %127s", devname.c_str()) == 1) {
-      dev = find_device(jcr, devname);
-      if (dev) {
+   if (sscanf(dir->msg, "release %127s drive=%d", devname.c_str(), &drive) == 2) {
+      dcr = find_device(jcr, devname, drive);
+      if (dcr) {
+         dev = dcr->dev;
          P(dev->mutex);               /* Use P to avoid indefinite block */
          if (!dev->is_open()) {
             Dmsg0(90, "Device already released\n");
          P(dev->mutex);               /* Use P to avoid indefinite block */
          if (!dev->is_open()) {
             Dmsg0(90, "Device already released\n");
-            bnet_fsend(dir, _("3911 Device %s already released.\n"), 
+            bnet_fsend(dir, _("3921 Device %s already released.\n"), 
                dev->print_name());
 
          } else if (dev->dev_blocked == BST_WAITING_FOR_SYSOP ||
                     dev->dev_blocked == BST_UNMOUNTED_WAITING_FOR_SYSOP) {
             Dmsg2(90, "%d waiter dev_block=%d. doing unmount\n", dev->num_waiting,
                dev->dev_blocked);
                dev->print_name());
 
          } else if (dev->dev_blocked == BST_WAITING_FOR_SYSOP ||
                     dev->dev_blocked == BST_UNMOUNTED_WAITING_FOR_SYSOP) {
             Dmsg2(90, "%d waiter dev_block=%d. doing unmount\n", dev->num_waiting,
                dev->dev_blocked);
-            bnet_fsend(dir, _("3912 Device %s waiting for mount.\n"), 
+            bnet_fsend(dir, _("3922 Device %s waiting for mount.\n"), 
                dev->print_name());
 
          } else if (dev->dev_blocked == BST_DOING_ACQUIRE) {
                dev->print_name());
 
          } else if (dev->dev_blocked == BST_DOING_ACQUIRE) {
-            bnet_fsend(dir, _("3913 Device %s is busy in acquire.\n"), 
+            bnet_fsend(dir, _("3923 Device %s is busy in acquire.\n"), 
                dev->print_name());
 
          } else if (dev->dev_blocked == BST_WRITING_LABEL) {
                dev->print_name());
 
          } else if (dev->dev_blocked == BST_WRITING_LABEL) {
@@ -749,28 +863,34 @@ static bool release_cmd(JCR *jcr)
          } else {                     /* device not being used */
             Dmsg0(90, "Device not in use, unmounting\n");
             release_volume(jcr->dcr);
          } else {                     /* device not being used */
             Dmsg0(90, "Device not in use, unmounting\n");
             release_volume(jcr->dcr);
-            bnet_fsend(dir, _("3012 Device %s released.\n"), 
+            bnet_fsend(dir, _("3022 Device %s released.\n"), 
                dev->print_name());
          }
          V(dev->mutex);
                dev->print_name());
          }
          V(dev->mutex);
+         free_dcr(dcr);
+         jcr->dcr = NULL;
       } else {
       } else {
-         bnet_fsend(dir, _("3999 Device \"%s\" not found\n"), devname.c_str());
+         bnet_fsend(dir, _("3999 Device \"%s\" not found or could not be opened.\n"), devname.c_str());
       }
    } else {
       /* NB dir->msg gets clobbered in bnet_fsend, so save command */
       pm_strcpy(jcr->errmsg, dir->msg);
       }
    } else {
       /* NB dir->msg gets clobbered in bnet_fsend, so save command */
       pm_strcpy(jcr->errmsg, dir->msg);
-      bnet_fsend(dir, _("3917 Error scanning release command: %s\n"), jcr->errmsg);
+      bnet_fsend(dir, _("3927 Error scanning release command: %s\n"), jcr->errmsg);
    }
    bnet_sig(dir, BNET_EOD);
    return true;
 }
 
 
    }
    bnet_sig(dir, BNET_EOD);
    return true;
 }
 
 
+static bool bootstrap_cmd(JCR *jcr)
+{
+   return get_bootstrap_file(jcr, jcr->dir_bsock);
+}
 
 /*
  * Autochanger command from Director
  */
 
 /*
  * Autochanger command from Director
  */
-static bool autochanger_cmd(JCR *jcr)
+static bool changer_cmd(JCR *jcr)
 {
    POOL_MEM devname;
    BSOCK *dir = jcr->dir_bsock;
 {
    POOL_MEM devname;
    BSOCK *dir = jcr->dir_bsock;
@@ -778,39 +898,47 @@ static bool autochanger_cmd(JCR *jcr)
    DCR *dcr;
    const char *cmd = NULL;
    bool ok = false;
    DCR *dcr;
    const char *cmd = NULL;
    bool ok = false;
+   /*
+    * A safe_cmd may call autochanger script but does not load/unload
+    *    slots so it can be done at the same time that the drive is open.
+    */
+   bool safe_cmd = false;
 
 
-   if (sscanf(dir->msg, "autochanger list %127s ", devname.c_str()) == 1) {
+   if (sscanf(dir->msg, "autochanger list %127s", devname.c_str()) == 1) {
       cmd = "list";
       cmd = "list";
-      ok = true;
-   } else if (sscanf(dir->msg, "autochanger slots %127s ", devname.c_str()) == 1) {
+      safe_cmd = ok = true;
+   } else if (sscanf(dir->msg, "autochanger slots %127s", devname.c_str()) == 1) {
       cmd = "slots";
       cmd = "slots";
-      ok = true;
+      safe_cmd = ok = true;
+   } else if (sscanf(dir->msg, "autochanger drives %127s", devname.c_str()) == 1) {
+      cmd = "drives";
+      safe_cmd = ok = true;
    }
    if (ok) {
    }
    if (ok) {
-      dev = find_device(jcr, devname);
-      dcr = jcr->dcr;
-      if (dev) {
+      dcr = find_device(jcr, devname, -1);
+      if (dcr) {
+         dev = dcr->dev;
          P(dev->mutex);               /* Use P to avoid indefinite block */
          P(dev->mutex);               /* Use P to avoid indefinite block */
-         if (!dev->is_tape()) {
+         if (!dev->device->changer_res) {
             bnet_fsend(dir, _("3995 Device %s is not an autochanger.\n"), 
                dev->print_name());
             bnet_fsend(dir, _("3995 Device %s is not an autochanger.\n"), 
                dev->print_name());
-         } else if (!dev->is_open()) {
-            autochanger_cmd(dcr, dir, cmd);
          /* Under certain "safe" conditions, we can steal the lock */
          /* Under certain "safe" conditions, we can steal the lock */
-         } else if (dev->can_steal_lock()) {
+         } else if (safe_cmd || !dev->is_open() || dev->can_steal_lock()) {
             autochanger_cmd(dcr, dir, cmd);
             autochanger_cmd(dcr, dir, cmd);
-         } else if (dev->is_busy()) {
+         } else if (dev->is_busy() || dev->is_blocked()) {
             send_dir_busy_message(dir, dev);
          } else {                     /* device not being used */
             autochanger_cmd(dcr, dir, cmd);
          }
          V(dev->mutex);
             send_dir_busy_message(dir, dev);
          } else {                     /* device not being used */
             autochanger_cmd(dcr, dir, cmd);
          }
          V(dev->mutex);
+         free_dcr(dcr);
+         jcr->dcr = NULL;
       } else {
       } else {
-         bnet_fsend(dir, _("3999 Device \"%s\" not found\n"), devname.c_str());
+         bnet_fsend(dir, _("3999 Device \"%s\" not found or could not be opened.\n"), devname.c_str());
       }
    } else {  /* error on scanf */
       pm_strcpy(jcr->errmsg, dir->msg);
       }
    } else {  /* error on scanf */
       pm_strcpy(jcr->errmsg, dir->msg);
-      bnet_fsend(dir, _("3908 Error scanning autocharger list/slots command: %s\n"),
+      bnet_fsend(dir, _("3908 Error scanning autocharger drives/list/slots command: %s\n"),
          jcr->errmsg);
    }
    bnet_sig(dir, BNET_EOD);
          jcr->errmsg);
    }
    bnet_sig(dir, BNET_EOD);
@@ -825,26 +953,32 @@ static bool readlabel_cmd(JCR *jcr)
    POOL_MEM devname;
    BSOCK *dir = jcr->dir_bsock;
    DEVICE *dev;
    POOL_MEM devname;
    BSOCK *dir = jcr->dir_bsock;
    DEVICE *dev;
+   DCR *dcr;
    int Slot;
    int Slot;
+   int drive;
 
 
-   if (sscanf(dir->msg, "readlabel %127s Slot=%d", devname.c_str(), &Slot) == 2) {
-      dev = find_device(jcr, devname);
-      if (dev) {
+   if (sscanf(dir->msg, "readlabel %127s Slot=%d drive=%d", devname.c_str(), 
+       &Slot, &drive) == 3) {
+      dcr = find_device(jcr, devname, drive);
+      if (dcr) {
+         dev = dcr->dev;
          P(dev->mutex);               /* Use P to avoid indefinite block */
          if (!dev->is_open()) {
             read_volume_label(jcr, dev, Slot);
          P(dev->mutex);               /* Use P to avoid indefinite block */
          if (!dev->is_open()) {
             read_volume_label(jcr, dev, Slot);
-            force_close_device(dev);
+            dev->close();
          /* Under certain "safe" conditions, we can steal the lock */
          } else if (dev->can_steal_lock()) {
             read_volume_label(jcr, dev, Slot);
          /* Under certain "safe" conditions, we can steal the lock */
          } else if (dev->can_steal_lock()) {
             read_volume_label(jcr, dev, Slot);
-         } else if (dev->is_busy()) {
+         } else if (dev->is_busy() || dev->is_blocked()) {
             send_dir_busy_message(dir, dev);
          } else {                     /* device not being used */
             read_volume_label(jcr, dev, Slot);
          }
          V(dev->mutex);
             send_dir_busy_message(dir, dev);
          } else {                     /* device not being used */
             read_volume_label(jcr, dev, Slot);
          }
          V(dev->mutex);
+         free_dcr(dcr);
+         jcr->dcr = NULL;
       } else {
       } else {
-         bnet_fsend(dir, _("3999 Device \"%s\" not found\n"), devname.c_str());
+         bnet_fsend(dir, _("3999 Device \"%s\" not found or could not be opened.\n"), devname.c_str());
       }
    } else {
       pm_strcpy(jcr->errmsg, dir->msg);
       }
    } else {
       pm_strcpy(jcr->errmsg, dir->msg);
@@ -854,6 +988,7 @@ static bool readlabel_cmd(JCR *jcr)
    return true;
 }
 
    return true;
 }
 
+
 /*
  * Read the tape label
  *
 /*
  * Read the tape label
  *
@@ -876,8 +1011,8 @@ static void read_volume_label(JCR *jcr, DEVICE *dev, int Slot)
    switch (read_dev_volume_label(dcr)) {
    case VOL_OK:
       /* DO NOT add quotes around the Volume name. It is scanned in the DIR */
    switch (read_dev_volume_label(dcr)) {
    case VOL_OK:
       /* DO NOT add quotes around the Volume name. It is scanned in the DIR */
-      bnet_fsend(dir, _("3001 Volume=%s Slot=%d\n"), dev->VolHdr.VolName, Slot);
-      Dmsg1(100, "Volume: %s\n", dev->VolHdr.VolName);
+      bnet_fsend(dir, _("3001 Volume=%s Slot=%d\n"), dev->VolHdr.VolumeName, Slot);
+      Dmsg1(100, "Volume: %s\n", dev->VolHdr.VolumeName);
       break;
    default:
       bnet_fsend(dir, _("3902 Cannot mount Volume on Storage Device %s because:\n%s"),
       break;
    default:
       bnet_fsend(dir, _("3902 Cannot mount Volume on Storage Device %s because:\n%s"),
@@ -894,7 +1029,6 @@ static bool try_autoload_device(JCR *jcr, int slot, const char *VolName)
 {
    DCR *dcr = jcr->dcr;
    BSOCK *dir = jcr->dir_bsock;
 {
    DCR *dcr = jcr->dcr;
    BSOCK *dir = jcr->dir_bsock;
-   DEVICE *dev = dcr->dev;
 
    bstrncpy(dcr->VolumeName, VolName, sizeof(dcr->VolumeName));
    dcr->VolCatInfo.Slot = slot;
 
    bstrncpy(dcr->VolumeName, VolName, sizeof(dcr->VolumeName));
    dcr->VolCatInfo.Slot = slot;
@@ -902,25 +1036,43 @@ static bool try_autoload_device(JCR *jcr, int slot, const char *VolName)
    if (autoload_device(dcr, 0, dir) < 0) {    /* autoload if possible */
       return false;
    }
    if (autoload_device(dcr, 0, dir) < 0) {    /* autoload if possible */
       return false;
    }
-
-   /* Ensure that the device is open -- autoload_device() closes it */
-   for ( ; !dev->is_open(); ) {
-      if (open_dev(dev, dcr->VolumeName, 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;
 }
 
 static void send_dir_busy_message(BSOCK *dir, DEVICE *dev)
 {
    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"),
+   if (dev->is_blocked()) {
+      switch (dev->dev_blocked) {
+      case BST_UNMOUNTED:
+         bnet_fsend(dir, _("3931 Device %s is BLOCKED. user unmounted.\n"),
+            dev->print_name());
+         break;
+      case BST_UNMOUNTED_WAITING_FOR_SYSOP:
+         bnet_fsend(dir, _("3932 Device %s is BLOCKED. user unmounted during wait for media/mount.\n"),
+             dev->print_name());
+         break;
+      case BST_WAITING_FOR_SYSOP:
+         bnet_fsend(dir, _("3933 Device %s is BLOCKED waiting for media.\n"),
+            dev->print_name());
+         break;
+      case BST_DOING_ACQUIRE:
+         bnet_fsend(dir, _("3934 Device %s is being initialized.\n"),
+            dev->print_name());
+         break;
+      case BST_WRITING_LABEL:
+         bnet_fsend(dir, _("3935 Device %s is blocked labeling a Volume.\n"),
+            dev->print_name());
+         break;
+      default:
+         bnet_fsend(dir, _("3935 Device %s is blocked for unknown reason.\n"),
+            dev->print_name());
+         break;
+      }
+   } else if (dev->can_read()) {
+       bnet_fsend(dir, _("3936 Device %s is busy reading.\n"),
                    dev->print_name());;
    } else {
                    dev->print_name());;
    } else {
-       bnet_fsend(dir, _("3912 Device %s is busy with %d writer(s).\n"),
+       bnet_fsend(dir, _("3937 Device %s is busy with %d writer(s).\n"),
           dev->print_name(), dev->num_writers);
    }
 }
           dev->print_name(), dev->num_writers);
    }
 }