libzypp  16.6.1
MediaISO.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
12 #include <iostream>
13 
14 #include "zypp/base/Logger.h"
15 #include "zypp/media/Mount.h"
16 
17 #include "zypp/media/MediaISO.h"
18 
19 
20 #define LOSETUP_TOOL_PATH "/sbin/losetup"
21 
22 using std::string;
23 using std::endl;
24 
26 namespace zypp
27 {
28 
30  namespace media
31  {
32 
34  //
35  // MediaISO Url:
36  //
37  // Schema: iso
38  // Path name: subdir to the location of desired files inside
39  // of the ISO.
40  // Query parameters:
41  // url: The iso filename source media url pointing
42  // to a directory containing the ISO file.
43  // mnt: Prefered attach point for source media url.
44  // iso: The name of the iso file.
45  // filesystem: Optional, defaults to "auto".
46  //
48  MediaISO::MediaISO(const Url &url_r,
49  const Pathname &attach_point_hint_r)
50  : MediaHandler(url_r, attach_point_hint_r,
51  url_r.getPathName(), // urlpath below attachpoint
52  false) // does_download
53  {
54  MIL << "MediaISO::MediaISO(" << url_r << ", "
55  << attach_point_hint_r << ")" << std::endl;
56 
57  _isofile = _url.getQueryParam("iso");
58  if( _isofile.empty())
59  {
60  ERR << "Media url does not contain iso filename" << std::endl;
62  }
63 
64  _filesystem = _url.getQueryParam("filesystem");
65  if( _filesystem.empty())
66  _filesystem = "auto";
67 
68  std::string arg;
69  zypp::Url src;
70  try
71  {
72  // this percent-decodes the query parameter, it must be later encoded
73  // again before used in a Url object
74  arg = _url.getQueryParam("url");
75  if( arg.empty() && _isofile.dirname().absolute())
76  {
77  src = std::string("dir:///");
80  }
81  else
82  {
83  src = url::encode(arg, URL_SAFE_CHARS);
84  }
85  }
86  catch(const zypp::url::UrlException &e)
87  {
88  ZYPP_CAUGHT(e);
89  ERR << "Unable to parse iso filename source media url" << std::endl;
91  ne.remember(e);
92  ZYPP_THROW(ne);
93  }
94  if( !src.isValid())
95  {
96  ERR << "Invalid iso filename source media url" << std::endl;
98  }
99  if( src.getScheme() == "iso")
100  {
101  ERR << "ISO filename source media url with iso scheme (nested iso): "
102  << src.asString() << std::endl;
104  }
105  else
106  if( !(src.getScheme() == "hd" ||
107  src.getScheme() == "dir" ||
108  src.getScheme() == "file" ||
109  src.getScheme() == "nfs" ||
110  src.getScheme() == "nfs4" ||
111  src.getScheme() == "smb" ||
112  src.getScheme() == "cifs"))
113  {
114  ERR << "ISO filename source media url scheme is not supported: "
115  << src.asString() << std::endl;
117  }
118 
119  MediaManager manager;
120 
121  _parentId = manager.open(src, _url.getQueryParam("mnt"));
122  }
123 
124  // ---------------------------------------------------------------
126  {
127  try
128  {
129  release();
130 
131  if( _parentId)
132  {
133  DBG << "Closing parent handler..." << std::endl;
134  MediaManager manager;
135  if(manager.isOpen(_parentId))
136  manager.close(_parentId);
137  _parentId = 0;
138  }
139  }
140  catch( ... )
141  {}
142  }
143 
144  // ---------------------------------------------------------------
145  bool
147  {
148  return checkAttached(false);
149  }
150 
151  // ---------------------------------------------------------------
153  {
154  const char* argv[] =
155  {
157  "-f",
158  NULL
159  };
161 
162  string out = losetup.receiveLine();
163  string device = out.substr(0, out.size() - 1); // remove the trailing endl
164  for(; out.length(); out = losetup.receiveLine())
165  DBG << "losetup: " << out;
166 
167  if (losetup.close() != 0)
168  {
169  ERR << LOSETUP_TOOL_PATH " failed to find an unused loop device." << std::endl;
171  }
172 
173  DBG << "found " << device << endl;
174  return device;
175  }
176 
177  // ---------------------------------------------------------------
178  void MediaISO::attachTo(bool next)
179  {
180  if(next)
182 
183  MediaManager manager;
184  manager.attach(_parentId);
185 
186  try
187  {
188  manager.provideFile(_parentId, _isofile);
189  }
190  catch(const MediaException &e1)
191  {
192  ZYPP_CAUGHT(e1);
193  try
194  {
195  manager.release(_parentId);
196  }
197  catch(const MediaException &e2)
198  {
199  ZYPP_CAUGHT(e2);
200  }
201 
203  "Unable to find iso filename on source media",
205  );
206  e3.remember(e1);
207  ZYPP_THROW(e3);
208  }
209 
210  // if the provided file is a symlink, expand it (#274651)
211  // (this will probably work only for file/dir and cd/dvd schemes)
212  Pathname isofile = expandlink(manager.localPath(_parentId, _isofile));
213  if( isofile.empty() || !PathInfo(isofile).isFile())
214  {
216  }
217 
219  string loopdev = findUnusedLoopDevice(); // (bnc #428009)
220 
221  MediaSourceRef media( new MediaSource("iso", loopdev));
222  PathInfo dinfo(loopdev);
223  if( dinfo.isBlk())
224  {
225  media->maj_nr = dinfo.devMajor();
226  media->min_nr = dinfo.devMinor();
227  }
228  else
229  ERR << loopdev << " is not a block device" << endl;
230 
231  AttachedMedia ret( findAttachedMedia( media));
232  if( ret.mediaSource &&
233  ret.attachPoint &&
234  !ret.attachPoint->empty())
235  {
236  DBG << "Using a shared media "
237  << ret.mediaSource->name
238  << " attached on "
239  << ret.attachPoint->path
240  << std::endl;
244  return;
245  }
246 
248  {
250  }
251  std::string mountpoint( attachPoint().asString() );
252  std::string mountopts("ro,loop=" + loopdev);
253 
254  Mount mount;
255  mount.mount(isofile.asString(), mountpoint,
256  _filesystem, mountopts);
257 
258  setMediaSource(media);
259 
260  // wait for /etc/mtab update ...
261  // (shouldn't be needed)
262  int limit = 3;
263  bool mountsucceeded;
264  while( !(mountsucceeded=isAttached()) && --limit)
265  {
266  sleep(1);
267  }
268 
269  if( !mountsucceeded)
270  {
272  try
273  {
274  mount.umount(attachPoint().asString());
275  manager.release(_parentId);
276  }
277  catch (const MediaException & excpt_r)
278  {
279  ZYPP_CAUGHT(excpt_r);
280  }
282  "Unable to verify that the media was mounted",
283  isofile.asString(), mountpoint
284  ));
285  }
286  }
287 
288  // ---------------------------------------------------------------
289 
290  void MediaISO::releaseFrom(const std::string & ejectDev)
291  {
292  Mount mount;
293  mount.umount(attachPoint().asString());
294 
295  if( _parentId)
296  {
297  // Unmounting the iso already succeeded,
298  // so don't let exceptions escape.
299  MediaManager manager;
300  try
301  {
302  manager.release(_parentId);
303  }
304  catch ( const Exception & excpt_r )
305  {
306  ZYPP_CAUGHT( excpt_r );
307  WAR << "Not been able to cleanup the parent mount." << endl;
308  }
309  }
310  // else:
311  // the media manager has reset the _parentId
312  // and will destroy the parent handler itself.
313  }
314 
315  // ---------------------------------------------------------------
316  void MediaISO::getFile(const Pathname &filename) const
317  {
318  MediaHandler::getFile(filename);
319  }
320 
321  // ---------------------------------------------------------------
322  void MediaISO::getDir(const Pathname &dirname,
323  bool recurse_r) const
324  {
325  MediaHandler::getDir(dirname, recurse_r);
326  }
327 
328  // ---------------------------------------------------------------
329  void MediaISO::getDirInfo(std::list<std::string> &retlist,
330  const Pathname &dirname,
331  bool dots) const
332  {
333  MediaHandler::getDirInfo( retlist, dirname, dots );
334  }
335 
336  // ---------------------------------------------------------------
338  const Pathname &dirname,
339  bool dots) const
340  {
341  MediaHandler::getDirInfo(retlist, dirname, dots);
342  }
343 
344  bool MediaISO::getDoesFileExist( const Pathname & filename ) const
345  {
346  return MediaHandler::getDoesFileExist( filename );
347  }
348 
350  } // namespace media
352 
354 } // namespace zypp
356 
357 // vim: set ts=2 sts=2 sw=2 ai et:
358 
std::string getScheme() const
Returns the scheme name of the URL.
Definition: Url.cc:527
virtual void releaseFrom(const std::string &ejectDev="")
Call concrete handler to release the media.
Definition: MediaISO.cc:290
virtual bool isAttached() const
True if media is attached.
Definition: MediaISO.cc:146
#define MIL
Definition: Logger.h:64
Interface to the mount program.
Definition: Mount.h:69
std::string asString(const DefaultIntegral< Tp, TInitial > &obj)
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:321
virtual void getDir(const Pathname &dirname, bool recurse_r) const =0
Call concrete handler to provide directory content (not recursive!) below attach point.
zypp::RW_pointer< MediaSource > MediaSourceRef
Definition: MediaSource.h:124
std::string findUnusedLoopDevice()
Definition: MediaISO.cc:152
void setAttachPoint(const Pathname &path, bool temp)
Set a new attach point.
std::string _filesystem
Definition: MediaISO.h:40
bool isUseableAttachPoint(const Pathname &path, bool mtab=true) const
Ask media manager, if the specified path is already used as attach point or if there are another atta...
std::string encode(const std::string &str, const std::string &safe, EEncoding eflag)
Encodes a string using URL percent encoding.
Definition: UrlUtils.cc:32
Base class for all URL exceptions.
Definition: UrlException.h:31
bool isOpen(MediaAccessId accessId) const
Query if the media access is open / exists.
std::string basename() const
Return the last component of this path.
Definition: Pathname.h:124
unsigned int devMinor() const
Definition: PathInfo.cc:252
bool checkAttached(bool matchMountFs) const
Check actual mediaSource attachment against the current mount table of the system.
#define ERR
Definition: Logger.h:66
void mount(const std::string &source, const std::string &target, const std::string &filesystem, const std::string &options, const Environment &environment=Environment())
mount device
Definition: Mount.cc:66
Pathname localPath(MediaAccessId accessId, const Pathname &pathname) const
Shortcut for &#39;localRoot() + pathname&#39;, but returns an empty pathname if media is not attached...
void remember(const Exception &old_r)
Store an other Exception as history.
Definition: Exception.cc:89
void release(MediaAccessId accessId, const std::string &ejectDev="")
Release the attached media and optionally eject.
bool empty() const
Test for an empty path.
Definition: Pathname.h:113
void setPathName(const std::string &path, EEncoding eflag=zypp::url::E_DECODED)
Set the path name.
Definition: Url.cc:758
AttachPointRef attachPoint
Definition: MediaSource.h:145
std::string asString() const
Returns a default string representation of the Url object.
Definition: Url.cc:491
virtual void getDir(const Pathname &dirname, bool recurse_r) const
Call concrete handler to provide directory content (not recursive!) below attach point.
Definition: MediaISO.cc:322
std::string getQueryParam(const std::string &param, EEncoding eflag=zypp::url::E_DECODED) const
Return the value for the specified query parameter.
Definition: Url.cc:654
MediaSourceRef mediaSource
Definition: MediaSource.h:144
Abstract base class for &#39;physical&#39; MediaHandler like MediaCD, etc.
Definition: MediaHandler.h:45
A simple structure containing references to a media source and its attach point.
Definition: MediaSource.h:133
Execute a program and give access to its io An object of this class encapsulates the execution of an ...
const Url _url
Url to handle.
Definition: MediaHandler.h:110
void setMediaSource(const MediaSourceRef &ref)
Set new media source reference.
const std::string & asString() const
String representation.
Definition: Pathname.h:90
Just inherits Exception to separate media exceptions.
Pathname dirname() const
Return all but the last component od this path.
Definition: Pathname.h:120
#define WAR
Definition: Logger.h:65
std::list< DirEntry > DirContent
Returned by readdir.
Definition: PathInfo.h:547
virtual bool getDoesFileExist(const Pathname &filename) const
check if a file exists
Definition: MediaISO.cc:344
#define URL_SAFE_CHARS
Characters that are safe for URL without percent-encoding.
Definition: UrlUtils.h:22
bool absolute() const
Test for an absolute path.
Definition: Pathname.h:115
std::string receiveLine()
Read one line from the input stream.
bool isValid() const
Verifies the Url.
Definition: Url.cc:483
Thrown if /sbin/losetup fails to find an unused loop device for mounting an .iso image.
void removeAttachPoint()
Remove unused attach point.
virtual void attachTo(bool next=false)
Call concrete handler to attach the media.
Definition: MediaISO.cc:178
void attach(MediaAccessId accessId)
Attach the media using the concrete handler (checks all devices).
Media source internally used by MediaManager and MediaHandler.
Definition: MediaSource.h:36
int close()
Wait for the progamm to complete.
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
Definition: Exception.h:325
Manages access to the &#39;physical&#39; media, e.g CDROM drives, Disk volumes, directory trees...
Definition: MediaManager.h:473
virtual void getDirInfo(std::list< std::string > &retlist, const Pathname &dirname, bool dots=true) const =0
Call concrete handler to provide a content list of directory on media via retlist.
virtual bool getDoesFileExist(const Pathname &filename) const =0
check if a file exists
AttachedMedia findAttachedMedia(const MediaSourceRef &media) const
Ask the media manager if specified media source is already attached.
Base class for Exception.
Definition: Exception.h:143
Pathname attachPoint() const
Return the currently used attach point.
virtual void getDirInfo(std::list< std::string > &retlist, const Pathname &dirname, bool dots=true) const
Call concrete handler to provide a content list of directory on media via retlist.
Definition: MediaISO.cc:329
virtual void getFile(const Pathname &filename) const
Call concrete handler to provide file below attach point.
Definition: MediaISO.cc:316
MediaAccessId _parentId
Access Id of media handler we depend on.
Definition: MediaHandler.h:115
virtual void getFile(const Pathname &filename) const =0
Call concrete handler to provide file below attach point.
unsigned int devMajor() const
Definition: PathInfo.cc:242
Wrapper class for ::stat/::lstat.
Definition: PathInfo.h:220
#define LOSETUP_TOOL_PATH
Definition: MediaISO.cc:20
Pathname expandlink(const Pathname &path_r)
Recursively follows the symlink pointed to by path_r and returns the Pathname to the real file or dir...
Definition: PathInfo.cc:868
Pathname createAttachPoint() const
Try to create a default / temporary attach point.
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:1
void release(const std::string &ejectDev="")
Use concrete handler to release the media.
MediaAccessId open(const Url &url, const Pathname &preferred_attach_point="")
Opens the media access for specified with the url.
Url manipulation class.
Definition: Url.h:87
void umount(const std::string &path)
umount device
Definition: Mount.cc:162
void close(MediaAccessId accessId)
Close the media access with specified id.
#define DBG
Definition: Logger.h:63
MediaISO(const Url &url_r, const Pathname &attach_point_hint_r)
Definition: MediaISO.cc:48
void provideFile(MediaAccessId accessId, const Pathname &filename) const
Provide provide file denoted by relative path below of the &#39;attach point&#39; of the specified media and ...