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 // ---------------------------------------------------------------
564 void MediaManager::attach(MediaAccessId accessId)
566 MutexLock glock(g_Mutex);
568 ManagedMedia &ref( m_impl->findMM(accessId));
570 DBG << "attach(id=" << accessId << ")" << std::endl;
572 // try first mountable/mounted device
573 ref.handler->attach(false);
576 ref.checkDesired(accessId);
579 catch (const MediaException & ex)
583 if (!ref.handler->hasMoreDevices())
586 if (ref.handler->isAttached())
587 ref.handler->release();
590 MIL << "checkDesired(" << accessId << ") of first device failed,"
591 " going to try others with attach(true)" << std::endl;
593 while (ref.handler->hasMoreDevices())
597 // try to attach next device
598 ref.handler->attach(true);
599 ref.checkDesired(accessId);
602 catch (const MediaNotDesiredException & ex)
606 if (!ref.handler->hasMoreDevices())
608 MIL << "No desired media found after trying all detected devices." << std::endl;
612 AttachedMedia media(ref.handler->attachedMedia());
613 DBG << "Skipping " << media.mediaSource->asString() << ": not desired media." << std::endl;
615 ref.handler->release();
617 catch (const MediaException & ex)
621 if (!ref.handler->hasMoreDevices())
624 AttachedMedia media(ref.handler->attachedMedia());
625 DBG << "Skipping " << media.mediaSource->asString() << " because of exception thrown by attach(true)" << std::endl;
627 if (ref.handler->isAttached()) ref.handler->release();
632 // ---------------------------------------------------------------
634 MediaManager::release(MediaAccessId accessId, const std::string & ejectDev)
636 MutexLock glock(g_Mutex);
638 ManagedMedia &ref( m_impl->findMM(accessId));
640 DBG << "release(id=" << accessId;
641 if (!ejectDev.empty())
642 DBG << ", " << ejectDev;
643 DBG << ")" << std::endl;
645 if(!ejectDev.empty())
648 // release MediaISO handlers, that are using the one
649 // specified with accessId, because it provides the
650 // iso file and it will disappear now (forced release
653 ManagedMediaMap::iterator m(m_impl->mediaMap.begin());
654 for( ; m != m_impl->mediaMap.end(); ++m)
656 if( m->second.handler->dependsOnParent(accessId, false))
660 DBG << "Forcing release of handler depending on access id "
661 << accessId << std::endl;
662 m->second.desired = false;
663 m->second.handler->release();
665 catch(const MediaException &e)
673 ref.handler->release(ejectDev);
676 // ---------------------------------------------------------------
678 MediaManager::releaseAll()
680 MutexLock glock(g_Mutex);
682 MIL << "Releasing all attached media" << std::endl;
684 ManagedMediaMap::iterator m(m_impl->mediaMap.begin());
685 for( ; m != m_impl->mediaMap.end(); ++m)
687 if( m->second.handler->dependsOnParent())
692 if(m->second.handler->isAttached())
694 DBG << "Releasing media id " << m->first << std::endl;
695 m->second.desired = false;
696 m->second.handler->release();
700 DBG << "Media id " << m->first << " not attached " << std::endl;
703 catch(const MediaException & e)
706 ERR << "Failed to release media id " << m->first << std::endl;
710 MIL << "Exit" << std::endl;
713 // ---------------------------------------------------------------
715 MediaManager::disconnect(MediaAccessId accessId)
717 MutexLock glock(g_Mutex);
719 ManagedMedia &ref( m_impl->findMM(accessId));
721 ref.handler->disconnect();
724 // ---------------------------------------------------------------
726 MediaManager::isAttached(MediaAccessId accessId) const
728 MutexLock glock(g_Mutex);
730 ManagedMedia &ref( m_impl->findMM(accessId));
732 return ref.handler->isAttached();
735 // ---------------------------------------------------------------
736 bool MediaManager::isSharedMedia(MediaAccessId accessId) const
738 MutexLock glock(g_Mutex);
740 ManagedMedia &ref( m_impl->findMM(accessId));
742 return ref.handler->isSharedMedia();
745 // ---------------------------------------------------------------
747 MediaManager::isDesiredMedia(MediaAccessId accessId) const
749 MutexLock glock(g_Mutex);
751 ManagedMedia &ref( m_impl->findMM(accessId));
753 if( !ref.handler->isAttached())
760 ref.desired = ref.verifier->isDesiredMedia(ref.handler);
762 catch(const zypp::Exception &e) {
767 DBG << "isDesiredMedia(" << accessId << "): "
768 << (ref.desired ? "" : "not ")
769 << "desired (report by "
770 << ref.verifier->info() << ")" << std::endl;
774 // ---------------------------------------------------------------
776 MediaManager::isDesiredMedia(MediaAccessId accessId,
777 const MediaVerifierRef &verifier) const
779 MutexLock glock(g_Mutex);
781 MediaVerifierRef v(verifier);
783 ZYPP_THROW(MediaException("Invalid verifier reference"));
785 ManagedMedia &ref( m_impl->findMM(accessId));
787 bool desired = false;
788 if( ref.handler->isAttached())
791 desired = v->isDesiredMedia(ref.handler);
793 catch(const zypp::Exception &e) {
798 DBG << "isDesiredMedia(" << accessId << "): "
799 << (desired ? "" : "not ")
800 << "desired (report by "
801 << v->info() << ")" << std::endl;
805 // ---------------------------------------------------------------
807 MediaManager::isChangeable(MediaAccessId accessId)
809 return url(accessId).getScheme() == "cd" || url(accessId).getScheme() == "dvd";
812 // ---------------------------------------------------------------
814 MediaManager::localRoot(MediaAccessId accessId) const
816 MutexLock glock(g_Mutex);
818 ManagedMedia &ref( m_impl->findMM(accessId));
821 path = ref.handler->localRoot();
825 // ---------------------------------------------------------------
827 MediaManager::localPath(MediaAccessId accessId,
828 const Pathname & pathname) const
830 MutexLock glock(g_Mutex);
832 ManagedMedia &ref( m_impl->findMM(accessId));
835 path = ref.handler->localPath(pathname);
839 // ---------------------------------------------------------------
841 MediaManager::provideFile(MediaAccessId accessId,
842 const Pathname &filename ) const
844 MutexLock glock(g_Mutex);
846 ManagedMedia &ref( m_impl->findMM(accessId));
848 ref.checkDesired(accessId);
850 ref.handler->provideFile(filename);
853 // ---------------------------------------------------------------
855 MediaManager::provideDir(MediaAccessId accessId,
856 const Pathname &dirname) const
858 MutexLock glock(g_Mutex);
860 ManagedMedia &ref( m_impl->findMM(accessId));
862 ref.checkDesired(accessId);
864 ref.handler->provideDir(dirname);
867 // ---------------------------------------------------------------
869 MediaManager::provideDirTree(MediaAccessId accessId,
870 const Pathname &dirname) const
872 MutexLock glock(g_Mutex);
874 ManagedMedia &ref( m_impl->findMM(accessId));
876 ref.checkDesired(accessId);
878 ref.handler->provideDirTree(dirname);
881 // ---------------------------------------------------------------
883 MediaManager::releaseFile(MediaAccessId accessId,
884 const Pathname &filename) const
886 MutexLock glock(g_Mutex);
888 ManagedMedia &ref( m_impl->findMM(accessId));
890 ref.checkAttached(accessId);
892 ref.handler->releaseFile(filename);
895 // ---------------------------------------------------------------
897 MediaManager::releaseDir(MediaAccessId accessId,
898 const Pathname &dirname) const
900 MutexLock glock(g_Mutex);
902 ManagedMedia &ref( m_impl->findMM(accessId));
904 ref.checkAttached(accessId);
906 ref.handler->releaseDir(dirname);
910 // ---------------------------------------------------------------
912 MediaManager::releasePath(MediaAccessId accessId,
913 const Pathname &pathname) const
915 MutexLock glock(g_Mutex);
917 ManagedMedia &ref( m_impl->findMM(accessId));
919 ref.checkAttached(accessId);
921 ref.handler->releasePath(pathname);
924 // ---------------------------------------------------------------
926 MediaManager::dirInfo(MediaAccessId accessId,
927 std::list<std::string> &retlist,
928 const Pathname &dirname,
931 MutexLock glock(g_Mutex);
933 ManagedMedia &ref( m_impl->findMM(accessId));
935 // FIXME: ref.checkDesired(accessId); ???
936 ref.checkAttached(accessId);
938 ref.handler->dirInfo(retlist, dirname, dots);
941 // ---------------------------------------------------------------
943 MediaManager::dirInfo(MediaAccessId accessId,
944 filesystem::DirContent &retlist,
945 const Pathname &dirname,
948 MutexLock glock(g_Mutex);
950 ManagedMedia &ref( m_impl->findMM(accessId));
952 // FIXME: ref.checkDesired(accessId); ???
953 ref.checkAttached(accessId);
955 ref.handler->dirInfo(retlist, dirname, dots);
958 // ---------------------------------------------------------------
960 MediaManager::doesFileExist(MediaAccessId accessId, const Pathname & filename ) const
962 MutexLock glock(g_Mutex);
963 ManagedMedia &ref( m_impl->findMM(accessId));
965 // FIXME: ref.checkDesired(accessId); ???
966 ref.checkAttached(accessId);
968 return ref.handler->doesFileExist(filename);
971 // ---------------------------------------------------------------
973 MediaManager::getDetectedDevices(MediaAccessId accessId,
974 std::vector<std::string> & devices,
975 unsigned int & index) const
977 MutexLock glock(g_Mutex);
978 ManagedMedia &ref( m_impl->findMM(accessId));
979 return ref.handler->getDetectedDevices(devices, index);
982 // ---------------------------------------------------------------
985 MediaManager::getMountTableMTime()
987 MutexLock glock(g_Mutex);
988 return MediaManager_Impl::getMountTableMTime();
991 // ---------------------------------------------------------------
994 MediaManager::getMountEntries()
996 MutexLock glock(g_Mutex);
998 return MediaManager_Impl::getMountEntries();
1001 // ---------------------------------------------------------------
1003 MediaManager::isUseableAttachPoint(const Pathname &path,
1006 if( path.empty() || path == "/" || !PathInfo(path).isDir())
1009 MutexLock glock(g_Mutex);
1012 // check against our current attach points
1014 ManagedMediaMap::const_iterator m(m_impl->mediaMap.begin());
1015 for( ; m != m_impl->mediaMap.end(); ++m)
1017 AttachedMedia ret = m->second.handler->attachedMedia();
1018 if( ret.mediaSource && ret.attachPoint)
1020 std::string mnt(ret.attachPoint->path.asString());
1021 std::string our(path.asString());
1025 // already used as attach point
1029 if( mnt.size() > our.size() &&
1030 mnt.at(our.size()) == '/' &&
1031 !mnt.compare(0, our.size(), our))
1033 // mountpoint is bellow of path
1034 // (would hide the content)
1044 // check against system mount entries
1046 MountEntries entries( m_impl->getMountEntries());
1047 MountEntries::const_iterator e;
1048 for( e = entries.begin(); e != entries.end(); ++e)
1050 std::string mnt(Pathname(e->dir).asString());
1051 std::string our(path.asString());
1055 // already used as mountpoint
1059 if( mnt.size() > our.size() &&
1060 mnt.at(our.size()) == '/' &&
1061 !mnt.compare(0, our.size(), our))
1063 // mountpoint is bellow of path
1064 // (would hide the content)
1072 // ---------------------------------------------------------------
1074 MediaManager::getAttachedMedia(MediaAccessId &accessId) const
1076 MutexLock glock(g_Mutex);
1078 ManagedMedia &ref( m_impl->findMM(accessId));
1080 return ref.handler->attachedMedia();
1083 // ---------------------------------------------------------------
1085 MediaManager::findAttachedMedia(const MediaSourceRef &media) const
1087 MutexLock glock(g_Mutex);
1089 if( !media || media->type.empty())
1090 return AttachedMedia();
1092 ManagedMediaMap::const_iterator m(m_impl->mediaMap.begin());
1093 for( ; m != m_impl->mediaMap.end(); ++m)
1095 if( !m->second.handler->isAttached())
1098 AttachedMedia ret = m->second.handler->attachedMedia();
1099 if( ret.mediaSource && ret.mediaSource->equals( *media))
1102 return AttachedMedia();
1105 // ---------------------------------------------------------------
1107 MediaManager::forceReleaseShared(const MediaSourceRef &media)
1109 MutexLock glock(g_Mutex);
1111 if( !media || media->type.empty())
1114 ManagedMediaMap::iterator m(m_impl->mediaMap.begin());
1115 for( ; m != m_impl->mediaMap.end(); ++m)
1117 if( !m->second.handler->isAttached())
1120 AttachedMedia ret = m->second.handler->attachedMedia();
1121 if( ret.mediaSource && ret.mediaSource->equals( *media))
1123 m->second.handler->release();
1124 m->second.desired = false;
1129 //////////////////////////////////////////////////////////////////
1130 } // namespace media
1131 ////////////////////////////////////////////////////////////////////
1133 ////////////////////////////////////////////////////////////////////
1135 //////////////////////////////////////////////////////////////////////
1137 ** vim: set ts=2 sts=2 sw=2 ai et: