libzypp
10.5.0
|
00001 /*---------------------------------------------------------------------\ 00002 | ____ _ __ __ ___ | 00003 | |__ / \ / / . \ . \ | 00004 | / / \ V /| _/ _/ | 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 // MediaISO Url: 00036 // 00037 // Schema: iso 00038 // Path name: subdir to the location of desired files inside 00039 // of the ISO. 00040 // Query parameters: 00041 // url: The iso filename source media url pointing 00042 // to a directory containing the ISO file. 00043 // mnt: Prefered attach point for source media url. 00044 // iso: The name of the iso file. 00045 // filesystem: Optional, defaults to "auto". 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(), // urlpath below attachpoint 00052 false) // does_download 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 // this percent-decodes the query parameter, it must be later encoded 00073 // again before used in a Url object 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); // remove the trailing endl 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 // if the provided file is a symlink, expand it (#274651) 00211 // (this will probably work only for file/dir and cd/dvd schemes) 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(); // (bnc #428009) 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 // wait for /etc/mtab update ... 00265 // (shouldn't be needed) 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 // Unmounting the iso already succeeded, 00302 // so don't let exceptions escape. 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 // else: 00315 // the media manager has reset the _parentId 00316 // and will destroy the parent handler itself. 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 } // namespace media 00356 00358 } // namespace zypp 00360 00361 // vim: set ts=2 sts=2 sw=2 ai et: 00362