MediaCD.cc

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00013 #include <iostream>
00014 
00015 #include "zypp/base/Logger.h"
00016 #include "zypp/ExternalProgram.h"
00017 #include "zypp/media/Mount.h"
00018 #include "zypp/media/MediaCD.h"
00019 #include "zypp/media/MediaManager.h"
00020 #include "zypp/Url.h"
00021 #include "zypp/target/hal/HalContext.h"
00022 
00023 #include <cstring> // strerror
00024 #include <cstdlib> // getenv
00025 
00026 #include <errno.h>
00027 #include <dirent.h>
00028 
00029 #include <sys/ioctl.h>
00030 #include <sys/stat.h>
00031 #include <fcntl.h>
00032 #include <unistd.h> // geteuid, ...
00033 
00034 #include <linux/cdrom.h>
00035 
00036 /*
00037 ** verify devices names as late as possible (while attach)
00038 */
00039 #define  DELAYED_VERIFY          1
00040 
00041 /*
00042 ** try umount of foreign (user/automounter) media on eject
00043 **   0 = don't force, 1 = automounted only, 2 == all
00044 */
00045 #define  FORCE_RELEASE_FOREIGN   2
00046 
00047 /*
00048 ** Reuse foreign (user/automounter) mount points.
00049 ** 0 = don't use, 1 = automounted only, 2 = all
00050 */
00051 #define  REUSE_FOREIGN_MOUNTS    2
00052 
00053 /*
00054 ** if to throw exception on eject errors or ignore them
00055 */
00056 #define  REPORT_EJECT_ERRORS     1
00057 
00058 /*
00059 ** If defined to the full path of the eject utility,
00060 ** it will be used additionally to the eject-ioctl.
00061 */
00062 #define EJECT_TOOL_PATH "/bin/eject"
00063 
00064 
00065 using namespace std;
00066 
00067 namespace zypp {
00068   namespace media {
00069 
00070     namespace {
00071 
00072       bool isNewDevice(const std::list<MediaSource> &devices,
00073                        const MediaSource            &media)
00074       {
00075         std::list<MediaSource>::const_iterator d( devices.begin());
00076         for( ; d != devices.end(); ++d)
00077         {
00078           if( media.equals( *d))
00079             return false;
00080         }
00081         return true;
00082       }
00083 
00084       inline Pathname get_sysfs_path()
00085       {
00086         Pathname sysfs_path;
00087         if(::getuid() == ::geteuid() && ::getgid() == ::getegid())
00088         {
00089           const char *env = ::getenv("SYSFS_PATH");
00090           if( env && *env)
00091           {
00092             sysfs_path = env;
00093             if( PathInfo(sysfs_path, PathInfo::LSTAT).isDir())
00094               return sysfs_path;
00095           }
00096         }
00097         sysfs_path = "/sys";
00098         if( PathInfo(sysfs_path, PathInfo::LSTAT).isDir())
00099           return sysfs_path;
00100         else
00101           return Pathname();
00102       }
00103 
00104     }
00105 
00106 
00108 //
00109 //      CLASS NAME : MediaCD
00110 //
00112 
00114     //
00115     //
00116     //  METHOD NAME : MediaCD::MediaCD
00117     //  METHOD TYPE : Constructor
00118     //
00119     //  DESCRIPTION :
00120     //
00121     MediaCD::MediaCD( const Url &      url_r,
00122                   const Pathname & attach_point_hint_r )
00123       : MediaHandler( url_r, attach_point_hint_r,
00124                     url_r.getPathName(), // urlpath below attachpoint
00125                     false )
00126       //, does_download
00127       , _lastdev(-1), _lastdev_tried(-1)
00128     {
00129       MIL << "MediaCD::MediaCD(" << url_r << ", "
00130           << attach_point_hint_r << ")" << endl;
00131 
00132       if( url_r.getScheme() != "dvd" && url_r.getScheme() != "cd")
00133       {
00134         ERR << "Unsupported schema in the Url: " << url_r.asString()
00135                                                  << std::endl;
00136         ZYPP_THROW(MediaUnsupportedUrlSchemeException(_url));
00137       }
00138 
00139 #if !DELAYED_VERIFY
00140       DeviceList detected( detectDevices(
00141         url_r.getScheme() == "dvd" ? true : false
00142       ));
00143 #endif
00144 
00145       string devices = _url.getQueryParam("devices");
00146       if (!devices.empty())
00147       {
00148         string::size_type pos;
00149         DBG << "parse " << devices << endl;
00150         while(!devices.empty())
00151         {
00152             pos = devices.find(',');
00153             string device = devices.substr(0,pos);
00154             if (!device.empty())
00155             {
00156 #if DELAYED_VERIFY
00157               MediaSource media("cdrom", device, 0, 0);
00158               _devices.push_back( media);
00159                DBG << "use device (delayed verify)" << device << endl;
00160 #else
00161               bool is_ok = false;
00162               PathInfo dinfo(device);
00163               if( dinfo.isBlk())
00164               {
00165                 MediaSource media("cdrom", device, dinfo.major(),
00166                                                    dinfo.minor());
00167                 DeviceList::const_iterator d( detected.begin());
00168                 for( ; d != detected.end(); ++d)
00169                 {
00170                   if( media.equals( *d))
00171                   {
00172                     is_ok = true;
00173                     _devices.push_back( *d);
00174                     DBG << "use device " << device << endl;
00175                   }
00176                 }
00177               }
00178 
00179               if( !is_ok)
00180               {
00181                 ERR << "Device " << device << " is not acceptable "
00182                     << "for " << _url.getScheme() << std::endl;
00183                 ZYPP_THROW(MediaBadUrlException(_url,
00184                   "Invalid device name in URL devices argument"
00185                 ));
00186               }
00187 #endif
00188             }
00189             if (pos!=string::npos)
00190                 devices=devices.substr(pos+1);
00191             else
00192                 devices.erase();
00193         }
00194       }
00195       else
00196       {
00197 #if DELAYED_VERIFY
00198         DBG << "going to use on-demand device list" << endl;
00199         return;
00200 #else
00201         DBG << "going to use default device list" << endl;
00202         //default is /dev/cdrom; for dvd: /dev/dvd if it exists
00203         string device( "/dev/cdrom" );
00204         if ( _url.getScheme() == "dvd" && PathInfo( "/dev/dvd" ).isBlk() ) {
00205           device = "/dev/dvd";
00206         }
00207 
00208         PathInfo dinfo(device);
00209         if( dinfo.isBlk())
00210         {
00211           MediaSource media("cdrom", device, dinfo.major(), dinfo.minor());
00212 
00213           DeviceList::const_iterator d( detected.begin());
00214           for( ; d != detected.end(); ++d)
00215           {
00216             // /dev/cdrom or /dev/dvd to the front
00217             if( media.equals( *d))
00218               _devices.push_front( *d);
00219             else
00220               _devices.push_back( *d);
00221           }
00222         }
00223         else
00224         {
00225           // no /dev/cdrom or /dev/dvd link
00226           _devices = detected;
00227         }
00228 #endif
00229       }
00230 
00231       if( _devices.empty())
00232       {
00233         ERR << "Unable to find any cdrom drive for " << _url.asString()
00234                                                      << std::endl;
00235         ZYPP_THROW(MediaBadUrlEmptyDestinationException(_url));
00236       }
00237     }
00238 
00240     //
00241     //
00242     //  METHOD NAME : MediaCD::openTray
00243     //  METHOD TYPE : bool
00244     //
00245     bool MediaCD::openTray( const std::string & device_r )
00246     {
00247       int fd = ::open( device_r.c_str(), O_RDONLY|O_NONBLOCK );
00248       int res = -1;
00249 
00250       if ( fd != -1)
00251       {
00252         res = ::ioctl( fd, CDROMEJECT );
00253         ::close( fd );
00254       }
00255 
00256       if ( res )
00257       {
00258         if( fd == -1)
00259         {
00260           WAR << "Unable to open '" << device_r
00261               << "' (" << ::strerror( errno ) << ")" << endl;
00262         }
00263         else
00264         {
00265           WAR << "Eject " << device_r
00266               << " failed (" << ::strerror( errno ) << ")" << endl;
00267         }
00268 
00269 #if defined(EJECT_TOOL_PATH)
00270         DBG << "Try to eject " << device_r << " using "
00271             << EJECT_TOOL_PATH << " utility" << std::endl;
00272 
00273         const char *cmd[3];
00274         cmd[0] = EJECT_TOOL_PATH;
00275         cmd[1] = device_r.c_str();
00276         cmd[2] = NULL;
00277         ExternalProgram eject(cmd, ExternalProgram::Stderr_To_Stdout);
00278 
00279         for(std::string out( eject.receiveLine());
00280             out.length(); out = eject.receiveLine())
00281         {
00282           DBG << " " << out;
00283         }
00284 
00285         if(eject.close() != 0)
00286         {
00287           WAR << "Eject of " << device_r << " failed." << std::endl;
00288           return false;
00289         }
00290 #else
00291         return false;
00292 #endif
00293       }
00294       MIL << "Eject of " << device_r << " successful." << endl;
00295       return true;
00296     }
00297 
00299     //
00300     //
00301     //  METHOD NAME : MediaCD::closeTray
00302     //  METHOD TYPE : bool
00303     //
00304     bool MediaCD::closeTray( const std::string & device_r )
00305     {
00306       int fd = ::open( device_r.c_str(), O_RDONLY|O_NONBLOCK );
00307       if ( fd == -1 ) {
00308         WAR << "Unable to open '" << device_r << "' (" << ::strerror( errno ) << ")" << endl;
00309         return false;
00310       }
00311       int res = ::ioctl( fd, CDROMCLOSETRAY );
00312       ::close( fd );
00313       if ( res ) {
00314         WAR << "Close tray " << device_r << " failed (" << ::strerror( errno ) << ")" << endl;
00315         return false;
00316       }
00317       DBG << "Close tray " << device_r << endl;
00318       return true;
00319     }
00320 
00322     //
00323     //
00324     //  METHOD NAME : MediaCD::detectDevices
00325     //  METHOD TYPE : MediaCD::DeviceList
00326     //
00327     MediaCD::DeviceList
00328     MediaCD::detectDevices(bool supportingDVD)
00329     {
00330       using namespace zypp::target::hal;
00331 
00332       DeviceList detected;
00333       try
00334       {
00335         HalContext hal(true);
00336 
00337         std::vector<std::string> drv_udis;
00338         drv_udis = hal.findDevicesByCapability("storage.cdrom");
00339 
00340         DBG << "Found " << drv_udis.size() << " cdrom drive udis" << std::endl;
00341         for(size_t d = 0; d < drv_udis.size(); d++)
00342         {
00343           HalDrive drv( hal.getDriveFromUDI( drv_udis[d]));
00344 
00345           if( drv)
00346           {
00347             bool supportsDVD=false;
00348             if( supportingDVD)
00349             {
00350               std::vector<std::string> caps;
00351               try {
00352                 caps = drv.getCdromCapabilityNames();
00353               }
00354               catch(const HalException &e)
00355               {
00356                 ZYPP_CAUGHT(e);
00357               }
00358 
00359               std::vector<std::string>::const_iterator ci;
00360               for( ci=caps.begin(); ci != caps.end(); ++ci)
00361               {
00362                 if( *ci == "dvd")
00363                   supportsDVD = true;
00364               }
00365             }
00366 
00367             MediaSource media("cdrom", drv.getDeviceFile(),
00368                                        drv.getDeviceMajor(),
00369                                        drv.getDeviceMinor());
00370             DBG << "Found " << drv_udis[d] << ": "
00371                             << media.asString() << std::endl;
00372             if( supportingDVD && supportsDVD)
00373             {
00374               detected.push_front(media);
00375             }
00376             else
00377             {
00378               detected.push_back(media);
00379             }
00380           }
00381         }
00382       }
00383       catch(const zypp::target::hal::HalException &e)
00384       {
00385         ZYPP_CAUGHT(e);
00386       }
00387 
00388       //
00389       // Bug #163971
00390       // Hal does not include SCSI / Virtual CDROMs on iSeries ...
00391       //
00392       // Hmm... always? We can't detect DVD here.
00393       if( detected.empty())
00394       {
00395         Pathname    sysfs_path( get_sysfs_path());
00396         if(sysfs_path.empty())
00397           return detected;
00398 
00399         std::string sys_name;
00400         std::string dev_name;
00401 
00402         // SCSI cdrom devices (/dev/sr0, ...)
00403         sys_name = sysfs_path.cat("block/sr").asString();
00404         dev_name = "/dev/sr";
00405         DBG << "Collecting SCSI CD-ROM devices ("
00406             << dev_name << "X)" << std::endl;
00407         for(size_t i=0; i < 16; i++)
00408         {
00409           PathInfo sys_info(sys_name + str::numstring(i));
00410           PathInfo dev_info(dev_name + str::numstring(i));
00411           if( sys_info.isDir() && dev_info.isBlk())
00412           {
00413             // Hmm.. how to check if it supports DVDs?
00414             MediaSource media("cdrom", dev_info.asString(),
00415                                        dev_info.major(),
00416                                        dev_info.minor());
00417             if( isNewDevice(detected, media))
00418             {
00419               DBG << "Found SCSI CDROM "
00420                   << media.asString()
00421                   << std::endl;
00422               detected.push_back(media);
00423             }
00424           }
00425         }
00426 
00427         // IBM iSeries virtual CD-ROM devices (how many?)
00428 #if powerpc
00429         sys_name = sysfs_path.cat("block/iseries!vcd").asString();
00430         dev_name = "/dev/iseries/vcd";
00431         DBG << "Collecting iSeries virtual CD-ROM devices ("
00432             << dev_name << "X)" << std::endl;
00433         for(size_t i=0; i < 8; i++)
00434         {
00435           char drive_letter = 'a' + i;
00436           PathInfo sys_info(sys_name + drive_letter);
00437           PathInfo dev_info(dev_name + drive_letter);
00438           if( sys_info.isDir() && dev_info.isBlk())
00439           {
00440             // Hmm.. how to check if it supports DVDs?
00441             MediaSource media("cdrom", dev_info.asString(),
00442                                        dev_info.major(),
00443                                        dev_info.minor());
00444             if( isNewDevice(detected, media))
00445             {
00446               DBG << "Found iSeries virtual CDROM "
00447                   << media.asString()
00448                   << std::endl;
00449               detected.push_back(media);
00450             }
00451           }
00452         }
00453 #endif // powerpc
00454 
00455         // Other device types?
00456       }
00457       return detected;
00458     }
00459 
00460 
00462     //
00463     //
00464     //  METHOD NAME : MediaCD::attachTo
00465     //  METHOD TYPE : PMError
00466     //
00467     //  DESCRIPTION : Asserted that not already attached, and attachPoint is a directory.
00468     //
00469     void MediaCD::attachTo(bool next)
00470     {
00471       DBG << "next " << next << " last " << _lastdev << " last tried " << _lastdev_tried << endl;
00472       if (next && _lastdev == -1)
00473         ZYPP_THROW(MediaNotSupportedException(url()));
00474 
00475 #if DELAYED_VERIFY
00476       DeviceList detected( detectDevices(
00477         _url.getScheme() == "dvd" ? true : false
00478       ));
00479 
00480       if(_devices.empty())
00481       {
00482         DBG << "creating on-demand device list" << endl;
00483         //default is /dev/cdrom; for dvd: /dev/dvd if it exists
00484         string device( "/dev/cdrom" );
00485         if ( _url.getScheme() == "dvd" && PathInfo( "/dev/dvd" ).isBlk() ) {
00486           device = "/dev/dvd";
00487         }
00488 
00489         PathInfo dinfo(device);
00490         if( dinfo.isBlk())
00491         {
00492           MediaSource media("cdrom", device, dinfo.major(), dinfo.minor());
00493 
00494           DeviceList::const_iterator d( detected.begin());
00495           for( ; d != detected.end(); ++d)
00496           {
00497             // /dev/cdrom or /dev/dvd to the front
00498             if( media.equals( *d))
00499               _devices.push_front( *d);
00500             else
00501               _devices.push_back( *d);
00502           }
00503         }
00504         else
00505         {
00506           // no /dev/cdrom or /dev/dvd link
00507           _devices = detected;
00508         }
00509       }
00510 #endif
00511 
00512       Mount mount;
00513       string mountpoint = attachPoint().asString();
00514       bool mountsucceeded = false;
00515       int count = 0;
00516       MediaMountException merr;
00517 
00518       string options = _url.getQueryParam("mountoptions");
00519       if (options.empty())
00520       {
00521         options="ro";
00522       }
00523 
00524       //TODO: make configurable
00525       list<string> filesystems;
00526 
00527       // if DVD, try UDF filesystem before iso9660
00528       if ( _url.getScheme() == "dvd" )
00529         filesystems.push_back("udf");
00530 
00531       filesystems.push_back("iso9660");
00532 
00533       // try all devices in sequence
00534       for (DeviceList::iterator it = _devices.begin()
00535         ; !mountsucceeded && it != _devices.end()
00536         ; ++it, count++ )
00537       {
00538         DBG << "count " << count << endl;
00539         if (next && count <=_lastdev_tried )
00540         {
00541                 DBG << "skipping device " << it->name << endl;
00542                 continue;
00543         }
00544 
00545         _lastdev_tried = count;
00546 
00547 #if DELAYED_VERIFY
00548         MediaSource temp( *it);
00549         bool        valid=false;
00550         PathInfo    dinfo(temp.name);
00551         if( dinfo.isBlk())
00552         {
00553           temp.maj_nr = dinfo.major();
00554           temp.min_nr = dinfo.minor();
00555 
00556           DeviceList::const_iterator d( detected.begin());
00557           for( ; d != detected.end(); ++d)
00558           {
00559             if( temp.equals( *d))
00560             {
00561               valid = true;
00562               break;
00563             }
00564           }
00565         }
00566         if( !valid)
00567         {
00568                 DBG << "skipping invalid device: " << it->name << endl;
00569                 continue;
00570         }
00571         MediaSourceRef media( new MediaSource(temp));
00572 #else
00573         MediaSourceRef media( new MediaSource( *it));
00574 #endif
00575 
00576         AttachedMedia ret( findAttachedMedia( media));
00577 
00578         if( ret.mediaSource && ret.attachPoint &&
00579            !ret.attachPoint->empty())
00580         {
00581           DBG << "Using a shared media "
00582               << ret.mediaSource->name
00583               << " attached on "
00584               << ret.attachPoint->path
00585               << endl;
00586           removeAttachPoint();
00587           setAttachPoint(ret.attachPoint);
00588           setMediaSource(ret.mediaSource);
00589           _lastdev = count;
00590           mountsucceeded = true;
00591           break;
00592         }
00593 
00594 #if REUSE_FOREIGN_MOUNTS > 0
00595         {
00596           MediaManager  manager;
00597           MountEntries  entries( manager.getMountEntries());
00598           MountEntries::const_iterator e;
00599           for( e = entries.begin(); e != entries.end(); ++e)
00600           {
00601             bool        is_device = false;
00602             std::string dev_path(Pathname(e->src).asString());
00603             PathInfo    dev_info;
00604 
00605             if( dev_path.compare(0, sizeof("/dev/")-1, "/dev/") == 0 &&
00606                 dev_info(e->src) && dev_info.isBlk())
00607             {
00608               is_device = true;
00609             }
00610 
00611             if( is_device && media->maj_nr == dev_info.major() &&
00612                              media->min_nr == dev_info.minor())
00613             {
00614               AttachPointRef ap( new AttachPoint(e->dir, false));
00615               AttachedMedia  am( media, ap);
00616               //
00617               // 1 = automounted only, 2 == all
00618               //
00619 #if REUSE_FOREIGN_MOUNTS == 1
00620               if( isAutoMountedMedia(am))
00621 #endif
00622               {
00623                 DBG << "Using a system mounted media "
00624                     << media->name
00625                     << " attached on "
00626                     << ap->path
00627                     << endl;
00628 
00629                 media->iown = false; // mark attachment as foreign
00630 
00631                 setMediaSource(media);
00632                 setAttachPoint(ap);
00633                 _lastdev = count;
00634                 mountsucceeded = true;
00635                 break;
00636               }
00637             }
00638           }
00639           if( mountsucceeded)
00640             break;
00641         }
00642 #endif  // REUSE_FOREIGN_MOUNTS
00643 
00644         // close tray
00645         closeTray( it->name );
00646 
00647         // try all filesystems in sequence
00648         for(list<string>::iterator fsit = filesystems.begin()
00649             ; !mountsucceeded && fsit != filesystems.end()
00650             ; ++fsit)
00651         {
00652           try {
00653             if( !isUseableAttachPoint(Pathname(mountpoint)))
00654             {
00655               mountpoint = createAttachPoint().asString();
00656               setAttachPoint( mountpoint, true);
00657               if( mountpoint.empty())
00658               {
00659                 ZYPP_THROW( MediaBadAttachPointException(url()));
00660               }
00661             }
00662 
00663             mount.mount(it->name, mountpoint, *fsit, options);
00664 
00665             setMediaSource(media);
00666 
00667             // wait for /etc/mtab update ...
00668             // (shouldn't be needed)
00669             int limit = 5;
00670             while( !(mountsucceeded=isAttached()) && --limit)
00671             {
00672               sleep(1);
00673             }
00674 
00675             if( mountsucceeded)
00676             {
00677               _lastdev = count;
00678             }
00679             else
00680             {
00681               setMediaSource(MediaSourceRef());
00682               try
00683               {
00684                 mount.umount(attachPoint().asString());
00685               }
00686               catch (const MediaException & excpt_r)
00687               {
00688                 ZYPP_CAUGHT(excpt_r);
00689               }
00690               ZYPP_THROW(MediaMountException(
00691                 "Unable to verify that the media was mounted",
00692                 it->name, mountpoint
00693               ));
00694             }
00695           }
00696           catch (const MediaMountException &e)
00697           {
00698             merr = e;
00699             removeAttachPoint();
00700             ZYPP_CAUGHT(e);
00701           }
00702           catch (const MediaException & excpt_r)
00703           {
00704             removeAttachPoint();
00705             ZYPP_CAUGHT(excpt_r);
00706           }
00707         }
00708       }
00709 
00710       if (!mountsucceeded)
00711       {
00712         _lastdev = -1;
00713 
00714         if( !merr.mountOutput().empty())
00715         {
00716           ZYPP_THROW(MediaMountException(merr.mountError(),
00717                                          _url.asString(),
00718                                          mountpoint,
00719                                          merr.mountOutput()));
00720         }
00721         else
00722         {
00723           ZYPP_THROW(MediaMountException("Mounting media failed",
00724                                          _url.asString(), mountpoint));
00725         }
00726       }
00727       DBG << _lastdev << " " << count << endl;
00728     }
00729 
00730 
00732     //
00733     //
00734     //  METHOD NAME : MediaCD::releaseFrom
00735     //  METHOD TYPE : PMError
00736     //
00737     //  DESCRIPTION : Asserted that media is attached.
00738     //
00739     void MediaCD::releaseFrom( bool eject )
00740     {
00741       Mount mount;
00742       try {
00743         AttachedMedia am( attachedMedia());
00744         if(am.mediaSource && am.mediaSource->iown)
00745           mount.umount(am.attachPoint->path.asString());
00746       }
00747       catch (const Exception & excpt_r)
00748       {
00749         ZYPP_CAUGHT(excpt_r);
00750         if (eject)
00751         {
00752 #if FORCE_RELEASE_FOREIGN > 0
00753           /* 1 = automounted only, 2 = all */
00754           forceRelaseAllMedia(false, FORCE_RELEASE_FOREIGN == 1);
00755 #endif
00756           if(openTray( mediaSourceName()))
00757             return;
00758         }
00759         ZYPP_RETHROW(excpt_r);
00760       }
00761 
00762       // eject device
00763       if (eject)
00764       {
00765 #if FORCE_RELEASE_FOREIGN > 0
00766         /* 1 = automounted only, 2 = all */
00767         forceRelaseAllMedia(false, FORCE_RELEASE_FOREIGN == 1);
00768 #endif
00769         if( !openTray( mediaSourceName() ))
00770         {
00771 #if REPORT_EJECT_ERRORS
00772           ZYPP_THROW(MediaNotEjectedException(mediaSourceName()));
00773 #endif
00774         }
00775       }
00776     }
00777 
00779     //
00780     //
00781     //  METHOD NAME : MediaCD::forceEject
00782     //  METHOD TYPE : void
00783     //
00784     // Asserted that media is not attached.
00785     //
00786     void MediaCD::forceEject()
00787     {
00788       bool ejected=false;
00789       if ( !isAttached()) {     // no device mounted in this instance
00790 #if DELAYED_VERIFY
00791         DeviceList detected( detectDevices(
00792           _url.getScheme() == "dvd" ? true : false
00793         ));
00794 
00795         if(_devices.empty())
00796         {
00797           DBG << "creating on-demand device list" << endl;
00798           //default is /dev/cdrom; for dvd: /dev/dvd if it exists
00799           string device( "/dev/cdrom" );
00800           if ( _url.getScheme() == "dvd" && PathInfo( "/dev/dvd" ).isBlk() ) {
00801            device = "/dev/dvd";
00802           }
00803 
00804           PathInfo dinfo(device);
00805           if( dinfo.isBlk())
00806           {
00807             MediaSource media("cdrom", device, dinfo.major(), dinfo.minor());
00808 
00809             DeviceList::const_iterator d( detected.begin());
00810             for( ; d != detected.end(); ++d)
00811             {
00812               // /dev/cdrom or /dev/dvd to the front
00813               if( media.equals( *d))
00814                 _devices.push_front( *d);
00815               else
00816                 _devices.push_back( *d);
00817             }
00818           }
00819           else
00820           {
00821             // no /dev/cdrom or /dev/dvd link
00822             _devices = detected;
00823           }
00824         }
00825 #endif
00826 
00827         DeviceList::iterator it;
00828         for( it = _devices.begin(); it != _devices.end(); ++it ) {
00829           MediaSourceRef media( new MediaSource( *it));
00830 #if DELAYED_VERIFY
00831           bool        valid=false;
00832           PathInfo    dinfo(media->name);
00833           if( dinfo.isBlk())
00834           {
00835             media->maj_nr = dinfo.major();
00836             media->min_nr = dinfo.minor();
00837 
00838             DeviceList::const_iterator d( detected.begin());
00839             for( ; d != detected.end(); ++d)
00840             {
00841               if( media->equals( *d))
00842               {
00843                 valid = true;
00844                 break;
00845               }
00846             }
00847           }
00848           if( !valid)
00849           {
00850             DBG << "skipping invalid device: " << it->name << endl;
00851             continue;
00852           }
00853 #endif
00854 
00855           // FIXME: we have also to check if it is mounted in the system
00856           AttachedMedia ret( findAttachedMedia( media));
00857           if( !ret.mediaSource)
00858           {
00859 #if FORCE_RELEASE_FOREIGN > 0
00860             /* 1 = automounted only, 2 = all */
00861             forceRelaseAllMedia(media, false, FORCE_RELEASE_FOREIGN == 1);
00862 #endif
00863             if ( openTray( it->name ) )
00864             {
00865               ejected = true;
00866               break; // on 1st success
00867             }
00868           }
00869         }
00870       }
00871       if( !ejected)
00872       {
00873 #if REPORT_EJECT_ERRORS
00874         ZYPP_THROW(MediaNotEjectedException());
00875 #endif
00876       }
00877     }
00878 
00879     bool MediaCD::isAutoMountedMedia(const AttachedMedia &media)
00880     {
00881       bool is_automounted = false;
00882       if( media.mediaSource && !media.mediaSource->name.empty())
00883       {
00884         using namespace zypp::target::hal;
00885 
00886         try
00887         {
00888           HalContext hal(true);
00889 
00890           HalVolume vol = hal.getVolumeFromDeviceFile(media.mediaSource->name);
00891           if( vol)
00892           {
00893             std::string udi = vol.getUDI();
00894             std::string key;
00895             std::string mnt;
00896 
00897             try
00898             {
00899               key = "info.hal_mount.created_mount_point";
00900               mnt = hal.getDevicePropertyString(udi, key);
00901 
00902               if(media.attachPoint->path == mnt)
00903                 is_automounted = true;
00904             }
00905             catch(const HalException &e1)
00906             {
00907               ZYPP_CAUGHT(e1);
00908 
00909               try
00910               {
00911                 key = "volume.mount_point";
00912                 mnt = hal.getDevicePropertyString(udi, key);
00913 
00914                 if(media.attachPoint->path == mnt)
00915                   is_automounted = true;
00916               }
00917               catch(const HalException &e2)
00918               {
00919                 ZYPP_CAUGHT(e2);
00920               }
00921             }
00922           }
00923         }
00924         catch(const HalException &e)
00925         {
00926           ZYPP_CAUGHT(e);
00927         }
00928       }
00929       DBG << "Media "       << media.mediaSource->asString()
00930           << " attached on " << media.attachPoint->path
00931           << " is"           << (is_automounted ? "" : " not")
00932           << " automounted"  << std::endl;
00933       return is_automounted;
00934     }
00935 
00937     //
00938     //  METHOD NAME : MediaCD::isAttached
00939     //  METHOD TYPE : bool
00940     //
00941     //  DESCRIPTION : Override check if media is attached.
00942     //
00943     bool
00944     MediaCD::isAttached() const
00945     {
00946       return checkAttached(false);
00947     }
00948 
00950     //
00951     //  METHOD NAME : MediaCD::getFile
00952     //  METHOD TYPE : PMError
00953     //
00954     //  DESCRIPTION : Asserted that media is attached.
00955     //
00956     void MediaCD::getFile( const Pathname & filename ) const
00957     {
00958       MediaHandler::getFile( filename );
00959     }
00960 
00962     //
00963     //  METHOD NAME : MediaCD::getDir
00964     //  METHOD TYPE : PMError
00965     //
00966     //  DESCRIPTION : Asserted that media is attached.
00967     //
00968     void MediaCD::getDir( const Pathname & dirname, bool recurse_r ) const
00969     {
00970       MediaHandler::getDir( dirname, recurse_r );
00971     }
00972 
00974     //
00975     //
00976     //  METHOD NAME : MediaCD::getDirInfo
00977     //  METHOD TYPE : PMError
00978     //
00979     //  DESCRIPTION : Asserted that media is attached and retlist is empty.
00980     //
00981     void MediaCD::getDirInfo( std::list<std::string> & retlist,
00982                               const Pathname & dirname, bool dots ) const
00983     {
00984       MediaHandler::getDirInfo( retlist, dirname, dots );
00985     }
00986 
00988     //
00989     //
00990     //  METHOD NAME : MediaCD::getDirInfo
00991     //  METHOD TYPE : PMError
00992     //
00993     //  DESCRIPTION : Asserted that media is attached and retlist is empty.
00994     //
00995     void MediaCD::getDirInfo( filesystem::DirContent & retlist,
00996                               const Pathname & dirname, bool dots ) const
00997     {
00998       MediaHandler::getDirInfo( retlist, dirname, dots );
00999     }
01000 
01001     bool MediaCD::getDoesFileExist( const Pathname & filename ) const
01002     {
01003       return MediaHandler::getDoesFileExist( filename );
01004     }
01005 
01006     bool MediaCD::hasMoreDevices()
01007     {
01008       if (_devices.size() == 0)
01009         return false;
01010       else if (_lastdev_tried < 0)
01011         return true;
01012 
01013       return (unsigned) _lastdev_tried < _devices.size() - 1;
01014     }
01015   } // namespace media
01016 } // namespace zypp
01017 // vim: set ts=8 sts=2 sw=2 ai noet:

Generated on Tue Sep 25 19:23:01 2007 for libzypp by  doxygen 1.5.3