libzypp
10.5.0
|
00001 /*---------------------------------------------------------------------\ 00002 | ____ _ __ __ ___ | 00003 | |__ / \ / / . \ . \ | 00004 | / / \ V /| _/ _/ | 00005 | / /__ | | | | | | | 00006 | /_____||_| |_| |_| | 00007 | | 00008 \---------------------------------------------------------------------*/ 00013 #include "zypp/base/Logger.h" 00014 #include "zypp/base/String.h" 00015 #include "zypp/media/Mount.h" 00016 #include "zypp/media/MediaDISK.h" 00017 #include "zypp/media/MediaManager.h" 00018 00019 #include <iostream> 00020 #include <fstream> 00021 #include <sstream> 00022 00023 #include <sys/types.h> 00024 #include <sys/mount.h> 00025 #include <errno.h> 00026 #include <dirent.h> 00027 00028 /* 00029 ** verify devices names as late as possible (while attach) 00030 */ 00031 #define DELAYED_VERIFY 1 00032 00033 using namespace std; 00034 00035 namespace zypp { 00036 namespace media { 00037 00039 // 00040 // CLASS NAME : MediaDISK 00041 // 00043 00045 // 00046 // 00047 // METHOD NAME : MediaDISK::MediaDISK 00048 // METHOD TYPE : Constructor 00049 // 00050 // DESCRIPTION : 00051 // 00052 MediaDISK::MediaDISK( const Url & url_r, 00053 const Pathname & attach_point_hint_r ) 00054 : MediaHandler( url_r, attach_point_hint_r, 00055 url_r.getPathName(), // urlpath below attachpoint 00056 false ) // does_download 00057 { 00058 MIL << "MediaDISK::MediaDISK(" << url_r << ", " << attach_point_hint_r << ")" << endl; 00059 00060 _device = Pathname(_url.getQueryParam("device")).asString(); 00061 if( _device.empty()) 00062 { 00063 ERR << "Media url does not contain a device specification" << std::endl; 00064 ZYPP_THROW(MediaBadUrlEmptyDestinationException(_url)); 00065 } 00066 #if DELAYED_VERIFY 00067 DBG << "Verify of " << _device << " delayed" << std::endl; 00068 #else 00069 if( !verifyIfDiskVolume( _device)) 00070 { 00071 ZYPP_THROW(MediaBadUrlEmptyDestinationException(_url)); 00072 } 00073 #endif 00074 00075 _filesystem = _url.getQueryParam("filesystem"); 00076 if(_filesystem.empty()) 00077 _filesystem="auto"; 00078 00079 } 00080 00082 // 00083 // METHOD NAME : MediaDISK::verifyIfDiskVolume 00084 // METHOD TYPE : void 00085 // 00086 // DESCRIPTION : Check if specified device file name is 00087 // a disk volume device or throw an error. 00088 // 00089 bool MediaDISK::verifyIfDiskVolume(const Pathname &dev_name) 00090 { 00091 if( dev_name.empty() || 00092 dev_name.asString().compare(0, sizeof("/dev/")-1, "/dev/")) 00093 { 00094 ERR << "Specified device name " << dev_name 00095 << " is not allowed" << std::endl; 00096 return false; 00097 } 00098 00099 PathInfo dev_info(dev_name); 00100 if( !dev_info.isBlk()) 00101 { 00102 ERR << "Specified device name " << dev_name 00103 << " is not a block device" << std::endl; 00104 return false; 00105 } 00106 00107 // check if a volume using /dev/disk/by-uuid links first 00108 { 00109 Pathname dpath("/dev/disk/by-uuid"); 00110 std::list<Pathname> dlist; 00111 if( zypp::filesystem::readdir(dlist, dpath) == 0) 00112 { 00113 std::list<Pathname>::const_iterator it; 00114 for(it = dlist.begin(); it != dlist.end(); ++it) 00115 { 00116 PathInfo vol_info(*it); 00117 if( vol_info.isBlk() && vol_info.major() == dev_info.major() && 00118 vol_info.minor() == dev_info.minor()) 00119 { 00120 DBG << "Specified device name " << dev_name 00121 << " is a volume (disk/by-uuid link " 00122 << vol_info.path() << ")" 00123 << std::endl; 00124 return true; 00125 } 00126 } 00127 } 00128 } 00129 00130 // check if a volume using /dev/disk/by-label links 00131 // (e.g. vbd mapped volumes in a XEN vm) 00132 { 00133 Pathname dpath("/dev/disk/by-label"); 00134 std::list<Pathname> dlist; 00135 if( zypp::filesystem::readdir(dlist, dpath) == 0) 00136 { 00137 std::list<Pathname>::const_iterator it; 00138 for(it = dlist.begin(); it != dlist.end(); ++it) 00139 { 00140 PathInfo vol_info(*it); 00141 if( vol_info.isBlk() && vol_info.major() == dev_info.major() && 00142 vol_info.minor() == dev_info.minor()) 00143 { 00144 DBG << "Specified device name " << dev_name 00145 << " is a volume (disk/by-label link " 00146 << vol_info.path() << ")" 00147 << std::endl; 00148 return true; 00149 } 00150 } 00151 } 00152 } 00153 00154 // check if a filesystem volume using the 'blkid' tool 00155 // (there is no /dev/disk link for some of them) 00156 ExternalProgram::Arguments args; 00157 args.push_back( "blkid" ); 00158 args.push_back( "-p" ); 00159 args.push_back( dev_name.asString() ); 00160 00161 ExternalProgram cmd( args, ExternalProgram::Stderr_To_Stdout ); 00162 cmd >> DBG; 00163 if ( cmd.close() != 0 ) 00164 { 00165 ERR << cmd.execError() << endl 00166 << "Specified device name " << dev_name 00167 << " is not a usable disk volume" 00168 << std::endl; 00169 return false; 00170 } 00171 return true; 00172 } 00173 00175 // 00176 // 00177 // METHOD NAME : MediaDISK::attachTo 00178 // METHOD TYPE : PMError 00179 // 00180 // DESCRIPTION : Asserted that not already attached, and attachPoint is a directory. 00181 // 00182 void MediaDISK::attachTo(bool next) 00183 { 00184 if(next) 00185 ZYPP_THROW(MediaNotSupportedException(url())); 00186 // FIXME 00187 // do mount --bind <partition>/<dir> to <to> 00188 // mount /dev/<partition> /tmp_mount 00189 // mount /tmp_mount/<dir> <to> --bind -o ro 00190 // FIXME: try all filesystems 00191 00192 if(_device.empty()) 00193 ZYPP_THROW(MediaBadUrlEmptyDestinationException(url())); 00194 00195 PathInfo dev_info(_device); 00196 if(!dev_info.isBlk()) 00197 ZYPP_THROW(MediaBadUrlEmptyDestinationException(url())); 00198 #if DELAYED_VERIFY 00199 DBG << "Verifying " << _device << " ..." << std::endl; 00200 if( !verifyIfDiskVolume( _device)) 00201 { 00202 ZYPP_THROW(MediaBadUrlEmptyDestinationException(_url)); 00203 } 00204 #endif 00205 00206 if(_filesystem.empty()) 00207 ZYPP_THROW(MediaBadUrlEmptyFilesystemException(url())); 00208 00209 MediaSourceRef media( new MediaSource( 00210 "disk", _device, dev_info.major(), dev_info.minor() 00211 )); 00212 AttachedMedia ret( findAttachedMedia( media)); 00213 00214 if( ret.mediaSource && 00215 ret.attachPoint && 00216 !ret.attachPoint->empty()) 00217 { 00218 DBG << "Using a shared media " 00219 << ret.mediaSource->name 00220 << " attached on " 00221 << ret.attachPoint->path 00222 << endl; 00223 00224 removeAttachPoint(); 00225 setAttachPoint(ret.attachPoint); 00226 setMediaSource(ret.mediaSource); 00227 return; 00228 } 00229 00230 MediaManager manager; 00231 MountEntries entries( manager.getMountEntries()); 00232 MountEntries::const_iterator e; 00233 for( e = entries.begin(); e != entries.end(); ++e) 00234 { 00235 bool is_device = false; 00236 std::string dev_path(Pathname(e->src).asString()); 00237 PathInfo dev_info; 00238 00239 if( dev_path.compare(0, sizeof("/dev/")-1, "/dev/") == 0 && 00240 dev_info(e->src) && dev_info.isBlk()) 00241 { 00242 is_device = true; 00243 } 00244 00245 if( is_device && media->maj_nr == dev_info.major() && 00246 media->min_nr == dev_info.minor()) 00247 { 00248 AttachPointRef ap( new AttachPoint(e->dir, false)); 00249 AttachedMedia am( media, ap); 00250 { 00251 DBG << "Using a system mounted media " 00252 << media->name 00253 << " attached on " 00254 << ap->path 00255 << endl; 00256 00257 media->iown = false; // mark attachment as foreign 00258 00259 setMediaSource(media); 00260 setAttachPoint(ap); 00261 return; 00262 } 00263 } 00264 } 00265 00266 Mount mount; 00267 std::string mountpoint = attachPoint().asString(); 00268 if( !isUseableAttachPoint(attachPoint())) 00269 { 00270 mountpoint = createAttachPoint().asString(); 00271 if( mountpoint.empty()) 00272 ZYPP_THROW( MediaBadAttachPointException(url())); 00273 setAttachPoint( mountpoint, true); 00274 } 00275 00276 string options = _url.getQueryParam("mountoptions"); 00277 if(options.empty()) 00278 { 00279 options = "ro"; 00280 } 00281 00282 if( !media->bdir.empty()) 00283 { 00284 options += ",bind"; 00285 mount.mount(media->bdir, mountpoint, "none", options); 00286 } 00287 else 00288 { 00289 mount.mount(_device, mountpoint, _filesystem, options); 00290 } 00291 00292 setMediaSource(media); 00293 00294 // wait for /etc/mtab update ... 00295 // (shouldn't be needed) 00296 int limit = 3; 00297 bool mountsucceeded; 00298 while( !(mountsucceeded=isAttached()) && --limit) 00299 { 00300 sleep(1); 00301 } 00302 00303 if( !mountsucceeded) 00304 { 00305 setMediaSource(MediaSourceRef()); 00306 try 00307 { 00308 mount.umount(attachPoint().asString()); 00309 } 00310 catch (const MediaException & excpt_r) 00311 { 00312 ZYPP_CAUGHT(excpt_r); 00313 } 00314 ZYPP_THROW(MediaMountException( 00315 "Unable to verify that the media was mounted", 00316 _device, mountpoint 00317 )); 00318 } 00319 } 00320 00322 // 00323 // METHOD NAME : MediaDISK::isAttached 00324 // METHOD TYPE : bool 00325 // 00326 // DESCRIPTION : Override check if media is attached. 00327 // 00328 bool 00329 MediaDISK::isAttached() const 00330 { 00331 return checkAttached(false); 00332 } 00333 00335 // 00336 // 00337 // METHOD NAME : MediaDISK::releaseFrom 00338 // METHOD TYPE : PMError 00339 // 00340 // DESCRIPTION : Asserted that media is attached. 00341 // 00342 void MediaDISK::releaseFrom( const std::string & ejectDev ) 00343 { 00344 AttachedMedia am( attachedMedia()); 00345 if(am.mediaSource && am.mediaSource->iown) 00346 { 00347 Mount mount; 00348 mount.umount(attachPoint().asString()); 00349 } 00350 } 00351 00353 // 00354 // METHOD NAME : MediaDISK::getFile 00355 // METHOD TYPE : PMError 00356 // 00357 // DESCRIPTION : Asserted that media is attached. 00358 // 00359 void MediaDISK::getFile (const Pathname & filename) const 00360 { 00361 MediaHandler::getFile( filename ); 00362 } 00363 00365 // 00366 // METHOD NAME : MediaDISK::getDir 00367 // METHOD TYPE : PMError 00368 // 00369 // DESCRIPTION : Asserted that media is attached. 00370 // 00371 void MediaDISK::getDir( const Pathname & dirname, bool recurse_r ) const 00372 { 00373 MediaHandler::getDir( dirname, recurse_r ); 00374 } 00375 00377 // 00378 // 00379 // METHOD NAME : MediaDISK::getDirInfo 00380 // METHOD TYPE : PMError 00381 // 00382 // DESCRIPTION : Asserted that media is attached and retlist is empty. 00383 // 00384 void MediaDISK::getDirInfo( std::list<std::string> & retlist, 00385 const Pathname & dirname, bool dots ) const 00386 { 00387 MediaHandler::getDirInfo( retlist, dirname, dots ); 00388 } 00389 00391 // 00392 // 00393 // METHOD NAME : MediaDISK::getDirInfo 00394 // METHOD TYPE : PMError 00395 // 00396 // DESCRIPTION : Asserted that media is attached and retlist is empty. 00397 // 00398 void MediaDISK::getDirInfo( filesystem::DirContent & retlist, 00399 const Pathname & dirname, bool dots ) const 00400 { 00401 MediaHandler::getDirInfo( retlist, dirname, dots ); 00402 } 00403 00404 bool MediaDISK::getDoesFileExist( const Pathname & filename ) const 00405 { 00406 return MediaHandler::getDoesFileExist( filename ); 00407 } 00408 00409 } // namespace media 00410 } // namespace zypp 00411 // vim: set ts=8 sts=2 sw=2 ai noet: