]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/stored/mount.c
Keep correct errno when FSF fails
[bacula/bacula] / bacula / src / stored / mount.c
index 93a3804dea0b4086b8b1be10ded99d3f5e23c6e0..f88867f3628b620c3184e109ab0a12436f6fa244 100644 (file)
@@ -1,16 +1,7 @@
-/*
- *
- *  Routines for handling mounting tapes for reading and for
- *    writing.
- *
- *   Kern Sibbald, August MMII
- *
- *   Version $Id$
- */
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2002-2006 Free Software Foundation Europe e.V.
+   Copyright (C) 2002-2007 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.
    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
    Switzerland, email:ftf@fsfeurope.org.
 */
+/*
+ *
+ *  Routines for handling mounting tapes for reading and for
+ *    writing.
+ *
+ *   Kern Sibbald, August MMII
+ *
+ *   Version $Id$
+ */
 
 #include "bacula.h"                   /* pull in global headers */
 #include "stored.h"                   /* pull in Storage Deamon headers */
 
 static void mark_volume_not_inchanger(DCR *dcr);
-static int try_autolabel(DCR *dcr);
+static int try_autolabel(DCR *dcr, bool opened);
 
 enum {
    try_next_vol = 1,
@@ -172,11 +172,15 @@ mount_next_vol:
    }
 
    /* Ensure the device is open */
-   if (dev_cap(dev, CAP_STREAM)) {
+   if (dev->has_cap(CAP_STREAM)) {
       mode = OPEN_WRITE_ONLY;
    } else {
       mode = OPEN_READ_WRITE;
    }
+   /* Try autolabel if enabled */
+   if (dev->open(dcr, mode) < 0) {
+      try_autolabel(dcr, false);      /* try to create a new volume label */
+   }
    while (dev->open(dcr, mode) < 0) {
       Dmsg1(150, "open_device failed: ERR=%s\n", dev->bstrerror());
       if ((dev->is_file() && dev->is_removable()) || dev->is_dvd()) {
@@ -196,7 +200,7 @@ mount_next_vol:
             dev->unmount(0);
          }
       }
-      if (try_autolabel(dcr) == try_read_vol) {
+      if (try_autolabel(dcr, false) == try_read_vol) {
          break;                       /* created a new volume label */
       }
       /* If DVD, ignore the error, very often you cannot open the device
@@ -243,6 +247,7 @@ read_volume:
       break;                    /* got a Volume */
    case VOL_NAME_ERROR:
       VOLUME_CAT_INFO dcrVolCatInfo, devVolCatInfo;
+      char VolumeName[MAX_NAME_LENGTH];
 
       /* If not removable, Volume is broken */
       if (!dev->is_removable()) {
@@ -268,6 +273,7 @@ read_volume:
       dcrVolCatInfo = dcr->VolCatInfo;      /* structure assignment */
       devVolCatInfo = dev->VolCatInfo;      /* structure assignment */
       /* Check if this is a valid Volume in the pool */
+      bstrncpy(VolumeName, dcr->VolumeName, sizeof(VolumeName));
       bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName));
       if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_WRITE)) {
          /* Restore desired volume name, note device info out of sync */
@@ -290,6 +296,7 @@ read_volume:
              jcr->dir_bsock->msg);
          ask = true;
          /* Restore saved DCR before continuing */
+         bstrncpy(dcr->VolumeName, VolumeName, sizeof(dcr->VolumeName));
          dcr->VolCatInfo = dcrVolCatInfo;  /* structure assignment */
          goto mount_next_vol;
       }
@@ -312,7 +319,7 @@ read_volume:
       }
       /* Fall through wanted */
    case VOL_NO_LABEL:
