libzypp  9.1.2
MediaCD.cc
Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00012 extern "C"
00013 {
00014 #include <sys/ioctl.h>
00015 #include <linux/cdrom.h>
00016 #if HAVE_UDEV
00017 #include <libudev.h>
00018 #endif
00019 }
00020 
00021 #ifndef HAVE_UDEV
00022 #if HAVE_HAL
00023 #include "zypp/target/hal/HalContext.h"
00024 #endif
00025 #endif
00026 
00027 #include <cstring> // strerror
00028 #include <cstdlib> // getenv
00029 #include <iostream>
00030 
00031 #include "zypp/base/Logger.h"
00032 #include "zypp/ExternalProgram.h"
00033 #include "zypp/media/Mount.h"
00034 #include "zypp/media/MediaCD.h"
00035 #include "zypp/media/MediaManager.h"
00036 #include "zypp/Url.h"
00037 #include "zypp/AutoDispose.h"
00038 
00039 
00040 
00041 /*
00042 ** if to throw exception on eject errors or ignore them
00043 */
00044 #define  REPORT_EJECT_ERRORS     1
00045 
00046 /*
00047 ** If defined to the full path of the eject utility,
00048 ** it will be used additionally to the eject-ioctl.
00049 */
00050 #define EJECT_TOOL_PATH "/bin/eject"
00051 
00052 
00053 using namespace std;
00054 
00055 namespace zypp {
00056   namespace media {
00057 
00059 //
00060 //  CLASS NAME : MediaCD
00061 //
00063 
00064 
00066   //
00067   //
00068   //  METHOD NAME : MediaCD::MediaCD
00069   //  METHOD TYPE : Constructor
00070   //
00071   //  DESCRIPTION :
00072   //
00073   MediaCD::MediaCD( const Url &      url_r,
00074                     const Pathname & attach_point_hint_r )
00075     : MediaHandler( url_r, attach_point_hint_r,
00076                     url_r.getPathName(), // urlpath below attachpoint
00077                     false ),
00078       _lastdev(-1), _lastdev_tried(-1)
00079   {
00080     MIL << "MediaCD::MediaCD(" << url_r << ", " << attach_point_hint_r << ")"
00081         << endl;
00082 
00083     if( url_r.getScheme() != "dvd" && url_r.getScheme() != "cd")
00084     {
00085       ERR << "Unsupported schema in the Url: " << url_r.asString() << endl;
00086       ZYPP_THROW(MediaUnsupportedUrlSchemeException(_url));
00087     }
00088 
00089     string devices = _url.getQueryParam("devices");
00090     if (!devices.empty())
00091     {
00092       string::size_type pos;
00093       DBG << "parse " << devices << endl;
00094       while(!devices.empty())
00095       {
00096         pos = devices.find(',');
00097         string device = devices.substr(0,pos);
00098         if (!device.empty())
00099         {
00100           MediaSource media("cdrom", device, 0, 0);
00101           _devices.push_back( media);
00102           DBG << "use device (delayed verify)" << device << endl;
00103         }
00104         if (pos!=string::npos)
00105           devices=devices.substr(pos+1);
00106         else
00107           devices.erase();
00108       }
00109     }
00110     else
00111     {
00112       DBG << "going to use on-demand device list" << endl;
00113       return;
00114     }
00115 
00116     if( _devices.empty())
00117     {
00118       ERR << "Unable to find any cdrom drive for " << _url.asString() << endl;
00119       ZYPP_THROW(MediaBadUrlEmptyDestinationException(_url));
00120     }
00121   }
00122 
00124   //
00125   //
00126   //  METHOD NAME : MediaCD::openTray
00127   //  METHOD TYPE : bool
00128   //
00129   bool MediaCD::openTray( const std::string & device_r )
00130   {
00131     int fd = ::open( device_r.c_str(), O_RDONLY|O_NONBLOCK );
00132     int res = -1;
00133 
00134     if ( fd != -1)
00135     {
00136       res = ::ioctl( fd, CDROMEJECT );
00137       ::close( fd );
00138     }
00139 
00140     if ( res )
00141     {
00142       if( fd == -1)
00143       {
00144         WAR << "Unable to open '" << device_r
00145             << "' (" << ::strerror( errno ) << ")" << endl;
00146       }
00147       else
00148       {
00149         WAR << "Eject " << device_r
00150             << " failed (" << ::strerror( errno ) << ")" << endl;
00151       }
00152 
00153 #if defined(EJECT_TOOL_PATH)
00154       DBG << "Try to eject " << device_r << " using "
00155         << EJECT_TOOL_PATH << " utility" << std::endl;
00156 
00157       const char *cmd[3];
00158       cmd[0] = EJECT_TOOL_PATH;
00159       cmd[1] = device_r.c_str();
00160       cmd[2] = NULL;
00161       ExternalProgram eject(cmd, ExternalProgram::Stderr_To_Stdout);
00162 
00163       for(std::string out( eject.receiveLine());
00164           out.length(); out = eject.receiveLine())
00165       {
00166         DBG << " " << out;
00167       }
00168 
00169       if(eject.close() != 0)
00170       {
00171         WAR << "Eject of " << device_r << " failed." << std::endl;
00172         return false;
00173       }
00174 #else
00175       return false;
00176 #endif
00177     }
00178     MIL << "Eject of " << device_r << " successful." << endl;
00179     return true;
00180   }
00181 
00183   //
00184   //
00185   //    METHOD NAME : MediaCD::closeTray
00186   //    METHOD TYPE : bool
00187   //
00188   bool MediaCD::closeTray( const std::string & device_r )
00189   {
00190     int fd = ::open( device_r.c_str(), O_RDONLY|O_NONBLOCK );
00191     if ( fd == -1 ) {
00192       WAR << "Unable to open '" << device_r << "' (" << ::strerror( errno ) << ")" << endl;
00193       return false;
00194     }
00195     int res = ::ioctl( fd, CDROMCLOSETRAY );
00196     ::close( fd );
00197     if ( res ) {
00198       WAR << "Close tray " << device_r << " failed (" << ::strerror( errno ) << ")" << endl;
00199       return false;
00200     }
00201     DBG << "Close tray " << device_r << endl;
00202     return true;
00203   }
00204 
00206   //
00207   //
00208   //  METHOD NAME : MediaCD::detectDevices
00209   //  METHOD TYPE : MediaCD::DeviceList
00210   //
00211   MediaCD::DeviceList MediaCD::detectDevices( bool supportingDVD ) const
00212   {
00213     DeviceList detected;
00214 #ifdef HAVE_UDEV
00215     // http://www.kernel.org/pub/linux/utils/kernel/hotplug/libudev/index.html
00216     zypp::AutoDispose<struct udev *> udev( ::udev_new(), ::udev_unref );
00217     if ( ! udev )
00218     {
00219       ERR << "Can't create udev context." << endl;
00220       return DeviceList();
00221     }
00222 
00223     zypp::AutoDispose<struct udev_enumerate *> enumerate( ::udev_enumerate_new(udev), ::udev_enumerate_unref );
00224     if ( ! enumerate )
00225     {
00226       ERR << "Can't create udev list entry." << endl;
00227       return DeviceList();
00228     }
00229 
00230     ::udev_enumerate_add_match_subsystem( enumerate, "block" );
00231     ::udev_enumerate_add_match_property( enumerate, "ID_CDROM", "1" );
00232     ::udev_enumerate_scan_devices( enumerate );
00233 
00234     struct udev_list_entry * entry = 0;
00235     udev_list_entry_foreach( entry, ::udev_enumerate_get_list_entry( enumerate ) )
00236     {
00237       zypp::AutoDispose<struct udev_device *> device( ::udev_device_new_from_syspath( ::udev_enumerate_get_udev( enumerate ),
00238                                                                                       ::udev_list_entry_get_name( entry ) ),
00239                                                       ::udev_device_unref );
00240       if ( ! device )
00241       {
00242         ERR << "Can't create udev device." << endl;
00243         continue;
00244       }
00245 
00246       if ( supportingDVD && ! ::udev_device_get_property_value( device, "ID_CDROM_DVD" ) )
00247       {
00248         continue;       // looking for dvd only
00249       }
00250 
00251       const char * devnodePtr( ::udev_device_get_devnode( device ) );
00252       if ( ! devnodePtr )
00253       {
00254         ERR << "Got NULL devicenode." << endl;
00255         continue;
00256       }
00257 
00258       // In case we need it someday:
00259       //const char * mountpath = ::udev_device_get_property_value( device, "FSTAB_DIR" );
00260 
00261       PathInfo devnode( devnodePtr );
00262       if ( devnode.isBlk() )
00263       {
00264         MediaSource media( "cdrom", devnode.path().asString(), devnode.major(), devnode.minor() );
00265         DBG << "Found (udev): " << media << std::endl;
00266         detected.push_back( media );
00267       }
00268     }
00269     if ( detected.empty() )
00270       WAR << "Did not find any CD/DVD device." << endl;
00271 #elif HAVE_HAL
00272     using namespace zypp::target::hal;
00273     try
00274     {
00275       HalContext hal(true);
00276 
00277       std::vector<std::string> drv_udis;
00278       drv_udis = hal.findDevicesByCapability("storage.cdrom");
00279 
00280       DBG << "Found " << drv_udis.size() << " cdrom drive udis" << std::endl;
00281       for(size_t d = 0; d < drv_udis.size(); d++)
00282       {
00283         HalDrive drv( hal.getDriveFromUDI( drv_udis[d]));
00284 
00285         if( drv)
00286         {
00287           bool supportsDVD=false;
00288           if( supportingDVD)
00289           {
00290             std::vector<std::string> caps;
00291             try {
00292               caps = drv.getCdromCapabilityNames();
00293             }
00294             catch(const HalException &e)
00295             {
00296               ZYPP_CAUGHT(e);
00297             }
00298 
00299             std::vector<std::string>::const_iterator ci;
00300             for( ci=caps.begin(); ci != caps.end(); ++ci)
00301             {
00302               if( *ci == "dvd")
00303                 supportsDVD = true;
00304             }
00305           }
00306 
00307           MediaSource media("cdrom", drv.getDeviceFile(),
00308                             drv.getDeviceMajor(),
00309                             drv.getDeviceMinor());
00310           DBG << "Found " << drv_udis[d] << ": "
00311               << media.asString() << std::endl;
00312           if( supportingDVD && supportsDVD)
00313           {
00314             detected.push_front(media);
00315           }
00316           else
00317           {
00318             detected.push_back(media);
00319           }
00320         }
00321       }
00322     }
00323     catch(const zypp::target::hal::HalException &e)
00324     {
00325       ZYPP_CAUGHT(e);
00326     }
00327 #else // manual way
00328 #warning Poor CDROM devices detection without udev/HAL
00329     WAR << "Cdrom drive detection without HAL! " << std::endl;
00330     PathInfo dvdinfo( "/dev/dvd" );
00331     PathInfo cdrinfo( "/dev/cdrom" );
00332     if ( dvdinfo.isBlk() )
00333     {
00334       MediaSource media( "cdrom", dvdinfo.path().asString(), dvdinfo.major(), dvdinfo.minor() );
00335       DBG << "Found (NO_HAL): " << media << std::endl;
00336       detected.push_back( media );
00337     }
00338     if ( cdrinfo.isBlk()
00339          && ! ( cdrinfo.major() == dvdinfo.major() && cdrinfo.minor() == dvdinfo.minor() ) )
00340     {
00341       MediaSource media( "cdrom", cdrinfo.path().asString(), cdrinfo.major(), cdrinfo.minor() );
00342       DBG << "Found (NO_HAL): " << media << std::endl;
00343       detected.push_back( media );
00344     }
00345 #endif
00346     return detected;
00347   }
00348 
00349 
00351   //
00352   //
00353   //  METHOD NAME : MediaCD::attachTo
00354   //  METHOD TYPE : PMError
00355   //
00356   //  DESCRIPTION : Asserted that not already attached, and attachPoint is a directory.
00357   //
00358   void MediaCD::attachTo(bool next)
00359   {
00360     DBG << "next " << next << " last " << _lastdev << " last tried " << _lastdev_tried << endl;
00361     if (next && _lastdev == -1)
00362       ZYPP_THROW(MediaNotSupportedException(url()));
00363 
00364     DeviceList detected(
00365       detectDevices(_url.getScheme() == "dvd" ? true : false));
00366 
00367     if(_devices.empty())
00368     {
00369       DBG << "creating on-demand device list" << endl;
00370       //default is /dev/cdrom; for dvd: /dev/dvd if it exists
00371       string device( "/dev/cdrom" );
00372       if ( _url.getScheme() == "dvd" && PathInfo( "/dev/dvd" ).isBlk() )
00373       {
00374         device = "/dev/dvd";
00375       }
00376 
00377       PathInfo dinfo(device);
00378       if( dinfo.isBlk())
00379       {
00380         MediaSource media("cdrom", device, dinfo.major(), dinfo.minor());
00381 
00382         DeviceList::const_iterator d( detected.begin());
00383         for( ; d != detected.end(); ++d)
00384         {
00385           // /dev/cdrom or /dev/dvd to the front
00386           if( media.equals( *d))
00387             _devices.push_front( *d);
00388           else
00389             _devices.push_back( *d);
00390         }
00391       }
00392       else
00393       {
00394         // no /dev/cdrom or /dev/dvd link
00395         _devices = detected;
00396       }
00397     }
00398 
00399     Mount mount;
00400     string mountpoint = attachPoint().asString();
00401     bool mountsucceeded = false;
00402     int count = 0;
00403     MediaMountException merr;
00404 
00405     string options = _url.getQueryParam("mountoptions");
00406     if (options.empty())
00407     {
00408       options="ro";
00409     }
00410 
00411     //TODO: make configurable
00412     list<string> filesystems;
00413 
00414     // if DVD, try UDF filesystem before iso9660
00415     if ( _url.getScheme() == "dvd" )
00416       filesystems.push_back("udf");
00417 
00418     filesystems.push_back("iso9660");
00419 
00420     // try all devices in sequence
00421     for (DeviceList::iterator it = _devices.begin()
00422     ; !mountsucceeded && it != _devices.end()
00423     ; ++it, count++ )
00424     {
00425       DBG << "count " << count << endl;
00426       if (next && count <=_lastdev_tried )
00427       {
00428         DBG << "skipping device " << it->name << endl;
00429         continue;
00430       }
00431 
00432       _lastdev_tried = count;
00433 
00434       MediaSource temp( *it);
00435       bool        valid=false;
00436       PathInfo    dinfo(temp.name);
00437       if( dinfo.isBlk())
00438       {
00439         temp.maj_nr = dinfo.major();
00440         temp.min_nr = dinfo.minor();
00441 
00442         DeviceList::const_iterator d( detected.begin());
00443         for( ; d != detected.end(); ++d)
00444         {
00445           if( temp.equals( *d))
00446           {
00447             valid = true;
00448             break;
00449           }
00450         }
00451       }
00452       if( !valid)
00453       {
00454         DBG << "skipping invalid device: " << it->name << endl;
00455         continue;
00456       }
00457 
00458       MediaSourceRef media( new MediaSource(temp));
00459       AttachedMedia ret( findAttachedMedia( media));
00460 
00461       if( ret.mediaSource && ret.attachPoint &&
00462          !ret.attachPoint->empty())
00463       {
00464         DBG << "Using a shared media "
00465             << ret.mediaSource->name
00466             << " attached on "
00467             << ret.attachPoint->path
00468             << endl;
00469         removeAttachPoint();
00470         setAttachPoint(ret.attachPoint);
00471         setMediaSource(ret.mediaSource);
00472         _lastdev = count;
00473         mountsucceeded = true;
00474         break;
00475       }
00476 
00477       {
00478         MediaManager  manager;
00479         MountEntries  entries( manager.getMountEntries());
00480         MountEntries::const_iterator e;
00481         for( e = entries.begin(); e != entries.end(); ++e)
00482         {
00483           bool        is_device = false;
00484           std::string dev_path(Pathname(e->src).asString());
00485           PathInfo    dev_info;
00486 
00487           if( dev_path.compare(0, sizeof("/dev/")-1, "/dev/") == 0 &&
00488               dev_info(e->src) && dev_info.isBlk())
00489           {
00490             is_device = true;
00491           }
00492 
00493           if( is_device && media->maj_nr == dev_info.major() &&
00494                            media->min_nr == dev_info.minor())
00495           {
00496             AttachPointRef ap( new AttachPoint(e->dir, false));
00497             AttachedMedia  am( media, ap);
00498             {
00499               DBG << "Using a system mounted media "
00500                   << media->name
00501                   << " attached on "
00502                   << ap->path
00503                   << endl;
00504 
00505               media->iown = false; // mark attachment as foreign
00506 
00507               setMediaSource(media);
00508               setAttachPoint(ap);
00509               _lastdev = count;
00510               mountsucceeded = true;
00511               break;
00512             }
00513           }
00514         }
00515         if( mountsucceeded)
00516           break;
00517       }
00518 
00519       // close tray
00520       closeTray( it->name );
00521 
00522       // try all filesystems in sequence
00523       for(list<string>::iterator fsit = filesystems.begin()
00524           ; !mountsucceeded && fsit != filesystems.end()
00525           ; ++fsit)
00526       {
00527         try
00528         {
00529           if( !isUseableAttachPoint(Pathname(mountpoint)))
00530           {
00531             mountpoint = createAttachPoint().asString();
00532             setAttachPoint( mountpoint, true);
00533             if( mountpoint.empty())
00534             {
00535               ZYPP_THROW( MediaBadAttachPointException(url()));
00536             }
00537           }
00538 
00539           mount.mount(it->name, mountpoint, *fsit, options);
00540 
00541           setMediaSource(media);
00542 
00543           // wait for /etc/mtab update ...
00544           // (shouldn't be needed)
00545           int limit = 5;
00546           while( !(mountsucceeded=isAttached()) && --limit)
00547           {
00548             sleep(1);
00549           }
00550 
00551           if( mountsucceeded)
00552           {
00553             _lastdev = count;
00554           }
00555           else
00556           {
00557             setMediaSource(MediaSourceRef());
00558             try
00559             {
00560               mount.umount(attachPoint().asString());
00561             }
00562             catch (const MediaException & excpt_r)
00563             {
00564               ZYPP_CAUGHT(excpt_r);
00565             }
00566             ZYPP_THROW(MediaMountException(
00567               "Unable to verify that the media was mounted",
00568               it->name, mountpoint
00569             ));
00570           }
00571         }
00572         catch (const MediaMountException &e)
00573         {
00574           merr = e;
00575           removeAttachPoint();
00576           ZYPP_CAUGHT(e);
00577         }
00578         catch (const MediaException & excpt_r)
00579         {
00580           removeAttachPoint();
00581           ZYPP_CAUGHT(excpt_r);
00582         }
00583       } // for filesystems
00584     } // for _devices
00585 
00586     if (!mountsucceeded)
00587     {
00588       _lastdev = -1;
00589 
00590       if( !merr.mountOutput().empty())
00591       {
00592         ZYPP_THROW(MediaMountException(merr.mountError(),
00593                                        _url.asString(),
00594                                        mountpoint,
00595                                        merr.mountOutput()));
00596       }
00597       else
00598       {
00599         ZYPP_THROW(MediaMountException("Mounting media failed",
00600                                        _url.asString(), mountpoint));
00601       }
00602     }
00603     DBG << _lastdev << " " << count << endl;
00604   }
00605 
00606 
00608   //
00609   //
00610   //  METHOD NAME : MediaCD::releaseFrom
00611   //  METHOD TYPE : PMError
00612   //
00613   //  DESCRIPTION : Asserted that media is attached.
00614   //
00615   void MediaCD::releaseFrom( const std::string & ejectDev )
00616   {
00617     Mount mount;
00618     try
00619     {
00620       AttachedMedia am( attachedMedia());
00621       if(am.mediaSource && am.mediaSource->iown)
00622         mount.umount(am.attachPoint->path.asString());
00623     }
00624     catch (const Exception & excpt_r)
00625     {
00626       ZYPP_CAUGHT(excpt_r);
00627       if (!ejectDev.empty())
00628       {
00629         forceRelaseAllMedia(false);
00630         if(openTray( ejectDev ))
00631           return;
00632       }
00633       ZYPP_RETHROW(excpt_r);
00634     }
00635 
00636     // eject device
00637     if (!ejectDev.empty())
00638     {
00639       forceRelaseAllMedia(false);
00640       if( !openTray( ejectDev ))
00641       {
00642 #if REPORT_EJECT_ERRORS
00643         ZYPP_THROW(MediaNotEjectedException(ejectDev));
00644 #endif
00645       }
00646     }
00647   }
00648 
00650   //
00651   //
00652   //  METHOD NAME : MediaCD::forceEject
00653   //  METHOD TYPE : void
00654   //
00655   // Asserted that media is not attached.
00656   //
00657   void MediaCD::forceEject(const std::string & ejectDev)
00658   {
00659     bool ejected=false;
00660     if ( !isAttached()) {       // no device mounted in this instance
00661 
00662       DeviceList detected(
00663           detectDevices(_url.getScheme() == "dvd" ? true : false));
00664 
00665       if(_devices.empty())
00666       {
00667         DBG << "creating on-demand device list" << endl;
00668         //default is /dev/cdrom; for dvd: /dev/dvd if it exists
00669         string device( "/dev/cdrom" );
00670         if ( _url.getScheme() == "dvd" && PathInfo( "/dev/dvd" ).isBlk() ) {
00671           device = "/dev/dvd";
00672         }
00673 
00674         PathInfo dinfo(device);
00675         if( dinfo.isBlk())
00676         {
00677           MediaSource media("cdrom", device, dinfo.major(), dinfo.minor());
00678 
00679           DeviceList::const_iterator d( detected.begin());
00680           for( ; d != detected.end(); ++d)
00681           {
00682             // /dev/cdrom or /dev/dvd to the front
00683             if( media.equals( *d))
00684               _devices.push_front( *d);
00685             else
00686               _devices.push_back( *d);
00687           }
00688         }
00689         else
00690         {
00691           // no /dev/cdrom or /dev/dvd link
00692           _devices = detected;
00693         }
00694       }
00695 
00696       DeviceList::iterator it;
00697       for( it = _devices.begin(); it != _devices.end(); ++it ) {
00698         MediaSourceRef media( new MediaSource( *it));
00699         if (media->name != ejectDev)
00700           continue;
00701 
00702         bool        valid=false;
00703         PathInfo    dinfo(media->name);
00704         if( dinfo.isBlk())
00705         {
00706           media->maj_nr = dinfo.major();
00707           media->min_nr = dinfo.minor();
00708 
00709           DeviceList::const_iterator d( detected.begin());
00710           for( ; d != detected.end(); ++d)
00711           {
00712             if( media->equals( *d))
00713             {
00714               valid = true;
00715               break;
00716             }
00717           }
00718         }
00719         if( !valid)
00720         {
00721           DBG << "skipping invalid device: " << it->name << endl;
00722           continue;
00723         }
00724 
00725         // FIXME: we have also to check if it is mounted in the system
00726         AttachedMedia ret( findAttachedMedia( media));
00727         if( !ret.mediaSource)
00728         {
00729           forceRelaseAllMedia(media, false);
00730           if ( openTray( it->name ) )
00731           {
00732             ejected = true;
00733             break; // on 1st success
00734           }
00735         }
00736       }
00737     }
00738     if( !ejected)
00739     {
00740 #if REPORT_EJECT_ERRORS
00741       ZYPP_THROW(MediaNotEjectedException());
00742 #endif
00743     }
00744   }
00745 
00747   //
00748   //  METHOD NAME : MediaCD::isAttached
00749   //  METHOD TYPE : bool
00750   //
00751   //  DESCRIPTION : Override check if media is attached.
00752   //
00753   bool
00754   MediaCD::isAttached() const
00755   {
00756     return checkAttached(false);
00757   }
00758 
00760   //
00761   //  METHOD NAME : MediaCD::getFile
00762   //  METHOD TYPE : PMError
00763   //
00764   //  DESCRIPTION : Asserted that media is attached.
00765   //
00766   void MediaCD::getFile( const Pathname & filename ) const
00767   {
00768     MediaHandler::getFile( filename );
00769   }
00770 
00772   //
00773   //  METHOD NAME : MediaCD::getDir
00774   //  METHOD TYPE : PMError
00775   //
00776   //  DESCRIPTION : Asserted that media is attached.
00777   //
00778   void MediaCD::getDir( const Pathname & dirname, bool recurse_r ) const
00779   {
00780     MediaHandler::getDir( dirname, recurse_r );
00781   }
00782 
00784   //
00785   //
00786   //  METHOD NAME : MediaCD::getDirInfo
00787   //  METHOD TYPE : PMError
00788   //
00789   //  DESCRIPTION : Asserted that media is attached and retlist is empty.
00790   //
00791   void MediaCD::getDirInfo( std::list<std::string> & retlist,
00792                             const Pathname & dirname, bool dots ) const
00793   {
00794     MediaHandler::getDirInfo( retlist, dirname, dots );
00795   }
00796 
00798   //
00799   //
00800   //  METHOD NAME : MediaCD::getDirInfo
00801   //  METHOD TYPE : PMError
00802   //
00803   //  DESCRIPTION : Asserted that media is attached and retlist is empty.
00804   //
00805   void MediaCD::getDirInfo( filesystem::DirContent & retlist,
00806                             const Pathname & dirname, bool dots ) const
00807   {
00808     MediaHandler::getDirInfo( retlist, dirname, dots );
00809   }
00810 
00811   bool MediaCD::getDoesFileExist( const Pathname & filename ) const
00812   {
00813     return MediaHandler::getDoesFileExist( filename );
00814   }
00815 
00816   bool MediaCD::hasMoreDevices()
00817   {
00818     if (_devices.size() == 0)
00819       return false;
00820     else if (_lastdev_tried < 0)
00821       return true;
00822 
00823     return (unsigned) _lastdev_tried < _devices.size() - 1;
00824   }
00825 
00826   void
00827   MediaCD::getDetectedDevices(std::vector<std::string> & devices,
00828                               unsigned int & index) const
00829   {
00830     index = 0;
00831     if (!devices.empty())
00832       devices.clear();
00833 
00834     for (DeviceList::const_iterator it = _devices.begin();
00835          it != _devices.end(); ++it)
00836       devices.push_back(it->name);
00837 
00838     if (_lastdev >= 0)
00839       index = _lastdev;
00840 
00841     // try to detect again if _devices are empty (maybe this method will be
00842     // called before _devices get actually filled)
00843     if (devices.empty())
00844     {
00845       DBG << "no device list so far, trying to detect" << endl;
00846 
00847       DeviceList detected(
00848         detectDevices(_url.getScheme() == "dvd" ? true : false));
00849 
00850       for (DeviceList::const_iterator it = detected.begin();
00851            it != detected.end(); ++it)
00852         devices.push_back(it->name);
00853 
00854       // don't know which one is in use in this case
00855       index = 0;
00856     }
00857 
00858     MIL << "got " << devices.size() << " detected devices, current: "
00859         << (index < devices.size() ? devices[index] : "<none>")
00860         << "(" << index << ")" << endl;
00861   }
00862 
00863 
00864   } // namespace media
00865 } // namespace zypp
00866 // vim: set ts=8 sts=2 sw=2 ai noet: