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

Generated on Thu Jul 6 00:07:21 2006 for zypp by  doxygen 1.4.6