-      switch (try_autolabel(dcr)) {
+      switch (try_autolabel(dcr, true)) {
       case try_next_vol:
          goto mount_next_vol;
       case try_read_vol:
@@ -380,7 +387,7 @@ read_volume:
                  " part=%d size=%s\n"), dcr->VolumeName, 
                  dev->part, edit_uint64(dev->VolCatInfo.VolCatBytes,ed1));
          } else {
-            Jmsg(jcr, M_ERROR, 0, _("I cannot write on Volume \"%s\" because: "
+            Jmsg(jcr, M_ERROR, 0, _("Bacula cannot write on DVD Volume \"%s\" because: "
                  "The sizes do not match! Volume=%s Catalog=%s\n"),
                  dcr->VolumeName,
                  edit_uint64(dev->part_start + dev->part_size, ed1),
@@ -388,9 +395,7 @@ read_volume:
             mark_volume_in_error(dcr);
             goto mount_next_vol;
          }
-      }
-      /* *****FIXME**** we should do some checking for files too */
-      if (dev->is_tape()) {
+      } else if (dev->is_tape()) {
          /*
           * Check if we are positioned on the tape at the same place
           * that the database says we should be.
@@ -399,12 +404,29 @@ read_volume:
             Jmsg(jcr, M_INFO, 0, _("Ready to append to end of Volume \"%s\" at file=%d.\n"),
                  dcr->VolumeName, dev->get_file());
          } else {
-            Jmsg(jcr, M_ERROR, 0, _("I cannot write on Volume \"%s\" because:\n"
+            Jmsg(jcr, M_ERROR, 0, _("Bacula cannot write on tape Volume \"%s\" because:\n"
                  "The number of files mismatch! Volume=%u Catalog=%u\n"),
                  dcr->VolumeName, dev->get_file(), dev->VolCatInfo.VolCatFiles);
             mark_volume_in_error(dcr);
             goto mount_next_vol;
          }
+      } else if (dev->is_file()) {
+         char ed1[50], ed2[50];
+         boffset_t pos;
+         pos = dev->lseek(dcr, (boffset_t)0, SEEK_END);
+         if (dev->VolCatInfo.VolCatBytes == (uint64_t)pos) {
+            Jmsg(jcr, M_INFO, 0, _("Ready to append to end of Volume \"%s\""
+                 " size=%s\n"), dcr->VolumeName, 
+                 edit_uint64(dev->VolCatInfo.VolCatBytes, ed1));
+         } else {
+            Jmsg(jcr, M_ERROR, 0, _("Bacula cannot write on disk Volume \"%s\" because: "
+                 "The sizes do not match! Volume=%s Catalog=%s\n"),
+                 dcr->VolumeName,
+                 edit_uint64(pos, ed1),
+                 edit_uint64(dev->VolCatInfo.VolCatBytes, ed2));
+            mark_volume_in_error(dcr);
+            goto mount_next_vol;
+         }
       }
       dev->VolCatInfo.VolCatMounts++;      /* Update mounts */
       Dmsg1(150, "update volinfo mounts=%d\n", dev->VolCatInfo.VolCatMounts);
@@ -431,9 +453,9 @@ read_volume:
                  dcr->VolumeName, (unsigned int)dev->file_addr);
          }
          else {
-            Jmsg(jcr, M_ERROR, 0, _("I cannot write on Volume \"%s\" because:\n"
+            Jmsg(jcr, M_ERROR, 0, _("Bacula cannot write on Volume \"%s\" because:\n"
                                     "The EOD file address is wrong: Volume file address=%u != Catalog Endblock=%u(+1)\n"
-                                    "You probably removed DVD last part in spool directory.\n"),
+                                    "Perhaps You removed the DVD last part in spool directory.\n"),
                  dcr->VolumeName, (unsigned int)dev->file_addr, (unsigned int)dev->VolCatInfo.EndBlock);
             mark_volume_in_error(dcr);
             goto mount_next_vol;
@@ -461,10 +483,24 @@ read_volume:
  * As noted above, at this point dcr->VolCatInfo has what
  *   the Director wants and dev->VolCatInfo has info on the
  *   previous tape (or nothing).
+ *
+ * Return codes are:
+ *   try_next_vol        label failed, look for another volume
+ *   try_read_vol        labeled volume, now re-read the label
+ *   try_error           hard error (catalog update)
+ *   try_default         I couldn't do anything
  */
-static int try_autolabel(DCR *dcr)
+static int try_autolabel(DCR *dcr, bool opened)
 {
    DEVICE *dev = dcr->dev;
+
+   if (dev->poll && !dev->is_tape()) {
+      return try_default;       /* if polling, don't try to create new labels */
+   }
+   /* For a tape require it to be opened and read before labeling */
+   if (!opened && dev->is_tape()) {
+      return try_default;
+   }
    if (dev->has_cap(CAP_LABEL) && (dcr->VolCatInfo.VolCatBytes == 0 ||
          (!dev->is_tape() && strcmp(dcr->VolCatInfo.VolCatStatus,
                                 "Recycle") == 0))) {
@@ -473,7 +509,9 @@ static int try_autolabel(DCR *dcr)
       if (!write_new_volume_label_to_dev(dcr, dcr->VolumeName,
              dcr->pool_name, false, /* no relabel */ false /* defer DVD label */)) {
          Dmsg0(150, "!write_vol_label\n");
-         mark_volume_in_error(dcr);
+         if (opened) { 
+            mark_volume_in_error(dcr);
+         }
          return try_next_vol;
       }
       Dmsg0(150, "dir_update_vol_info. Set Append\n");
@@ -487,7 +525,7 @@ static int try_autolabel(DCR *dcr)
       return try_read_vol;   /* read label we just wrote */
    }
    if (!dev->has_cap(CAP_LABEL) && dcr->VolCatInfo.VolCatBytes == 0) {
-      Jmsg(dcr->jcr, M_INFO, 0, _("Warning device %s not configured to autolabel Volumes.\n"), 
+      Jmsg(dcr->jcr, M_WARNING, 0, _("Device %s not configured to autolabel Volumes.\n"), 
          dev->print_name());
    }
    /* If not removable, Volume is broken */
@@ -552,8 +590,7 @@ void release_volume(DCR *dcr)
    dev->EndBlock = dev->EndFile = 0;
    memset(&dev->VolCatInfo, 0, sizeof(dev->VolCatInfo));
    memset(&dcr->VolCatInfo, 0, sizeof(dcr->VolCatInfo));
-   free_volume(dev);
-   memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
+   dev->clear_volhdr();
    /* Force re-read of label */
    dev->clear_labeled();
    dev->clear_read();
@@ -561,7 +598,7 @@ void release_volume(DCR *dcr)
    dev->label_type = B_BACULA_LABEL;
    dcr->VolumeName[0] = 0;
 
-   if (dev->is_open() && (!dev->is_tape() || !dev_cap(dev, CAP_ALWAYSOPEN))) {
+   if (dev->is_open() && (!dev->is_tape() || !dev->has_cap(CAP_ALWAYSOPEN))) {
       dev->close();
    }
 
@@ -580,11 +617,11 @@ bool mount_next_read_volume(DCR *dcr)
 {
    DEVICE *dev = dcr->dev;
    JCR *jcr = dcr->jcr;
-   Dmsg2(90, "NumVolumes=%d CurVolume=%d\n", jcr->NumVolumes, jcr->CurVolume);
+   Dmsg2(90, "NumReadVolumes=%d CurReadVolume=%d\n", jcr->NumReadVolumes, jcr->CurReadVolume);
    /*
     * End Of Tape -- mount next Volume (if another specified)
     */
-   if (jcr->NumVolumes > 1 && jcr->CurVolume < jcr->NumVolumes) {
+   if (jcr->NumReadVolumes > 1 && jcr->CurReadVolume < jcr->NumReadVolumes) {
       dev->close();
       if (!acquire_device_for_read(dcr)) {
          Jmsg2(jcr, M_FATAL, 0, _("Cannot open Dev=%s, Vol=%s\n"), dev->print_name(),