Imported Upstream version 16.3.2
[platform/upstream/libzypp.git] / zypp / media / MediaDISK.cc
index a09337f..c9f2260 100644 (file)
@@ -6,21 +6,30 @@
 |                         /_____||_| |_| |_|                           |
 |                                                                      |
 \---------------------------------------------------------------------*/
-/** \file zypp/media/MediaDISK.h
+/** \file zypp/media/MediaDISK.cc
  *
 */
 
-#include <iostream>
-
 #include "zypp/base/Logger.h"
+#include "zypp/base/String.h"
 #include "zypp/media/Mount.h"
 #include "zypp/media/MediaDISK.h"
+#include "zypp/media/MediaManager.h"
+
+#include <iostream>
+#include <fstream>
+#include <sstream>
 
 #include <sys/types.h>
 #include <sys/mount.h>
 #include <errno.h>
 #include <dirent.h>
 
+/*
+** verify devices names as late as possible (while attach)
+*/
+#define DELAYED_VERIFY           1
+
 using namespace std;
 
 namespace zypp {
@@ -46,11 +55,120 @@ namespace zypp {
                    url_r.getPathName(), // urlpath below attachpoint
                    false ) // does_download
     {
+      MIL << "MediaDISK::MediaDISK(" << url_r << ", " << attach_point_hint_r << ")" << endl;
+
       _device = Pathname(_url.getQueryParam("device")).asString();
+      if( _device.empty())
+      {
+       ERR << "Media url does not contain a device specification" << std::endl;
+       ZYPP_THROW(MediaBadUrlEmptyDestinationException(_url));
+      }
+#if DELAYED_VERIFY
+      DBG << "Verify of " << _device << " delayed" << std::endl;
+#else
+      if( !verifyIfDiskVolume( _device))
+      {
+       ZYPP_THROW(MediaBadUrlEmptyDestinationException(_url));
+      }
+#endif
+
       _filesystem = _url.getQueryParam("filesystem");
       if(_filesystem.empty())
        _filesystem="auto";
-       MIL << "MediaDISK::MediaDISK(" << url_r << ", " << attach_point_hint_r << ")" << endl;
+
+    }
+
+    ///////////////////////////////////////////////////////////////////
+    //
+    // METHOD NAME : MediaDISK::verifyIfDiskVolume
+    // METHOD TYPE : void
+    //
+    // DESCRIPTION : Check if specified device file name is
+    //                a disk volume device or throw an error.
+    //
+    bool MediaDISK::verifyIfDiskVolume(const Pathname &dev_name)
+    {
+      if( dev_name.empty() ||
+         dev_name.asString().compare(0, sizeof("/dev/")-1, "/dev/"))
+      {
+       ERR << "Specified device name " << dev_name
+           << " is not allowed" << std::endl;
+       return false;
+      }
+
+      PathInfo dev_info(dev_name);
+      if( !dev_info.isBlk())
+      {
+       ERR << "Specified device name " << dev_name
+           << " is not a block device" << std::endl;
+       return false;
+      }
+
+      // check if a volume using /dev/disk/by-uuid links first
+      {
+       Pathname            dpath("/dev/disk/by-uuid");
+       std::list<Pathname> dlist;
+       if( zypp::filesystem::readdir(dlist, dpath) == 0)
+       {
+         std::list<Pathname>::const_iterator it;
+         for(it = dlist.begin(); it != dlist.end(); ++it)
+         {
+           PathInfo vol_info(*it);
+           if( vol_info.isBlk() && vol_info.devMajor() == dev_info.devMajor() &&
+                                   vol_info.devMinor() == dev_info.devMinor())
+           {
+             DBG << "Specified device name " << dev_name
+                 << " is a volume (disk/by-uuid link "
+                 << vol_info.path() << ")"
+                 << std::endl;
+             return true;
+           }
+         }
+       }
+      }
+
+      // check if a volume using /dev/disk/by-label links
+      // (e.g. vbd mapped volumes in a XEN vm)
+      {
+       Pathname            dpath("/dev/disk/by-label");
+       std::list<Pathname> dlist;
+       if( zypp::filesystem::readdir(dlist, dpath) == 0)
+       {
+         std::list<Pathname>::const_iterator it;
+         for(it = dlist.begin(); it != dlist.end(); ++it)
+         {
+           PathInfo vol_info(*it);
+           if( vol_info.isBlk() && vol_info.devMajor() == dev_info.devMajor() &&
+                                   vol_info.devMinor() == dev_info.devMinor())
+           {
+             DBG << "Specified device name " << dev_name
+                 << " is a volume (disk/by-label link "
+                 << vol_info.path() << ")"
+                 << std::endl;
+             return true;
+           }
+         }
+       }
+      }
+
+      // check if a filesystem volume using the 'blkid' tool
+      // (there is no /dev/disk link for some of them)
+      ExternalProgram::Arguments args;
+      args.push_back( "blkid" );
+      args.push_back( "-p" );
+      args.push_back( dev_name.asString() );
+
+      ExternalProgram cmd( args, ExternalProgram::Stderr_To_Stdout );
+      cmd >> DBG;
+      if ( cmd.close() != 0 )
+      {
+       ERR << cmd.execError() << endl
+           << "Specified device name " << dev_name
+           << " is not a usable disk volume"
+           << std::endl;
+       return false;
+      }
+      return true;
     }
 
     ///////////////////////////////////////////////////////////////////
@@ -70,19 +188,26 @@ namespace zypp {
       //   mount /dev/<partition> /tmp_mount
       //   mount /tmp_mount/<dir> <to> --bind -o ro
       // FIXME: try all filesystems
-    
+
       if(_device.empty())
        ZYPP_THROW(MediaBadUrlEmptyDestinationException(url()));
-    
+
       PathInfo dev_info(_device);
       if(!dev_info.isBlk())
         ZYPP_THROW(MediaBadUrlEmptyDestinationException(url()));
+#if DELAYED_VERIFY
+      DBG << "Verifying " << _device << " ..." << std::endl;
+      if( !verifyIfDiskVolume( _device))
+      {
+       ZYPP_THROW(MediaBadUrlEmptyDestinationException(_url));
+      }
+#endif
 
       if(_filesystem.empty())
        ZYPP_THROW(MediaBadUrlEmptyFilesystemException(url()));
 
       MediaSourceRef media( new MediaSource(
-       "disk", _device, dev_info.major(), dev_info.minor()
+       "disk", _device, dev_info.devMajor(), dev_info.devMinor()
       ));
       AttachedMedia  ret( findAttachedMedia( media));
 
@@ -102,32 +227,72 @@ namespace zypp {
        return;
       }
 
-      Mount mount;
-      std::string mountpoint = attachPoint().asString();
-      if( !isUseableAttachPoint(attachPoint()))
+      MediaManager  manager;
+      MountEntries  entries( manager.getMountEntries());
+      MountEntries::const_iterator e;
+      for( e = entries.begin(); e != entries.end(); ++e)
+      {
+       bool        is_device = false;
+       std::string dev_path(Pathname(e->src).asString());
+       PathInfo    dev_info;
+
+       if( dev_path.compare(0, sizeof("/dev/")-1, "/dev/") == 0 &&
+           dev_info(e->src) && dev_info.isBlk())
+       {
+         is_device = true;
+       }
+
+       if( is_device && media->maj_nr == dev_info.devMajor() &&
+                        media->min_nr == dev_info.devMinor())
+       {
+         AttachPointRef ap( new AttachPoint(e->dir, false));
+         AttachedMedia  am( media, ap);
+         {
+           DBG << "Using a system mounted media "
+               << media->name
+               << " attached on "
+               << ap->path
+               << endl;
+
+           media->iown = false; // mark attachment as foreign
+
+           setMediaSource(media);
+           setAttachPoint(ap);
+           return;
+         }
+       }
+      }
+
+      if( !isUseableAttachPoint( attachPoint() ) )
       {
-       mountpoint = createAttachPoint().asString();
-       if( mountpoint.empty())
-         ZYPP_THROW( MediaBadAttachPointException(url()));
-       setAttachPoint( mountpoint, true);
+       setAttachPoint( createAttachPoint(), true );
       }
+      std::string mountpoint( attachPoint().asString() );
 
+      Mount mount;
       string options = _url.getQueryParam("mountoptions");
       if(options.empty())
       {
-       options="ro";
+       options = "ro";
       }
 
-      mount.mount(_device,mountpoint,_filesystem,options);
+      if( !media->bdir.empty())
+      {
+       options += ",bind";
+       mount.mount(media->bdir, mountpoint, "none", options);
+      }
+      else
+      {
+       mount.mount(_device, mountpoint, _filesystem, options);
+      }
 
       setMediaSource(media);
 
       // wait for /etc/mtab update ...
       // (shouldn't be needed)
-      int limit = 10;
+      int limit = 3;
       bool mountsucceeded;
-      while( !(mountsucceeded=isAttached()) && limit--)
+      while( !(mountsucceeded=isAttached()) && --limit)
       {
         sleep(1);
       }
@@ -160,7 +325,7 @@ namespace zypp {
     bool
     MediaDISK::isAttached() const
     {
-      return checkAttached(true);
+      return checkAttached(false);
     }
 
     ///////////////////////////////////////////////////////////////////
@@ -171,13 +336,16 @@ namespace zypp {
     //
     // DESCRIPTION : Asserted that media is attached.
     //
-    void MediaDISK::releaseFrom( bool eject )
+    void MediaDISK::releaseFrom( const std::string & ejectDev )
     {
-      Mount mount;
-      mount.umount(attachPoint().asString());
+      AttachedMedia am( attachedMedia());
+      if(am.mediaSource && am.mediaSource->iown)
+      {
+        Mount mount;
+        mount.umount(attachPoint().asString());
+      }
     }
 
-
     ///////////////////////////////////////////////////////////////////
     //
     // METHOD NAME : MediaDISK::getFile
@@ -189,7 +357,7 @@ namespace zypp {
     {
       MediaHandler::getFile( filename );
     }
-    
+
     ///////////////////////////////////////////////////////////////////
     //
     // METHOD NAME : MediaDISK::getDir
@@ -201,7 +369,7 @@ namespace zypp {
     {
       MediaHandler::getDir( dirname, recurse_r );
     }
-    
+
     ///////////////////////////////////////////////////////////////////
     //
     //
@@ -215,7 +383,7 @@ namespace zypp {
     {
       MediaHandler::getDirInfo( retlist, dirname, dots );
     }
-    
+
     ///////////////////////////////////////////////////////////////////
     //
     //
@@ -230,5 +398,11 @@ namespace zypp {
       MediaHandler::getDirInfo( retlist, dirname, dots );
     }
 
+    bool MediaDISK::getDoesFileExist( const Pathname & filename ) const
+    {
+      return MediaHandler::getDoesFileExist( filename );
+    }
+
   } // namespace media
 } // namespace zypp
+// vim: set ts=8 sts=2 sw=2 ai noet: