1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/media/MediaISO.cc
14 #include "zypp/base/Logger.h"
15 #include "zypp/media/Mount.h"
17 #include "zypp/media/MediaISO.h"
20 #define LOSETUP_TOOL_PATH "/sbin/losetup"
25 //////////////////////////////////////////////////////////////////////
27 { ////////////////////////////////////////////////////////////////////
29 ////////////////////////////////////////////////////////////////////
31 { //////////////////////////////////////////////////////////////////
33 ///////////////////////////////////////////////////////////////////
38 // Path name: subdir to the location of desired files inside
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".
47 ///////////////////////////////////////////////////////////////////
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
54 MIL << "MediaISO::MediaISO(" << url_r << ", "
55 << attach_point_hint_r << ")" << std::endl;
57 _isofile = _url.getQueryParam("iso");
60 ERR << "Media url does not contain iso filename" << std::endl;
61 ZYPP_THROW(MediaBadUrlEmptyDestinationException(_url));
64 _filesystem = _url.getQueryParam("filesystem");
65 if( _filesystem.empty())
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())
77 src = std::string("dir:///");
78 src.setPathName(url::encode(_isofile.dirname().asString(), URL_SAFE_CHARS));
79 _isofile = _isofile.basename();
83 src = url::encode(arg, URL_SAFE_CHARS);
86 catch(const zypp::url::UrlException &e)
89 ERR << "Unable to parse iso filename source media url" << std::endl;
90 MediaBadUrlException ne(_url);
96 ERR << "Invalid iso filename source media url" << std::endl;
97 ZYPP_THROW(MediaBadUrlException(src));
99 if( src.getScheme() == "iso")
101 ERR << "ISO filename source media url with iso scheme (nested iso): "
102 << src.asString() << std::endl;
103 ZYPP_THROW(MediaUnsupportedUrlSchemeException(src));
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"))
114 ERR << "ISO filename source media url scheme is not supported: "
115 << src.asString() << std::endl;
116 ZYPP_THROW(MediaUnsupportedUrlSchemeException(src));
119 MediaManager manager;
121 _parentId = manager.open(src, _url.getQueryParam("mnt"));
124 // ---------------------------------------------------------------
125 MediaISO::~MediaISO()
133 DBG << "Closing parent handler..." << std::endl;
134 MediaManager manager;
135 if(manager.isOpen(_parentId))
136 manager.close(_parentId);
144 // ---------------------------------------------------------------
146 MediaISO::isAttached() const
148 return checkAttached(false);
151 // ---------------------------------------------------------------
152 string MediaISO::findUnusedLoopDevice()
160 ExternalProgram losetup(argv, ExternalProgram::Stderr_To_Stdout);
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;
167 if (losetup.close() != 0)
169 ERR << LOSETUP_TOOL_PATH " failed to find an unused loop device." << std::endl;
170 ZYPP_THROW(MediaNoLoopDeviceException(_url));
173 DBG << "found " << device << endl;
177 // ---------------------------------------------------------------
178 void MediaISO::attachTo(bool next)
181 ZYPP_THROW(MediaNotSupportedException(_url));
183 MediaManager manager;
184 manager.attach(_parentId);
188 manager.provideFile(_parentId, _isofile);
190 catch(const MediaException &e1)
195 manager.release(_parentId);
197 catch(const MediaException &e2)
202 MediaMountException e3(
203 "Unable to find iso filename on source media",
204 _url.asString(), attachPoint().asString()
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())
215 ZYPP_THROW(MediaNotSupportedException(_url));
218 //! \todo make this thread-safe - another thread might pick up the same device
219 string loopdev = findUnusedLoopDevice(); // (bnc #428009)
221 MediaSourceRef media( new MediaSource("iso", loopdev));
222 PathInfo dinfo(loopdev);
225 media->maj_nr = dinfo.devMajor();
226 media->min_nr = dinfo.devMinor();
229 ERR << loopdev << " is not a block device" << endl;
231 AttachedMedia ret( findAttachedMedia( media));
232 if( ret.mediaSource &&
234 !ret.attachPoint->empty())
236 DBG << "Using a shared media "
237 << ret.mediaSource->name
239 << ret.attachPoint->path
242 setAttachPoint(ret.attachPoint);
243 setMediaSource(ret.mediaSource);
247 std::string mountpoint = attachPoint().asString();
248 if( !isUseableAttachPoint(attachPoint()))
250 mountpoint = createAttachPoint().asString();
251 if( mountpoint.empty())
252 ZYPP_THROW( MediaBadAttachPointException(url()));
253 setAttachPoint( mountpoint, true);
256 std::string mountopts("ro,loop=" + loopdev);
259 mount.mount(isofile.asString(), mountpoint,
260 _filesystem, mountopts);
262 setMediaSource(media);
264 // wait for /etc/mtab update ...
265 // (shouldn't be needed)
268 while( !(mountsucceeded=isAttached()) && --limit)
275 setMediaSource(MediaSourceRef());
278 mount.umount(attachPoint().asString());
279 manager.release(_parentId);
281 catch (const MediaException & excpt_r)
283 ZYPP_CAUGHT(excpt_r);
285 ZYPP_THROW(MediaMountException(
286 "Unable to verify that the media was mounted",
287 isofile.asString(), mountpoint
292 // ---------------------------------------------------------------
294 void MediaISO::releaseFrom(const std::string & ejectDev)
297 mount.umount(attachPoint().asString());
301 // Unmounting the iso already succeeded,
302 // so don't let exceptions escape.
303 MediaManager manager;
306 manager.release(_parentId);
308 catch ( const Exception & excpt_r )
310 ZYPP_CAUGHT( excpt_r );
311 WAR << "Not been able to cleanup the parent mount." << endl;
315 // the media manager has reset the _parentId
316 // and will destroy the parent handler itself.
319 // ---------------------------------------------------------------
320 void MediaISO::getFile(const Pathname &filename) const
322 MediaHandler::getFile(filename);
325 // ---------------------------------------------------------------
326 void MediaISO::getDir(const Pathname &dirname,
327 bool recurse_r) const
329 MediaHandler::getDir(dirname, recurse_r);
332 // ---------------------------------------------------------------
333 void MediaISO::getDirInfo(std::list<std::string> &retlist,
334 const Pathname &dirname,
337 MediaHandler::getDirInfo( retlist, dirname, dots );
340 // ---------------------------------------------------------------
341 void MediaISO::getDirInfo(filesystem::DirContent &retlist,
342 const Pathname &dirname,
345 MediaHandler::getDirInfo(retlist, dirname, dots);
348 bool MediaISO::getDoesFileExist( const Pathname & filename ) const
350 return MediaHandler::getDoesFileExist( filename );
353 //////////////////////////////////////////////////////////////////
355 ////////////////////////////////////////////////////////////////////
357 ////////////////////////////////////////////////////////////////////
359 //////////////////////////////////////////////////////////////////////
361 // vim: set ts=2 sts=2 sw=2 ai et: