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));
107 if( !(src.getScheme() == "hd" ||
108 src.getScheme() == "dir" ||
109 src.getScheme() == "file" ||
110 src.getScheme() == "nfs" ||
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));
120 MediaManager manager;
122 _parentId = manager.open(src, _url.getQueryParam("mnt"));
125 // ---------------------------------------------------------------
126 MediaISO::~MediaISO()
134 DBG << "Closing parent handler..." << std::endl;
135 MediaManager manager;
136 if(manager.isOpen(_parentId))
137 manager.close(_parentId);
145 // ---------------------------------------------------------------
147 MediaISO::isAttached() const
149 return checkAttached(false);
152 // ---------------------------------------------------------------
153 string MediaISO::findUnusedLoopDevice()
161 ExternalProgram losetup(argv, ExternalProgram::Stderr_To_Stdout);
163 string out = losetup.receiveLine();
164 string device = out.substr(0, out.size() - 1); // remove the trailing endl
165 for(; out.length(); out = losetup.receiveLine())
166 DBG << "losetup: " << out;
168 if (losetup.close() != 0)
170 ERR << LOSETUP_TOOL_PATH " failed to find an unused loop device." << std::endl;
171 ZYPP_THROW(MediaNoLoopDeviceException(_url));
174 DBG << "found " << device << endl;
178 // ---------------------------------------------------------------
179 void MediaISO::attachTo(bool next)
182 ZYPP_THROW(MediaNotSupportedException(_url));
184 MediaManager manager;
185 manager.attach(_parentId, false);
189 manager.provideFile(_parentId, _isofile);
191 catch(const MediaException &e1)
196 manager.release(_parentId);
198 catch(const MediaException &e2)
203 MediaMountException e3(
204 "Unable to find iso filename on source media",
205 _url.asString(), attachPoint().asString()
211 // if the provided file is a symlink, expand it (#274651)
212 // (this will probably work only for file/dir and cd/dvd schemes)
213 Pathname isofile = expandlink(manager.localPath(_parentId, _isofile));
214 if( isofile.empty() || !PathInfo(isofile).isFile())
216 ZYPP_THROW(MediaNotSupportedException(_url));
219 //! \todo make this thread-safe - another thread might pick up the same device
220 string loopdev = findUnusedLoopDevice(); // (bnc #428009)
222 MediaSourceRef media( new MediaSource("iso", loopdev));
223 PathInfo dinfo(loopdev);
226 media->maj_nr = dinfo.major();
227 media->min_nr = dinfo.minor();
230 ERR << loopdev << " is not a block device" << endl;
232 AttachedMedia ret( findAttachedMedia( media));
233 if( ret.mediaSource &&
235 !ret.attachPoint->empty())
237 DBG << "Using a shared media "
238 << ret.mediaSource->name
240 << ret.attachPoint->path
243 setAttachPoint(ret.attachPoint);
244 setMediaSource(ret.mediaSource);
248 std::string mountpoint = attachPoint().asString();
249 if( !isUseableAttachPoint(attachPoint()))
251 mountpoint = createAttachPoint().asString();
252 if( mountpoint.empty())
253 ZYPP_THROW( MediaBadAttachPointException(url()));
254 setAttachPoint( mountpoint, true);
257 std::string mountopts("ro,loop=" + loopdev);
260 mount.mount(isofile.asString(), mountpoint,
261 _filesystem, mountopts);
263 setMediaSource(media);
265 // wait for /etc/mtab update ...
266 // (shouldn't be needed)
269 while( !(mountsucceeded=isAttached()) && --limit)
276 setMediaSource(MediaSourceRef());
279 mount.umount(attachPoint().asString());
280 manager.release(_parentId);
282 catch (const MediaException & excpt_r)
284 ZYPP_CAUGHT(excpt_r);
286 ZYPP_THROW(MediaMountException(
287 "Unable to verify that the media was mounted",
288 isofile.asString(), mountpoint
293 // ---------------------------------------------------------------
295 void MediaISO::releaseFrom(const std::string & ejectDev)
298 mount.umount(attachPoint().asString());
302 MediaManager manager;
303 manager.release(_parentId);
306 // the media manager has reset the _parentId
307 // and will destroy the parent handler itself.
310 // ---------------------------------------------------------------
311 void MediaISO::getFile(const Pathname &filename) const
313 MediaHandler::getFile(filename);
316 // ---------------------------------------------------------------
317 void MediaISO::getDir(const Pathname &dirname,
318 bool recurse_r) const
320 MediaHandler::getDir(dirname, recurse_r);
323 // ---------------------------------------------------------------
324 void MediaISO::getDirInfo(std::list<std::string> &retlist,
325 const Pathname &dirname,
328 MediaHandler::getDirInfo( retlist, dirname, dots );
331 // ---------------------------------------------------------------
332 void MediaISO::getDirInfo(filesystem::DirContent &retlist,
333 const Pathname &dirname,
336 MediaHandler::getDirInfo(retlist, dirname, dots);
339 bool MediaISO::getDoesFileExist( const Pathname & filename ) const
341 return MediaHandler::getDoesFileExist( filename );
344 //////////////////////////////////////////////////////////////////
346 ////////////////////////////////////////////////////////////////////
348 ////////////////////////////////////////////////////////////////////
350 //////////////////////////////////////////////////////////////////////
352 // vim: set ts=2 sts=2 sw=2 ai et: