- detect and use unused loop device for mounting ISO images
authorJan Kupec <jkupec@suse.cz>
Wed, 8 Oct 2008 14:24:19 +0000 (14:24 +0000)
committerJan Kupec <jkupec@suse.cz>
Wed, 8 Oct 2008 14:24:19 +0000 (14:24 +0000)
  (bnc #428009)

zypp/media/MediaException.cc
zypp/media/MediaException.h
zypp/media/MediaHandler.cc
zypp/media/MediaISO.cc
zypp/media/MediaISO.h

index e169b27..029867d 100644 (file)
@@ -266,6 +266,14 @@ namespace zypp
         return str << form(_(" SSL certificate problem, verify that the CA cert is OK for '%s'."), _url.c_str()) << endl;
       return str << _msg << endl;
     }
+
+    std::ostream & MediaNoLoopDeviceException::dumpOn( std::ostream & str ) const
+    {
+      if (msg().empty())
+        return str << form(_("Cannot find available loop device to mount the image file from '%s'"), _url.c_str()) << endl;
+      return str << msg() << endl;
+    }
+
   /////////////////////////////////////////////////////////////////
   } // namespace media
 } // namespace zypp
index 39d6b32..0388f9e 100644 (file)
@@ -594,6 +594,28 @@ class MediaAria2cInitException : public MediaException
       std::string _url;
       std::string _msg;
     };
+
+    /**
+     * Thrown if /sbin/losetup fails to find an unused loop device for mounting
+     * an .iso image.
+     * 
+     * UI hint: tell user to check permissions to read /dev/loop# or enablement
+     * of support for loop devices.
+     * 
+     * \see MediaISO
+     */
+    class MediaNoLoopDeviceException : public MediaException
+    {
+    public:
+      MediaNoLoopDeviceException(const Url & url_r, const std::string & msg = "")
+        : MediaException(msg)
+        , _url(url_r.asString())
+      {}
+      virtual ~MediaNoLoopDeviceException() throw() {};
+    protected:
+      virtual std::ostream & dumpOn( std::ostream & str ) const;
+      std::string _url;
+    };
   /////////////////////////////////////////////////////////////////
   } // namespace media
 } // namespace zypp
index 9796f64..a202601 100644 (file)
@@ -581,21 +581,6 @@ MediaHandler::checkAttached(bool matchMountFs) const
          }
           // differs
         }
-        else // mixed cases:
-        {
-          // Type ISO: Since 11.1 mtab might contain the name of
-          // the loop device instead of the iso file:
-          if ( ref.mediaSource->type == "iso"
-               && str::hasPrefix( Pathname(e->src).asString(), "/dev/loop" )
-               && ref.attachPoint->path == Pathname(e->dir) )
-          {
-            DBG << "Found bound media "
-                << ref.mediaSource->asString()
-                << " in the mount table as " << e->src << std::endl;
-            _isAttached = true;
-            break;
-          }
-        }
       }
 
       if( !_isAttached)
index 270b6ee..fbd6dc9 100644 (file)
@@ -9,11 +9,18 @@
 /** \file zypp/media/MediaISO.cc
  *
  */
-#include "zypp/media/MediaISO.h"
+#include <iostream>
+
 #include "zypp/base/Logger.h"
 #include "zypp/media/Mount.h"
 
-#include <iostream>
+#include "zypp/media/MediaISO.h"
+
+
+#define LOSETUP_TOOL_PATH "/sbin/losetup"
+
+using std::string;
+using std::endl;
 
 //////////////////////////////////////////////////////////////////////
 namespace zypp
@@ -141,6 +148,32 @@ namespace zypp
     }
 
     // ---------------------------------------------------------------
+    string MediaISO::findUnusedLoopDevice()
+    {
+      const char* argv[] =
+      {
+        LOSETUP_TOOL_PATH,
+        "-f",
+        NULL
+      };
+      ExternalProgram losetup(argv, ExternalProgram::Stderr_To_Stdout);
+
+      string out = losetup.receiveLine();
+      string device = out.substr(0, out.size() - 1); // remove the trailing endl
+      for(; out.length(); out = losetup.receiveLine())
+        DBG << "losetup: " << out;
+
+      if (losetup.close() != 0)
+      {
+        ERR << LOSETUP_TOOL_PATH " failed to find an unused loop device." << std::endl;
+        ZYPP_THROW(MediaNoLoopDeviceException(_url));
+      }
+
+      DBG << "found " << device << endl;
+      return device;
+    }
+
+    // ---------------------------------------------------------------
     void MediaISO::attachTo(bool next)
     {
       if(next)
@@ -181,9 +214,18 @@ namespace zypp
         ZYPP_THROW(MediaNotSupportedException(_url));
       }
 
-      MediaSourceRef media( new MediaSource(
-        "iso", isofile.asString()
-      ));
+      //! \todo make this thread-safe - another thread might pick up the same device 
+      string loopdev = findUnusedLoopDevice(); // (bnc #428009)
+
+      MediaSourceRef media( new MediaSource("iso",  loopdev));
+      PathInfo dinfo(loopdev);
+      if( dinfo.isBlk())
+      {
+        media->maj_nr = dinfo.major();
+        media->min_nr = dinfo.minor();
+      }
+      else
+        ERR << loopdev << " is not a block device" << endl;
 
       AttachedMedia  ret( findAttachedMedia( media));
       if( ret.mediaSource &&
@@ -210,7 +252,7 @@ namespace zypp
         setAttachPoint( mountpoint, true);
       }
 
-      std::string mountopts("ro,loop");
+      std::string mountopts("ro,loop=" + loopdev);
 
       Mount mount;
       mount.mount(isofile.asString(), mountpoint,
index 7828e8b..79715bd 100644 (file)
@@ -39,6 +39,9 @@ namespace zypp
         MediaAccessId _isosource;
         std::string   _filesystem;
 
+      private:
+        std::string findUnusedLoopDevice();
+
       protected:
 
        virtual void attachTo (bool next = false);