- Fixed a hen and egg problem with iso handlers while media manager
[platform/upstream/libzypp.git] / zypp / media / MediaManager.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/media/MediaManager.cc
10  *
11 */
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
19 #include <zypp/base/String.h>
20 #include <zypp/base/Logger.h>
21 #include <zypp/Pathname.h>
22 #include <zypp/PathInfo.h>
23
24 #include <map>
25 #include <list>
26 #include <iostream>
27
28
29 //////////////////////////////////////////////////////////////////////
30 namespace zypp
31 { ////////////////////////////////////////////////////////////////////
32
33   ////////////////////////////////////////////////////////////////////
34   namespace media
35   { //////////////////////////////////////////////////////////////////
36
37     using zypp::thread::Mutex;
38     using zypp::thread::MutexLock;
39
40     //////////////////////////////////////////////////////////////////
41     namespace // anonymous
42     { ////////////////////////////////////////////////////////////////
43
44
45       // -------------------------------------------------------------
46       // STATIC
47       static Mutex  g_Mutex;
48
49
50       // -------------------------------------------------------------
51       struct ManagedMedia
52       {
53         ~ManagedMedia()
54         {}
55
56         ManagedMedia()
57           : desired (false)
58         {}
59
60         ManagedMedia(const ManagedMedia &m)
61           : desired (m.desired)
62           , handler (m.handler)
63           , verifier(m.verifier)
64         {}
65
66         ManagedMedia(const MediaAccessRef &h, const MediaVerifierRef &v)
67           : desired (false)
68           , handler (h)
69           , verifier(v)
70         {}
71
72         inline void
73         checkAttached()
74         {
75           if( !handler->isAttached())
76           {
77             desired = false;
78             ZYPP_THROW(MediaNotAttachedException(
79               handler->url()
80             ));
81           }
82         }
83
84         inline void
85         checkDesired()
86         {
87           checkAttached();
88
89           if( !desired)
90           {
91             try {
92               desired = verifier->isDesiredMedia(handler);
93             }
94             catch(const zypp::Exception &e) {
95               ZYPP_CAUGHT(e);
96               desired = false;
97             }
98
99             if( !desired)
100             {
101               ZYPP_THROW(MediaNotDesiredException(
102                 handler->url()
103               ));
104             }
105
106             DBG << "checkDesired(): desired (report)" << std::endl;
107           } else {
108             DBG << "checkDesired(): desired (cached)" << std::endl;
109           }
110         }
111
112         bool             desired;
113         MediaAccessRef   handler;
114         MediaVerifierRef verifier;
115       };
116
117
118       // -------------------------------------------------------------
119       typedef std::map<MediaAccessId, ManagedMedia> ManagedMediaMap;
120
121
122       ////////////////////////////////////////////////////////////////
123     } // anonymous
124     //////////////////////////////////////////////////////////////////
125
126
127     //////////////////////////////////////////////////////////////////
128     class MediaManager_Impl
129     {
130     private:
131       friend class MediaManager;
132
133       MediaAccessId   last_accessid;
134       ManagedMediaMap mediaMap;
135
136       MediaManager_Impl()
137         : last_accessid(0)
138       {}
139
140     public:
141       ~MediaManager_Impl()
142       {
143         MutexLock glock(g_Mutex);
144
145         try
146         {
147           // remove depending (iso) handlers first
148           ManagedMediaMap::iterator it;
149           bool found;
150           do
151           {
152             found = false;
153             for(it = mediaMap.begin(); it != mediaMap.end(); ++it)
154             {
155               if( it->second.handler->dependsOnParent())
156               {
157                 found = true;
158                 it->second.handler->resetParentId();
159                 mediaMap.erase(it);
160               }
161             }
162           } while(found);
163
164           // remove all other handlers
165           mediaMap.clear();
166         }
167         catch( ... )
168         {}
169       }
170
171       inline MediaAccessId
172       nextAccessId()
173       {
174         return ++last_accessid;
175       }
176
177       inline bool
178       hasId(MediaAccessId accessId) const
179       {
180         return mediaMap.find(accessId) != mediaMap.end();
181       }
182
183       inline ManagedMedia &
184       findMM(MediaAccessId accessId)
185       {
186         ManagedMediaMap::iterator it( mediaMap.find(accessId));
187         if( it == mediaMap.end())
188         {
189           ZYPP_THROW(MediaNotOpenException(
190             "Invalid media access id " + str::numstring(accessId)
191           ));
192         }
193         return it->second;
194       }
195
196       static inline time_t
197       getMountTableMTime()
198       {
199         return zypp::PathInfo("/etc/mtab").mtime();
200       }
201
202       static inline MountEntries
203       getMountEntries()
204       {
205         return Mount::getEntries("/etc/mtab");
206       }
207
208     };
209
210
211     //////////////////////////////////////////////////////////////////
212     // STATIC
213     zypp::RW_pointer<MediaManager_Impl> MediaManager::m_impl(NULL);
214
215
216     //////////////////////////////////////////////////////////////////
217     MediaManager::MediaManager()
218     {
219       MutexLock glock(g_Mutex);
220       if( !m_impl)
221       {
222         m_impl.reset( new MediaManager_Impl());
223       }
224     }
225
226     // ---------------------------------------------------------------
227     MediaManager::~MediaManager()
228     {
229     }
230
231     // ---------------------------------------------------------------
232     MediaAccessId
233     MediaManager::open(const Url &url, const Pathname &preferred_attach_point)
234     {
235       MutexLock glock(g_Mutex);
236
237       // create new access handler for it
238       MediaAccessRef handler( new MediaAccess());
239       MediaVerifierRef verifier( new NoVerifier());
240       ManagedMedia tmp( handler, verifier);
241
242       tmp.handler->open(url, preferred_attach_point);
243
244       MediaAccessId nextId = m_impl->nextAccessId();
245
246       m_impl->mediaMap[nextId] = tmp;
247
248       DBG << "Opened new media access using id " << nextId
249           << " to " << url.asString() << std::endl;
250       return nextId;
251     }
252
253     // ---------------------------------------------------------------
254     void
255     MediaManager::close(MediaAccessId accessId)
256     {
257       MutexLock glock(g_Mutex);
258
259       ManagedMediaMap::iterator m(m_impl->mediaMap.begin());
260       for( ; m != m_impl->mediaMap.end(); ++m)
261       {
262         if( m->second.handler->dependsOnParent(accessId))
263         {
264           // Hmm.. throw MediaIsSharedException instead?
265           try
266           {
267             DBG << "Forcing release of handler depending on access id "
268                 << accessId << std::endl;
269             m->second.handler->resetParentId();
270             m->second.handler->release();
271             m->second.desired  = false;
272           }
273           catch(const MediaException &e)
274           {
275             ZYPP_CAUGHT(e);
276           }
277         }
278       }
279
280       DBG << "Closing access handler with using id "
281           << accessId << std::endl;
282
283       ManagedMedia &ref( m_impl->findMM(accessId));
284       ref.handler->close();
285
286       m_impl->mediaMap.erase(accessId);
287     }
288
289     // ---------------------------------------------------------------
290     bool
291     MediaManager::isOpen(MediaAccessId accessId) const
292     {
293       MutexLock glock(g_Mutex);
294
295       ManagedMediaMap::iterator it( m_impl->mediaMap.find(accessId));
296       return it != m_impl->mediaMap.end() &&
297              it->second.handler->isOpen();
298     }
299
300     // ---------------------------------------------------------------
301     std::string
302     MediaManager::protocol(MediaAccessId accessId) const
303     {
304       MutexLock glock(g_Mutex);
305
306       ManagedMedia &ref( m_impl->findMM(accessId));
307
308       return ref.handler->protocol();
309     }
310
311     // ---------------------------------------------------------------
312           bool
313     MediaManager::downloads(MediaAccessId accessId) const
314     {
315       MutexLock glock(g_Mutex);
316
317       ManagedMedia &ref( m_impl->findMM(accessId));
318
319       return ref.handler->downloads();
320     }
321
322     // ---------------------------------------------------------------
323     // STATIC
324     bool
325     MediaManager::downloads(const Url &url)
326     {
327       return MediaAccess::downloads( url);
328     }
329
330     // ---------------------------------------------------------------
331     Url
332     MediaManager::url(MediaAccessId accessId) const
333     {
334       MutexLock glock(g_Mutex);
335
336       ManagedMedia &ref( m_impl->findMM(accessId));
337
338       return ref.handler->url();
339     }
340
341     // ---------------------------------------------------------------
342     void
343     MediaManager::addVerifier(MediaAccessId           accessId,
344                               const MediaVerifierRef &verifier)
345     {
346       MutexLock glock(g_Mutex);
347
348       if( !verifier)
349         ZYPP_THROW(MediaException("Invalid verifier reference"));
350
351       ManagedMedia &ref( m_impl->findMM(accessId));
352
353       MediaVerifierRef(verifier).swap(ref.verifier);
354       ref.desired = false;
355     }
356
357     // ---------------------------------------------------------------
358     void
359     MediaManager::delVerifier(MediaAccessId accessId)
360     {
361       MutexLock glock(g_Mutex);
362
363       ManagedMedia &ref( m_impl->findMM(accessId));
364
365       MediaVerifierRef verifier( new NoVerifier());
366       ref.verifier.swap(verifier);
367       ref.desired  = false;
368     }
369
370     // ---------------------------------------------------------------
371     bool
372     MediaManager::setAttachPrefix(const Pathname &attach_prefix)
373     {
374       MutexLock glock(g_Mutex);
375
376       return MediaHandler::setAttachPrefix(attach_prefix);
377     }
378
379     // ---------------------------------------------------------------
380     void
381     MediaManager::attach(MediaAccessId accessId, bool next)
382     {
383       MutexLock glock(g_Mutex);
384
385       ManagedMedia &ref( m_impl->findMM(accessId));
386
387       return ref.handler->attach(next);
388     }
389
390     // ---------------------------------------------------------------
391     void
392     MediaManager::release(MediaAccessId accessId, bool eject)
393     {
394       MutexLock glock(g_Mutex);
395
396       ManagedMedia &ref( m_impl->findMM(accessId));
397
398       if( eject)
399       {
400         //
401         // release MediaISO handlers, that are using the one
402         // specified with accessId, because it provides the
403         // iso file and it will disappear now (forced release).
404         //
405         ManagedMediaMap::iterator m(m_impl->mediaMap.begin());
406         for( ; m != m_impl->mediaMap.end(); ++m)
407         {
408           if( m->second.handler->dependsOnParent(accessId))
409           {
410             try
411             {
412               DBG << "Forcing release of handler depending on access id "
413                   << accessId << std::endl;
414               m->second.handler->release(!eject);
415               m->second.desired  = false;
416             }
417             catch(const MediaException &e)
418             {
419               ZYPP_CAUGHT(e);
420             }
421           }
422         }
423       }
424       ref.handler->release(eject);
425       ref.desired  = false;
426     }
427
428     // ---------------------------------------------------------------
429     void
430     MediaManager::disconnect(MediaAccessId accessId)
431     {
432       MutexLock glock(g_Mutex);
433
434       ManagedMedia &ref( m_impl->findMM(accessId));
435
436       ref.handler->disconnect();
437     }
438
439     // ---------------------------------------------------------------
440     bool
441     MediaManager::isAttached(MediaAccessId accessId) const
442     {
443       MutexLock glock(g_Mutex);
444
445       ManagedMedia &ref( m_impl->findMM(accessId));
446
447       return ref.handler->isAttached();
448     }
449
450     // ---------------------------------------------------------------
451     bool MediaManager::isSharedMedia(MediaAccessId accessId) const
452     {
453       MutexLock glock(g_Mutex);
454
455       ManagedMedia &ref( m_impl->findMM(accessId));
456
457       return ref.handler->isSharedMedia();
458     }
459
460     // ---------------------------------------------------------------
461     bool
462     MediaManager::isDesiredMedia(MediaAccessId accessId) const
463     {
464       MutexLock glock(g_Mutex);
465
466       ManagedMedia &ref( m_impl->findMM(accessId));
467
468       if( !ref.handler->isAttached())
469       {
470         ref.desired = false;
471       }
472       else
473       {
474         try {
475           ref.desired = ref.verifier->isDesiredMedia(ref.handler);
476         }
477         catch(const zypp::Exception &e) {
478           ZYPP_CAUGHT(e);
479           ref.desired = false;
480         }
481       }
482       return ref.desired;
483     }
484
485     // ---------------------------------------------------------------
486     bool
487     MediaManager::isDesiredMedia(MediaAccessId           accessId,
488                                  const MediaVerifierRef &verifier) const
489     {
490       MutexLock glock(g_Mutex);
491
492       MediaVerifierRef v(verifier);
493       if( !v)
494         ZYPP_THROW(MediaException("Invalid verifier reference"));
495
496       ManagedMedia &ref( m_impl->findMM(accessId));
497
498       bool desired = false;
499       if( ref.handler->isAttached())
500       {
501         try {
502           desired = v->isDesiredMedia(ref.handler);
503         }
504         catch(const zypp::Exception &e) {
505           ZYPP_CAUGHT(e);
506           desired = false;
507         }
508       }
509       return desired;
510     }
511
512     // ---------------------------------------------------------------
513     Pathname
514     MediaManager::localRoot(MediaAccessId accessId) const
515     {
516       MutexLock glock(g_Mutex);
517
518       ManagedMedia &ref( m_impl->findMM(accessId));
519
520       Pathname path;
521       path = ref.handler->localRoot();
522       return path;
523     }
524
525     // ---------------------------------------------------------------
526     Pathname
527     MediaManager::localPath(MediaAccessId accessId,
528                             const Pathname & pathname) const
529     {
530       MutexLock glock(g_Mutex);
531
532       ManagedMedia &ref( m_impl->findMM(accessId));
533
534       Pathname path;
535       path = ref.handler->localPath(pathname);
536       return path;
537     }
538
539     // ---------------------------------------------------------------
540     void
541     MediaManager::provideFile(MediaAccessId   accessId,
542                               const Pathname &filename,
543                               bool            cached,
544                               bool            checkonly) const
545     {
546       MutexLock glock(g_Mutex);
547
548       ManagedMedia &ref( m_impl->findMM(accessId));
549
550       ref.checkDesired();
551
552       ref.handler->provideFile(filename, cached, checkonly);
553     }
554
555     // ---------------------------------------------------------------
556     void
557     MediaManager::provideDir(MediaAccessId   accessId,
558                              const Pathname &dirname) const
559     {
560       MutexLock glock(g_Mutex);
561
562       ManagedMedia &ref( m_impl->findMM(accessId));
563
564       ref.checkDesired();
565
566       ref.handler->provideDir(dirname);
567     }
568
569     // ---------------------------------------------------------------
570     void
571     MediaManager::provideDirTree(MediaAccessId   accessId,
572                                  const Pathname &dirname) const
573     {
574       MutexLock glock(g_Mutex);
575
576       ManagedMedia &ref( m_impl->findMM(accessId));
577
578       ref.checkDesired();
579
580       ref.handler->provideDirTree(dirname);
581     }
582
583     // ---------------------------------------------------------------
584     void
585     MediaManager::releaseFile(MediaAccessId   accessId,
586                               const Pathname &filename) const
587     {
588       MutexLock glock(g_Mutex);
589
590       ManagedMedia &ref( m_impl->findMM(accessId));
591
592       ref.checkAttached();
593
594       ref.handler->releaseFile(filename);
595     }
596
597     // ---------------------------------------------------------------
598     void
599     MediaManager::releaseDir(MediaAccessId   accessId,
600                              const Pathname &dirname) const
601     {
602       MutexLock glock(g_Mutex);
603
604       ManagedMedia &ref( m_impl->findMM(accessId));
605
606       ref.checkAttached();
607
608       ref.handler->releaseDir(dirname);
609     }
610
611
612     // ---------------------------------------------------------------
613     void
614     MediaManager::releasePath(MediaAccessId   accessId,
615                               const Pathname &pathname) const
616     {
617       MutexLock glock(g_Mutex);
618
619       ManagedMedia &ref( m_impl->findMM(accessId));
620
621       ref.checkAttached();
622
623       ref.handler->releasePath(pathname);
624     }
625
626     // ---------------------------------------------------------------
627     void
628     MediaManager::dirInfo(MediaAccessId           accessId,
629                           std::list<std::string> &retlist,
630                           const Pathname         &dirname,
631                           bool                    dots) const
632     {
633       MutexLock glock(g_Mutex);
634
635       ManagedMedia &ref( m_impl->findMM(accessId));
636
637       // FIXME: ref.checkDesired(); ???
638       ref.checkAttached();
639
640       ref.handler->dirInfo(retlist, dirname, dots);
641     }
642
643     // ---------------------------------------------------------------
644     void
645     MediaManager::dirInfo(MediaAccessId           accessId,
646                           filesystem::DirContent &retlist,
647                           const Pathname         &dirname,
648                           bool                    dots) const
649     {
650       MutexLock glock(g_Mutex);
651
652       ManagedMedia &ref( m_impl->findMM(accessId));
653
654       // FIXME: ref.checkDesired(); ???
655       ref.checkAttached();
656
657       ref.handler->dirInfo(retlist, dirname, dots);
658     }
659
660     // ---------------------------------------------------------------
661     // STATIC
662     time_t
663     MediaManager::getMountTableMTime()
664     {
665       MutexLock glock(g_Mutex);
666       return MediaManager_Impl::getMountTableMTime();
667     }
668
669     // ---------------------------------------------------------------
670     // STATIC
671     MountEntries
672     MediaManager::getMountEntries()
673     {
674       MutexLock glock(g_Mutex);
675
676       return MediaManager_Impl::getMountEntries();
677     }
678
679     // ---------------------------------------------------------------
680     bool
681     MediaManager::isUseableAttachPoint(const Pathname &path) const
682     {
683       if( path.empty() || path == "/" || !PathInfo(path).isDir())
684         return false;
685
686       MutexLock glock(g_Mutex);
687
688       //
689       // check against our current attach points
690       //
691       ManagedMediaMap::const_iterator m(m_impl->mediaMap.begin());
692       for( ; m != m_impl->mediaMap.end(); ++m)
693       {
694         AttachedMedia ret = m->second.handler->attachedMedia();
695         if( ret.mediaSource && ret.attachPoint)
696         {
697           std::string mnt(ret.attachPoint->path.asString());
698           std::string our(path.asString());
699
700           if( our == mnt)
701           {
702             // already used as attach point
703             return false;
704           }
705           else
706           if( mnt.size() > our.size()   &&
707               mnt.at(our.size()) == '/' &&
708              !mnt.compare(0, our.size(), our))
709           {
710             // mountpoint is bellow of path
711             // (would hide the content)
712             return false;
713           }
714         }
715       }
716
717       //
718       // check against system mount entries
719       //
720       MountEntries  entries( m_impl->getMountEntries());
721       MountEntries::const_iterator e;
722       for( e = entries.begin(); e != entries.end(); ++e)
723       {
724         std::string mnt(Pathname(e->dir).asString());
725         std::string our(path.asString());
726
727         if( our == mnt)
728         {
729           // already used as mountpoint
730           return false;
731         }
732         else
733         if( mnt.size() > our.size()   &&
734             mnt.at(our.size()) == '/' &&
735            !mnt.compare(0, our.size(), our))
736         {
737           // mountpoint is bellow of path
738           // (would hide the content)
739           return false;
740         }
741       }
742       return true;
743     }
744
745     // ---------------------------------------------------------------
746     AttachedMedia
747     MediaManager::getAttachedMedia(MediaAccessId &accessId) const
748     {
749       MutexLock glock(g_Mutex);
750
751       ManagedMedia &ref( m_impl->findMM(accessId));
752
753       return ref.handler->attachedMedia();
754     }
755
756     // ---------------------------------------------------------------
757     AttachedMedia
758     MediaManager::findAttachedMedia(const MediaSourceRef &media) const
759     {
760       MutexLock glock(g_Mutex);
761
762       if( !media || media->type.empty())
763         return AttachedMedia();
764
765       ManagedMediaMap::const_iterator m(m_impl->mediaMap.begin());
766       for( ; m != m_impl->mediaMap.end(); ++m)
767       {
768         if( !m->second.handler->isAttached())
769           continue;
770
771         AttachedMedia ret = m->second.handler->attachedMedia();
772         if( ret.mediaSource && ret.mediaSource->equals( *media))
773             return ret;
774       }
775       return AttachedMedia();
776     }
777
778     // ---------------------------------------------------------------
779     void
780     MediaManager::forceMediaRelease(const MediaSourceRef &media)
781     {
782       MutexLock glock(g_Mutex);
783
784       if( !media || media->type.empty())
785         return;
786
787       ManagedMediaMap::iterator m(m_impl->mediaMap.begin());
788       for( ; m != m_impl->mediaMap.end(); ++m)
789       {
790         if( !m->second.handler->isAttached())
791           continue;
792
793         AttachedMedia ret = m->second.handler->attachedMedia();
794         if( ret.mediaSource && ret.mediaSource->equals( *media))
795         {
796           m->second.handler->release(false);
797           m->second.desired  = false;
798         }
799       }
800     }
801
802     //////////////////////////////////////////////////////////////////
803   } // namespace media
804   ////////////////////////////////////////////////////////////////////
805
806   ////////////////////////////////////////////////////////////////////
807 } // namespace zypp
808 //////////////////////////////////////////////////////////////////////
809 /*
810 ** vim: set ts=2 sts=2 sw=2 ai et:
811 */