libzypp  10.5.0
MediaDISK.cc
Go to the documentation of this file.
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: