MediaISO.cc
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00012 #include <iostream>
00013
00014 #include "zypp/base/Logger.h"
00015 #include "zypp/media/Mount.h"
00016
00017 #include "zypp/media/MediaISO.h"
00018
00019
00020 #define LOSETUP_TOOL_PATH "/sbin/losetup"
00021
00022 using std::string;
00023 using std::endl;
00024
00026 namespace zypp
00027 {
00028
00030 namespace media
00031 {
00032
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00048 MediaISO::MediaISO(const Url &url_r,
00049 const Pathname &attach_point_hint_r)
00050 : MediaHandler(url_r, attach_point_hint_r,
00051 url_r.getPathName(),
00052 false)
00053 {
00054 MIL << "MediaISO::MediaISO(" << url_r << ", "
00055 << attach_point_hint_r << ")" << std::endl;
00056
00057 _isofile = _url.getQueryParam("iso");
00058 if( _isofile.empty())
00059 {
00060 ERR << "Media url does not contain iso filename" << std::endl;
00061 ZYPP_THROW(MediaBadUrlEmptyDestinationException(_url));
00062 }
00063
00064 _filesystem = _url.getQueryParam("filesystem");
00065 if( _filesystem.empty())
00066 _filesystem = "auto";
00067
00068 std::string arg;
00069 zypp::Url src;
00070 try
00071 {
00072
00073
00074 arg = _url.getQueryParam("url");
00075 if( arg.empty() && _isofile.dirname().absolute())
00076 {
00077 src = std::string("dir:///");
00078 src.setPathName(url::encode(_isofile.dirname().asString(), URL_SAFE_CHARS));
00079 _isofile = _isofile.basename();
00080 }
00081 else
00082 {
00083 src = url::encode(arg, URL_SAFE_CHARS);
00084 }
00085 }
00086 catch(const zypp::url::UrlException &e)
00087 {
00088 ZYPP_CAUGHT(e);
00089 ERR << "Unable to parse iso filename source media url" << std::endl;
00090 MediaBadUrlException ne(_url);
00091 ne.remember(e);
00092 ZYPP_THROW(ne);
00093 }
00094 if( !src.isValid())
00095 {
00096 ERR << "Invalid iso filename source media url" << std::endl;
00097 ZYPP_THROW(MediaBadUrlException(src));
00098 }
00099 if( src.getScheme() == "iso")
00100 {
00101 ERR << "ISO filename source media url with iso scheme (nested iso): "
00102 << src.asString() << std::endl;
00103 ZYPP_THROW(MediaUnsupportedUrlSchemeException(src));
00104 }
00105 else
00106 if( !(src.getScheme() == "hd" ||
00107 src.getScheme() == "dir" ||
00108 src.getScheme() == "file" ||
00109 src.getScheme() == "nfs" ||
00110 src.getScheme() == "nfs4" ||
00111 src.getScheme() == "smb" ||
00112 src.getScheme() == "cifs"))
00113 {
00114 ERR << "ISO filename source media url scheme is not supported: "
00115 << src.asString() << std::endl;
00116 ZYPP_THROW(MediaUnsupportedUrlSchemeException(src));
00117 }
00118
00119 MediaManager manager;
00120
00121 _parentId = manager.open(src, _url.getQueryParam("mnt"));
00122 }
00123
00124
00125 MediaISO::~MediaISO()
00126 {
00127 try
00128 {
00129 release();
00130
00131 if( _parentId)
00132 {
00133 DBG << "Closing parent handler..." << std::endl;
00134 MediaManager manager;
00135 if(manager.isOpen(_parentId))
00136 manager.close(_parentId);
00137 _parentId = 0;
00138 }
00139 }
00140 catch( ... )
00141 {}
00142 }
00143
00144
00145 bool
00146 MediaISO::isAttached() const
00147 {
00148 return checkAttached(false);
00149 }
00150
00151
00152 string MediaISO::findUnusedLoopDevice()
00153 {
00154 const char* argv[] =
00155 {
00156 LOSETUP_TOOL_PATH,
00157 "-f",
00158 NULL
00159 };
00160 ExternalProgram losetup(argv, ExternalProgram::Stderr_To_Stdout);
00161
00162 string out = losetup.receiveLine();
00163 string device = out.substr(0, out.size() - 1);
00164 for(; out.length(); out = losetup.receiveLine())
00165 DBG << "losetup: " << out;
00166
00167 if (losetup.close() != 0)
00168 {
00169 ERR << LOSETUP_TOOL_PATH " failed to find an unused loop device." << std::endl;
00170 ZYPP_THROW(MediaNoLoopDeviceException(_url));
00171 }
00172
00173 DBG << "found " << device << endl;
00174 return device;
00175 }
00176
00177
00178 void MediaISO::attachTo(bool next)
00179 {
00180 if(next)
00181 ZYPP_THROW(MediaNotSupportedException(_url));
00182
00183 MediaManager manager;
00184 manager.attach(_parentId);
00185
00186 try
00187 {
00188 manager.provideFile(_parentId, _isofile);
00189 }
00190 catch(const MediaException &e1)
00191 {
00192 ZYPP_CAUGHT(e1);
00193 try
00194 {
00195 manager.release(_parentId);
00196 }
00197 catch(const MediaException &e2)
00198 {
00199 ZYPP_CAUGHT(e2);
00200 }
00201
00202 MediaMountException e3(
00203 "Unable to find iso filename on source media",
00204 _url.asString(), attachPoint().asString()
00205 );
00206 e3.remember(e1);
00207 ZYPP_THROW(e3);
00208 }
00209
00210
00211
00212 Pathname isofile = expandlink(manager.localPath(_parentId, _isofile));
00213 if( isofile.empty() || !PathInfo(isofile).isFile())
00214 {
00215 ZYPP_THROW(MediaNotSupportedException(_url));
00216 }
00217
00219 string loopdev = findUnusedLoopDevice();
00220
00221 MediaSourceRef media( new MediaSource("iso", loopdev));
00222 PathInfo dinfo(loopdev);
00223 if( dinfo.isBlk())
00224 {
00225 media->maj_nr = dinfo.major();
00226 media->min_nr = dinfo.minor();
00227 }
00228 else
00229 ERR << loopdev << " is not a block device" << endl;
00230
00231 AttachedMedia ret( findAttachedMedia( media));
00232 if( ret.mediaSource &&
00233 ret.attachPoint &&
00234 !ret.attachPoint->empty())
00235 {
00236 DBG << "Using a shared media "
00237 << ret.mediaSource->name
00238 << " attached on "
00239 << ret.attachPoint->path
00240 << std::endl;
00241 removeAttachPoint();
00242 setAttachPoint(ret.attachPoint);
00243 setMediaSource(ret.mediaSource);
00244 return;
00245 }
00246
00247 std::string mountpoint = attachPoint().asString();
00248 if( !isUseableAttachPoint(attachPoint()))
00249 {
00250 mountpoint = createAttachPoint().asString();
00251 if( mountpoint.empty())
00252 ZYPP_THROW( MediaBadAttachPointException(url()));
00253 setAttachPoint( mountpoint, true);
00254 }
00255
00256 std::string mountopts("ro,loop=" + loopdev);
00257
00258 Mount mount;
00259 mount.mount(isofile.asString(), mountpoint,
00260 _filesystem, mountopts);
00261
00262 setMediaSource(media);
00263
00264
00265
00266 int limit = 3;
00267 bool mountsucceeded;
00268 while( !(mountsucceeded=isAttached()) && --limit)
00269 {
00270 sleep(1);
00271 }
00272
00273 if( !mountsucceeded)
00274 {
00275 setMediaSource(MediaSourceRef());
00276 try
00277 {
00278 mount.umount(attachPoint().asString());
00279 manager.release(_parentId);
00280 }
00281 catch (const MediaException & excpt_r)
00282 {
00283 ZYPP_CAUGHT(excpt_r);
00284 }
00285 ZYPP_THROW(MediaMountException(
00286 "Unable to verify that the media was mounted",
00287 isofile.asString(), mountpoint
00288 ));
00289 }
00290 }
00291
00292
00293
00294 void MediaISO::releaseFrom(const std::string & ejectDev)
00295 {
00296 Mount mount;
00297 mount.umount(attachPoint().asString());
00298
00299 if( _parentId)
00300 {
00301
00302
00303 MediaManager manager;
00304 try
00305 {
00306 manager.release(_parentId);
00307 }
00308 catch ( const Exception & excpt_r )
00309 {
00310 ZYPP_CAUGHT( excpt_r );
00311 WAR << "Not been able to cleanup the parent mount." << endl;
00312 }
00313 }
00314
00315
00316
00317 }
00318
00319
00320 void MediaISO::getFile(const Pathname &filename) const
00321 {
00322 MediaHandler::getFile(filename);
00323 }
00324
00325
00326 void MediaISO::getDir(const Pathname &dirname,
00327 bool recurse_r) const
00328 {
00329 MediaHandler::getDir(dirname, recurse_r);
00330 }
00331
00332
00333 void MediaISO::getDirInfo(std::list<std::string> &retlist,
00334 const Pathname &dirname,
00335 bool dots) const
00336 {
00337 MediaHandler::getDirInfo( retlist, dirname, dots );
00338 }
00339
00340
00341 void MediaISO::getDirInfo(filesystem::DirContent &retlist,
00342 const Pathname &dirname,
00343 bool dots) const
00344 {
00345 MediaHandler::getDirInfo(retlist, dirname, dots);
00346 }
00347
00348 bool MediaISO::getDoesFileExist( const Pathname & filename ) const
00349 {
00350 return MediaHandler::getDoesFileExist( filename );
00351 }
00352
00354 }
00356
00358 }
00360
00361
00362