Disable using libhal (bnc#590707)
[platform/upstream/libzypp.git] / zypp / media / MediaCD.cc
index b1dbc06..5d91182 100644 (file)
@@ -18,7 +18,6 @@
 #include "zypp/media/MediaCD.h"
 #include "zypp/media/MediaManager.h"
 #include "zypp/Url.h"
-#include "zypp/target/hal/HalContext.h"
 
 #include <cstring> // strerror
 #include <cstdlib> // getenv
 
 #include <linux/cdrom.h>
 
-/*
-** verify devices names as late as possible (while attach)
-*/
-#define  DELAYED_VERIFY          1
+#define NO_HAL
 
 /*
 ** try umount of foreign (user/automounter) media on eject
 **   0 = don't force, 1 = automounted only, 2 == all
 */
-#define  FORCE_RELEASE_FOREIGN   1
+#define  FORCE_RELEASE_FOREIGN   2
+
+/*
+** Reuse foreign (user/automounter) mount points.
+** 0 = don't use, 1 = automounted only, 2 = all
+*/
+#define  REUSE_FOREIGN_MOUNTS    2
 
 /*
 ** if to throw exception on eject errors or ignore them
 */
 #define EJECT_TOOL_PATH "/bin/eject"
 
+
 using namespace std;
 
 namespace zypp {
   namespace media {
 
-    namespace {
-
-      bool isNewDevice(const std::list<MediaSource> &devices,
-                       const MediaSource            &media)
-      {
-       std::list<MediaSource>::const_iterator d( devices.begin());
-       for( ; d != devices.end(); ++d)
-       {
-         if( media.equals( *d))
-           return false;
-       }
-       return true;
-      }
-
-      inline Pathname get_sysfs_path()
-      {
-       Pathname sysfs_path;
-       if(::getuid() == ::geteuid() && ::getgid() == ::getegid())
-       {
-         const char *env = ::getenv("SYSFS_PATH");
-         if( env && *env)
-         {
-           sysfs_path = env;
-           if( PathInfo(sysfs_path, PathInfo::LSTAT).isDir())
-             return sysfs_path;
-         }
-       }
-       sysfs_path = "/sys";
-       if( PathInfo(sysfs_path, PathInfo::LSTAT).isDir())
-         return sysfs_path;
-       else
-         return Pathname();
-      }
-
-    }
-
-
 ///////////////////////////////////////////////////////////////////
 //
-//     CLASS NAME : MediaCD
+//  CLASS NAME : MediaCD
 //
 ///////////////////////////////////////////////////////////////////
 
-    ///////////////////////////////////////////////////////////////////
-    //
-    //
-    // METHOD NAME : MediaCD::MediaCD
-    // METHOD TYPE : Constructor
-    //
-    // DESCRIPTION :
-    //
-    MediaCD::MediaCD( const Url &      url_r,
-                 const Pathname & attach_point_hint_r )
-      : MediaHandler( url_r, attach_point_hint_r,
-                   url_r.getPathName(), // urlpath below attachpoint
-                   false )
-      //, does_download
-      , _lastdev(-1)
+
+  ///////////////////////////////////////////////////////////////////
+  //
+  //
+  //  METHOD NAME : MediaCD::MediaCD
+  //  METHOD TYPE : Constructor
+  //
+  //  DESCRIPTION :
+  //
+  MediaCD::MediaCD( const Url &      url_r,
+                    const Pathname & attach_point_hint_r )
+    : MediaHandler( url_r, attach_point_hint_r,
+                    url_r.getPathName(), // urlpath below attachpoint
+                    false ),
+      _lastdev(-1), _lastdev_tried(-1)
+  {
+    MIL << "MediaCD::MediaCD(" << url_r << ", " << attach_point_hint_r << ")"
+        << endl;
+
+    if( url_r.getScheme() != "dvd" && url_r.getScheme() != "cd")
     {
-      MIL << "MediaCD::MediaCD(" << url_r << ", "
-          << attach_point_hint_r << ")" << endl;
+      ERR << "Unsupported schema in the Url: " << url_r.asString() << endl;
+      ZYPP_THROW(MediaUnsupportedUrlSchemeException(_url));
+    }
 
-      if( url_r.getScheme() != "dvd" && url_r.getScheme() != "cd")
+    string devices = _url.getQueryParam("devices");
+    if (!devices.empty())
+    {
+      string::size_type pos;
+      DBG << "parse " << devices << endl;
+      while(!devices.empty())
       {
-       ERR << "Unsupported schema in the Url: " << url_r.asString()
-                                                << std::endl;
-       ZYPP_THROW(MediaUnsupportedUrlSchemeException(_url));
+        pos = devices.find(',');
+        string device = devices.substr(0,pos);
+        if (!device.empty())
+        {
+          MediaSource media("cdrom", device, 0, 0);
+          _devices.push_back( media);
+          DBG << "use device (delayed verify)" << device << endl;
+        }
+        if (pos!=string::npos)
+          devices=devices.substr(pos+1);
+        else
+          devices.erase();
       }
+    }
+    else
+    {
+      DBG << "going to use on-demand device list" << endl;
+      return;
+    }
 
-#if !DELAYED_VERIFY
-      DeviceList detected( detectDevices(
-       url_r.getScheme() == "dvd" ? true : false
-      ));
-#endif
+    if( _devices.empty())
+    {
+      ERR << "Unable to find any cdrom drive for " << _url.asString() << endl;
+      ZYPP_THROW(MediaBadUrlEmptyDestinationException(_url));
+    }
+  }
+
+  ///////////////////////////////////////////////////////////////////
+  //
+  //
+  //  METHOD NAME : MediaCD::openTray
+  //  METHOD TYPE : bool
+  //
+  bool MediaCD::openTray( const std::string & device_r )
+  {
+    int fd = ::open( device_r.c_str(), O_RDONLY|O_NONBLOCK );
+    int res = -1;
+
+    if ( fd != -1)
+    {
+      res = ::ioctl( fd, CDROMEJECT );
+      ::close( fd );
+    }
 
-      string devices = _url.getQueryParam("devices");
-      if (!devices.empty())
+    if ( res )
+    {
+      if( fd == -1)
       {
-       string::size_type pos;
-       DBG << "parse " << devices << endl;
-       while(!devices.empty())
-       {
-           pos = devices.find(',');
-           string device = devices.substr(0,pos);
-           if (!device.empty())
-           {
-#if DELAYED_VERIFY
-             MediaSource media("cdrom", device, 0, 0);
-             _devices.push_back( media);
-              DBG << "use device (delayed verify)" << device << endl;
-#else
-             bool is_ok = false;
-             PathInfo dinfo(device);
-             if( dinfo.isBlk())
-             {
-               MediaSource media("cdrom", device, dinfo.major(),
-                                                  dinfo.minor());
-               DeviceList::const_iterator d( detected.begin());
-               for( ; d != detected.end(); ++d)
-               {
-                 if( media.equals( *d))
-                 {
-                   is_ok = true;
-                   _devices.push_back( *d);
-                   DBG << "use device " << device << endl;
-                 }
-               }
-             }
-
-             if( !is_ok)
-             {
-               ERR << "Device " << device << " is not acceptable "
-                   << "for " << _url.getScheme() << std::endl;
-               ZYPP_THROW(MediaBadUrlException(_url,
-                 "Invalid device name in URL devices argument"
-               ));
-             }
-#endif
-           }
-           if (pos!=string::npos)
-               devices=devices.substr(pos+1);
-           else
-               devices.erase();
-       }
+        WAR << "Unable to open '" << device_r
+            << "' (" << ::strerror( errno ) << ")" << endl;
       }
       else
       {
-#if DELAYED_VERIFY
-       DBG << "going to use on-demand device list" << endl;
-       return;
-#else
-       DBG << "going to use default device list" << endl;
-       //default is /dev/cdrom; for dvd: /dev/dvd if it exists
-        string device( "/dev/cdrom" );
-       if ( _url.getScheme() == "dvd" && PathInfo( "/dev/dvd" ).isBlk() ) {
-         device = "/dev/dvd";
-       }
-
-       PathInfo dinfo(device);
-       if( dinfo.isBlk())
-       {
-         MediaSource media("cdrom", device, dinfo.major(), dinfo.minor());
-
-         DeviceList::const_iterator d( detected.begin());
-         for( ; d != detected.end(); ++d)
-         {
-           // /dev/cdrom or /dev/dvd to the front
-           if( media.equals( *d))
-             _devices.push_front( *d);
-           else
-             _devices.push_back( *d);
-         }
-       }
-       else
-       {
-         // no /dev/cdrom or /dev/dvd link
-         _devices = detected;
-       }
-#endif
+        WAR << "Eject " << device_r
+            << " failed (" << ::strerror( errno ) << ")" << endl;
       }
 
-      if( _devices.empty())
-      {
-       ERR << "Unable to find any cdrom drive for " << _url.asString()
-                                                    << std::endl;
-       ZYPP_THROW(MediaBadUrlEmptyDestinationException(_url));
-      }
-    }
+#if defined(EJECT_TOOL_PATH)
+      DBG << "Try to eject " << device_r << " using "
+        << EJECT_TOOL_PATH << " utility" << std::endl;
 
-    ///////////////////////////////////////////////////////////////////
-    //
-    //
-    // METHOD NAME : MediaCD::openTray
-    // METHOD TYPE : bool
-    //
-    bool MediaCD::openTray( const std::string & device_r )
-    {
-      int fd = ::open( device_r.c_str(), O_RDONLY|O_NONBLOCK );
-      int res = -1;
+      const char *cmd[3];
+      cmd[0] = EJECT_TOOL_PATH;
+      cmd[1] = device_r.c_str();
+      cmd[2] = NULL;
+      ExternalProgram eject(cmd, ExternalProgram::Stderr_To_Stdout);
 
-      if ( fd != -1)
+      for(std::string out( eject.receiveLine());
+          out.length(); out = eject.receiveLine())
       {
-       res = ::ioctl( fd, CDROMEJECT );
-       ::close( fd );
+        DBG << " " << out;
       }
 
-      if ( res )
+      if(eject.close() != 0)
       {
-       if( fd == -1)
-       {
-         WAR << "Unable to open '" << device_r
-             << "' (" << ::strerror( errno ) << ")" << endl;
-       }
-       else
-       {
-         WAR << "Eject " << device_r
-             << " failed (" << ::strerror( errno ) << ")" << endl;
-       }
-
-#if defined(EJECT_TOOL_PATH)
-       DBG << "Try to eject " << device_r << " using "
-           << EJECT_TOOL_PATH << " utility" << std::endl;
-
-       const char *cmd[3];
-       cmd[0] = EJECT_TOOL_PATH;
-       cmd[1] = device_r.c_str();
-       cmd[2] = NULL;
-       ExternalProgram eject(cmd, ExternalProgram::Stderr_To_Stdout);
-
-       for(std::string out( eject.receiveLine());
-           out.length(); out = eject.receiveLine())
-       {
-         DBG << " " << out;
-       }
-
-       if(eject.close() != 0)
-       {
-         WAR << "Eject of " << device_r << " failed." << std::endl;
-         return false;
-       }
-#else
+        WAR << "Eject of " << device_r << " failed." << std::endl;
         return false;
-#endif
       }
-      MIL << "Eject of " << device_r << " successful." << endl;
-      return true;
+#else
+      return false;
+#endif
     }
-
-    ///////////////////////////////////////////////////////////////////
-    //
-    //
-    // METHOD NAME : MediaCD::closeTray
-    // METHOD TYPE : bool
-    //
-    bool MediaCD::closeTray( const std::string & device_r )
+    MIL << "Eject of " << device_r << " successful." << endl;
+    return true;
+  }
+
+  ///////////////////////////////////////////////////////////////////
+  //
+  //
+  //   METHOD NAME : MediaCD::closeTray
+  //   METHOD TYPE : bool
+  //
+  bool MediaCD::closeTray( const std::string & device_r )
+  {
+    int fd = ::open( device_r.c_str(), O_RDONLY|O_NONBLOCK );
+    if ( fd == -1 ) {
+      WAR << "Unable to open '" << device_r << "' (" << ::strerror( errno ) << ")" << endl;
+      return false;
+    }
+    int res = ::ioctl( fd, CDROMCLOSETRAY );
+    ::close( fd );
+    if ( res ) {
+      WAR << "Close tray " << device_r << " failed (" << ::strerror( errno ) << ")" << endl;
+      return false;
+    }
+    DBG << "Close tray " << device_r << endl;
+    return true;
+  }
+
+  ///////////////////////////////////////////////////////////////////
+  //
+  //
+  //  METHOD NAME : MediaCD::detectDevices
+  //  METHOD TYPE : MediaCD::DeviceList
+  //
+  MediaCD::DeviceList
+  MediaCD::detectDevices(bool supportingDVD) const
+  {
+    DeviceList detected;
+
+#warning Poor CDROM devices detection without HAL
+    /** \todo rewite using e.g. 'hwinfo --cdrom' or libudev */
+    WAR << "Cdrom drive detection without HAL! " << std::endl;
+    PathInfo dvdinfo( "/dev/dvd" );
+    PathInfo cdrinfo( "/dev/cdrom" );
+    if ( dvdinfo.isBlk() )
     {
-      int fd = ::open( device_r.c_str(), O_RDONLY|O_NONBLOCK );
-      if ( fd == -1 ) {
-        WAR << "Unable to open '" << device_r << "' (" << ::strerror( errno ) << ")" << endl;
-        return false;
-      }
-      int res = ::ioctl( fd, CDROMCLOSETRAY );
-      ::close( fd );
-      if ( res ) {
-        WAR << "Close tray " << device_r << " failed (" << ::strerror( errno ) << ")" << endl;
-        return false;
-      }
-      DBG << "Close tray " << device_r << endl;
-      return true;
+      MediaSource media( "cdrom", dvdinfo.path().asString(), dvdinfo.major(), dvdinfo.minor() );
+      DBG << "Found (NO_HAL): " << media << std::endl;
+      detected.push_back( media );
     }
-
-    ///////////////////////////////////////////////////////////////////
-    //
-    //
-    // METHOD NAME : MediaCD::detectDevices
-    // METHOD TYPE : MediaCD::DeviceList
-    //
-    MediaCD::DeviceList
-    MediaCD::detectDevices(bool supportingDVD)
+    if ( cdrinfo.isBlk()
+         && ! ( cdrinfo.major() == dvdinfo.major() && cdrinfo.minor() == dvdinfo.minor() ) )
     {
-      using namespace zypp::target::hal;
+      MediaSource media( "cdrom", cdrinfo.path().asString(), cdrinfo.major(), cdrinfo.minor() );
+      DBG << "Found (NO_HAL): " << media << std::endl;
+      detected.push_back( media );
+    }
 
-      DeviceList detected;
-      try
+    return detected;
+  }
+
+
+  ///////////////////////////////////////////////////////////////////
+  //
+  //
+  //  METHOD NAME : MediaCD::attachTo
+  //  METHOD TYPE : PMError
+  //
+  //  DESCRIPTION : Asserted that not already attached, and attachPoint is a directory.
+  //
+  void MediaCD::attachTo(bool next)
+  {
+    DBG << "next " << next << " last " << _lastdev << " last tried " << _lastdev_tried << endl;
+    if (next && _lastdev == -1)
+      ZYPP_THROW(MediaNotSupportedException(url()));
+
+    DeviceList detected(
+      detectDevices(_url.getScheme() == "dvd" ? true : false));
+
+    if(_devices.empty())
+    {
+      DBG << "creating on-demand device list" << endl;
+      //default is /dev/cdrom; for dvd: /dev/dvd if it exists
+      string device( "/dev/cdrom" );
+      if ( _url.getScheme() == "dvd" && PathInfo( "/dev/dvd" ).isBlk() )
       {
-       HalContext hal(true);
-
-       std::vector<std::string> drv_udis;
-       drv_udis = hal.findDevicesByCapability("storage.cdrom");
-
-       DBG << "Found " << drv_udis.size() << " cdrom drive udis" << std::endl;
-       for(size_t d = 0; d < drv_udis.size(); d++)
-       {
-         HalDrive drv( hal.getDriveFromUDI( drv_udis[d]));
-
-         if( drv)
-         {
-           bool supportsDVD=false;
-           if( supportingDVD)
-           {
-             std::vector<std::string> caps;
-             try {
-               caps = drv.getCdromCapabilityNames();
-             }
-             catch(const HalException &e)
-             {
-               ZYPP_CAUGHT(e);
-             }
-
-             std::vector<std::string>::const_iterator ci;
-             for( ci=caps.begin(); ci != caps.end(); ++ci)
-             {
-               if( *ci == "dvd")
-                 supportsDVD = true;
-             }
-           }
-
-           MediaSource media("cdrom", drv.getDeviceFile(),
-                                      drv.getDeviceMajor(),
-                                      drv.getDeviceMinor());
-           DBG << "Found " << drv_udis[d] << ": "
-                           << media.asString() << std::endl;
-           if( supportingDVD && supportsDVD)
-           {
-             detected.push_front(media);
-           }
-           else
-           {
-             detected.push_back(media);
-           }
-         }
-       }
+        device = "/dev/dvd";
       }
-      catch(const zypp::target::hal::HalException &e)
+
+      PathInfo dinfo(device);
+      if( dinfo.isBlk())
       {
-       ZYPP_CAUGHT(e);
+        MediaSource media("cdrom", device, dinfo.major(), dinfo.minor());
+
+        DeviceList::const_iterator d( detected.begin());
+        for( ; d != detected.end(); ++d)
+        {
+          // /dev/cdrom or /dev/dvd to the front
+          if( media.equals( *d))
+            _devices.push_front( *d);
+          else
+            _devices.push_back( *d);
+        }
       }
-
-      //
-      // Bug #163971
-      // Hal does not include SCSI / Virtual CDROMs on iSeries ...
-      //
-      // Hmm... always? We can't detect DVD here.
-      if( detected.empty())
+      else
       {
-       Pathname    sysfs_path( get_sysfs_path());
-       if(sysfs_path.empty())
-         return detected;
-
-       std::string sys_name;
-       std::string dev_name;
-
-       // SCSI cdrom devices (/dev/sr0, ...)
-       sys_name = sysfs_path.cat("block/sr").asString();
-       dev_name = "/dev/sr";
-       DBG << "Collecting SCSI CD-ROM devices ("
-           << dev_name << "X)" << std::endl;
-       for(size_t i=0; i < 16; i++)
-       {
-         PathInfo sys_info(sys_name + str::numstring(i));
-         PathInfo dev_info(dev_name + str::numstring(i));
-         if( sys_info.isDir() && dev_info.isBlk())
-         {
-           // Hmm.. how to check if it supports DVDs?
-           MediaSource media("cdrom", dev_info.asString(),
-                                      dev_info.major(),
-                                      dev_info.minor());
-           if( isNewDevice(detected, media))
-           {
-             DBG << "Found SCSI CDROM "
-                 << media.asString()
-                 << std::endl;
-             detected.push_back(media);
-           }
-         }
-       }
-
-       // IBM iSeries virtual CD-ROM devices (how many?)
-#if powerpc
-       sys_name = sysfs_path.cat("block/iseries!vcd").asString();
-       dev_name = "/dev/iseries/vcd";
-       DBG << "Collecting iSeries virtual CD-ROM devices ("
-           << dev_name << "X)" << std::endl;
-       for(size_t i=0; i < 8; i++)
-       {
-         char drive_letter = 'a' + i;
-         PathInfo sys_info(sys_name + drive_letter);
-         PathInfo dev_info(dev_name + drive_letter);
-         if( sys_info.isDir() && dev_info.isBlk())
-         {
-           // Hmm.. how to check if it supports DVDs?
-           MediaSource media("cdrom", dev_info.asString(),
-                                      dev_info.major(),
-                                      dev_info.minor());
-           if( isNewDevice(detected, media))
-           {
-             DBG << "Found iSeries virtual CDROM "
-                 << media.asString()
-                 << std::endl;
-             detected.push_back(media);
-           }
-         }
-       }
-#endif // powerpc
-
-       // Other device types?
+        // no /dev/cdrom or /dev/dvd link
+        _devices = detected;
       }
-      return detected;
     }
 
+    Mount mount;
+    string mountpoint = attachPoint().asString();
+    bool mountsucceeded = false;
+    int count = 0;
+    MediaMountException merr;
 
-    ///////////////////////////////////////////////////////////////////
-    //
-    //
-    // METHOD NAME : MediaCD::attachTo
-    // METHOD TYPE : PMError
-    //
-    // DESCRIPTION : Asserted that not already attached, and attachPoint is a directory.
-    //
-    void MediaCD::attachTo(bool next)
+    string options = _url.getQueryParam("mountoptions");
+    if (options.empty())
     {
-      DBG << "next " << next << " last " << _lastdev << endl;
-      if (next && _lastdev == -1)
-       ZYPP_THROW(MediaNotSupportedException(url()));
+      options="ro";
+    }
 
-#if DELAYED_VERIFY
-      DeviceList detected( detectDevices(
-       _url.getScheme() == "dvd" ? true : false
-      ));
+    //TODO: make configurable
+    list<string> filesystems;
 
-      if(_devices.empty())
-      {
-       DBG << "creating on-demand device list" << endl;
-       //default is /dev/cdrom; for dvd: /dev/dvd if it exists
-        string device( "/dev/cdrom" );
-       if ( _url.getScheme() == "dvd" && PathInfo( "/dev/dvd" ).isBlk() ) {
-         device = "/dev/dvd";
-       }
-
-       PathInfo dinfo(device);
-       if( dinfo.isBlk())
-       {
-         MediaSource media("cdrom", device, dinfo.major(), dinfo.minor());
-
-         DeviceList::const_iterator d( detected.begin());
-         for( ; d != detected.end(); ++d)
-         {
-           // /dev/cdrom or /dev/dvd to the front
-           if( media.equals( *d))
-             _devices.push_front( *d);
-           else
-             _devices.push_back( *d);
-         }
-       }
-       else
-       {
-         // no /dev/cdrom or /dev/dvd link
-         _devices = detected;
-       }
-      }
-#endif
+    // if DVD, try UDF filesystem before iso9660
+    if ( _url.getScheme() == "dvd" )
+      filesystems.push_back("udf");
 
-      Mount mount;
-      string mountpoint = attachPoint().asString();
-      bool mountsucceeded = false;
-      int count = 0;
-      MediaMountException merr;
+    filesystems.push_back("iso9660");
 
-      string options = _url.getQueryParam("mountoptions");
-      if (options.empty())
+    // try all devices in sequence
+    for (DeviceList::iterator it = _devices.begin()
+    ; !mountsucceeded && it != _devices.end()
+    ; ++it, count++ )
+    {
+      DBG << "count " << count << endl;
+      if (next && count <=_lastdev_tried )
       {
-       options="ro";
+        DBG << "skipping device " << it->name << endl;
+        continue;
       }
 
-      //TODO: make configurable
-      list<string> filesystems;
+      _lastdev_tried = count;
 
-      // if DVD, try UDF filesystem before iso9660
-      if ( _url.getScheme() == "dvd" )
-       filesystems.push_back("udf");
+      MediaSource temp( *it);
+      bool        valid=false;
+      PathInfo    dinfo(temp.name);
+      if( dinfo.isBlk())
+      {
+        temp.maj_nr = dinfo.major();
+        temp.min_nr = dinfo.minor();
+
+        DeviceList::const_iterator d( detected.begin());
+        for( ; d != detected.end(); ++d)
+        {
+          if( temp.equals( *d))
+          {
+            valid = true;
+            break;
+          }
+        }
+      }
+      if( !valid)
+      {
+        DBG << "skipping invalid device: " << it->name << endl;
+        continue;
+      }
 
-      filesystems.push_back("iso9660");
+      MediaSourceRef media( new MediaSource(temp));
+      AttachedMedia ret( findAttachedMedia( media));
 
-      // try all devices in sequence
-      for (DeviceList::iterator it = _devices.begin()
-       ; !mountsucceeded && it != _devices.end()
-       ; ++it, count++ )
+      if( ret.mediaSource && ret.attachPoint &&
+         !ret.attachPoint->empty())
       {
-       DBG << "count " << count << endl;
-       if (next && count<=_lastdev )
-       {
-               DBG << "skipping device " << it->name << endl;
-               continue;
-       }
-#if DELAYED_VERIFY
-       MediaSource temp( *it);
-       bool        valid=false;
-       PathInfo    dinfo(temp.name);
-       if( dinfo.isBlk())
-       {
-         temp.maj_nr = dinfo.major();
-         temp.min_nr = dinfo.minor();
-
-         DeviceList::const_iterator d( detected.begin());
-         for( ; d != detected.end(); ++d)
-         {
-           if( temp.equals( *d))
-           {
-             valid = true;
-             break;
-           }
-         }
-       }
-       if( !valid)
-       {
-               DBG << "skipping invalid device: " << it->name << endl;
-               continue;
-       }
-       MediaSourceRef media( new MediaSource(temp));
-#else
-       MediaSourceRef media( new MediaSource( *it));
-#endif
-
-       AttachedMedia ret( findAttachedMedia( media));
-
-       if( ret.mediaSource && ret.attachPoint &&
-          !ret.attachPoint->empty())
-       {
-         DBG << "Using a shared media "
-             << ret.mediaSource->name
-             << " attached on "
-             << ret.attachPoint->path
-             << endl;
-         removeAttachPoint();
-         setAttachPoint(ret.attachPoint);
-         setMediaSource(ret.mediaSource);
-         _lastdev = count;
-         mountsucceeded = true;
-         break;
-       }
-       // FIXME: hmm... we may also
-       // - check against hal/mtab if still mounted
-       // - if !ret, check if already mounted (e.g.
-       //   by automounter) and reuse (!temp) ?
-
-       // close tray
-       closeTray( it->name );
-
-       // try all filesystems in sequence
-       for(list<string>::iterator fsit = filesystems.begin()
-           ; !mountsucceeded && fsit != filesystems.end()
-           ; ++fsit)
-       {
-         try {
-           if( !isUseableAttachPoint(Pathname(mountpoint)))
-           {
-             mountpoint = createAttachPoint().asString();
-             setAttachPoint( mountpoint, true);
-             if( mountpoint.empty())
-             {
-               ZYPP_THROW( MediaBadAttachPointException(url()));
-             }
-           }
-
-           mount.mount(it->name, mountpoint, *fsit, options);
-
-           setMediaSource(media);
-
-           // wait for /etc/mtab update ...
-           // (shouldn't be needed)
-           int limit = 5;
-           while( !(mountsucceeded=isAttached()) && --limit)
-           {
-             sleep(1);
-           }
-
-           if( mountsucceeded)
-           {
-             _lastdev = count;
-           }
-           else
-           {
-             setMediaSource(MediaSourceRef());
-             try
-             {
-               mount.umount(attachPoint().asString());
-             }
-             catch (const MediaException & excpt_r)
-             {
-               ZYPP_CAUGHT(excpt_r);
-             }
-             ZYPP_THROW(MediaMountException(
-               "Unable to verify that the media was mounted",
-               it->name, mountpoint
-             ));
-           }
-         }
-         catch (const MediaMountException &e)
-         {
-           merr = e;
-           removeAttachPoint();
-           ZYPP_CAUGHT(e);
-         }
-         catch (const MediaException & excpt_r)
-         {
-           removeAttachPoint();
-           ZYPP_CAUGHT(excpt_r);
-         }
-       }
+        DBG << "Using a shared media "
+            << ret.mediaSource->name
+            << " attached on "
+            << ret.attachPoint->path
+            << endl;
+        removeAttachPoint();
+        setAttachPoint(ret.attachPoint);
+        setMediaSource(ret.mediaSource);
+        _lastdev = count;
+        mountsucceeded = true;
+        break;
       }
 
-      if (!mountsucceeded)
+#if REUSE_FOREIGN_MOUNTS > 0
       {
-       _lastdev = -1;
-
-       if( !merr.mountOutput().empty())
-       {
-         ZYPP_THROW(MediaMountException(merr.mountError(),
-                                        _url.asString(),
-                                        mountpoint,
-                                        merr.mountOutput()));
-       }
-       else
-       {
-         ZYPP_THROW(MediaMountException("Mounting media failed",
-                                        _url.asString(), mountpoint));
-       }
+        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.major() &&
+                           media->min_nr == dev_info.minor())
+          {
+            AttachPointRef ap( new AttachPoint(e->dir, false));
+            AttachedMedia  am( media, ap);
+            //
+            // 1 = automounted only, 2 == all
+            //
+#if REUSE_FOREIGN_MOUNTS == 1
+            if( isAutoMountedMedia(am))
+#endif
+            {
+              DBG << "Using a system mounted media "
+                  << media->name
+                  << " attached on "
+                  << ap->path
+                  << endl;
+
+              media->iown = false; // mark attachment as foreign
+
+              setMediaSource(media);
+              setAttachPoint(ap);
+              _lastdev = count;
+              mountsucceeded = true;
+              break;
+            }
+          }
+        }
+        if( mountsucceeded)
+          break;
       }
-      DBG << _lastdev << " " << count << endl;
-    }
+#endif  // REUSE_FOREIGN_MOUNTS
 
+      // close tray
+      closeTray( it->name );
 
-    ///////////////////////////////////////////////////////////////////
-    //
-    //
-    // METHOD NAME : MediaCD::releaseFrom
-    // METHOD TYPE : PMError
-    //
-    // DESCRIPTION : Asserted that media is attached.
-    //
-    void MediaCD::releaseFrom( bool eject )
+      // try all filesystems in sequence
+      for(list<string>::iterator fsit = filesystems.begin()
+          ; !mountsucceeded && fsit != filesystems.end()
+          ; ++fsit)
+      {
+        try
+        {
+          if( !isUseableAttachPoint(Pathname(mountpoint)))
+          {
+            mountpoint = createAttachPoint().asString();
+            setAttachPoint( mountpoint, true);
+            if( mountpoint.empty())
+            {
+              ZYPP_THROW( MediaBadAttachPointException(url()));
+            }
+          }
+
+          mount.mount(it->name, mountpoint, *fsit, options);
+
+          setMediaSource(media);
+
+          // wait for /etc/mtab update ...
+          // (shouldn't be needed)
+          int limit = 5;
+          while( !(mountsucceeded=isAttached()) && --limit)
+          {
+            sleep(1);
+          }
+
+          if( mountsucceeded)
+          {
+            _lastdev = count;
+          }
+          else
+          {
+            setMediaSource(MediaSourceRef());
+            try
+            {
+              mount.umount(attachPoint().asString());
+            }
+            catch (const MediaException & excpt_r)
+            {
+              ZYPP_CAUGHT(excpt_r);
+            }
+            ZYPP_THROW(MediaMountException(
+              "Unable to verify that the media was mounted",
+              it->name, mountpoint
+            ));
+          }
+        }
+        catch (const MediaMountException &e)
+        {
+          merr = e;
+          removeAttachPoint();
+          ZYPP_CAUGHT(e);
+        }
+        catch (const MediaException & excpt_r)
+        {
+          removeAttachPoint();
+          ZYPP_CAUGHT(excpt_r);
+        }
+      } // for filesystems
+    } // for _devices
+
+    if (!mountsucceeded)
     {
-      Mount mount;
-      try {
-       mount.umount(attachPoint().asString());
+      _lastdev = -1;
+
+      if( !merr.mountOutput().empty())
+      {
+        ZYPP_THROW(MediaMountException(merr.mountError(),
+                                       _url.asString(),
+                                       mountpoint,
+                                       merr.mountOutput()));
       }
-      catch (const Exception & excpt_r)
+      else
       {
-       ZYPP_CAUGHT(excpt_r);
-       if (eject)
-       {
-#if FORCE_RELEASE_FOREIGN
-         forceRelaseAllMedia(false, FORCE_RELEASE_FOREIGN != 2);
-#endif
-         if(openTray( mediaSourceName()))
-           return;
-       }
-       ZYPP_RETHROW(excpt_r);
+        ZYPP_THROW(MediaMountException("Mounting media failed",
+                                       _url.asString(), mountpoint));
       }
-
-      // eject device
-      if (eject)
+    }
+    DBG << _lastdev << " " << count << endl;
+  }
+
+
+  ///////////////////////////////////////////////////////////////////
+  //
+  //
+  //  METHOD NAME : MediaCD::releaseFrom
+  //  METHOD TYPE : PMError
+  //
+  //  DESCRIPTION : Asserted that media is attached.
+  //
+  void MediaCD::releaseFrom( const std::string & ejectDev )
+  {
+    Mount mount;
+    try
+    {
+      AttachedMedia am( attachedMedia());
+      if(am.mediaSource && am.mediaSource->iown)
+        mount.umount(am.attachPoint->path.asString());
+    }
+    catch (const Exception & excpt_r)
+    {
+      ZYPP_CAUGHT(excpt_r);
+      if (!ejectDev.empty())
       {
-#if FORCE_RELEASE_FOREIGN
-        forceRelaseAllMedia(false, FORCE_RELEASE_FOREIGN != 2);
+#if FORCE_RELEASE_FOREIGN > 0
+        /* 1 = automounted only, 2 = all */
+        forceRelaseAllMedia(false, FORCE_RELEASE_FOREIGN == 1);
 #endif
-        if( !openTray( mediaSourceName() ))
-       {
-#if REPORT_EJECT_ERRORS
-         ZYPP_THROW(MediaNotEjectedException(mediaSourceName()));
-#endif
-       }
+        if(openTray( ejectDev ))
+          return;
       }
+      ZYPP_RETHROW(excpt_r);
     }
 
-    ///////////////////////////////////////////////////////////////////
-    //
-    //
-    // METHOD NAME : MediaCD::forceEject
-    // METHOD TYPE : void
-    //
-    // Asserted that media is not attached.
-    //
-    void MediaCD::forceEject()
+    // eject device
+    if (!ejectDev.empty())
     {
-      bool ejected=false;
-      if ( !isAttached()) {    // no device mounted in this instance
-#if DELAYED_VERIFY
-       DeviceList detected( detectDevices(
-         _url.getScheme() == "dvd" ? true : false
-       ));
-
-       if(_devices.empty())
-       {
-         DBG << "creating on-demand device list" << endl;
-         //default is /dev/cdrom; for dvd: /dev/dvd if it exists
-         string device( "/dev/cdrom" );
-         if ( _url.getScheme() == "dvd" && PathInfo( "/dev/dvd" ).isBlk() ) {
-          device = "/dev/dvd";
-         }
-
-         PathInfo dinfo(device);
-         if( dinfo.isBlk())
-         {
-           MediaSource media("cdrom", device, dinfo.major(), dinfo.minor());
-
-           DeviceList::const_iterator d( detected.begin());
-           for( ; d != detected.end(); ++d)
-           {
-             // /dev/cdrom or /dev/dvd to the front
-             if( media.equals( *d))
-               _devices.push_front( *d);
-             else
-               _devices.push_back( *d);
-           }
-         }
-         else
-         {
-           // no /dev/cdrom or /dev/dvd link
-           _devices = detected;
-         }
-       }
-#endif
-
-       DeviceList::iterator it;
-       for( it = _devices.begin(); it != _devices.end(); ++it ) {
-         MediaSourceRef media( new MediaSource( *it));
-#if DELAYED_VERIFY
-         bool        valid=false;
-         PathInfo    dinfo(media->name);
-         if( dinfo.isBlk())
-         {
-           media->maj_nr = dinfo.major();
-           media->min_nr = dinfo.minor();
-
-           DeviceList::const_iterator d( detected.begin());
-           for( ; d != detected.end(); ++d)
-           {
-             if( media->equals( *d))
-             {
-               valid = true;
-               break;
-             }
-           }
-         }
-         if( !valid)
-         {
-           DBG << "skipping invalid device: " << it->name << endl;
-           continue;
-         }
+#if FORCE_RELEASE_FOREIGN > 0
+      /* 1 = automounted only, 2 = all */
+      forceRelaseAllMedia(false, FORCE_RELEASE_FOREIGN == 1);
 #endif
-
-         // FIXME: we have also to check if it is mounted in the system
-         AttachedMedia ret( findAttachedMedia( media));
-         if( !ret.mediaSource)
-         {
-#if FORCE_RELEASE_FOREIGN
-           forceRelaseAllMedia(media, false, FORCE_RELEASE_FOREIGN != 2);
-#endif
-           if ( openTray( it->name ) )
-           {
-             ejected = true;
-             break; // on 1st success
-           }
-         }
-       }
-      }
-      if( !ejected)
+      if( !openTray( ejectDev ))
       {
 #if REPORT_EJECT_ERRORS
-       ZYPP_THROW(MediaNotEjectedException());
+        ZYPP_THROW(MediaNotEjectedException(ejectDev));
 #endif
       }
     }
+  }
+
+  ///////////////////////////////////////////////////////////////////
+  //
+  //
+  //  METHOD NAME : MediaCD::forceEject
+  //  METHOD TYPE : void
+  //
+  // Asserted that media is not attached.
+  //
+  void MediaCD::forceEject(const std::string & ejectDev)
+  {
+    bool ejected=false;
+    if ( !isAttached()) {      // no device mounted in this instance
+
+      DeviceList detected(
+          detectDevices(_url.getScheme() == "dvd" ? true : false));
 
-    bool MediaCD::isAutoMountedMedia(const AttachedMedia &media)
-    {
-      bool is_automounted = false;
-      if( media.mediaSource && !media.mediaSource->name.empty())
+      if(_devices.empty())
       {
-        using namespace zypp::target::hal;
-
-       try
-       {
-         HalContext hal(true);
-
-         HalVolume vol = hal.getVolumeFromDeviceFile(media.mediaSource->name);
-         if( vol)
-         {
-           std::string udi = vol.getUDI();
-           std::string key = "info.hal_mount.created_mount_point";
-           std::string mnt = hal.getDevicePropertyString(udi, key);
-
-           if(media.attachPoint->path == mnt)
-             is_automounted = true;
-         }
-       }
-        catch(const HalException &e)
-       {
-         ZYPP_CAUGHT(e);
-       }
+        DBG << "creating on-demand device list" << endl;
+        //default is /dev/cdrom; for dvd: /dev/dvd if it exists
+        string device( "/dev/cdrom" );
+        if ( _url.getScheme() == "dvd" && PathInfo( "/dev/dvd" ).isBlk() ) {
+          device = "/dev/dvd";
+        }
+
+        PathInfo dinfo(device);
+        if( dinfo.isBlk())
+        {
+          MediaSource media("cdrom", device, dinfo.major(), dinfo.minor());
+
+          DeviceList::const_iterator d( detected.begin());
+          for( ; d != detected.end(); ++d)
+          {
+            // /dev/cdrom or /dev/dvd to the front
+            if( media.equals( *d))
+              _devices.push_front( *d);
+            else
+              _devices.push_back( *d);
+          }
+        }
+        else
+        {
+          // no /dev/cdrom or /dev/dvd link
+          _devices = detected;
+        }
       }
-      DBG << "Media "       << media.mediaSource->asString()
-          << " attached on " << media.attachPoint->path
-          << " is"           << (is_automounted ? "" : " not")
-          << " automounted"  << std::endl;
-      return is_automounted;
-    }
 
-    ///////////////////////////////////////////////////////////////////
-    //
-    // METHOD NAME : MediaCD::isAttached
-    // METHOD TYPE : bool
-    //
-    // DESCRIPTION : Override check if media is attached.
-    //
-    bool
-    MediaCD::isAttached() const
-    {
-      return checkAttached(false);
+      DeviceList::iterator it;
+      for( it = _devices.begin(); it != _devices.end(); ++it ) {
+        MediaSourceRef media( new MediaSource( *it));
+        if (media->name != ejectDev)
+          continue;
+
+        bool        valid=false;
+        PathInfo    dinfo(media->name);
+        if( dinfo.isBlk())
+        {
+          media->maj_nr = dinfo.major();
+          media->min_nr = dinfo.minor();
+
+          DeviceList::const_iterator d( detected.begin());
+          for( ; d != detected.end(); ++d)
+          {
+            if( media->equals( *d))
+            {
+              valid = true;
+              break;
+            }
+          }
+        }
+        if( !valid)
+        {
+          DBG << "skipping invalid device: " << it->name << endl;
+          continue;
+        }
+
+        // FIXME: we have also to check if it is mounted in the system
+        AttachedMedia ret( findAttachedMedia( media));
+        if( !ret.mediaSource)
+        {
+#if FORCE_RELEASE_FOREIGN > 0
+          /* 1 = automounted only, 2 = all */
+          forceRelaseAllMedia(media, false, FORCE_RELEASE_FOREIGN == 1);
+#endif
+          if ( openTray( it->name ) )
+          {
+            ejected = true;
+            break; // on 1st success
+          }
+        }
+      }
     }
-
-    ///////////////////////////////////////////////////////////////////
-    //
-    // METHOD NAME : MediaCD::getFile
-    // METHOD TYPE : PMError
-    //
-    // DESCRIPTION : Asserted that media is attached.
-    //
-    void MediaCD::getFile( const Pathname & filename ) const
+    if( !ejected)
     {
-      MediaHandler::getFile( filename );
+#if REPORT_EJECT_ERRORS
+      ZYPP_THROW(MediaNotEjectedException());
+#endif
     }
+  }
 
-    ///////////////////////////////////////////////////////////////////
-    //
-    // METHOD NAME : MediaCD::getDir
-    // METHOD TYPE : PMError
-    //
-    // DESCRIPTION : Asserted that media is attached.
-    //
-    void MediaCD::getDir( const Pathname & dirname, bool recurse_r ) const
+  bool MediaCD::isAutoMountedMedia(const AttachedMedia &media)
+  {
+    bool is_automounted = false;
+    if( media.mediaSource && !media.mediaSource->name.empty())
     {
-      MediaHandler::getDir( dirname, recurse_r );
+#ifndef NO_HAL
+      using namespace zypp::target::hal;
+      try
+      {
+        HalContext hal(true);
+
+        HalVolume vol = hal.getVolumeFromDeviceFile(media.mediaSource->name);
+        if( vol)
+        {
+          std::string udi = vol.getUDI();
+          std::string key;
+          std::string mnt;
+
+          try
+          {
+            key = "info.hal_mount.created_mount_point";
+            mnt = hal.getDevicePropertyString(udi, key);
+
+            if(media.attachPoint->path == mnt)
+              is_automounted = true;
+          }
+          catch(const HalException &e1)
+          {
+            ZYPP_CAUGHT(e1);
+
+            try
+            {
+              key = "volume.mount_point";
+              mnt = hal.getDevicePropertyString(udi, key);
+
+              if(media.attachPoint->path == mnt)
+                is_automounted = true;
+            }
+            catch(const HalException &e2)
+            {
+              ZYPP_CAUGHT(e2);
+            }
+          }
+        }
+      }
+      catch(const HalException &e)
+      {
+        ZYPP_CAUGHT(e);
+      }
+#else // NO_HAL
+#warning Can not detect automounted media without HAL
+    INT << "Can not detect automounted media without HAL!" << endl;
+    // ma@: This codepath is probably unused due to 'REUSE_FOREIGN_MOUNTS == 2'
+    // Maybe we should cleanup all this automount-specail-handling.
+#endif
     }
+    DBG << "Media "        << media.mediaSource->asString()
+        << " attached on " << media.attachPoint->path
+        << " is"           << (is_automounted ? "" : " not")
+        << " automounted"  << std::endl;
+    return is_automounted;
+  }
+
+  ///////////////////////////////////////////////////////////////////
+  //
+  //  METHOD NAME : MediaCD::isAttached
+  //  METHOD TYPE : bool
+  //
+  //  DESCRIPTION : Override check if media is attached.
+  //
+  bool
+  MediaCD::isAttached() const
+  {
+    return checkAttached(false);
+  }
+
+  ///////////////////////////////////////////////////////////////////
+  //
+  //  METHOD NAME : MediaCD::getFile
+  //  METHOD TYPE : PMError
+  //
+  //  DESCRIPTION : Asserted that media is attached.
+  //
+  void MediaCD::getFile( const Pathname & filename ) const
+  {
+    MediaHandler::getFile( filename );
+  }
+
+  ///////////////////////////////////////////////////////////////////
+  //
+  //  METHOD NAME : MediaCD::getDir
+  //  METHOD TYPE : PMError
+  //
+  //  DESCRIPTION : Asserted that media is attached.
+  //
+  void MediaCD::getDir( const Pathname & dirname, bool recurse_r ) const
+  {
+    MediaHandler::getDir( dirname, recurse_r );
+  }
+
+  ///////////////////////////////////////////////////////////////////
+  //
+  //
+  //  METHOD NAME : MediaCD::getDirInfo
+  //  METHOD TYPE : PMError
+  //
+  //  DESCRIPTION : Asserted that media is attached and retlist is empty.
+  //
+  void MediaCD::getDirInfo( std::list<std::string> & retlist,
+                            const Pathname & dirname, bool dots ) const
+  {
+    MediaHandler::getDirInfo( retlist, dirname, dots );
+  }
+
+  ///////////////////////////////////////////////////////////////////
+  //
+  //
+  //  METHOD NAME : MediaCD::getDirInfo
+  //  METHOD TYPE : PMError
+  //
+  //  DESCRIPTION : Asserted that media is attached and retlist is empty.
+  //
+  void MediaCD::getDirInfo( filesystem::DirContent & retlist,
+                            const Pathname & dirname, bool dots ) const
+  {
+    MediaHandler::getDirInfo( retlist, dirname, dots );
+  }
+
+  bool MediaCD::getDoesFileExist( const Pathname & filename ) const
+  {
+    return MediaHandler::getDoesFileExist( filename );
+  }
+
+  bool MediaCD::hasMoreDevices()
+  {
+    if (_devices.size() == 0)
+      return false;
+    else if (_lastdev_tried < 0)
+      return true;
 
-    ///////////////////////////////////////////////////////////////////
-    //
-    //
-    // METHOD NAME : MediaCD::getDirInfo
-    // METHOD TYPE : PMError
-    //
-    // DESCRIPTION : Asserted that media is attached and retlist is empty.
-    //
-    void MediaCD::getDirInfo( std::list<std::string> & retlist,
-                             const Pathname & dirname, bool dots ) const
-    {
-      MediaHandler::getDirInfo( retlist, dirname, dots );
-    }
+    return (unsigned) _lastdev_tried < _devices.size() - 1;
+  }
 
-    ///////////////////////////////////////////////////////////////////
-    //
-    //
-    // METHOD NAME : MediaCD::getDirInfo
-    // METHOD TYPE : PMError
-    //
-    // DESCRIPTION : Asserted that media is attached and retlist is empty.
-    //
-    void MediaCD::getDirInfo( filesystem::DirContent & retlist,
-                             const Pathname & dirname, bool dots ) const
-    {
-      MediaHandler::getDirInfo( retlist, dirname, dots );
-    }
+  void
+  MediaCD::getDetectedDevices(std::vector<std::string> & devices,
+                              unsigned int & index) const
+  {
+    index = 0;
+    if (!devices.empty())
+      devices.clear();
+
+    for (DeviceList::const_iterator it = _devices.begin();
+         it != _devices.end(); ++it)
+      devices.push_back(it->name);
 
-    bool MediaCD::getDoesFileExist( const Pathname & filename ) const
+    if (_lastdev >= 0)
+      index = _lastdev;
+
+    // try to detect again if _devices are empty (maybe this method will be
+    // called before _devices get actually filled)
+    if (devices.empty())
     {
-      return MediaHandler::getDoesFileExist( filename );
+      DBG << "no device list so far, trying to detect" << endl;
+
+      DeviceList detected(
+        detectDevices(_url.getScheme() == "dvd" ? true : false));
+
+      for (DeviceList::const_iterator it = detected.begin();
+           it != detected.end(); ++it)
+        devices.push_back(it->name);
+
+      // don't know which one is in use in this case
+      index = 0;
     }
 
+    MIL << "got " << devices.size() << " detected devices, current: "
+        << (index < devices.size() ? devices[index] : "<none>")
+        << "(" << index << ")" << endl;
+  }
+
+
   } // namespace media
 } // namespace zypp
 // vim: set ts=8 sts=2 sw=2 ai noet: