1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/media/MediaManager.cc
12 #include <zypp/media/MediaException.h>
13 #include <zypp/media/MediaManager.h>
14 #include <zypp/media/MediaHandler.h>
15 #include <zypp/media/Mount.h>
16 #include <zypp/thread/Mutex.h>
17 #include <zypp/thread/MutexLock.h>
18 #include <zypp/target/hal/HalContext.h>
20 #include <zypp/base/String.h>
21 #include <zypp/base/Logger.h>
22 #include <zypp/Pathname.h>
23 #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, bool eject)
649 MutexLock glock(g_Mutex);
651 ManagedMedia &ref( m_impl->findMM(accessId));
653 DBG << "release(id=" << accessId
654 << (eject ? ", eject)" : ")") << std::endl;
658 // release MediaISO handlers, that are using the one
659 // specified with accessId, because it provides the
660 // iso file and it will disappear now (forced release
663 ManagedMediaMap::iterator m(m_impl->mediaMap.begin());
664 for( ; m != m_impl->mediaMap.end(); ++m)
666 if( m->second.handler->dependsOnParent(accessId, false))
670 DBG << "Forcing release of handler depending on access id "
671 << accessId << std::endl;
672 m->second.desired = false;
673 m->second.handler->release(!eject);
675 catch(const MediaException &e)
683 ref.handler->release(eject);
686 // ---------------------------------------------------------------
688 MediaManager::releaseAll()
690 MutexLock glock(g_Mutex);
692 MIL << "Releasing all attached media" << std::endl;
694 ManagedMediaMap::iterator m(m_impl->mediaMap.begin());
695 for( ; m != m_impl->mediaMap.end(); ++m)
697 if( m->second.handler->dependsOnParent())
702 if(m->second.handler->isAttached())
704 DBG << "Releasing media id " << m->first << std::endl;
705 m->second.desired = false;
706 m->second.handler->release(false);
710 DBG << "Media id " << m->first << " not attached " << std::endl;
713 catch(const MediaException & e)
716 ERR << "Failed to release media id " << m->first << std::endl;
720 MIL << "Exit" << std::endl;
723 // ---------------------------------------------------------------
725 MediaManager::disconnect(MediaAccessId accessId)
727 MutexLock glock(g_Mutex);
729 ManagedMedia &ref( m_impl->findMM(accessId));
731 ref.handler->disconnect();
734 // ---------------------------------------------------------------
736 MediaManager::isAttached(MediaAccessId accessId) const
738 MutexLock glock(g_Mutex);
740 ManagedMedia &ref( m_impl->findMM(accessId));
742 return ref.handler->isAttached();
745 // ---------------------------------------------------------------
746 bool MediaManager::isSharedMedia(MediaAccessId accessId) const
748 MutexLock glock(g_Mutex);
750 ManagedMedia &ref( m_impl->findMM(accessId));
752 return ref.handler->isSharedMedia();
755 // ---------------------------------------------------------------
757 MediaManager::isDesiredMedia(MediaAccessId accessId) const
759 MutexLock glock(g_Mutex);
761 ManagedMedia &ref( m_impl->findMM(accessId));
763 if( !ref.handler->isAttached())
770 ref.desired = ref.verifier->isDesiredMedia(ref.handler);
772 catch(const zypp::Exception &e) {
777 DBG << "isDesiredMedia(" << accessId << "): "
778 << (ref.desired ? "" : "not ")
779 << "desired (report by "
780 << ref.verifier->info() << ")" << std::endl;
784 // ---------------------------------------------------------------
786 MediaManager::isDesiredMedia(MediaAccessId accessId,
787 const MediaVerifierRef &verifier) const
789 MutexLock glock(g_Mutex);
791 MediaVerifierRef v(verifier);
793 ZYPP_THROW(MediaException("Invalid verifier reference"));
795 ManagedMedia &ref( m_impl->findMM(accessId));
797 bool desired = false;
798 if( ref.handler->isAttached())
801 desired = v->isDesiredMedia(ref.handler);
803 catch(const zypp::Exception &e) {
808 DBG << "isDesiredMedia(" << accessId << "): "
809 << (desired ? "" : "not ")
810 << "desired (report by "
811 << v->info() << ")" << std::endl;
815 // ---------------------------------------------------------------
817 MediaManager::isChangeable(MediaAccessId accessId)
819 return url(accessId).getScheme() == "cd" || url(accessId).getScheme() == "dvd";
822 // ---------------------------------------------------------------
824 MediaManager::localRoot(MediaAccessId accessId) const
826 MutexLock glock(g_Mutex);
828 ManagedMedia &ref( m_impl->findMM(accessId));
831 path = ref.handler->localRoot();
835 // ---------------------------------------------------------------
837 MediaManager::localPath(MediaAccessId accessId,
838 const Pathname & pathname) const
840 MutexLock glock(g_Mutex);
842 ManagedMedia &ref( m_impl->findMM(accessId));
845 path = ref.handler->localPath(pathname);
849 // ---------------------------------------------------------------
851 MediaManager::provideFile(MediaAccessId accessId,
852 const Pathname &filename,
854 bool checkonly) const
856 MutexLock glock(g_Mutex);
858 ManagedMedia &ref( m_impl->findMM(accessId));
860 ref.checkDesired(accessId);
862 ref.handler->provideFile(filename, cached, checkonly);
865 // ---------------------------------------------------------------
867 MediaManager::provideDir(MediaAccessId accessId,
868 const Pathname &dirname) const
870 MutexLock glock(g_Mutex);
872 ManagedMedia &ref( m_impl->findMM(accessId));
874 ref.checkDesired(accessId);
876 ref.handler->provideDir(dirname);
879 // ---------------------------------------------------------------
881 MediaManager::provideDirTree(MediaAccessId accessId,
882 const Pathname &dirname) const
884 MutexLock glock(g_Mutex);
886 ManagedMedia &ref( m_impl->findMM(accessId));
888 ref.checkDesired(accessId);
890 ref.handler->provideDirTree(dirname);
893 // ---------------------------------------------------------------
895 MediaManager::releaseFile(MediaAccessId accessId,
896 const Pathname &filename) const
898 MutexLock glock(g_Mutex);
900 ManagedMedia &ref( m_impl->findMM(accessId));
902 ref.checkAttached(accessId);
904 ref.handler->releaseFile(filename);
907 // ---------------------------------------------------------------
909 MediaManager::releaseDir(MediaAccessId accessId,
910 const Pathname &dirname) const
912 MutexLock glock(g_Mutex);
914 ManagedMedia &ref( m_impl->findMM(accessId));
916 ref.checkAttached(accessId);
918 ref.handler->releaseDir(dirname);
922 // ---------------------------------------------------------------
924 MediaManager::releasePath(MediaAccessId accessId,
925 const Pathname &pathname) const
927 MutexLock glock(g_Mutex);
929 ManagedMedia &ref( m_impl->findMM(accessId));
931 ref.checkAttached(accessId);
933 ref.handler->releasePath(pathname);
936 // ---------------------------------------------------------------
938 MediaManager::dirInfo(MediaAccessId accessId,
939 std::list<std::string> &retlist,
940 const Pathname &dirname,
943 MutexLock glock(g_Mutex);
945 ManagedMedia &ref( m_impl->findMM(accessId));
947 // FIXME: ref.checkDesired(accessId); ???
948 ref.checkAttached(accessId);
950 ref.handler->dirInfo(retlist, dirname, dots);
953 // ---------------------------------------------------------------
955 MediaManager::dirInfo(MediaAccessId accessId,
956 filesystem::DirContent &retlist,
957 const Pathname &dirname,
960 MutexLock glock(g_Mutex);
962 ManagedMedia &ref( m_impl->findMM(accessId));
964 // FIXME: ref.checkDesired(accessId); ???
965 ref.checkAttached(accessId);
967 ref.handler->dirInfo(retlist, dirname, dots);
970 // ---------------------------------------------------------------
972 MediaManager::doesFileExist(MediaAccessId accessId, const Pathname & filename ) const
974 MutexLock glock(g_Mutex);
975 ManagedMedia &ref( m_impl->findMM(accessId));
977 // FIXME: ref.checkDesired(accessId); ???
978 ref.checkAttached(accessId);
980 return ref.handler->doesFileExist(filename);
983 // ---------------------------------------------------------------
986 MediaManager::getMountTableMTime()
988 MutexLock glock(g_Mutex);
989 return MediaManager_Impl::getMountTableMTime();
992 // ---------------------------------------------------------------
995 MediaManager::getMountEntries()
997 MutexLock glock(g_Mutex);
999 return MediaManager_Impl::getMountEntries();
1002 // ---------------------------------------------------------------
1004 MediaManager::isUseableAttachPoint(const Pathname &path,
1007 if( path.empty() || path == "/" || !PathInfo(path).isDir())
1010 MutexLock glock(g_Mutex);
1013 // check against our current attach points
1015 ManagedMediaMap::const_iterator m(m_impl->mediaMap.begin());
1016 for( ; m != m_impl->mediaMap.end(); ++m)
1018 AttachedMedia ret = m->second.handler->attachedMedia();
1019 if( ret.mediaSource && ret.attachPoint)
1021 std::string mnt(ret.attachPoint->path.asString());
1022 std::string our(path.asString());
1026 // already used as attach point
1030 if( mnt.size() > our.size() &&
1031 mnt.at(our.size()) == '/' &&
1032 !mnt.compare(0, our.size(), our))
1034 // mountpoint is bellow of path
1035 // (would hide the content)
1045 // check against system mount entries
1047 MountEntries entries( m_impl->getMountEntries());
1048 MountEntries::const_iterator e;
1049 for( e = entries.begin(); e != entries.end(); ++e)
1051 std::string mnt(Pathname(e->dir).asString());
1052 std::string our(path.asString());
1056 // already used as mountpoint
1060 if( mnt.size() > our.size() &&
1061 mnt.at(our.size()) == '/' &&
1062 !mnt.compare(0, our.size(), our))
1064 // mountpoint is bellow of path
1065 // (would hide the content)
1073 // ---------------------------------------------------------------
1075 MediaManager::getAttachedMedia(MediaAccessId &accessId) const
1077 MutexLock glock(g_Mutex);
1079 ManagedMedia &ref( m_impl->findMM(accessId));
1081 return ref.handler->attachedMedia();
1084 // ---------------------------------------------------------------
1086 MediaManager::findAttachedMedia(const MediaSourceRef &media) const
1088 MutexLock glock(g_Mutex);
1090 if( !media || media->type.empty())
1091 return AttachedMedia();
1093 ManagedMediaMap::const_iterator m(m_impl->mediaMap.begin());
1094 for( ; m != m_impl->mediaMap.end(); ++m)
1096 if( !m->second.handler->isAttached())
1099 AttachedMedia ret = m->second.handler->attachedMedia();
1100 if( ret.mediaSource && ret.mediaSource->equals( *media))
1103 return AttachedMedia();
1106 // ---------------------------------------------------------------
1108 MediaManager::forceReleaseShared(const MediaSourceRef &media)
1110 MutexLock glock(g_Mutex);
1112 if( !media || media->type.empty())
1115 ManagedMediaMap::iterator m(m_impl->mediaMap.begin());
1116 for( ; m != m_impl->mediaMap.end(); ++m)
1118 if( !m->second.handler->isAttached())
1121 AttachedMedia ret = m->second.handler->attachedMedia();
1122 if( ret.mediaSource && ret.mediaSource->equals( *media))
1124 m->second.handler->release(false);
1125 m->second.desired = false;
1130 //////////////////////////////////////////////////////////////////
1131 } // namespace media
1132 ////////////////////////////////////////////////////////////////////
1134 ////////////////////////////////////////////////////////////////////
1136 //////////////////////////////////////////////////////////////////////
1138 ** vim: set ts=2 sts=2 sw=2 ai et: