]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/stored/autochanger.c
Fix bug #1891
[bacula/bacula] / bacula / src / stored / autochanger.c
index 792dfe3bcb9f91ff4344b8566fdc214b6f1a42ca..653b6502ca9a4b55eec81ec86c3ea260d17fc99b 100644 (file)
@@ -1,12 +1,12 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2002-2008 Free Software Foundation Europe e.V.
+   Copyright (C) 2002-2011 Free Software Foundation Europe e.V.
 
    The main author of Bacula is Kern Sibbald, with contributions from
    many others, a complete list can be found in the file AUTHORS.
    This program is Free Software; you can redistribute it and/or
-   modify it under the terms of version two of the GNU General Public
+   modify it under the terms of version three of the GNU Affero General Public
    License as published by the Free Software Foundation and included
    in the file LICENSE.
 
@@ -15,7 +15,7 @@
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Affero General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
@@ -31,7 +31,6 @@
  *
  *   Kern Sibbald, August MMII
  *                            
- *   Version $Id$
  */
 
 #include "bacula.h"                   /* pull in global headers */
@@ -130,7 +129,7 @@ int autoload_device(DCR *dcr, int writing, BSOCK *dir)
 
    slot = dcr->VolCatInfo.InChanger ? dcr->VolCatInfo.Slot : 0;
    Dmsg3(100, "autoload: slot=%d InChgr=%d Vol=%s\n", dcr->VolCatInfo.Slot,
-         dcr->VolCatInfo.InChanger, dcr->VolCatInfo.VolCatName);
+         dcr->VolCatInfo.InChanger, dcr->getVolCatName());
    /*
     * Handle autoloaders here.  If we cannot autoload it, we
     *  will return 0 so that the sysop will be asked to load it.
@@ -150,17 +149,26 @@ int autoload_device(DCR *dcr, int writing, BSOCK *dir)
 
    changer = get_pool_memory(PM_FNAME);
    if (slot <= 0) {
-      Jmsg(jcr, M_INFO, 0, _("Invalid slot=%d defined in catalog for Volume \"%s\" "
-           "on %s. Manual load may be required.\n"), slot, dcr->VolCatInfo.VolCatName,
-           dev->print_name());
+      /* Suppress info when polling */
+      if (!dev->poll) {
+         Jmsg(jcr, M_INFO, 0, _("No slot defined in catalog (slot=%d) for Volume \"%s\" on %s.\n"), 
+              slot, dcr->getVolCatName(), dev->print_name());
+         Jmsg(jcr, M_INFO, 0, _("Cartridge change or \"update slots\" may be required.\n"));
+      }
       rtn_stat = 0;
    } else if (!dcr->device->changer_name) {
-      Jmsg(jcr, M_INFO, 0, _("No \"Changer Device\" for %s. Manual load of Volume may be required.\n"),
-           dev->print_name());
+      /* Suppress info when polling */
+      if (!dev->poll) {
+         Jmsg(jcr, M_INFO, 0, _("No \"Changer Device\" for %s. Manual load of Volume may be required.\n"),
+              dev->print_name());
+      }
       rtn_stat = 0;
   } else if (!dcr->device->changer_command) {
-      Jmsg(jcr, M_INFO, 0, _("No \"Changer Command\" for %s. Manual load of Volume may be requird.\n"),
-           dev->print_name());
+      /* Suppress info when polling */
+      if (!dev->poll) {
+         Jmsg(jcr, M_INFO, 0, _("No \"Changer Command\" for %s. Manual load of Volume may be requird.\n"),
+              dev->print_name());
+      }
       rtn_stat = 0;
   } else {
       /* Attempt to load the Volume */
@@ -267,8 +275,11 @@ int get_autochanger_loaded_slot(DCR *dcr)
    /* Find out what is loaded, zero means device is unloaded */
    changer = get_pool_memory(PM_FNAME);
    lock_changer(dcr);
-   Jmsg(jcr, M_INFO, 0, _("3301 Issuing autochanger \"loaded? drive %d\" command.\n"),
-        drive);
+   /* Suppress info when polling */
+   if (!dev->poll) {
+      Jmsg(jcr, M_INFO, 0, _("3301 Issuing autochanger \"loaded? drive %d\" command.\n"),
+           drive);
+   }
    changer = edit_device_codes(dcr, changer, dcr->device->changer_command, "loaded");
    Dmsg1(100, "Run program=%s\n", changer);
    status = run_program_full_output(changer, timeout, results.addr());
@@ -276,13 +287,23 @@ int get_autochanger_loaded_slot(DCR *dcr)
    if (status == 0) {
       loaded = str_to_int32(results.c_str());
       if (loaded > 0) {
-         Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded? drive %d\", result is Slot %d.\n"),
-              drive, loaded);
+         /* Suppress info when polling */
+         if (!dev->poll) {
+            Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded? drive %d\", result is Slot %d.\n"),
+                 drive, loaded);
+         }
          dev->set_slot(loaded);
       } else {
-         Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded? drive %d\", result: nothing loaded.\n"),
-              drive);
-         dev->clear_slot();   /* unknown */
+         /* Suppress info when polling */
+         if (!dev->poll) {
+            Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded? drive %d\", result: nothing loaded.\n"),
+                 drive);
+         }
+         if (loaded == 0) {      /* no slot loaded */
+            dev->set_slot(0);
+         } else {                /* probably some error */
+            dev->clear_slot();   /* unknown */
+         }
       }
    } else {
       berrno be;
@@ -300,8 +321,13 @@ static void lock_changer(DCR *dcr)
 {
    AUTOCHANGER *changer_res = dcr->device->changer_res;
    if (changer_res) {
+      int errstat;
       Dmsg1(200, "Locking changer %s\n", changer_res->hdr.name);
-      P(changer_res->changer_mutex);  /* Lock changer script */
+      if ((errstat=rwl_writelock(&changer_res->changer_lock)) != 0) {
+         berrno be;
+         Jmsg(dcr->jcr, M_ERROR_TERM, 0, _("Lock failure on autochanger. ERR=%s\n"),
+              be.bstrerror(errstat));
+      }
    }
 }
 
@@ -309,8 +335,13 @@ static void unlock_changer(DCR *dcr)
 {
    AUTOCHANGER *changer_res = dcr->device->changer_res;
    if (changer_res) {
+      int errstat;
       Dmsg1(200, "Unlocking changer %s\n", changer_res->hdr.name);
-      V(changer_res->changer_mutex);  /* Unlock changer script */
+      if ((errstat=rwl_writeunlock(&changer_res->changer_lock)) != 0) {
+         berrno be;
+         Jmsg(dcr->jcr, M_ERROR_TERM, 0, _("Unlock failure on autochanger. ERR=%s\n"),
+              be.bstrerror(errstat));
+      }
    }
 }
 
@@ -343,6 +374,7 @@ bool unload_autochanger(DCR *dcr, int loaded)
       return true;
    }
 
+   lock_changer(dcr);
    if (loaded < 0) {
       loaded = get_autochanger_loaded_slot(dcr);
    }
@@ -350,7 +382,6 @@ bool unload_autochanger(DCR *dcr, int loaded)
    if (loaded > 0) {
       POOL_MEM results(PM_MESSAGE);
       POOLMEM *changer = get_pool_memory(PM_FNAME);
-      lock_changer(dcr);
       Jmsg(jcr, M_INFO, 0,
            _("3307 Issuing autochanger \"unload slot %d, drive %d\" command.\n"),
            loaded, dev->drive_index);
@@ -373,11 +404,15 @@ bool unload_autochanger(DCR *dcr, int loaded)
       } else {
          dev->set_slot(0);         /* nothing loaded */
       }
-      unlock_changer(dcr);
 
-      free_volume(dev);            /* Free any volume associated with this drive */
       free_pool_memory(changer);
    }
+   unlock_changer(dcr);
+
+   if (loaded > 0) {           /* free_volume outside from changer lock */
+      free_volume(dev);        /* Free any volume associated with this drive */
+   }
+
    if (ok) {
       dev->clear_unload();
    }
@@ -390,6 +425,7 @@ bool unload_autochanger(DCR *dcr, int loaded)
 static bool unload_other_drive(DCR *dcr, int slot)
 {
    DEVICE *dev = NULL;
+   DEVICE *dev_save;
    bool found = false;
    AUTOCHANGER *changer = dcr->dev->device->changer_res;
    DEVRES *device;
@@ -402,16 +438,35 @@ static bool unload_other_drive(DCR *dcr, int slot)
       return true;
    }
 
