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 #define DELAYED_VERIFY    1
00029 
00030 #define VOL_ID_TOOL_PATHS { "/sbin/vol_id", "/lib/udev/vol_id", NULL}
00031 
00032 using namespace std;
00033 
00034 namespace zypp {
00035   namespace media {
00036 
00038     //
00039     //  CLASS NAME : MediaDISK
00040     //
00042 
00044     //
00045     //
00046     //  METHOD NAME : MediaDISK::MediaDISK
00047     //  METHOD TYPE : Constructor
00048     //
00049     //  DESCRIPTION :
00050     //
00051     MediaDISK::MediaDISK( const Url &      url_r,
00052                           const Pathname & attach_point_hint_r )
00053         : MediaHandler( url_r, attach_point_hint_r,
00054                     url_r.getPathName(), // urlpath below attachpoint
00055                     false ) // does_download
00056     {
00057       MIL << "MediaDISK::MediaDISK(" << url_r << ", " << attach_point_hint_r << ")" << endl;
00058 
00059       _device = Pathname(_url.getQueryParam("device")).asString();
00060       if( _device.empty())
00061       {
00062         ERR << "Media url does not contain a device specification" << std::endl;
00063         ZYPP_THROW(MediaBadUrlEmptyDestinationException(_url));
00064       }
00065 #if DELAYED_VERIFY
00066       DBG << "Verify of " << _device << " delayed" << std::endl;
00067 #else
00068       if( !verifyIfDiskVolume( _device))
00069       {
00070         ZYPP_THROW(MediaBadUrlEmptyDestinationException(_url));
00071       }
00072 #endif
00073 
00074       _filesystem = _url.getQueryParam("filesystem");
00075       if(_filesystem.empty())
00076         _filesystem="auto";
00077 
00078     }
00079 
00081     //
00082     //  METHOD NAME : MediaDISK::verifyIfDiskVolume
00083     //  METHOD TYPE : void
00084     //
00085     //  DESCRIPTION : Check if specified device file name is
00086     //                a disk volume device or throw an error.
00087     //
00088     bool MediaDISK::verifyIfDiskVolume(const Pathname &dev_name)
00089     {
00090       if( dev_name.empty() ||
00091           dev_name.asString().compare(0, sizeof("/dev/")-1, "/dev/"))
00092       {
00093         ERR << "Specified device name " << dev_name
00094             << " is not allowed" << std::endl;
00095         return false;
00096       }
00097 
00098       PathInfo dev_info(dev_name);
00099       if( !dev_info.isBlk())
00100       {
00101         ERR << "Specified device name " << dev_name
00102             << " is not a block device" << std::endl;
00103         return false;
00104       }
00105 
00106       // check if a volume using /dev/disk/by-uuid links first
00107       {
00108         Pathname            dpath("/dev/disk/by-uuid");
00109         std::list<Pathname> dlist;
00110         if( zypp::filesystem::readdir(dlist, dpath) == 0)
00111         {
00112           std::list<Pathname>::const_iterator it;
00113           for(it = dlist.begin(); it != dlist.end(); ++it)
00114           {
00115             PathInfo vol_info(*it);
00116             if( vol_info.isBlk() && vol_info.major() == dev_info.major() &&
00117                                     vol_info.minor() == dev_info.minor())
00118             {
00119               DBG << "Specified device name " << dev_name
00120                   << " is a volume (disk/by-uuid link "
00121                   << vol_info.path() << ")"
00122                   << std::endl;
00123               return true;
00124             }
00125           }
00126         }
00127       }
00128 
00129       // check if a volume using /dev/disk/by-label links
00130       // (e.g. vbd mapped volumes in a XEN vm)
00131       {
00132         Pathname            dpath("/dev/disk/by-label");
00133         std::list<Pathname> dlist;
00134         if( zypp::filesystem::readdir(dlist, dpath) == 0)
00135         {
00136           std::list<Pathname>::const_iterator it;
00137           for(it = dlist.begin(); it != dlist.end(); ++it)
00138           {
00139             PathInfo vol_info(*it);
00140             if( vol_info.isBlk() && vol_info.major() == dev_info.major() &&
00141                                     vol_info.minor() == dev_info.minor())
00142             {
00143               DBG << "Specified device name " << dev_name
00144                   << " is a volume (disk/by-label link "
00145                   << vol_info.path() << ")"
00146                   << std::endl;
00147               return true;
00148             }
00149           }
00150         }
00151       }
00152 
00153       // check if a filesystem volume using the /sbin/vol_id tool
00154       // (there is no /dev/disk link for some of them)
00155       for(const char *vol_id_paths[] = VOL_ID_TOOL_PATHS,
00156                      **vol_id_path    = vol_id_paths;
00157           vol_id_path != NULL && *vol_id_path != NULL;
00158           vol_id_path++)
00159       {
00160         PathInfo vol_id_info(*vol_id_path);
00161         if( !vol_id_info.isFile() || !vol_id_info.isXUsr())
00162           continue;
00163 
00164         const char *cmd[3];
00165         cmd[0] = *vol_id_path;
00166         cmd[1] = dev_name.asString().c_str();
00167         cmd[2] = NULL;
00168 
00169         ExternalProgram vol_id(cmd, ExternalProgram::Stderr_To_Stdout);
00170 
00171         std::string vol_fs_usage;
00172         std::string vol_fs_uuid;
00173         std::string vol_fs_type;
00174 
00175         for(std::string out( vol_id.receiveLine());
00176             out.length(); out = vol_id.receiveLine())
00177         {
00178           out = str::rtrim(out);
00179 
00180           if( out.compare(0, sizeof("ID_FS_USAGE=")-1, "ID_FS_USAGE=") == 0)
00181           {
00182             vol_fs_usage = out.substr(sizeof("ID_FS_USAGE=")-1);
00183           }
00184           else
00185           if( out.compare(0, sizeof("ID_FS_TYPE=")-1, "ID_FS_TYPE=")   == 0)
00186           {
00187             vol_fs_type  = out.substr(sizeof("ID_FS_TYPE=")-1);
00188           }
00189           else
00190           if( out.compare(0, sizeof("ID_FS_UUID=")-1, "ID_FS_UUID=")   == 0)
00191           {
00192             vol_fs_uuid  = out.substr(sizeof("ID_FS_UUID=")-1);
00193           }
00194         }
00195 
00196         if( vol_id.close() == 0)
00197         {
00198           if( vol_fs_usage == "filesystem")
00199           {
00200             if(vol_fs_type == "iso9660" || vol_fs_type == "udf")
00201             {
00202               DBG << "Specified device name " << dev_name
00203                   << " is a CD/DVD volume (type " << vol_fs_type << ")"
00204                   << std::endl;
00205               return true;
00206             }
00207             else
00208             if(!vol_fs_type.empty() && !vol_fs_uuid.empty())
00209             {
00210               DBG << "Specified device name " << dev_name
00211                   << " is a volume (type " << vol_fs_type
00212                   << ", uuid " << vol_fs_uuid << ")"
00213                   << std::endl;
00214               return true;
00215             }
00216           }
00217         }
00218       }
00219 
00220       ERR << "Specified device name " << dev_name
00221           << " is not a usable disk volume"
00222           << std::endl;
00223       return false;
00224     }
00225 
00227     //
00228     //
00229     //  METHOD NAME : MediaDISK::attachTo
00230     //  METHOD TYPE : PMError
00231     //
00232     //  DESCRIPTION : Asserted that not already attached, and attachPoint is a directory.
00233     //
00234     void MediaDISK::attachTo(bool next)
00235     {
00236       if(next)
00237         ZYPP_THROW(MediaNotSupportedException(url()));
00238       // FIXME
00239       // do mount --bind <partition>/<dir> to <to>
00240       //   mount /dev/<partition> /tmp_mount
00241       //   mount /tmp_mount/<dir> <to> --bind -o ro
00242       // FIXME: try all filesystems
00243     
00244       if(_device.empty())
00245         ZYPP_THROW(MediaBadUrlEmptyDestinationException(url()));
00246     
00247       PathInfo dev_info(_device);
00248       if(!dev_info.isBlk())
00249         ZYPP_THROW(MediaBadUrlEmptyDestinationException(url()));
00250 #if DELAYED_VERIFY
00251       DBG << "Verifying " << _device << " ..." << std::endl;
00252       if( !verifyIfDiskVolume( _device))
00253       {
00254         ZYPP_THROW(MediaBadUrlEmptyDestinationException(_url));
00255       }
00256 #endif
00257 
00258       if(_filesystem.empty())
00259         ZYPP_THROW(MediaBadUrlEmptyFilesystemException(url()));
00260 
00261       MediaSourceRef media( new MediaSource(
00262         "disk", _device, dev_info.major(), dev_info.minor()
00263       ));
00264       AttachedMedia  ret( findAttachedMedia( media));
00265 
00266       if( ret.mediaSource &&
00267           ret.attachPoint &&
00268           !ret.attachPoint->empty())
00269       {
00270         DBG << "Using a shared media "
00271             << ret.mediaSource->name
00272             << " attached on "
00273             << ret.attachPoint->path
00274             << endl;
00275 
00276         removeAttachPoint();
00277         setAttachPoint(ret.attachPoint);
00278         setMediaSource(ret.mediaSource);
00279         return;
00280       }
00281 
00282       MediaManager  manager;
00283       MountEntries  entries( manager.getMountEntries());
00284       MountEntries::const_iterator e;
00285       for( e = entries.begin(); e != entries.end(); ++e)
00286       {
00287         bool        is_device = false;
00288         std::string dev_path(Pathname(e->src).asString());
00289         PathInfo    dev_info;
00290 
00291         if( dev_path.compare(0, sizeof("/dev/")-1, "/dev/") == 0 &&
00292             dev_info(e->src) && dev_info.isBlk())
00293         {
00294           is_device = true;
00295         }
00296 
00297         if( is_device && media->maj_nr == dev_info.major() &&
00298                          media->min_nr == dev_info.minor())
00299         {
00300           /*
00301           if( _filesystem != "auto" && _filesystem != e->type)
00302           {
00303             ZYPP_THROW();
00304           }
00305           */
00306           media->bdir = e->dir;
00307         }
00308       }
00309 
00310       Mount mount;
00311       std::string mountpoint = attachPoint().asString();
00312       if( !isUseableAttachPoint(attachPoint()))
00313       {
00314         mountpoint = createAttachPoint().asString();
00315         if( mountpoint.empty())
00316           ZYPP_THROW( MediaBadAttachPointException(url()));
00317         setAttachPoint( mountpoint, true);
00318       }
00319 
00320       string options = _url.getQueryParam("mountoptions");
00321       if(options.empty())
00322       {
00323         options = "ro";
00324       }
00325 
00326       if( !media->bdir.empty())
00327       {
00328         options += ",bind";
00329         mount.mount(media->bdir, mountpoint, "none", options);
00330       }
00331       else
00332       {
00333         mount.mount(_device, mountpoint, _filesystem, options);
00334       }
00335 
00336       setMediaSource(media);
00337 
00338       // wait for /etc/mtab update ...
00339       // (shouldn't be needed)
00340       int limit = 3;
00341       bool mountsucceeded;
00342       while( !(mountsucceeded=isAttached()) && --limit)
00343       {
00344         sleep(1);
00345       }
00346 
00347       if( !mountsucceeded)
00348       {
00349         setMediaSource(MediaSourceRef());
00350         try
00351         {
00352           mount.umount(attachPoint().asString());
00353         }
00354         catch (const MediaException & excpt_r)
00355         {
00356           ZYPP_CAUGHT(excpt_r);
00357         }
00358         ZYPP_THROW(MediaMountException(
00359           "Unable to verify that the media was mounted",
00360           _device, mountpoint
00361         ));
00362       }
00363     }
00364 
00366     //
00367     //  METHOD NAME : MediaDISK::isAttached
00368     //  METHOD TYPE : bool
00369     //
00370     //  DESCRIPTION : Override check if media is attached.
00371     //
00372     bool
00373     MediaDISK::isAttached() const
00374     {
00375       return checkAttached(false);
00376     }
00377 
00379     //
00380     //
00381     //  METHOD NAME : MediaDISK::releaseFrom
00382     //  METHOD TYPE : PMError
00383     //
00384     //  DESCRIPTION : Asserted that media is attached.
00385     //
00386     void MediaDISK::releaseFrom( bool eject )
00387     {
00388       Mount mount;
00389       mount.umount(attachPoint().asString());
00390     }
00391 
00392 
00394     //
00395     //  METHOD NAME : MediaDISK::getFile
00396     //  METHOD TYPE : PMError
00397     //
00398     //  DESCRIPTION : Asserted that media is attached.
00399     //
00400     void MediaDISK::getFile (const Pathname & filename) const
00401     {
00402       MediaHandler::getFile( filename );
00403     }
00404     
00406     //
00407     //  METHOD NAME : MediaDISK::getDir
00408     //  METHOD TYPE : PMError
00409     //
00410     //  DESCRIPTION : Asserted that media is attached.
00411     //
00412     void MediaDISK::getDir( const Pathname & dirname, bool recurse_r ) const
00413     {
00414       MediaHandler::getDir( dirname, recurse_r );
00415     }
00416     
00418     //
00419     //
00420     //  METHOD NAME : MediaDISK::getDirInfo
00421     //  METHOD TYPE : PMError
00422     //
00423     //  DESCRIPTION : Asserted that media is attached and retlist is empty.
00424     //
00425     void MediaDISK::getDirInfo( std::list<std::string> & retlist,
00426                                 const Pathname & dirname, bool dots ) const
00427     {
00428       MediaHandler::getDirInfo( retlist, dirname, dots );
00429     }
00430     
00432     //
00433     //
00434     //  METHOD NAME : MediaDISK::getDirInfo
00435     //  METHOD TYPE : PMError
00436     //
00437     //  DESCRIPTION : Asserted that media is attached and retlist is empty.
00438     //
00439     void MediaDISK::getDirInfo( filesystem::DirContent & retlist,
00440                                 const Pathname & dirname, bool dots ) const
00441     {
00442       MediaHandler::getDirInfo( retlist, dirname, dots );
00443     }
00444 
00445     bool MediaDISK::getDoesFileExist( const Pathname & filename ) const
00446     {
00447       return MediaHandler::getDoesFileExist( filename );
00448     }    
00449     
00450   } // namespace media
00451 } // namespace zypp
00452 // vim: set ts=8 sts=2 sw=2 ai noet:

Generated on Tue Sep 25 19:23:01 2007 for libzypp by  doxygen 1.5.3