1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/media/MediaManager.cc
17 #include "zypp/media/MediaException.h"
18 #include "zypp/media/MediaManager.h"
19 #include "zypp/media/MediaHandler.h"
20 #include "zypp/media/Mount.h"
21 #include "zypp/thread/Mutex.h"
22 #include "zypp/thread/MutexLock.h"
23 #include "zypp/target/hal/HalContext.h"
25 #include "zypp/base/String.h"
26 #include "zypp/base/Logger.h"
27 #include "zypp/Pathname.h"
28 #include "zypp/PathInfo.h"
30 #define DISABLE_AUTOMOUNTER 0
33 //////////////////////////////////////////////////////////////////////
35 { ////////////////////////////////////////////////////////////////////
37 ////////////////////////////////////////////////////////////////////
39 { //////////////////////////////////////////////////////////////////
41 using zypp::thread::Mutex;
42 using zypp::thread::MutexLock;
44 //////////////////////////////////////////////////////////////////
45 namespace // anonymous
46 { ////////////////////////////////////////////////////////////////
49 // -------------------------------------------------------------
54 // -------------------------------------------------------------
64 ManagedMedia(const ManagedMedia &m)
67 , verifier(m.verifier)
70 ManagedMedia(const MediaAccessRef &h, const MediaVerifierRef &v)
77 checkAttached(MediaAccessId id)
79 if( !handler->isAttached())
81 DBG << "checkAttached(" << id << ") not attached" << std::endl;
83 ZYPP_THROW(MediaNotAttachedException(
90 checkDesired(MediaAccessId id)
97 desired = verifier->isDesiredMedia(handler);
99 catch(const zypp::Exception &e) {
106 DBG << "checkDesired(" << id << "): not desired (report by "
107 << verifier->info() << ")" << std::endl;
108 ZYPP_THROW(MediaNotDesiredException(
113 DBG << "checkDesired(" << id << "): desired (report by "
114 << verifier->info() << ")" << std::endl;
116 DBG << "checkDesired(" << id << "): desired (cached)" << std::endl;
121 MediaAccessRef handler;
122 MediaVerifierRef verifier;
126 // -------------------------------------------------------------
127 typedef std::map<MediaAccessId, ManagedMedia> ManagedMediaMap;
130 // -------------------------------------------------------------
131 enum AutoMounterCleanUp
136 #define HAL_AUTOMOUNTER_UDI "/org/freedesktop/Hal/devices/computer"
137 #define HAL_AUTOMOUNTER_KEY "storage.disable_volume_handling"
139 // -------------------------------------------------------------
143 using namespace zypp::target::hal;
145 AutoMounterCleanUp cleanup(NONE);
146 #if DISABLE_AUTOMOUNTER
149 HalContext hal(true);
150 bool disabled(false);
153 XXX << "Checking HAL volume handling property"
157 disabled = hal.getDevicePropertyBool(
158 HAL_AUTOMOUNTER_UDI, HAL_AUTOMOUNTER_KEY
163 MIL << "HAL volume handling is already disabled"
169 XXX << "HAL volume handling is enabled"
173 catch(const HalException &e)
176 XXX << "HAL volume handling is enabled (no property)"
185 XXX << "Trying to disable HAL volume handling"
189 hal.setDevicePropertyBool(
190 HAL_AUTOMOUNTER_UDI, HAL_AUTOMOUNTER_KEY,
194 MIL << "Disabled HAL volume handling (automounter)"
197 catch(const HalException &e)
200 WAR << "Unable to disable HAL volume handling (automounter)"
207 catch(const HalException &e)
210 WAR << "Unable to disable HAL volume handling (automounter)"
213 #endif // DISABLE_AUTOMOUNTER
217 // -------------------------------------------------------------
219 restoreAutoMounter(AutoMounterCleanUp cleanup)
221 using namespace zypp::target::hal;
226 #if DISABLE_AUTOMOUNTER
229 HalContext hal(true);
231 if(cleanup == ENABLE)
233 XXX << "Trying to restore HAL volume handling -- enable"
236 hal.setDevicePropertyBool(
237 HAL_AUTOMOUNTER_UDI, HAL_AUTOMOUNTER_KEY,
242 if(cleanup == REMOVE)
244 XXX << "Trying to restore HAL volume handling -- remove"
247 hal.removeDeviceProperty(
248 HAL_AUTOMOUNTER_UDI, HAL_AUTOMOUNTER_KEY
253 MIL << "Restored HAL volume handling (automounter)"
256 catch(const HalException &e)
259 WAR << "Unable to restore HAL volume handling (automounter)"
262 #endif // DISABLE_AUTOMOUNTER
265 ////////////////////////////////////////////////////////////////
267 //////////////////////////////////////////////////////////////////
270 //////////////////////////////////////////////////////////////////
272 MediaVerifierBase::info() const
274 return std::string(typeid((*this)).name());
278 //////////////////////////////////////////////////////////////////
280 NoVerifier::info() const
282 return std::string("zypp::media::NoVerifier");
286 //////////////////////////////////////////////////////////////////
287 class MediaManager_Impl
290 friend class MediaManager;
292 MediaAccessId last_accessid;
293 AutoMounterCleanUp am_cleanup;
294 ManagedMediaMap mediaMap;
299 // disable automounter
300 am_cleanup = disableAutoMounter();
306 MutexLock glock(g_Mutex);
310 // remove depending (iso) handlers first
311 ManagedMediaMap::iterator it;
316 for(it = mediaMap.begin(); it != mediaMap.end(); /**/)
318 if( it->second.handler->dependsOnParent())
321 // let it forget its parent, we will
322 // destroy it later (in clear())...
323 it->second.handler->resetParentId();
324 mediaMap.erase( it++ ); // postfix! Incrementing before erase
331 // remove all other handlers
334 // restore automounter state
335 restoreAutoMounter(am_cleanup);
344 return ++last_accessid;
348 hasId(MediaAccessId accessId) const
350 return mediaMap.find(accessId) != mediaMap.end();
353 inline ManagedMedia &
354 findMM(MediaAccessId accessId)
356 ManagedMediaMap::iterator it( mediaMap.find(accessId));
357 if( it == mediaMap.end())
359 ZYPP_THROW(MediaNotOpenException(
360 "Invalid media access id " + str::numstring(accessId)
369 time_t mtime = zypp::PathInfo("/etc/mtab").mtime();
372 WAR << "Failed to retrieve modification time of '/etc/mtab'"
378 static inline MountEntries
381 // use "/etc/mtab" by default,
382 // fallback to "/proc/mounts"
383 return Mount::getEntries(/* "/etc/mtab" */);
389 //////////////////////////////////////////////////////////////////
391 zypp::RW_pointer<MediaManager_Impl> MediaManager::m_impl(NULL);
394 //////////////////////////////////////////////////////////////////
395 MediaManager::MediaManager()
397 MutexLock glock(g_Mutex);
400 m_impl.reset( new MediaManager_Impl());
404 // ---------------------------------------------------------------
405 MediaManager::~MediaManager()
409 // ---------------------------------------------------------------
411 MediaManager::open(const Url &url, const Pathname &preferred_attach_point)
413 MutexLock glock(g_Mutex);
415 // create new access handler for it
416 MediaAccessRef handler( new MediaAccess());
417 MediaVerifierRef verifier( new NoVerifier());
418 ManagedMedia tmp( handler, verifier);
420 tmp.handler->open(url, preferred_attach_point);
422 MediaAccessId nextId = m_impl->nextAccessId();
424 m_impl->mediaMap[nextId] = tmp;
426 DBG << "Opened new media access using id " << nextId
427 << " to " << url.asString() << std::endl;
431 // ---------------------------------------------------------------
433 MediaManager::close(MediaAccessId accessId)
435 MutexLock glock(g_Mutex);
438 // The MediaISO handler internally requests an accessId
439 // of a "parent" handler providing the iso file.
440 // The parent handler accessId is private to MediaISO,
441 // but the attached media source may be shared reference.
442 // This means, that if the accessId exactly matches the
443 // parent handler id, close was used on uninitialized
444 // accessId variable (or the accessId was guessed) and
445 // the close request to this id will be rejected here.
447 ManagedMediaMap::iterator m(m_impl->mediaMap.begin());
448 for( ; m != m_impl->mediaMap.end(); ++m)
450 if( m->second.handler->dependsOnParent(accessId, true))
452 ZYPP_THROW(MediaIsSharedException(
453 m->second.handler->url().asString()
458 DBG << "Close to access handler using id "
459 << accessId << " requested" << std::endl;
461 ManagedMedia &ref( m_impl->findMM(accessId));
462 ref.handler->close();
464 m_impl->mediaMap.erase(accessId);
467 // ---------------------------------------------------------------
469 MediaManager::isOpen(MediaAccessId accessId) const
471 MutexLock glock(g_Mutex);
473 ManagedMediaMap::iterator it( m_impl->mediaMap.find(accessId));
474 return it != m_impl->mediaMap.end() &&
475 it->second.handler->isOpen();
478 // ---------------------------------------------------------------
480 MediaManager::protocol(MediaAccessId accessId) const
482 MutexLock glock(g_Mutex);
484 ManagedMedia &ref( m_impl->findMM(accessId));
486 return ref.handler->protocol();
489 // ---------------------------------------------------------------
491 MediaManager::downloads(MediaAccessId accessId) const
493 MutexLock glock(g_Mutex);
495 ManagedMedia &ref( m_impl->findMM(accessId));
497 return ref.handler->downloads();
500 // ---------------------------------------------------------------
503 MediaManager::downloads(const Url &url)
505 return MediaAccess::downloads( url);
508 // ---------------------------------------------------------------
510 MediaManager::url(MediaAccessId accessId) const
512 MutexLock glock(g_Mutex);
514 ManagedMedia &ref( m_impl->findMM(accessId));
516 return ref.handler->url();
519 // ---------------------------------------------------------------
521 MediaManager::addVerifier(MediaAccessId accessId,
522 const MediaVerifierRef &verifier)
524 MutexLock glock(g_Mutex);
527 ZYPP_THROW(MediaException("Invalid verifier reference"));
529 ManagedMedia &ref( m_impl->findMM(accessId));
532 MediaVerifierRef(verifier).swap(ref.verifier);
534 DBG << "MediaVerifier change: id=" << accessId << ", verifier="
535 << verifier->info() << std::endl;
538 // ---------------------------------------------------------------
540 MediaManager::delVerifier(MediaAccessId accessId)
542 MutexLock glock(g_Mutex);
544 ManagedMedia &ref( m_impl->findMM(accessId));
546 MediaVerifierRef verifier( new NoVerifier());
548 ref.verifier.swap(verifier);
550 DBG << "MediaVerifier change: id=" << accessId << ", verifier="
551 << verifier->info() << std::endl;
554 // ---------------------------------------------------------------
556 MediaManager::setAttachPrefix(const Pathname &attach_prefix)
558 MutexLock glock(g_Mutex);
560 return MediaHandler::setAttachPrefix(attach_prefix);
563 // ---------------------------------------------------------------
565 MediaManager::attach(MediaAccessId accessId, bool next)
567 MutexLock glock(g_Mutex);
569 ManagedMedia &ref( m_impl->findMM(accessId));
571 DBG << "attach(id=" << accessId << ")" << std::endl;
573 return ref.handler->attach(next);
576 // ---------------------------------------------------------------
577 void MediaManager::attachDesiredMedia(MediaAccessId accessId)
579 MutexLock glock(g_Mutex);
581 ManagedMedia &ref( m_impl->findMM(accessId));
583 DBG << "attach(id=" << accessId << ")" << std::endl;
585 // try first mountable/mounted device
586 ref.handler->attach(false);
589 ref.checkDesired(accessId);
592 catch (const MediaException & ex)
596 if (!ref.handler->hasMoreDevices())
599 if (ref.handler->isAttached())
600 ref.handler->release();
603 MIL << "checkDesired(" << accessId << ") of first device failed,"
604 " going to try others with attach(true)" << std::endl;
606 while (ref.handler->hasMoreDevices())
610 // try to attach next device
611 ref.handler->attach(true);
612 ref.checkDesired(accessId);
615 catch (const MediaNotDesiredException & ex)
619 if (!ref.handler->hasMoreDevices())
621 MIL << "No desired media found after trying all detected devices." << std::endl;
625 AttachedMedia media(ref.handler->attachedMedia());
626 DBG << "Skipping " << media.mediaSource->asString() << ": not desired media." << std::endl;
628 ref.handler->release();
630 catch (const MediaException & ex)
634 if (!ref.handler->hasMoreDevices())
637 AttachedMedia media(ref.handler->attachedMedia());
638 DBG << "Skipping " << media.mediaSource->asString() << " because of exception thrown by attach(true)" << std::endl;
640 if (ref.handler->isAttached()) ref.handler->release();
645 // ---------------------------------------------------------------
647 MediaManager::release(MediaAccessId accessId, const std::string & ejectDev)
649 MutexLock glock(g_Mutex);
651 ManagedMedia &ref( m_impl->findMM(accessId));
653 DBG << "release(id=" << accessId;
654 if (!ejectDev.empty())
655 DBG << ", " << ejectDev;
656 DBG << ")" << std::endl;
658 if(!ejectDev.empty())
661 // release MediaISO handlers, that are using the one
662 // specified with accessId, because it provides the
663 // iso file and it will disappear now (forced release
666 ManagedMediaMap::iterator m(m_impl->mediaMap.begin());
667 for( ; m != m_impl->mediaMap.end(); ++m)
669 if( m->second.handler->dependsOnParent(accessId, false))
673 DBG << "Forcing release of handler depending on access id "
674 << accessId << std::endl;
675 m->second.desired = false;
676 m->second.handler->release();
678 catch(const MediaException &e)
686 ref.handler->release(ejectDev);
689 // ---------------------------------------------------------------
691 MediaManager::releaseAll()
693 MutexLock glock(g_Mutex);
695 MIL << "Releasing all attached media" << std::endl;
697 ManagedMediaMap::iterator m(m_impl->mediaMap.begin());
698 for( ; m != m_impl->mediaMap.end(); ++m)
700 if( m->second.handler->dependsOnParent())
705 if(m->second.handler->isAttached())
707 DBG << "Releasing media id " << m->first << std::endl;
708 m->second.desired = false;
709 m->second.handler->release();
713 DBG << "Media id " << m->first << " not attached " << std::endl;
716 catch(const MediaException & e)
719 ERR << "Failed to release media id " << m->first << std::endl;
723 MIL << "Exit" << std::endl;
726 // ---------------------------------------------------------------
728 MediaManager::disconnect(MediaAccessId accessId)
730 MutexLock glock(g_Mutex);
732 ManagedMedia &ref( m_impl->findMM(accessId));
734 ref.handler->disconnect();
737 // ---------------------------------------------------------------
739 MediaManager::isAttached(MediaAccessId accessId) const
741 MutexLock glock(g_Mutex);
743 ManagedMedia &ref( m_impl->findMM(accessId));
745 return ref.handler->isAttached();
748 // ---------------------------------------------------------------
749 bool MediaManager::isSharedMedia(MediaAccessId accessId) const
751 MutexLock glock(g_Mutex);
753 ManagedMedia &ref( m_impl->findMM(accessId));
755 return ref.handler->isSharedMedia();
758 // ---------------------------------------------------------------
760 MediaManager::isDesiredMedia(MediaAccessId accessId) const
762 MutexLock glock(g_Mutex);
764 ManagedMedia &ref( m_impl->findMM(accessId));
766 if( !ref.handler->isAttached())
773 ref.desired = ref.verifier->isDesiredMedia(ref.handler);
775 catch(const zypp::Exception &e) {
780 DBG << "isDesiredMedia(" << accessId << "): "
781 << (ref.desired ? "" : "not ")
782 << "desired (report by "
783 << ref.verifier->info() << ")" << std::endl;
787 // ---------------------------------------------------------------
789 MediaManager::isDesiredMedia(MediaAccessId accessId,
790 const MediaVerifierRef &verifier) const
792 MutexLock glock(g_Mutex);
794 MediaVerifierRef v(verifier);
796 ZYPP_THROW(MediaException("Invalid verifier reference"));
798 ManagedMedia &ref( m_impl->findMM(accessId));
800 bool desired = false;
801 if( ref.handler->isAttached())
804 desired = v->isDesiredMedia(ref.handler);
806 catch(const zypp::Exception &e) {
811 DBG << "isDesiredMedia(" << accessId << "): "
812 << (desired ? "" : "not ")
813 << "desired (report by "
814 << v->info() << ")" << std::endl;
818 // ---------------------------------------------------------------
820 MediaManager::isChangeable(MediaAccessId accessId)
822 return url(accessId).getScheme() == "cd" || url(accessId).getScheme() == "dvd";
825 // ---------------------------------------------------------------
827 MediaManager::localRoot(MediaAccessId accessId) const
829 MutexLock glock(g_Mutex);
831 ManagedMedia &ref( m_impl->findMM(accessId));
834 path = ref.handler->localRoot();
838 // ---------------------------------------------------------------
840 MediaManager::localPath(MediaAccessId accessId,
841 const Pathname & pathname) const
843 MutexLock glock(g_Mutex);
845 ManagedMedia &ref( m_impl->findMM(accessId));
848 path = ref.handler->localPath(pathname);
852 // ---------------------------------------------------------------
854 MediaManager::provideFile(MediaAccessId accessId,
855 const Pathname &filename ) const
857 MutexLock glock(g_Mutex);
859 ManagedMedia &ref( m_impl->findMM(accessId));
861 ref.checkDesired(accessId);
863 ref.handler->provideFile(filename);
866 // ---------------------------------------------------------------
868 MediaManager::provideDir(MediaAccessId accessId,
869 const Pathname &dirname) const
871 MutexLock glock(g_Mutex);
873 ManagedMedia &ref( m_impl->findMM(accessId));
875 ref.checkDesired(accessId);
877 ref.handler->provideDir(dirname);
880 // ---------------------------------------------------------------
882 MediaManager::provideDirTree(MediaAccessId accessId,
883 const Pathname &dirname) const
885 MutexLock glock(g_Mutex);
887 ManagedMedia &ref( m_impl->findMM(accessId));
889 ref.checkDesired(accessId);
891 ref.handler->provideDirTree(dirname);
894 // ---------------------------------------------------------------
896 MediaManager::releaseFile(MediaAccessId accessId,
897 const Pathname &filename) const
899 MutexLock glock(g_Mutex);
901 ManagedMedia &ref( m_impl->findMM(accessId));
903 ref.checkAttached(accessId);
905 ref.handler->releaseFile(filename);
908 // ---------------------------------------------------------------
910 MediaManager::releaseDir(MediaAccessId accessId,
911 const Pathname &dirname) const
913 MutexLock glock(g_Mutex);
915 ManagedMedia &ref( m_impl->findMM(accessId));
917 ref.checkAttached(accessId);
919 ref.handler->releaseDir(dirname);
923 // ---------------------------------------------------------------
925 MediaManager::releasePath(MediaAccessId accessId,
926 const Pathname &pathname) const
928 MutexLock glock(g_Mutex);
930 ManagedMedia &ref( m_impl->findMM(accessId));
932 ref.checkAttached(accessId);
934 ref.handler->releasePath(pathname);
937 // ---------------------------------------------------------------
939 MediaManager::dirInfo(MediaAccessId accessId,
940 std::list<std::string> &retlist,
941 const Pathname &dirname,
944 MutexLock glock(g_Mutex);
946 ManagedMedia &ref( m_impl->findMM(accessId));
948 // FIXME: ref.checkDesired(accessId); ???
949 ref.checkAttached(accessId);
951 ref.handler->dirInfo(retlist, dirname, dots);
954 // ---------------------------------------------------------------
956 MediaManager::dirInfo(MediaAccessId accessId,
957 filesystem::DirContent &retlist,
958 const Pathname &dirname,
961 MutexLock glock(g_Mutex);
963 ManagedMedia &ref( m_impl->findMM(accessId));
965 // FIXME: ref.checkDesired(accessId); ???
966 ref.checkAttached(accessId);
968 ref.handler->dirInfo(retlist, dirname, dots);
971 // ---------------------------------------------------------------
973 MediaManager::doesFileExist(MediaAccessId accessId, const Pathname & filename ) const
975 MutexLock glock(g_Mutex);
976 ManagedMedia &ref( m_impl->findMM(accessId));
978 // FIXME: ref.checkDesired(accessId); ???
979 ref.checkAttached(accessId);
981 return ref.handler->doesFileExist(filename);
984 // ---------------------------------------------------------------
986 MediaManager::getDetectedDevices(MediaAccessId accessId,
987 std::vector<std::string> & devices,
988 unsigned int & index) const
990 MutexLock glock(g_Mutex);
991 ManagedMedia &ref( m_impl->findMM(accessId));
992 return ref.handler->getDetectedDevices(devices, index);
995 // ---------------------------------------------------------------
998 MediaManager::getMountTableMTime()
1000 MutexLock glock(g_Mutex);
1001 return MediaManager_Impl::getMountTableMTime();
1004 // ---------------------------------------------------------------
1007 MediaManager::getMountEntries()
1009 MutexLock glock(g_Mutex);
1011 return MediaManager_Impl::getMountEntries();
1014 // ---------------------------------------------------------------
1016 MediaManager::isUseableAttachPoint(const Pathname &path,
1019 if( path.empty() || path == "/" || !PathInfo(path).isDir())
1022 MutexLock glock(g_Mutex);
1025 // check against our current attach points
1027 ManagedMediaMap::const_iterator m(m_impl->mediaMap.begin());
1028 for( ; m != m_impl->mediaMap.end(); ++m)
1030 AttachedMedia ret = m->second.handler->attachedMedia();
1031 if( ret.mediaSource && ret.attachPoint)
1033 std::string mnt(ret.attachPoint->path.asString());
1034 std::string our(path.asString());
1038 // already used as attach point
1042 if( mnt.size() > our.size() &&
1043 mnt.at(our.size()) == '/' &&
1044 !mnt.compare(0, our.size(), our))
1046 // mountpoint is bellow of path
1047 // (would hide the content)
1057 // check against system mount entries
1059 MountEntries entries( m_impl->getMountEntries());
1060 MountEntries::const_iterator e;
1061 for( e = entries.begin(); e != entries.end(); ++e)
1063 std::string mnt(Pathname(e->dir).asString());
1064 std::string our(path.asString());
1068 // already used as mountpoint
1072 if( mnt.size() > our.size() &&
1073 mnt.at(our.size()) == '/' &&
1074 !mnt.compare(0, our.size(), our))
1076 // mountpoint is bellow of path
1077 // (would hide the content)
1085 // ---------------------------------------------------------------
1087 MediaManager::getAttachedMedia(MediaAccessId &accessId) const
1089 MutexLock glock(g_Mutex);
1091 ManagedMedia &ref( m_impl->findMM(accessId));
1093 return ref.handler->attachedMedia();
1096 // ---------------------------------------------------------------
1098 MediaManager::findAttachedMedia(const MediaSourceRef &media) const
1100 MutexLock glock(g_Mutex);
1102 if( !media || media->type.empty())
1103 return AttachedMedia();
1105 ManagedMediaMap::const_iterator m(m_impl->mediaMap.begin());
1106 for( ; m != m_impl->mediaMap.end(); ++m)
1108 if( !m->second.handler->isAttached())
1111 AttachedMedia ret = m->second.handler->attachedMedia();
1112 if( ret.mediaSource && ret.mediaSource->equals( *media))
1115 return AttachedMedia();
1118 // ---------------------------------------------------------------
1120 MediaManager::forceReleaseShared(const MediaSourceRef &media)
1122 MutexLock glock(g_Mutex);
1124 if( !media || media->type.empty())
1127 ManagedMediaMap::iterator m(m_impl->mediaMap.begin());
1128 for( ; m != m_impl->mediaMap.end(); ++m)
1130 if( !m->second.handler->isAttached())
1133 AttachedMedia ret = m->second.handler->attachedMedia();
1134 if( ret.mediaSource && ret.mediaSource->equals( *media))
1136 m->second.handler->release();
1137 m->second.desired = false;
1142 //////////////////////////////////////////////////////////////////
1143 } // namespace media
1144 ////////////////////////////////////////////////////////////////////
1146 ////////////////////////////////////////////////////////////////////
1148 //////////////////////////////////////////////////////////////////////
1150 ** vim: set ts=2 sts=2 sw=2 ai et: