libzypp
10.5.0
|
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 ( const std::string & device : words ) 00222 { 00223 if ( device.empty() ) 00224 continue; 00225 00226 MediaSource media( "cdrom", device, 0, 0 ); 00227 _devices.push_back( media ); 00228 DBG << "use device (delayed verify)" << device << endl; 00229 } 00230 } 00231 else 00232 { 00233 DBG << "going to use on-demand device list" << endl; 00234 return; 00235 } 00236 00237 if ( _devices.empty() ) 00238 { 00239 ERR << "Unable to find any cdrom drive for " << _url.asString() << endl; 00240 ZYPP_THROW(MediaBadUrlEmptyDestinationException(_url)); 00241 } 00242 } 00243 00245 // 00246 // 00247 // METHOD NAME : MediaCD::openTray 00248 // METHOD TYPE : bool 00249 // 00250 bool MediaCD::openTray( const std::string & device_r ) 00251 { 00252 int fd = ::open( device_r.c_str(), O_RDONLY|O_NONBLOCK|O_CLOEXEC ); 00253 int res = -1; 00254 00255 if ( fd != -1) 00256 { 00257 res = ::ioctl( fd, CDROMEJECT ); 00258 ::close( fd ); 00259 } 00260 00261 if ( res ) 00262 { 00263 if( fd == -1) 00264 { 00265 WAR << "Unable to open '" << device_r 00266 << "' (" << ::strerror( errno ) << ")" << endl; 00267 } 00268 else 00269 { 00270 WAR << "Eject " << device_r 00271 << " failed (" << ::strerror( errno ) << ")" << endl; 00272 } 00273 00274 #if defined(EJECT_TOOL_PATH) 00275 DBG << "Try to eject " << device_r << " using " 00276 << EJECT_TOOL_PATH << " utility" << std::endl; 00277 00278 const char *cmd[3]; 00279 cmd[0] = EJECT_TOOL_PATH; 00280 cmd[1] = device_r.c_str(); 00281 cmd[2] = NULL; 00282 ExternalProgram eject(cmd, ExternalProgram::Stderr_To_Stdout); 00283 00284 for(std::string out( eject.receiveLine()); 00285 out.length(); out = eject.receiveLine()) 00286 { 00287 DBG << " " << out; 00288 } 00289 00290 if(eject.close() != 0) 00291 { 00292 WAR << "Eject of " << device_r << " failed." << std::endl; 00293 return false; 00294 } 00295 #else 00296 return false; 00297 #endif 00298 } 00299 MIL << "Eject of " << device_r << " successful." << endl; 00300 return true; 00301 } 00302 00304 // 00305 // 00306 // METHOD NAME : MediaCD::closeTray 00307 // METHOD TYPE : bool 00308 // 00309 bool MediaCD::closeTray( const std::string & device_r ) 00310 { 00311 int fd = ::open( device_r.c_str(), O_RDONLY|O_NONBLOCK|O_CLOEXEC ); 00312 if ( fd == -1 ) { 00313 WAR << "Unable to open '" << device_r << "' (" << ::strerror( errno ) << ")" << endl; 00314 return false; 00315 } 00316 int res = ::ioctl( fd, CDROMCLOSETRAY ); 00317 ::close( fd ); 00318 if ( res ) { 00319 WAR << "Close tray " << device_r << " failed (" << ::strerror( errno ) << ")" << endl; 00320 return false; 00321 } 00322 DBG << "Close tray " << device_r << endl; 00323 return true; 00324 } 00325 00326 00327 MediaCD::DeviceList MediaCD::detectDevices( bool supportingDVD_r ) const 00328 { 00329 DeviceList detected( systemDetectDevices( supportingDVD_r ) ); 00330 00331 if ( detected.empty() ) 00332 { 00333 WAR << "CD/DVD drive detection with HAL/UDEV failed! Guessing..." << std::endl; 00334 PathInfo dvdinfo( "/dev/dvd" ); 00335 PathInfo cdrinfo( "/dev/cdrom" ); 00336 if ( dvdinfo.isBlk() ) 00337 { 00338 MediaSource media( "cdrom", dvdinfo.path().asString(), dvdinfo.major(), dvdinfo.minor() ); 00339 DBG << "Found (GUESS): " << media << std::endl; 00340 detected.push_back( media ); 00341 } 00342 if ( cdrinfo.isBlk() 00343 && ! ( cdrinfo.major() == dvdinfo.major() && cdrinfo.minor() == dvdinfo.minor() ) ) 00344 { 00345 MediaSource media( "cdrom", cdrinfo.path().asString(), cdrinfo.major(), cdrinfo.minor() ); 00346 DBG << "Found (GUESS): " << media << std::endl; 00347 detected.push_back( media ); 00348 } 00349 } 00350 00351 // NOTE: On the fly build on-demand device list. Code was moved to 00352 // here to get rid of code duplication, while keeping the ABI. Acuallty 00353 // this code should be moved to a _devices accessor method. 00354 if ( _devices.empty() ) 00355 { 00356 DBG << "creating on-demand device list" << endl; 00357 //default is /dev/cdrom; for dvd: /dev/dvd if it exists 00358 string device( "/dev/cdrom" ); 00359 if ( _url.getScheme() == "dvd" && PathInfo( "/dev/dvd" ).isBlk() ) 00360 { 00361 device = "/dev/dvd"; 00362 } 00363 00364 PathInfo dinfo( device ); 00365 if ( dinfo.isBlk() ) 00366 { 00367 MediaSource media( "cdrom", device, dinfo.major(), dinfo.minor() ); 00368 if ( detected.empty() ) 00369 { 00370 _devices.push_front( media ); // better try this than nothing 00371 } 00372 else 00373 { 00374 for( const auto & d : detected ) 00375 { 00376 // /dev/cdrom or /dev/dvd to the front 00377 if ( media.equals( d ) ) 00378 _devices.push_front( d ); 00379 else 00380 _devices.push_back( d ); 00381 } 00382 } 00383 } 00384 else 00385 { 00386 // no /dev/cdrom or /dev/dvd link 00387 _devices = detected; 00388 } 00389 } 00390 00391 return detected; 00392 } 00393 00394 00396 // 00397 // 00398 // METHOD NAME : MediaCD::attachTo 00399 // METHOD TYPE : PMError 00400 // 00401 // DESCRIPTION : Asserted that not already attached, and attachPoint is a directory. 00402 // 00403 void MediaCD::attachTo( bool next ) 00404 { 00405 DBG << "next " << next << " last " << _lastdev << " last tried " << _lastdev_tried << endl; 00406 if ( next && _lastdev == -1 ) 00407 ZYPP_THROW(MediaNotSupportedException(url())); 00408 00409 // This also fills the _devices list on demand 00410 DeviceList detected( detectDevices( _url.getScheme() == "dvd" ? true : false ) ); 00411 00412 Mount mount; 00413 MediaMountException merr; 00414 string mountpoint = attachPoint().asString(); 00415 00416 string options = _url.getQueryParam( "mountoptions" ); 00417 if ( options.empty() ) 00418 { 00419 options="ro"; 00420 } 00421 00422 //TODO: make configurable 00423 list<string> filesystems; 00424 00425 // if DVD, try UDF filesystem before iso9660 00426 if ( _url.getScheme() == "dvd" ) 00427 filesystems.push_back("udf"); 00428 00429 filesystems.push_back("iso9660"); 00430 00431 // try all devices in sequence 00432 int count = 0; 00433 bool mountsucceeded = false; 00434 for ( DeviceList::iterator it = _devices.begin() ; ! mountsucceeded && it != _devices.end() ; ++it, ++count ) 00435 { 00436 DBG << "count " << count << endl; 00437 if (next && count <=_lastdev_tried ) 00438 { 00439 DBG << "skipping device " << it->name << endl; 00440 continue; 00441 } 00442 _lastdev_tried = count; 00443 00444 // bnc#755815: _devices contains either devices passed as url option 00445 // or autodetected ones. Accept both as long as they are block 00446 // devices. 00447 MediaSource temp( *it ); 00448 PathInfo dinfo( temp.name ); 00449 if ( ! dinfo.isBlk() ) 00450 { 00451 WAR << "skipping non block device: " << dinfo << endl; 00452 continue; 00453 } 00454 DBG << "trying device " << dinfo << endl; 00455 00456 temp.maj_nr = dinfo.major(); 00457 temp.min_nr = dinfo.minor(); 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 = 2; 00546 while( !(mountsucceeded=isAttached()) && --limit) 00547 { 00548 WAR << "Wait for /proc/mounts update and retry...." << endl; 00549 sleep(1); 00550 } 00551 00552 if( mountsucceeded) 00553 { 00554 _lastdev = count; 00555 } 00556 else 00557 { 00558 setMediaSource(MediaSourceRef()); 00559 try 00560 { 00561 mount.umount(attachPoint().asString()); 00562 } 00563 catch (const MediaException & excpt_r) 00564 { 00565 ZYPP_CAUGHT(excpt_r); 00566 } 00567 ZYPP_THROW(MediaMountException( 00568 "Unable to verify that the media was mounted", 00569 it->name, mountpoint 00570 )); 00571 } 00572 } 00573 catch (const MediaMountException &e) 00574 { 00575 merr = e; 00576 removeAttachPoint(); 00577 ZYPP_CAUGHT(e); 00578 } 00579 catch (const MediaException & excpt_r) 00580 { 00581 removeAttachPoint(); 00582 ZYPP_CAUGHT(excpt_r); 00583 } 00584 } // for filesystems 00585 } // for _devices 00586 00587 if (!mountsucceeded) 00588 { 00589 _lastdev = -1; 00590 00591 if( !merr.mountOutput().empty()) 00592 { 00593 ZYPP_THROW(MediaMountException(merr.mountError(), 00594 _url.asString(), 00595 mountpoint, 00596 merr.mountOutput())); 00597 } 00598 else 00599 { 00600 ZYPP_THROW(MediaMountException("Mounting media failed", 00601 _url.asString(), mountpoint)); 00602 } 00603 } 00604 DBG << _lastdev << " " << count << endl; 00605 } 00606 00607 00609 // 00610 // 00611 // METHOD NAME : MediaCD::releaseFrom 00612 // METHOD TYPE : PMError 00613 // 00614 // DESCRIPTION : Asserted that media is attached. 00615 // 00616 void MediaCD::releaseFrom( const std::string & ejectDev ) 00617 { 00618 Mount mount; 00619 try 00620 { 00621 AttachedMedia am( attachedMedia()); 00622 if(am.mediaSource && am.mediaSource->iown) 00623 mount.umount(am.attachPoint->path.asString()); 00624 } 00625 catch (const Exception & excpt_r) 00626 { 00627 ZYPP_CAUGHT(excpt_r); 00628 if (!ejectDev.empty()) 00629 { 00630 forceRelaseAllMedia(false); 00631 if(openTray( ejectDev )) 00632 return; 00633 } 00634 ZYPP_RETHROW(excpt_r); 00635 } 00636 00637 // eject device 00638 if (!ejectDev.empty()) 00639 { 00640 forceRelaseAllMedia(false); 00641 if( !openTray( ejectDev )) 00642 { 00643 #if REPORT_EJECT_ERRORS 00644 ZYPP_THROW(MediaNotEjectedException(ejectDev)); 00645 #endif 00646 } 00647 } 00648 } 00649 00651 // 00652 // 00653 // METHOD NAME : MediaCD::forceEject 00654 // METHOD TYPE : void 00655 // 00656 // Asserted that media is not attached. 00657 // 00658 void MediaCD::forceEject( const std::string & ejectDev_r ) 00659 { 00660 bool ejected = false; 00661 if ( ! isAttached() ) // no device mounted in this instance 00662 { 00663 // This also fills the _devices list on demand 00664 DeviceList detected( detectDevices( _url.getScheme() == "dvd" ? true : false ) ); 00665 for_( it, _devices.begin(), _devices.end() ) 00666 { 00667 MediaSourceRef media( new MediaSource( *it ) ); 00668 if ( media->name != ejectDev_r ) 00669 continue; 00670 00671 // bnc#755815: _devices contains either devices passed as url option 00672 // or autodetected ones. Accept both as long as they are block 00673 // devices. 00674 PathInfo dinfo( media->name ); 00675 if( ! dinfo.isBlk() ) 00676 { 00677 WAR << "skipping non block device: " << dinfo << endl; 00678 continue; 00679 } 00680 DBG << "trying device " << dinfo << endl; 00681 00682 // FIXME: we have also to check if it is mounted in the system 00683 AttachedMedia ret( findAttachedMedia( media)); 00684 if( !ret.mediaSource ) 00685 { 00686 forceRelaseAllMedia( media, false ); 00687 if ( openTray( it->name ) ) 00688 { 00689 ejected = true; 00690 break; // on 1st success 00691 } 00692 } 00693 } 00694 } 00695 #if REPORT_EJECT_ERRORS 00696 if( !ejected) 00697 { 00698 ZYPP_THROW(MediaNotEjectedException()); 00699 } 00700 #endif 00701 } 00702 00704 // 00705 // METHOD NAME : MediaCD::isAttached 00706 // METHOD TYPE : bool 00707 // 00708 // DESCRIPTION : Override check if media is attached. 00709 // 00710 bool 00711 MediaCD::isAttached() const 00712 { 00713 return checkAttached(false); 00714 } 00715 00717 // 00718 // METHOD NAME : MediaCD::getFile 00719 // METHOD TYPE : PMError 00720 // 00721 // DESCRIPTION : Asserted that media is attached. 00722 // 00723 void MediaCD::getFile( const Pathname & filename ) const 00724 { 00725 MediaHandler::getFile( filename ); 00726 } 00727 00729 // 00730 // METHOD NAME : MediaCD::getDir 00731 // METHOD TYPE : PMError 00732 // 00733 // DESCRIPTION : Asserted that media is attached. 00734 // 00735 void MediaCD::getDir( const Pathname & dirname, bool recurse_r ) const 00736 { 00737 MediaHandler::getDir( dirname, recurse_r ); 00738 } 00739 00741 // 00742 // 00743 // METHOD NAME : MediaCD::getDirInfo 00744 // METHOD TYPE : PMError 00745 // 00746 // DESCRIPTION : Asserted that media is attached and retlist is empty. 00747 // 00748 void MediaCD::getDirInfo( std::list<std::string> & retlist, 00749 const Pathname & dirname, bool dots ) const 00750 { 00751 MediaHandler::getDirInfo( retlist, dirname, dots ); 00752 } 00753 00755 // 00756 // 00757 // METHOD NAME : MediaCD::getDirInfo 00758 // METHOD TYPE : PMError 00759 // 00760 // DESCRIPTION : Asserted that media is attached and retlist is empty. 00761 // 00762 void MediaCD::getDirInfo( filesystem::DirContent & retlist, const Pathname & dirname, bool dots ) const 00763 { 00764 MediaHandler::getDirInfo( retlist, dirname, dots ); 00765 } 00766 00767 00768 bool MediaCD::getDoesFileExist( const Pathname & filename ) const 00769 { 00770 return MediaHandler::getDoesFileExist( filename ); 00771 } 00772 00773 00774 bool MediaCD::hasMoreDevices() 00775 { 00776 if (_devices.size() == 0) 00777 return false; 00778 else if (_lastdev_tried < 0) 00779 return true; 00780 00781 return (unsigned) _lastdev_tried < _devices.size() - 1; 00782 } 00783 00784 00785 void MediaCD::getDetectedDevices( std::vector<std::string> & devices, unsigned int & index ) const 00786 { 00787 if ( ! devices.empty() ) 00788 devices.clear(); 00789 00790 if ( _devices.empty() ) 00791 // This also fills the _devices list on demand 00792 detectDevices( _url.getScheme() == "dvd" ? true : false ); 00793 00794 for ( const auto & it : _devices ) 00795 devices.push_back( it.name ); 00796 00797 index = ( _lastdev >= 0 ? (unsigned)_lastdev : 0 ); 00798 00799 MIL << "got " << devices.size() << " detected devices, current: " 00800 << (index < devices.size() ? devices[index] : "<none>") 00801 << "(" << index << ")" << endl; 00802 } 00803 00804 } // namespace media 00806 } // namespace zypp