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