Imported Upstream version 16.3.2
[platform/upstream/libzypp.git] / zypp / media / MediaManager.cc
index 33067c8..7295132 100644 (file)
@@ -9,22 +9,22 @@
 /** \file zypp/media/MediaManager.cc
  *
 */
-#include <zypp/media/MediaException.h>
-#include <zypp/media/MediaManager.h>
-#include <zypp/media/MediaHandler.h>
-#include <zypp/media/Mount.h>
-#include <zypp/thread/Mutex.h>
-#include <zypp/thread/MutexLock.h>
-
-#include <zypp/base/String.h>
-#include <zypp/base/Logger.h>
-#include <zypp/Pathname.h>
-#include <zypp/PathInfo.h>
-
 #include <map>
 #include <list>
 #include <iostream>
+#include <typeinfo>
+
+#include "zypp/media/MediaException.h"
+#include "zypp/media/MediaManager.h"
+#include "zypp/media/MediaHandler.h"
+#include "zypp/media/Mount.h"
+#include "zypp/thread/Mutex.h"
+#include "zypp/thread/MutexLock.h"
 
+#include "zypp/base/String.h"
+#include "zypp/base/Logger.h"
+#include "zypp/Pathname.h"
+#include "zypp/PathInfo.h"
 
 //////////////////////////////////////////////////////////////////////
 namespace zypp
@@ -70,10 +70,11 @@ namespace zypp
         {}
 
         inline void
-        checkAttached()
+        checkAttached(MediaAccessId id)
         {
           if( !handler->isAttached())
           {
+            DBG << "checkAttached(" << id << ") not attached" << std::endl;
             desired = false;
             ZYPP_THROW(MediaNotAttachedException(
               handler->url()
@@ -82,9 +83,9 @@ namespace zypp
         }
 
         inline void
-        checkDesired()
+        checkDesired(MediaAccessId id)
         {
-          checkAttached();
+          checkAttached(id);
 
           if( !desired)
           {
@@ -98,14 +99,17 @@ namespace zypp
 
             if( !desired)
             {
+              DBG << "checkDesired(" << id << "): not desired (report by "
+                  << verifier->info() << ")" << std::endl;
               ZYPP_THROW(MediaNotDesiredException(
                 handler->url()
               ));
             }
 
-            DBG << "checkDesired(): desired (report)" << std::endl;
+            DBG << "checkDesired(" << id << "): desired (report by "
+                << verifier->info() << ")" << std::endl;
           } else {
-            DBG << "checkDesired(): desired (cached)" << std::endl;
+            DBG << "checkDesired(" << id << "): desired (cached)" << std::endl;
           }
         }
 
@@ -118,29 +122,69 @@ namespace zypp
       // -------------------------------------------------------------
       typedef std::map<MediaAccessId, ManagedMedia> ManagedMediaMap;
 
-
       ////////////////////////////////////////////////////////////////
     } // anonymous
     //////////////////////////////////////////////////////////////////
 
 
     //////////////////////////////////////////////////////////////////
-    class MediaManager::Impl
+    std::string
+    MediaVerifierBase::info() const
+    {
+      return std::string(typeid((*this)).name());
+    }
+
+
+    //////////////////////////////////////////////////////////////////
+    std::string
+    NoVerifier::info() const
+    {
+      return std::string("zypp::media::NoVerifier");
+    }
+
+
+    //////////////////////////////////////////////////////////////////
+    class MediaManager_Impl
     {
     private:
-      MediaAccessId last_accessid;
+      friend class MediaManager;
 
-    public:
-      ManagedMediaMap mediaMap;
+      MediaAccessId       last_accessid;
+      ManagedMediaMap     mediaMap;
 
-      Impl()
+      MediaManager_Impl()
         : last_accessid(0)
       {}
 
-      ~Impl()
+    public:
+      ~MediaManager_Impl()
       {
+        MutexLock glock(g_Mutex);
+
         try
         {
+          // remove depending (iso) handlers first
+          ManagedMediaMap::iterator it;
+          bool found;
+          do
+          {
+            found = false;
+            for(it = mediaMap.begin(); it != mediaMap.end(); /**/)
+            {
+              if( it->second.handler->dependsOnParent())
+              {
+                found = true;
+                // let it forget its parent, we will
+                // destroy it later (in clear())...
+                it->second.handler->resetParentId();
+                mediaMap.erase( it++ ); // postfix! Incrementing before erase
+              } else {
+                ++it;
+              }
+            }
+          } while(found);
+
+          // remove all other handlers
           mediaMap.clear();
         }
         catch( ... )
@@ -172,16 +216,22 @@ namespace zypp
         return it->second;
       }
 
-      inline time_t
-      getMountTableMTime() const
+      static inline time_t
+      getMountTableMTime()
       {
-        return zypp::PathInfo("/etc/mtab").mtime();
+        time_t mtime = zypp::PathInfo("/etc/mtab").mtime();
+        if( mtime <= 0)
+        {
+          WAR << "Failed to retrieve modification time of '/etc/mtab'"
+              << std::endl;
+        }
+        return mtime;
       }
 
-      inline MountEntries
+      static inline MountEntries
       getMountEntries()
       {
-        return Mount::getEntries("/etc/mtab");
+        return Mount::getEntries();
       }
 
     };
@@ -189,7 +239,7 @@ namespace zypp
 
     //////////////////////////////////////////////////////////////////
     // STATIC
-    zypp::RW_pointer<MediaManager::Impl> MediaManager::m_impl(NULL);
+    zypp::RW_pointer<MediaManager_Impl> MediaManager::m_impl;
 
 
     //////////////////////////////////////////////////////////////////
@@ -198,7 +248,7 @@ namespace zypp
       MutexLock glock(g_Mutex);
       if( !m_impl)
       {
-        m_impl.reset( new MediaManager::Impl());
+        m_impl.reset( new MediaManager_Impl());
       }
     }
 
@@ -235,9 +285,33 @@ namespace zypp
     {
       MutexLock glock(g_Mutex);
 
-      ManagedMedia &ref( m_impl->findMM(accessId));
+      //
+      // The MediaISO handler internally requests an accessId
+      // of a "parent" handler providing the iso file.
+      // The parent handler accessId is private to MediaISO,
+      // but the attached media source may be shared reference.
+      // This means, that if the accessId exactly matches the
+      // parent handler id, close was used on uninitialized
+      // accessId variable (or the accessId was guessed) and
+      // the close request to this id will be rejected here.
+      //
+      ManagedMediaMap::iterator m(m_impl->mediaMap.begin());
+      for( ; m != m_impl->mediaMap.end(); ++m)
+      {
+        if( m->second.handler->dependsOnParent(accessId, true))
+        {
+          ZYPP_THROW(MediaIsSharedException(
+            m->second.handler->url().asString()
+          ));
+        }
+      }
+
+      DBG << "Close to access handler using id "
+          << accessId << " requested" << std::endl;
 
+      ManagedMedia &ref( m_impl->findMM(accessId));
       ref.handler->close();
+
       m_impl->mediaMap.erase(accessId);
     }
 
@@ -275,14 +349,6 @@ namespace zypp
     }
 
     // ---------------------------------------------------------------
-    // STATIC
-    bool
-    MediaManager::downloads(const Url &url)
-    {
-      return MediaAccess::downloads( url);
-    }
-
-    // ---------------------------------------------------------------
     Url
     MediaManager::url(MediaAccessId accessId) const
     {
@@ -305,8 +371,11 @@ namespace zypp
 
       ManagedMedia &ref( m_impl->findMM(accessId));
 
-      MediaVerifierRef(verifier).swap(ref.verifier);
       ref.desired = false;
+      MediaVerifierRef(verifier).swap(ref.verifier);
+
+      DBG << "MediaVerifier change: id=" << accessId << ", verifier="
+          << verifier->info() << std::endl;
     }
 
     // ---------------------------------------------------------------
@@ -318,8 +387,11 @@ namespace zypp
       ManagedMedia &ref( m_impl->findMM(accessId));
 
       MediaVerifierRef verifier( new NoVerifier());
-      ref.verifier.swap(verifier);
       ref.desired  = false;
+      ref.verifier.swap(verifier);
+
+      DBG << "MediaVerifier change: id=" << accessId << ", verifier="
+          << verifier->info() << std::endl;
     }
 
     // ---------------------------------------------------------------
@@ -332,60 +404,106 @@ namespace zypp
     }
 
     // ---------------------------------------------------------------
-    void
-    MediaManager::attach(MediaAccessId accessId, bool next)
+    void MediaManager::attach(MediaAccessId accessId)
     {
       MutexLock glock(g_Mutex);
 
       ManagedMedia &ref( m_impl->findMM(accessId));
 
-      return ref.handler->attach(next);
-    }
+      DBG << "attach(id=" << accessId << ")" << std::endl;
 
-    // ---------------------------------------------------------------
-    void
-    MediaManager::reattach(MediaAccessId   accessId,
-                           const Pathname &attach_point,
-                           bool            temporary)
-    {
-      MutexLock glock(g_Mutex);
+      // try first mountable/mounted device
+      ref.handler->attach(false);
+      try
+      {
+        ref.checkDesired(accessId);
+        return;
+      }
+      catch (const MediaException & ex)
+      {
+        ZYPP_CAUGHT(ex);
 
-      ManagedMedia &ref( m_impl->findMM(accessId));
+        if (!ref.handler->hasMoreDevices())
+          ZYPP_RETHROW(ex);
 
-      ManagedMediaMap::iterator m(m_impl->mediaMap.begin());
-      for( ; m != m_impl->mediaMap.end(); ++m)
+        if (ref.handler->isAttached())
+          ref.handler->release();
+      }
+
+      MIL << "checkDesired(" << accessId << ") of first device failed,"
+        " going to try others with attach(true)" << std::endl;
+
+      while (ref.handler->hasMoreDevices())
       {
-        // don't allow a reattach if it is the
-        // source for an loop mounted ISO file
-        if( m->second.handler->dependsOnParent(accessId))
+        try
         {
-          ZYPP_THROW(MediaIsSharedException(
-            m->second.handler->url().asString()
-          ));
+          // try to attach next device
+          ref.handler->attach(true);
+          ref.checkDesired(accessId);
+          return;
+        }
+        catch (const MediaNotDesiredException & ex)
+        {
+          ZYPP_CAUGHT(ex);
+
+          if (!ref.handler->hasMoreDevices())
+          {
+            MIL << "No desired media found after trying all detected devices." << std::endl;
+            ZYPP_RETHROW(ex);
+          }
+
+          AttachedMedia media(ref.handler->attachedMedia());
+          DBG << "Skipping " << media.mediaSource->asString() << ": not desired media." << std::endl;
+
+          ref.handler->release();
+        }
+        catch (const MediaException & ex)
+        {
+          ZYPP_CAUGHT(ex);
+
+          if (!ref.handler->hasMoreDevices())
+            ZYPP_RETHROW(ex);
+
+          AttachedMedia media(ref.handler->attachedMedia());
+          DBG << "Skipping " << media.mediaSource->asString() << " because of exception thrown by attach(true)" << std::endl;
+
+          if (ref.handler->isAttached()) ref.handler->release();
         }
       }
-      return ref.handler->reattach(attach_point, temporary);
     }
 
     // ---------------------------------------------------------------
     void
-    MediaManager::release(MediaAccessId accessId, bool eject)
+    MediaManager::release(MediaAccessId accessId, const std::string & ejectDev)
     {
       MutexLock glock(g_Mutex);
 
       ManagedMedia &ref( m_impl->findMM(accessId));
 
-      if( eject)
+      DBG << "release(id=" << accessId;
+      if (!ejectDev.empty())
+        DBG << ", " << ejectDev;
+      DBG << ")" << std::endl;
+
+      if(!ejectDev.empty())
       {
+        //
+        // release MediaISO handlers, that are using the one
+        // specified with accessId, because it provides the
+        // iso file and it will disappear now (forced release
+        // with eject).
+        //
         ManagedMediaMap::iterator m(m_impl->mediaMap.begin());
         for( ; m != m_impl->mediaMap.end(); ++m)
         {
-          if( m->second.handler->dependsOnParent(accessId))
+          if( m->second.handler->dependsOnParent(accessId, false))
           {
             try
             {
-              m->second.handler->release(!eject);
+              DBG << "Forcing release of handler depending on access id "
+                  << accessId << std::endl;
               m->second.desired  = false;
+              m->second.handler->release();
             }
             catch(const MediaException &e)
             {
@@ -394,8 +512,45 @@ namespace zypp
           }
         }
       }
-      ref.handler->release(eject);
       ref.desired  = false;
+      ref.handler->release(ejectDev);
+    }
+
+    // ---------------------------------------------------------------
+    void
+    MediaManager::releaseAll()
+    {
+      MutexLock glock(g_Mutex);
+
+      MIL << "Releasing all attached media" << std::endl;
+
+      ManagedMediaMap::iterator m(m_impl->mediaMap.begin());
+      for( ; m != m_impl->mediaMap.end(); ++m)
+      {
+        if( m->second.handler->dependsOnParent())
+          continue;
+
+        try
+        {
+          if(m->second.handler->isAttached())
+          {
+            DBG << "Releasing media id " << m->first << std::endl;
+            m->second.desired  = false;
+            m->second.handler->release();
+          }
+          else
+          {
+            DBG << "Media id " << m->first << " not attached " << std::endl;
+          }
+        }
+        catch(const MediaException & e)
+        {
+          ZYPP_CAUGHT(e);
+          ERR << "Failed to release media id " << m->first << std::endl;
+        }
+      }
+
+      MIL << "Exit" << std::endl;
     }
 
     // ---------------------------------------------------------------
@@ -452,6 +607,10 @@ namespace zypp
           ref.desired = false;
         }
       }
+      DBG << "isDesiredMedia(" << accessId << "): "
+          << (ref.desired ? "" : "not ")
+          << "desired (report by "
+          << ref.verifier->info() << ")" << std::endl;
       return ref.desired;
     }
 
@@ -479,10 +638,21 @@ namespace zypp
           desired = false;
         }
       }
+      DBG << "isDesiredMedia(" << accessId << "): "
+          << (desired ? "" : "not ")
+          << "desired (report by "
+          << v->info() << ")" << std::endl;
       return desired;
     }
 
     // ---------------------------------------------------------------
+    bool
+    MediaManager::isChangeable(MediaAccessId accessId)
+    {
+      return url(accessId).getScheme() == "cd" || url(accessId).getScheme() == "dvd";
+    }
+
+    // ---------------------------------------------------------------
     Pathname
     MediaManager::localRoot(MediaAccessId accessId) const
     {
@@ -512,17 +682,29 @@ namespace zypp
     // ---------------------------------------------------------------
     void
     MediaManager::provideFile(MediaAccessId   accessId,
-                              const Pathname &filename,
-                              bool            cached,
-                              bool            checkonly) const
+                              const Pathname &filename ) const
+    {
+      MutexLock glock(g_Mutex);
+
+      ManagedMedia &ref( m_impl->findMM(accessId));
+
+      ref.checkDesired(accessId);
+
+      ref.handler->provideFile(filename);
+    }
+
+    // ---------------------------------------------------------------
+    void
+    MediaManager::setDeltafile(MediaAccessId   accessId,
+                              const Pathname &filename ) const
     {
       MutexLock glock(g_Mutex);
 
       ManagedMedia &ref( m_impl->findMM(accessId));
 
-      ref.checkDesired();
+      ref.checkDesired(accessId);
 
-      ref.handler->provideFile(filename, cached, checkonly);
+      ref.handler->setDeltafile(filename);
     }
 
     // ---------------------------------------------------------------
@@ -534,7 +716,7 @@ namespace zypp
 
       ManagedMedia &ref( m_impl->findMM(accessId));
 
-      ref.checkDesired();
+      ref.checkDesired(accessId);
 
       ref.handler->provideDir(dirname);
     }
@@ -548,7 +730,7 @@ namespace zypp
 
       ManagedMedia &ref( m_impl->findMM(accessId));
 
-      ref.checkDesired();
+      ref.checkDesired(accessId);
 
       ref.handler->provideDirTree(dirname);
     }
@@ -562,7 +744,7 @@ namespace zypp
 
       ManagedMedia &ref( m_impl->findMM(accessId));
 
-      ref.checkAttached();
+      ref.checkAttached(accessId);
 
       ref.handler->releaseFile(filename);
     }
@@ -576,7 +758,7 @@ namespace zypp
 
       ManagedMedia &ref( m_impl->findMM(accessId));
 
-      ref.checkAttached();
+      ref.checkAttached(accessId);
 
       ref.handler->releaseDir(dirname);
     }
@@ -591,7 +773,7 @@ namespace zypp
 
       ManagedMedia &ref( m_impl->findMM(accessId));
 
-      ref.checkAttached();
+      ref.checkAttached(accessId);
 
       ref.handler->releasePath(pathname);
     }
@@ -607,8 +789,8 @@ namespace zypp
 
       ManagedMedia &ref( m_impl->findMM(accessId));
 
-      // FIXME: ref.checkDesired(); ???
-      ref.checkAttached();
+      // FIXME: ref.checkDesired(accessId); ???
+      ref.checkAttached(accessId);
 
       ref.handler->dirInfo(retlist, dirname, dots);
     }
@@ -624,33 +806,59 @@ namespace zypp
 
       ManagedMedia &ref( m_impl->findMM(accessId));
 
-      // FIXME: ref.checkDesired(); ???
-      ref.checkAttached();
+      // FIXME: ref.checkDesired(accessId); ???
+      ref.checkAttached(accessId);
 
       ref.handler->dirInfo(retlist, dirname, dots);
     }
 
     // ---------------------------------------------------------------
-    time_t
-    MediaManager::getMountTableMTime() const
+    bool
+    MediaManager::doesFileExist(MediaAccessId  accessId, const Pathname & filename ) const
+    {
+      MutexLock glock(g_Mutex);
+      ManagedMedia &ref( m_impl->findMM(accessId));
+
+      // FIXME: ref.checkDesired(accessId); ???
+      ref.checkAttached(accessId);
+
+      return ref.handler->doesFileExist(filename);
+    }
+
+    // ---------------------------------------------------------------
+    void
+    MediaManager::getDetectedDevices(MediaAccessId accessId,
+                                     std::vector<std::string> & devices,
+                                     unsigned int & index) const
     {
       MutexLock glock(g_Mutex);
+      ManagedMedia &ref( m_impl->findMM(accessId));
+      return ref.handler->getDetectedDevices(devices, index);
+    }
 
-      return m_impl->getMountTableMTime();
+    // ---------------------------------------------------------------
+    // STATIC
+    time_t
+    MediaManager::getMountTableMTime()
+    {
+      MutexLock glock(g_Mutex);
+      return MediaManager_Impl::getMountTableMTime();
     }
 
     // ---------------------------------------------------------------
+    // STATIC
     MountEntries
-    MediaManager::getMountEntries() const
+    MediaManager::getMountEntries()
     {
       MutexLock glock(g_Mutex);
 
-      return m_impl->getMountEntries();
+      return MediaManager_Impl::getMountEntries();
     }
 
     // ---------------------------------------------------------------
     bool
-    MediaManager::isUseableAttachPoint(const Pathname &path) const
+    MediaManager::isUseableAttachPoint(const Pathname &path,
+                                       bool            mtab) const
     {
       if( path.empty() || path == "/" || !PathInfo(path).isDir())
         return false;
@@ -686,6 +894,9 @@ namespace zypp
         }
       }
 
+      if( !mtab)
+        return true;
+
       //
       // check against system mount entries
       //
@@ -711,6 +922,7 @@ namespace zypp
           return false;
         }
       }
+
       return true;
     }
 
@@ -749,7 +961,7 @@ namespace zypp
 
     // ---------------------------------------------------------------
     void
-    MediaManager::forceMediaRelease(const MediaSourceRef &media)
+    MediaManager::forceReleaseShared(const MediaSourceRef &media)
     {
       MutexLock glock(g_Mutex);
 
@@ -765,7 +977,7 @@ namespace zypp
         AttachedMedia ret = m->second.handler->attachedMedia();
         if( ret.mediaSource && ret.mediaSource->equals( *media))
         {
-          m->second.handler->release(false);
+          m->second.handler->release();
           m->second.desired  = false;
         }
       }