+   /*
+    * We look for the slot number corresponding to the tape
+    *   we want in other drives, and if possible, unload
+    *   it.
+    */
+   Dmsg0(100, "Wiffle through devices looking for slot\n");
    foreach_alist(device, changer->device) {
-      if (device->dev && device->dev->get_slot() == slot) {
+      dev = device->dev;
+      if (!dev) {
+         continue;
+      }
+      dev_save = dcr->dev;
+      dcr->dev = dev;
+      if (dev->get_slot() <= 0 && get_autochanger_loaded_slot(dcr) <= 0) {
+         dcr->dev = dev_save;
+         continue;
+      }
+      dcr->dev = dev_save;
+      if (dev->get_slot() == slot) {
          found = true;
-         dev = device->dev;
          break;
       }
    }
    if (!found) {
+      Dmsg1(100, "Slot=%d not found in another device\n", slot);
       return true;
-   }
+   } else {
+      Dmsg1(100, "Slot=%d found in another device\n", slot);
+   }   
 
    /* The Volume we want is on another device. */
    if (dev->is_busy()) {
@@ -457,14 +512,21 @@ bool unload_dev(DCR *dcr, DEVICE *dev)
    save_dev = dcr->dev;               /* save dcr device */
    dcr->dev = dev;                    /* temporarily point dcr at other device */
 
-   if (dev->get_slot() <= 0 && get_autochanger_loaded_slot(dcr) <= 0) {
+   /* Update slot if not set or not always_open */
+   if (dev->get_slot() <= 0 || !dev->has_cap(CAP_ALWAYSOPEN)) {
+      get_autochanger_loaded_slot(dcr);
+   }
+
+   /* Fail if we have no slot to unload */
+   if (dev->get_slot() <= 0) {
       dcr->dev = save_dev;
       return false;
    }
+   
    save_slot = dcr->VolCatInfo.Slot;
    dcr->VolCatInfo.Slot = dev->get_slot();
 
-   dev->dlock();
+//   dev->dlock();
 
    POOLMEM *changer_cmd = get_pool_memory(PM_FNAME);
    POOL_MEM results(PM_MESSAGE);
@@ -488,7 +550,7 @@ bool unload_dev(DCR *dcr, DEVICE *dev)
    if (stat != 0) {
       berrno be;
       be.set_errno(stat);
-      Jmsg(jcr, M_INFO, 0, _("3995 Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n"),
+      Jmsg(jcr, M_INFO, 0, _("3997 Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n"),
               dev->get_slot(), dev->drive_index, be.bstrerror());
 
       Dmsg3(100, "Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n",
@@ -504,7 +566,7 @@ bool unload_dev(DCR *dcr, DEVICE *dev)
    }
    unlock_changer(dcr);
 
-   dev->dunlock();
+//   dev->dunlock();
 
    free_volume(dev);               /* Free any volume associated with this drive */
    free_pool_memory(changer_cmd);
@@ -525,7 +587,6 @@ bool autochanger_cmd(DCR *dcr, BSOCK *dir, const char *cmd)
    POOLMEM *changer;
    BPIPE *bpipe;
    int len = sizeof_pool_memory(dir->msg) - 1;
-   bool ok = false;
    int stat;
 
    if (!dev->is_autochanger() || !dcr->device->changer_name ||
@@ -558,7 +619,7 @@ bool autochanger_cmd(DCR *dcr, BSOCK *dir, const char *cmd)
    bpipe = open_bpipe(changer, timeout, "r");
    if (!bpipe) {
       dir->fsend(_("3996 Open bpipe failed.\n"));
-      goto bail_out;
+      goto bail_out;            /* TODO: check if we need to return false */
    }
    if (bstrcmp(cmd, "list") || bstrcmp(cmd, "listall")) {
       /* Get output from changer */
@@ -586,8 +647,6 @@ bool autochanger_cmd(DCR *dcr, BSOCK *dir, const char *cmd)
       be.set_errno(stat);
       dir->fsend(_("Autochanger error: ERR=%s\n"), be.bstrerror());
    }
-   bnet_sig(dir, BNET_EOD);
-   ok = true;
 
 bail_out:
    unlock_changer(dcr);
@@ -654,7 +713,15 @@ char *edit_device_codes(DCR *dcr, char *omsg, const char *imsg, const char *cmd)
             str = dcr->jcr->Job;
             break;
          case 'v':
-            str = NPRT(dcr->VolumeName);
+            if (dcr->VolCatInfo.VolCatName[0]) {
+               str = dcr->VolCatInfo.VolCatName;
+            } else if (dcr->VolumeName[0]) {
+               str = dcr->VolumeName;
+            } else if (dcr->dev->vol && dcr->dev->vol->vol_name) {
+               str = dcr->dev->vol->vol_name;
+            } else {
+               str = dcr->dev->VolHdr.VolumeName;
+            }
             break;
          case 'f':
             str = NPRT(dcr->jcr->client_name);