libzypp  11.13.5
MediaManager.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
12 #include <map>
13 #include <list>
14 #include <iostream>
15 #include <typeinfo>
16 
20 #include "zypp/media/Mount.h"
21 #include "zypp/thread/Mutex.h"
22 #include "zypp/thread/MutexLock.h"
23 
24 #include "zypp/base/String.h"
25 #include "zypp/base/Logger.h"
26 #include "zypp/Pathname.h"
27 #include "zypp/PathInfo.h"
28 
30 namespace zypp
31 {
32 
34  namespace media
35  {
36 
37  using zypp::thread::Mutex;
39 
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(MediaAccessId id)
74  {
75  if( !handler->isAttached())
76  {
77  DBG << "checkAttached(" << id << ") not attached" << std::endl;
78  desired = false;
79  ZYPP_THROW(MediaNotAttachedException(
80  handler->url()
81  ));
82  }
83  }
84 
85  inline void
86  checkDesired(MediaAccessId id)
87  {
88  checkAttached(id);
89 
90  if( !desired)
91  {
92  try {
93  desired = verifier->isDesiredMedia(handler);
94  }
95  catch(const zypp::Exception &e) {
96  ZYPP_CAUGHT(e);
97  desired = false;
98  }
99 
100  if( !desired)
101  {
102  DBG << "checkDesired(" << id << "): not desired (report by "
103  << verifier->info() << ")" << std::endl;
104  ZYPP_THROW(MediaNotDesiredException(
105  handler->url()
106  ));
107  }
108 
109  DBG << "checkDesired(" << id << "): desired (report by "
110  << verifier->info() << ")" << std::endl;
111  } else {
112  DBG << "checkDesired(" << id << "): desired (cached)" << std::endl;
113  }
114  }
115 
116  bool desired;
119  };
120 
121 
122  // -------------------------------------------------------------
123  typedef std::map<MediaAccessId, ManagedMedia> ManagedMediaMap;
124 
126  } // anonymous
128 
129 
131  std::string
133  {
134  return std::string(typeid((*this)).name());
135  }
136 
137 
139  std::string
141  {
142  return std::string("zypp::media::NoVerifier");
143  }
144 
145 
148  {
149  private:
150  friend class MediaManager;
151 
153  ManagedMediaMap mediaMap;
154 
156  : last_accessid(0)
157  {}
158 
159  public:
161  {
162  MutexLock glock(g_Mutex);
163 
164  try
165  {
166  // remove depending (iso) handlers first
167  ManagedMediaMap::iterator it;
168  bool found;
169  do
170  {
171  found = false;
172  for(it = mediaMap.begin(); it != mediaMap.end(); )
173  {
174  if( it->second.handler->dependsOnParent())
175  {
176  found = true;
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
181  } else {
182  ++it;
183  }
184  }
185  } while(found);
186 
187  // remove all other handlers
188  mediaMap.clear();
189  }
190  catch( ... )
191  {}
192  }
193 
194  inline MediaAccessId
196  {
197  return ++last_accessid;
198  }
199 
200  inline bool
201  hasId(MediaAccessId accessId) const
202  {
203  return mediaMap.find(accessId) != mediaMap.end();
204  }
205 
206  inline ManagedMedia &
208  {
209  ManagedMediaMap::iterator it( mediaMap.find(accessId));
210  if( it == mediaMap.end())
211  {
213  "Invalid media access id " + str::numstring(accessId)
214  ));
215  }
216  return it->second;
217  }
218 
219  static inline time_t
221  {
222  time_t mtime = zypp::PathInfo("/etc/mtab").mtime();
223  if( mtime <= 0)
224  {
225  WAR << "Failed to retrieve modification time of '/etc/mtab'"
226  << std::endl;
227  }
228  return mtime;
229  }
230 
231  static inline MountEntries
233  {
234  return Mount::getEntries();
235  }
236 
237  };
238 
239 
241  // STATIC
243 
244 
247  {
248  MutexLock glock(g_Mutex);
249  if( !m_impl)
250  {
252  }
253  }
254 
255  // ---------------------------------------------------------------
257  {
258  }
259 
260  // ---------------------------------------------------------------
262  MediaManager::open(const Url &url, const Pathname &preferred_attach_point)
263  {
264  MutexLock glock(g_Mutex);
265 
266  // create new access handler for it
269  ManagedMedia tmp( handler, verifier);
270 
271  tmp.handler->open(url, preferred_attach_point);
272 
273  MediaAccessId nextId = m_impl->nextAccessId();
274 
275  m_impl->mediaMap[nextId] = tmp;
276 
277  DBG << "Opened new media access using id " << nextId
278  << " to " << url.asString() << std::endl;
279  return nextId;
280  }
281 
282  // ---------------------------------------------------------------
283  void
285  {
286  MutexLock glock(g_Mutex);
287 
288  //
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.
297  //
298  ManagedMediaMap::iterator m(m_impl->mediaMap.begin());
299  for( ; m != m_impl->mediaMap.end(); ++m)
300  {
301  if( m->second.handler->dependsOnParent(accessId, true))
302  {
304  m->second.handler->url().asString()
305  ));
306  }
307  }
308 
309  DBG << "Close to access handler using id "
310  << accessId << " requested" << std::endl;
311 
312  ManagedMedia &ref( m_impl->findMM(accessId));
313  ref.handler->close();
314 
315  m_impl->mediaMap.erase(accessId);
316  }
317 
318  // ---------------------------------------------------------------
319  bool
321  {
322  MutexLock glock(g_Mutex);
323 
324  ManagedMediaMap::iterator it( m_impl->mediaMap.find(accessId));
325  return it != m_impl->mediaMap.end() &&
326  it->second.handler->isOpen();
327  }
328 
329  // ---------------------------------------------------------------
330  std::string
332  {
333  MutexLock glock(g_Mutex);
334 
335  ManagedMedia &ref( m_impl->findMM(accessId));
336 
337  return ref.handler->protocol();
338  }
339 
340  // ---------------------------------------------------------------
341  bool
343  {
344  MutexLock glock(g_Mutex);
345 
346  ManagedMedia &ref( m_impl->findMM(accessId));
347 
348  return ref.handler->downloads();
349  }
350 
351  // ---------------------------------------------------------------
352  Url
354  {
355  MutexLock glock(g_Mutex);
356 
357  ManagedMedia &ref( m_impl->findMM(accessId));
358 
359  return ref.handler->url();
360  }
361 
362  // ---------------------------------------------------------------
363  void
365  const MediaVerifierRef &verifier)
366  {
367  MutexLock glock(g_Mutex);
368 
369  if( !verifier)
370  ZYPP_THROW(MediaException("Invalid verifier reference"));
371 
372  ManagedMedia &ref( m_impl->findMM(accessId));
373 
374  ref.desired = false;
375  MediaVerifierRef(verifier).swap(ref.verifier);
376 
377  DBG << "MediaVerifier change: id=" << accessId << ", verifier="
378  << verifier->info() << std::endl;
379  }
380 
381  // ---------------------------------------------------------------
382  void
384  {
385  MutexLock glock(g_Mutex);
386 
387  ManagedMedia &ref( m_impl->findMM(accessId));
388 
390  ref.desired = false;
391  ref.verifier.swap(verifier);
392 
393  DBG << "MediaVerifier change: id=" << accessId << ", verifier="
394  << verifier->info() << std::endl;
395  }
396 
397  // ---------------------------------------------------------------
398  bool
399  MediaManager::setAttachPrefix(const Pathname &attach_prefix)
400  {
401  MutexLock glock(g_Mutex);
402 
403  return MediaHandler::setAttachPrefix(attach_prefix);
404  }
405 
406  // ---------------------------------------------------------------
408  {
409  MutexLock glock(g_Mutex);
410 
411  ManagedMedia &ref( m_impl->findMM(accessId));
412 
413  DBG << "attach(id=" << accessId << ")" << std::endl;
414 
415  // try first mountable/mounted device
416  ref.handler->attach(false);
417  try
418  {
419  ref.checkDesired(accessId);
420  return;
421  }
422  catch (const MediaException & ex)
423  {
424  ZYPP_CAUGHT(ex);
425 
426  if (!ref.handler->hasMoreDevices())
427  ZYPP_RETHROW(ex);
428 
429  if (ref.handler->isAttached())
430  ref.handler->release();
431  }
432 
433  MIL << "checkDesired(" << accessId << ") of first device failed,"
434  " going to try others with attach(true)" << std::endl;
435 
436  while (ref.handler->hasMoreDevices())
437  {
438  try
439  {
440  // try to attach next device
441  ref.handler->attach(true);
442  ref.checkDesired(accessId);
443  return;
444  }
445  catch (const MediaNotDesiredException & ex)
446  {
447  ZYPP_CAUGHT(ex);
448 
449  if (!ref.handler->hasMoreDevices())
450  {
451  MIL << "No desired media found after trying all detected devices." << std::endl;
452  ZYPP_RETHROW(ex);
453  }
454 
455  AttachedMedia media(ref.handler->attachedMedia());
456  DBG << "Skipping " << media.mediaSource->asString() << ": not desired media." << std::endl;
457 
458  ref.handler->release();
459  }
460  catch (const MediaException & ex)
461  {
462  ZYPP_CAUGHT(ex);
463 
464  if (!ref.handler->hasMoreDevices())
465  ZYPP_RETHROW(ex);
466 
467  AttachedMedia media(ref.handler->attachedMedia());
468  DBG << "Skipping " << media.mediaSource->asString() << " because of exception thrown by attach(true)" << std::endl;
469 
470  if (ref.handler->isAttached()) ref.handler->release();
471  }
472  }
473  }
474 
475  // ---------------------------------------------------------------
476  void
477  MediaManager::release(MediaAccessId accessId, const std::string & ejectDev)
478  {
479  MutexLock glock(g_Mutex);
480 
481  ManagedMedia &ref( m_impl->findMM(accessId));
482 
483  DBG << "release(id=" << accessId;
484  if (!ejectDev.empty())
485  DBG << ", " << ejectDev;
486  DBG << ")" << std::endl;
487 
488  if(!ejectDev.empty())
489  {
490  //
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
494  // with eject).
495  //
496  ManagedMediaMap::iterator m(m_impl->mediaMap.begin());
497  for( ; m != m_impl->mediaMap.end(); ++m)
498  {
499  if( m->second.handler->dependsOnParent(accessId, false))
500  {
501  try
502  {
503  DBG << "Forcing release of handler depending on access id "
504  << accessId << std::endl;
505  m->second.desired = false;
506  m->second.handler->release();
507  }
508  catch(const MediaException &e)
509  {
510  ZYPP_CAUGHT(e);
511  }
512  }
513  }
514  }
515  ref.desired = false;
516  ref.handler->release(ejectDev);
517  }
518 
519  // ---------------------------------------------------------------
520  void
522  {
523  MutexLock glock(g_Mutex);
524 
525  MIL << "Releasing all attached media" << std::endl;
526 
527  ManagedMediaMap::iterator m(m_impl->mediaMap.begin());
528  for( ; m != m_impl->mediaMap.end(); ++m)
529  {
530  if( m->second.handler->dependsOnParent())
531  continue;
532 
533  try
534  {
535  if(m->second.handler->isAttached())
536  {
537  DBG << "Releasing media id " << m->first << std::endl;
538  m->second.desired = false;
539  m->second.handler->release();
540  }
541  else
542  {
543  DBG << "Media id " << m->first << " not attached " << std::endl;
544  }
545  }
546  catch(const MediaException & e)
547  {
548  ZYPP_CAUGHT(e);
549  ERR << "Failed to release media id " << m->first << std::endl;
550  }
551  }
552 
553  MIL << "Exit" << std::endl;
554  }
555 
556  // ---------------------------------------------------------------
557  void
559  {
560  MutexLock glock(g_Mutex);
561 
562  ManagedMedia &ref( m_impl->findMM(accessId));
563 
564  ref.handler->disconnect();
565  }
566 
567  // ---------------------------------------------------------------
568  bool
570  {
571  MutexLock glock(g_Mutex);
572 
573  ManagedMedia &ref( m_impl->findMM(accessId));
574 
575  return ref.handler->isAttached();
576  }
577 
578  // ---------------------------------------------------------------
580  {
581  MutexLock glock(g_Mutex);
582 
583  ManagedMedia &ref( m_impl->findMM(accessId));
584 
585  return ref.handler->isSharedMedia();
586  }
587 
588  // ---------------------------------------------------------------
589  bool
591  {
592  MutexLock glock(g_Mutex);
593 
594  ManagedMedia &ref( m_impl->findMM(accessId));
595 
596  if( !ref.handler->isAttached())
597  {
598  ref.desired = false;
599  }
600  else
601  {
602  try {
603  ref.desired = ref.verifier->isDesiredMedia(ref.handler);
604  }
605  catch(const zypp::Exception &e) {
606  ZYPP_CAUGHT(e);
607  ref.desired = false;
608  }
609  }
610  DBG << "isDesiredMedia(" << accessId << "): "
611  << (ref.desired ? "" : "not ")
612  << "desired (report by "
613  << ref.verifier->info() << ")" << std::endl;
614  return ref.desired;
615  }
616 
617  // ---------------------------------------------------------------
618  bool
620  const MediaVerifierRef &verifier) const
621  {
622  MutexLock glock(g_Mutex);
623 
624  MediaVerifierRef v(verifier);
625  if( !v)
626  ZYPP_THROW(MediaException("Invalid verifier reference"));
627 
628  ManagedMedia &ref( m_impl->findMM(accessId));
629 
630  bool desired = false;
631  if( ref.handler->isAttached())
632  {
633  try {
634  desired = v->isDesiredMedia(ref.handler);
635  }
636  catch(const zypp::Exception &e) {
637  ZYPP_CAUGHT(e);
638  desired = false;
639  }
640  }
641  DBG << "isDesiredMedia(" << accessId << "): "
642  << (desired ? "" : "not ")
643  << "desired (report by "
644  << v->info() << ")" << std::endl;
645  return desired;
646  }
647 
648  // ---------------------------------------------------------------
649  bool
651  {
652  return url(accessId).getScheme() == "cd" || url(accessId).getScheme() == "dvd";
653  }
654 
655  // ---------------------------------------------------------------
656  Pathname
658  {
659  MutexLock glock(g_Mutex);
660 
661  ManagedMedia &ref( m_impl->findMM(accessId));
662 
663  Pathname path;
664  path = ref.handler->localRoot();
665  return path;
666  }
667 
668  // ---------------------------------------------------------------
669  Pathname
671  const Pathname & pathname) const
672  {
673  MutexLock glock(g_Mutex);
674 
675  ManagedMedia &ref( m_impl->findMM(accessId));
676 
677  Pathname path;
678  path = ref.handler->localPath(pathname);
679  return path;
680  }
681 
682  // ---------------------------------------------------------------
683  void
685  const Pathname &filename ) const
686  {
687  MutexLock glock(g_Mutex);
688 
689  ManagedMedia &ref( m_impl->findMM(accessId));
690 
691  ref.checkDesired(accessId);
692 
693  ref.handler->provideFile(filename);
694  }
695 
696  // ---------------------------------------------------------------
697  void
699  const Pathname &filename ) const
700  {
701  MutexLock glock(g_Mutex);
702 
703  ManagedMedia &ref( m_impl->findMM(accessId));
704 
705  ref.checkDesired(accessId);
706 
707  ref.handler->setDeltafile(filename);
708  }
709 
710  // ---------------------------------------------------------------
711  void
713  const Pathname &dirname) const
714  {
715  MutexLock glock(g_Mutex);
716 
717  ManagedMedia &ref( m_impl->findMM(accessId));
718 
719  ref.checkDesired(accessId);
720 
721  ref.handler->provideDir(dirname);
722  }
723 
724  // ---------------------------------------------------------------
725  void
727  const Pathname &dirname) const
728  {
729  MutexLock glock(g_Mutex);
730 
731  ManagedMedia &ref( m_impl->findMM(accessId));
732 
733  ref.checkDesired(accessId);
734 
735  ref.handler->provideDirTree(dirname);
736  }
737 
738  // ---------------------------------------------------------------
739  void
741  const Pathname &filename) const
742  {
743  MutexLock glock(g_Mutex);
744 
745  ManagedMedia &ref( m_impl->findMM(accessId));
746 
747  ref.checkAttached(accessId);
748 
749  ref.handler->releaseFile(filename);
750  }
751 
752  // ---------------------------------------------------------------
753  void
755  const Pathname &dirname) const
756  {
757  MutexLock glock(g_Mutex);
758 
759  ManagedMedia &ref( m_impl->findMM(accessId));
760 
761  ref.checkAttached(accessId);
762 
763  ref.handler->releaseDir(dirname);
764  }
765 
766 
767  // ---------------------------------------------------------------
768  void
770  const Pathname &pathname) const
771  {
772  MutexLock glock(g_Mutex);
773 
774  ManagedMedia &ref( m_impl->findMM(accessId));
775 
776  ref.checkAttached(accessId);
777 
778  ref.handler->releasePath(pathname);
779  }
780 
781  // ---------------------------------------------------------------
782  void
784  std::list<std::string> &retlist,
785  const Pathname &dirname,
786  bool dots) const
787  {
788  MutexLock glock(g_Mutex);
789 
790  ManagedMedia &ref( m_impl->findMM(accessId));
791 
792  // FIXME: ref.checkDesired(accessId); ???
793  ref.checkAttached(accessId);
794 
795  ref.handler->dirInfo(retlist, dirname, dots);
796  }
797 
798  // ---------------------------------------------------------------
799  void
801  filesystem::DirContent &retlist,
802  const Pathname &dirname,
803  bool dots) const
804  {
805  MutexLock glock(g_Mutex);
806 
807  ManagedMedia &ref( m_impl->findMM(accessId));
808 
809  // FIXME: ref.checkDesired(accessId); ???
810  ref.checkAttached(accessId);
811 
812  ref.handler->dirInfo(retlist, dirname, dots);
813  }
814 
815  // ---------------------------------------------------------------
816  bool
817  MediaManager::doesFileExist(MediaAccessId accessId, const Pathname & filename ) const
818  {
819  MutexLock glock(g_Mutex);
820  ManagedMedia &ref( m_impl->findMM(accessId));
821 
822  // FIXME: ref.checkDesired(accessId); ???
823  ref.checkAttached(accessId);
824 
825  return ref.handler->doesFileExist(filename);
826  }
827 
828  // ---------------------------------------------------------------
829  void
831  std::vector<std::string> & devices,
832  unsigned int & index) const
833  {
834  MutexLock glock(g_Mutex);
835  ManagedMedia &ref( m_impl->findMM(accessId));
836  return ref.handler->getDetectedDevices(devices, index);
837  }
838 
839  // ---------------------------------------------------------------
840  // STATIC
841  time_t
843  {
844  MutexLock glock(g_Mutex);
846  }
847 
848  // ---------------------------------------------------------------
849  // STATIC
850  MountEntries
852  {
853  MutexLock glock(g_Mutex);
854 
856  }
857 
858  // ---------------------------------------------------------------
859  bool
861  bool mtab) const
862  {
863  if( path.empty() || path == "/" || !PathInfo(path).isDir())
864  return false;
865 
866  MutexLock glock(g_Mutex);
867 
868  //
869  // check against our current attach points
870  //
871  ManagedMediaMap::const_iterator m(m_impl->mediaMap.begin());
872  for( ; m != m_impl->mediaMap.end(); ++m)
873  {
874  AttachedMedia ret = m->second.handler->attachedMedia();
875  if( ret.mediaSource && ret.attachPoint)
876  {
877  std::string mnt(ret.attachPoint->path.asString());
878  std::string our(path.asString());
879 
880  if( our == mnt)
881  {
882  // already used as attach point
883  return false;
884  }
885  else
886  if( mnt.size() > our.size() &&
887  mnt.at(our.size()) == '/' &&
888  !mnt.compare(0, our.size(), our))
889  {
890  // mountpoint is bellow of path
891  // (would hide the content)
892  return false;
893  }
894  }
895  }
896 
897  if( !mtab)
898  return true;
899 
900  //
901  // check against system mount entries
902  //
903  MountEntries entries( m_impl->getMountEntries());
904  MountEntries::const_iterator e;
905  for( e = entries.begin(); e != entries.end(); ++e)
906  {
907  std::string mnt(Pathname(e->dir).asString());
908  std::string our(path.asString());
909 
910  if( our == mnt)
911  {
912  // already used as mountpoint
913  return false;
914  }
915  else
916  if( mnt.size() > our.size() &&
917  mnt.at(our.size()) == '/' &&
918  !mnt.compare(0, our.size(), our))
919  {
920  // mountpoint is bellow of path
921  // (would hide the content)
922  return false;
923  }
924  }
925 
926  return true;
927  }
928 
929  // ---------------------------------------------------------------
932  {
933  MutexLock glock(g_Mutex);
934 
935  ManagedMedia &ref( m_impl->findMM(accessId));
936 
937  return ref.handler->attachedMedia();
938  }
939 
940  // ---------------------------------------------------------------
943  {
944  MutexLock glock(g_Mutex);
945 
946  if( !media || media->type.empty())
947  return AttachedMedia();
948 
949  ManagedMediaMap::const_iterator m(m_impl->mediaMap.begin());
950  for( ; m != m_impl->mediaMap.end(); ++m)
951  {
952  if( !m->second.handler->isAttached())
953  continue;
954 
955  AttachedMedia ret = m->second.handler->attachedMedia();
956  if( ret.mediaSource && ret.mediaSource->equals( *media))
957  return ret;
958  }
959  return AttachedMedia();
960  }
961 
962  // ---------------------------------------------------------------
963  void
965  {
966  MutexLock glock(g_Mutex);
967 
968  if( !media || media->type.empty())
969  return;
970 
971  ManagedMediaMap::iterator m(m_impl->mediaMap.begin());
972  for( ; m != m_impl->mediaMap.end(); ++m)
973  {
974  if( !m->second.handler->isAttached())
975  continue;
976 
977  AttachedMedia ret = m->second.handler->attachedMedia();
978  if( ret.mediaSource && ret.mediaSource->equals( *media))
979  {
980  m->second.handler->release();
981  m->second.desired = false;
982  }
983  }
984  }
985 
987  } // namespace media
989 
991 } // namespace zypp
993 /*
994 ** vim: set ts=2 sts=2 sw=2 ai et:
995 */