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"
24 #include "zypp/base/String.h"
25 #include "zypp/base/Logger.h"
26 #include "zypp/Pathname.h"
27 #include "zypp/PathInfo.h"
29 //////////////////////////////////////////////////////////////////////
31 { ////////////////////////////////////////////////////////////////////
33 ////////////////////////////////////////////////////////////////////
35 { //////////////////////////////////////////////////////////////////
37 using zypp::thread::Mutex;
38 using zypp::thread::MutexLock;
40 //////////////////////////////////////////////////////////////////
41 namespace // anonymous
42 { ////////////////////////////////////////////////////////////////
45 // -------------------------------------------------------------
50 // -------------------------------------------------------------
60 ManagedMedia(const ManagedMedia &m)
63 , verifier(m.verifier)
66 ManagedMedia(const MediaAccessRef &h, const MediaVerifierRef &v)
73 checkAttached(MediaAccessId id)
75 if( !handler->isAttached())
77 DBG << "checkAttached(" << id << ") not attached" << std::endl;
79 ZYPP_THROW(MediaNotAttachedException(
86 checkDesired(MediaAccessId id)
93 desired = verifier->isDesiredMedia(handler);
95 catch(const zypp::Exception &e) {
102 DBG << "checkDesired(" << id << "): not desired (report by "
103 << verifier->info() << ")" << std::endl;
104 ZYPP_THROW(MediaNotDesiredException(
109 DBG << "checkDesired(" << id << "): desired (report by "
110 << verifier->info() << ")" << std::endl;
112 DBG << "checkDesired(" << id << "): desired (cached)" << std::endl;
117 MediaAccessRef handler;
118 MediaVerifierRef verifier;
122 // -------------------------------------------------------------
123 typedef std::map<MediaAccessId, ManagedMedia> ManagedMediaMap;
125 ////////////////////////////////////////////////////////////////
127 //////////////////////////////////////////////////////////////////
130 //////////////////////////////////////////////////////////////////
132 MediaVerifierBase::info() const
134 return std::string(typeid((*this)).name());
138 //////////////////////////////////////////////////////////////////
140 NoVerifier::info() const
142 return std::string("zypp::media::NoVerifier");
146 //////////////////////////////////////////////////////////////////
147 class MediaManager_Impl
150 friend class MediaManager;
152 MediaAccessId last_accessid;
153 ManagedMediaMap mediaMap;
162 MutexLock glock(g_Mutex);
166 // remove depending (iso) handlers first
167 ManagedMediaMap::iterator it;
172 for(it = mediaMap.begin(); it != mediaMap.end(); /**/)
174 if( it->second.handler->dependsOnParent())
177 // let it forget its parent, we will
178 // destroy it later (in clear())...
179 it->second.handler->resetParentId();
180 mediaMap.erase( it++ ); // postfix! Incrementing before erase
187 // remove all other handlers
197 return ++last_accessid;
201 hasId(MediaAccessId accessId) const
203 return mediaMap.find(accessId) != mediaMap.end();
206 inline ManagedMedia &
207 findMM(MediaAccessId accessId)
209 ManagedMediaMap::iterator it( mediaMap.find(accessId));
210 if( it == mediaMap.end())
212 ZYPP_THROW(MediaNotOpenException(
213 "Invalid media access id " + str::numstring(accessId)
222 time_t mtime = zypp::PathInfo("/etc/mtab").mtime();
225 WAR << "Failed to retrieve modification time of '/etc/mtab'"
231 static inline MountEntries
234 return Mount::getEntries();
240 //////////////////////////////////////////////////////////////////
242 zypp::RW_pointer<MediaManager_Impl> MediaManager::m_impl;
245 //////////////////////////////////////////////////////////////////
246 MediaManager::MediaManager()
248 MutexLock glock(g_Mutex);
251 m_impl.reset( new MediaManager_Impl());
255 // ---------------------------------------------------------------
256 MediaManager::~MediaManager()
260 // ---------------------------------------------------------------
262 MediaManager::open(const Url &url, const Pathname &preferred_attach_point)
264 MutexLock glock(g_Mutex);
266 // create new access handler for it
267 MediaAccessRef handler( new MediaAccess());
268 MediaVerifierRef verifier( new NoVerifier());
269 ManagedMedia tmp( handler, verifier);
271 tmp.handler->open(url, preferred_attach_point);
273 MediaAccessId nextId = m_impl->nextAccessId();
275 m_impl->mediaMap[nextId] = tmp;
277 DBG << "Opened new media access using id " << nextId
278 << " to " << url.asString() << std::endl;
282 // ---------------------------------------------------------------
284 MediaManager::close(MediaAccessId accessId)
286 MutexLock glock(g_Mutex);
289 // The MediaISO handler internally requests an accessId
290 // of a "parent" handler providing the iso file.
291 // The parent handler accessId is private to MediaISO,
292 // but the attached media source may be shared reference.
293 // This means, that if the accessId exactly matches the
294 // parent handler id, close was used on uninitialized
295 // accessId variable (or the accessId was guessed) and
296 // the close request to this id will be rejected here.
298 ManagedMediaMap::iterator m(m_impl->mediaMap.begin());
299 for( ; m != m_impl->mediaMap.end(); ++m)
301 if( m->second.handler->dependsOnParent(accessId, true))
303 ZYPP_THROW(MediaIsSharedException(
304 m->second.handler->url().asString()
309 DBG << "Close to access handler using id "
310 << accessId << " requested" << std::endl;
312 ManagedMedia &ref( m_impl->findMM(accessId));
313 ref.handler->close();
315 m_impl->mediaMap.erase(accessId);
318 // ---------------------------------------------------------------
320 MediaManager::isOpen(MediaAccessId accessId) const
322 MutexLock glock(g_Mutex);
324 ManagedMediaMap::iterator it( m_impl->mediaMap.find(accessId));
325 return it != m_impl->mediaMap.end() &&
326 it->second.handler->isOpen();
329 // ---------------------------------------------------------------
331 MediaManager::protocol(MediaAccessId accessId) const
333 MutexLock glock(g_Mutex);
335 ManagedMedia &ref( m_impl->findMM(accessId));
337 return ref.handler->protocol();
340 // ---------------------------------------------------------------
342 MediaManager::downloads(MediaAccessId accessId) const
344 MutexLock glock(g_Mutex);
346 ManagedMedia &ref( m_impl->findMM(accessId));
348 return ref.handler->downloads();
351 // ---------------------------------------------------------------
353 MediaManager::url(MediaAccessId accessId) const
355 MutexLock glock(g_Mutex);
357 ManagedMedia &ref( m_impl->findMM(accessId));
359 return ref.handler->url();
362 // ---------------------------------------------------------------
364 MediaManager::addVerifier(MediaAccessId accessId,
365 const MediaVerifierRef &verifier)
367 MutexLock glock(g_Mutex);
370 ZYPP_THROW(MediaException("Invalid verifier reference"));
372 ManagedMedia &ref( m_impl->findMM(accessId));
375 MediaVerifierRef(verifier).swap(ref.verifier);
377 DBG << "MediaVerifier change: id=" << accessId << ", verifier="
378 << verifier->info() << std::endl;
381 // ---------------------------------------------------------------
383 MediaManager::delVerifier(MediaAccessId accessId)
385 MutexLock glock(g_Mutex);
387 ManagedMedia &ref( m_impl->findMM(accessId));
389 MediaVerifierRef verifier( new NoVerifier());
391 ref.verifier.swap(verifier);
393 DBG << "MediaVerifier change: id=" << accessId << ", verifier="
394 << verifier->info() << std::endl;
397 // ---------------------------------------------------------------
399 MediaManager::setAttachPrefix(const Pathname &attach_prefix)
401 MutexLock glock(g_Mutex);
403 return MediaHandler::setAttachPrefix(attach_prefix);
406 // ---------------------------------------------------------------
407 void MediaManager::attach(MediaAccessId accessId)
409 MutexLock glock(g_Mutex);
411 ManagedMedia &ref( m_impl->findMM(accessId));
413 DBG << "attach(id=" << accessId << ")" << std::endl;
415 // try first mountable/mounted device
416 ref.handler->attach(false);
419 ref.checkDesired(accessId);
422 catch (const MediaException & ex)
426 if (!ref.handler->hasMoreDevices())
429 if (ref.handler->isAttached())
430 ref.handler->release();
433 MIL << "checkDesired(" << accessId << ") of first device failed,"
434 " going to try others with attach(true)" << std::endl;
436 while (ref.handler->hasMoreDevices())
440 // try to attach next device
441 ref.handler->attach(true);
442 ref.checkDesired(accessId);
445 catch (const MediaNotDesiredException & ex)
449 if (!ref.handler->hasMoreDevices())
451 MIL << "No desired media found after trying all detected devices." << std::endl;
455 AttachedMedia media(ref.handler->attachedMedia());
456 DBG << "Skipping " << media.mediaSource->asString() << ": not desired media." << std::endl;
458 ref.handler->release();
460 catch (const MediaException & ex)
464 if (!ref.handler->hasMoreDevices())
467 AttachedMedia media(ref.handler->attachedMedia());
468 DBG << "Skipping " << media.mediaSource->asString() << " because of exception thrown by attach(true)" << std::endl;
470 if (ref.handler->isAttached()) ref.handler->release();
475 // ---------------------------------------------------------------
477 MediaManager::release(MediaAccessId accessId, const std::string & ejectDev)
479 MutexLock glock(g_Mutex);
481 ManagedMedia &ref( m_impl->findMM(accessId));
483 DBG << "release(id=" << accessId;
484 if (!ejectDev.empty())
485 DBG << ", " << ejectDev;
486 DBG << ")" << std::endl;
488 if(!ejectDev.empty())
491 // release MediaISO handlers, that are using the one
492 // specified with accessId, because it provides the
493 // iso file and it will disappear now (forced release
496 ManagedMediaMap::iterator m(m_impl->mediaMap.begin());
497 for( ; m != m_impl->mediaMap.end(); ++m)
499 if( m->second.handler->dependsOnParent(accessId, false))
503 DBG << "Forcing release of handler depending on access id "
504 << accessId << std::endl;
505 m->second.desired = false;
506 m->second.handler->release();
508 catch(const MediaException &e)
516 ref.handler->release(ejectDev);
519 // ---------------------------------------------------------------
521 MediaManager::releaseAll()
523 MutexLock glock(g_Mutex);
525 MIL << "Releasing all attached media" << std::endl;
527 ManagedMediaMap::iterator m(m_impl->mediaMap.begin());
528 for( ; m != m_impl->mediaMap.end(); ++m)
530 if( m->second.handler->dependsOnParent())
535 if(m->second.handler->isAttached())
537 DBG << "Releasing media id " << m->first << std::endl;
538 m->second.desired = false;
539 m->second.handler->release();
543 DBG << "Media id " << m->first << " not attached " << std::endl;
546 catch(const MediaException & e)
549 ERR << "Failed to release media id " << m->first << std::endl;
553 MIL << "Exit" << std::endl;
556 // ---------------------------------------------------------------
558 MediaManager::disconnect(MediaAccessId accessId)
560 MutexLock glock(g_Mutex);
562 ManagedMedia &ref( m_impl->findMM(accessId));
564 ref.handler->disconnect();
567 // ---------------------------------------------------------------
569 MediaManager::isAttached(MediaAccessId accessId) const
571 MutexLock glock(g_Mutex);
573 ManagedMedia &ref( m_impl->findMM(accessId));
575 return ref.handler->isAttached();
578 // ---------------------------------------------------------------
579 bool MediaManager::isSharedMedia(MediaAccessId accessId) const
581 MutexLock glock(g_Mutex);
583 ManagedMedia &ref( m_impl->findMM(accessId));
585 return ref.handler->isSharedMedia();
588 // ---------------------------------------------------------------
590 MediaManager::isDesiredMedia(MediaAccessId accessId) const
592 MutexLock glock(g_Mutex);
594 ManagedMedia &ref( m_impl->findMM(accessId));
596 if( !ref.handler->isAttached())
603 ref.desired = ref.verifier->isDesiredMedia(ref.handler);
605 catch(const zypp::Exception &e) {
610 DBG << "isDesiredMedia(" << accessId << "): "
611 << (ref.desired ? "" : "not ")
612 << "desired (report by "
613 << ref.verifier->info() << ")" << std::endl;
617 // ---------------------------------------------------------------
619 MediaManager::isDesiredMedia(MediaAccessId accessId,
620 const MediaVerifierRef &verifier) const
622 MutexLock glock(g_Mutex);
624 MediaVerifierRef v(verifier);
626 ZYPP_THROW(MediaException("Invalid verifier reference"));
628 ManagedMedia &ref( m_impl->findMM(accessId));
630 bool desired = false;
631 if( ref.handler->isAttached())
634 desired = v->isDesiredMedia(ref.handler);
636 catch(const zypp::Exception &e) {
641 DBG << "isDesiredMedia(" << accessId << "): "
642 << (desired ? "" : "not ")
643 << "desired (report by "
644 << v->info() << ")" << std::endl;
648 // ---------------------------------------------------------------
650 MediaManager::isChangeable(MediaAccessId accessId)
652 return url(accessId).getScheme() == "cd" || url(accessId).getScheme() == "dvd";
655 // ---------------------------------------------------------------
657 MediaManager::localRoot(MediaAccessId accessId) const
659 MutexLock glock(g_Mutex);
661 ManagedMedia &ref( m_impl->findMM(accessId));
664 path = ref.handler->localRoot();
668 // ---------------------------------------------------------------
670 MediaManager::localPath(MediaAccessId accessId,
671 const Pathname & pathname) const
673 MutexLock glock(g_Mutex);
675 ManagedMedia &ref( m_impl->findMM(accessId));
678 path = ref.handler->localPath(pathname);
682 // ---------------------------------------------------------------
684 MediaManager::provideFile(MediaAccessId accessId,
685 const Pathname &filename ) const
687 MutexLock glock(g_Mutex);
689 ManagedMedia &ref( m_impl->findMM(accessId));
691 ref.checkDesired(accessId);
693 ref.handler->provideFile(filename);
696 // ---------------------------------------------------------------
698 MediaManager::setDeltafile(MediaAccessId accessId,
699 const Pathname &filename ) const
701 MutexLock glock(g_Mutex);
703 ManagedMedia &ref( m_impl->findMM(accessId));
705 ref.checkDesired(accessId);
707 ref.handler->setDeltafile(filename);
710 // ---------------------------------------------------------------
712 MediaManager::provideDir(MediaAccessId accessId,
713 const Pathname &dirname) const
715 MutexLock glock(g_Mutex);
717 ManagedMedia &ref( m_impl->findMM(accessId));
719 ref.checkDesired(accessId);
721 ref.handler->provideDir(dirname);
724 // ---------------------------------------------------------------
726 MediaManager::provideDirTree(MediaAccessId accessId,
727 const Pathname &dirname) const
729 MutexLock glock(g_Mutex);
731 ManagedMedia &ref( m_impl->findMM(accessId));
733 ref.checkDesired(accessId);
735 ref.handler->provideDirTree(dirname);
738 // ---------------------------------------------------------------
740 MediaManager::releaseFile(MediaAccessId accessId,
741 const Pathname &filename) const
743 MutexLock glock(g_Mutex);
745 ManagedMedia &ref( m_impl->findMM(accessId));
747 ref.checkAttached(accessId);
749 ref.handler->releaseFile(filename);
752 // ---------------------------------------------------------------
754 MediaManager::releaseDir(MediaAccessId accessId,
755 const Pathname &dirname) const
757 MutexLock glock(g_Mutex);
759 ManagedMedia &ref( m_impl->findMM(accessId));
761 ref.checkAttached(accessId);
763 ref.handler->releaseDir(dirname);
767 // ---------------------------------------------------------------
769 MediaManager::releasePath(MediaAccessId accessId,
770 const Pathname &pathname) const
772 MutexLock glock(g_Mutex);
774 ManagedMedia &ref( m_impl->findMM(accessId));
776 ref.checkAttached(accessId);
778 ref.handler->releasePath(pathname);
781 // ---------------------------------------------------------------
783 MediaManager::dirInfo(MediaAccessId accessId,
784 std::list<std::string> &retlist,
785 const Pathname &dirname,
788 MutexLock glock(g_Mutex);
790 ManagedMedia &ref( m_impl->findMM(accessId));
792 // FIXME: ref.checkDesired(accessId); ???
793 ref.checkAttached(accessId);
795 ref.handler->dirInfo(retlist, dirname, dots);
798 // ---------------------------------------------------------------
800 MediaManager::dirInfo(MediaAccessId accessId,
801 filesystem::DirContent &retlist,
802 const Pathname &dirname,
805 MutexLock glock(g_Mutex);
807 ManagedMedia &ref( m_impl->findMM(accessId));
809 // FIXME: ref.checkDesired(accessId); ???
810 ref.checkAttached(accessId);
812 ref.handler->dirInfo(retlist, dirname, dots);
815 // ---------------------------------------------------------------
817 MediaManager::doesFileExist(MediaAccessId accessId, const Pathname & filename ) const
819 MutexLock glock(g_Mutex);
820 ManagedMedia &ref( m_impl->findMM(accessId));
822 // FIXME: ref.checkDesired(accessId); ???
823 ref.checkAttached(accessId);
825 return ref.handler->doesFileExist(filename);
828 // ---------------------------------------------------------------
830 MediaManager::getDetectedDevices(MediaAccessId accessId,
831 std::vector<std::string> & devices,
832 unsigned int & index) const
834 MutexLock glock(g_Mutex);
835 ManagedMedia &ref( m_impl->findMM(accessId));
836 return ref.handler->getDetectedDevices(devices, index);
839 // ---------------------------------------------------------------
842 MediaManager::getMountTableMTime()
844 MutexLock glock(g_Mutex);
845 return MediaManager_Impl::getMountTableMTime();
848 // ---------------------------------------------------------------
851 MediaManager::getMountEntries()
853 MutexLock glock(g_Mutex);
855 return MediaManager_Impl::getMountEntries();
858 // ---------------------------------------------------------------
860 MediaManager::isUseableAttachPoint(const Pathname &path,
863 if( path.empty() || path == "/" || !PathInfo(path).isDir())
866 MutexLock glock(g_Mutex);
869 // check against our current attach points
871 ManagedMediaMap::const_iterator m(m_impl->mediaMap.begin());
872 for( ; m != m_impl->mediaMap.end(); ++m)
874 AttachedMedia ret = m->second.handler->attachedMedia();
875 if( ret.mediaSource && ret.attachPoint)
877 std::string mnt(ret.attachPoint->path.asString());
878 std::string our(path.asString());
882 // already used as attach point
886 if( mnt.size() > our.size() &&
887 mnt.at(our.size()) == '/' &&
888 !mnt.compare(0, our.size(), our))
890 // mountpoint is bellow of path
891 // (would hide the content)
901 // check against system mount entries
903 MountEntries entries( m_impl->getMountEntries());
904 MountEntries::const_iterator e;
905 for( e = entries.begin(); e != entries.end(); ++e)
907 std::string mnt(Pathname(e->dir).asString());
908 std::string our(path.asString());
912 // already used as mountpoint
916 if( mnt.size() > our.size() &&
917 mnt.at(our.size()) == '/' &&
918 !mnt.compare(0, our.size(), our))
920 // mountpoint is bellow of path
921 // (would hide the content)
929 // ---------------------------------------------------------------
931 MediaManager::getAttachedMedia(MediaAccessId &accessId) const
933 MutexLock glock(g_Mutex);
935 ManagedMedia &ref( m_impl->findMM(accessId));
937 return ref.handler->attachedMedia();
940 // ---------------------------------------------------------------
942 MediaManager::findAttachedMedia(const MediaSourceRef &media) const
944 MutexLock glock(g_Mutex);
946 if( !media || media->type.empty())
947 return AttachedMedia();
949 ManagedMediaMap::const_iterator m(m_impl->mediaMap.begin());
950 for( ; m != m_impl->mediaMap.end(); ++m)
952 if( !m->second.handler->isAttached())
955 AttachedMedia ret = m->second.handler->attachedMedia();
956 if( ret.mediaSource && ret.mediaSource->equals( *media))
959 return AttachedMedia();
962 // ---------------------------------------------------------------
964 MediaManager::forceReleaseShared(const MediaSourceRef &media)
966 MutexLock glock(g_Mutex);
968 if( !media || media->type.empty())
971 ManagedMediaMap::iterator m(m_impl->mediaMap.begin());
972 for( ; m != m_impl->mediaMap.end(); ++m)
974 if( !m->second.handler->isAttached())
977 AttachedMedia ret = m->second.handler->attachedMedia();
978 if( ret.mediaSource && ret.mediaSource->equals( *media))
980 m->second.handler->release();
981 m->second.desired = false;
986 //////////////////////////////////////////////////////////////////
988 ////////////////////////////////////////////////////////////////////
990 ////////////////////////////////////////////////////////////////////
992 //////////////////////////////////////////////////////////////////////
994 ** vim: set ts=2 sts=2 sw=2 ai et: