DiskUsageCounter.cc

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00012 extern "C"
00013 {
00014 #include <sys/statvfs.h>
00015 }
00016 
00017 #include <iostream>
00018 #include <fstream>
00019 
00020 #include "zypp/base/Easy.h"
00021 #include "zypp/base/LogTools.h"
00022 #include "zypp/base/DtorReset.h"
00023 #include "zypp/base/String.h"
00024 
00025 #include "zypp/DiskUsageCounter.h"
00026 #include "zypp/sat/Pool.h"
00027 #include "zypp/sat/detail/PoolImpl.h"
00028 
00029 using std::endl;
00030 
00032 namespace zypp
00033 { 
00034 
00036   namespace
00037   { 
00038 
00039     struct SatMap : private base::NonCopyable
00040     {
00041       SatMap()
00042       {
00043         ::map_init( &_installedmap, sat::Pool::instance().capacity() );
00044       }
00045 
00046       void add( sat::Solvable solv_r )
00047       {
00048         MAPSET( &_installedmap, solv_r.id() );
00049       }
00050 
00051       void add( const PoolItem & pi_r )
00052       { add( pi_r->satSolvable() ); }
00053 
00054       void add( const ResObject::constPtr & obj_r )
00055       { add( obj_r->satSolvable() ); }
00056 
00057       mutable ::Map _installedmap;
00058     };
00059 
00060     DiskUsageCounter::MountPointSet calcDiskUsage( DiskUsageCounter::MountPointSet result, const SatMap & installedmap_r )
00061     {
00062       if ( result.empty() )
00063       {
00064         // partitioning is not set
00065         return result;
00066       }
00067 
00068       sat::Pool satpool( sat::Pool::instance() );
00069 
00070       // init satsolver result vector with mountpoints
00071       static const ::DUChanges _initdu = { 0, 0, 0 };
00072       std::vector< ::DUChanges> duchanges( result.size(), _initdu );
00073       {
00074         unsigned idx = 0;
00075         for_( it, result.begin(), result.end() )
00076         {
00077           duchanges[idx].path = it->dir.c_str();
00078           ++idx;
00079         }
00080       }
00081 
00082       // now calc...
00083       ::pool_calc_duchanges( satpool.get(),
00084                              &installedmap_r._installedmap,
00085                              &duchanges[0],
00086                              duchanges.size() );
00087 
00088       // and process the result
00089       {
00090         unsigned idx = 0;
00091         for_( it, result.begin(), result.end() )
00092         {
00093           static const ByteCount blockAdjust( 2, ByteCount::K ); // (files * blocksize) / (2 * 1K)
00094           it->pkg_size = it->used_size          // current usage
00095                        + duchanges[idx].kbytes  // package data size
00096                        + ( duchanges[idx].files * it->block_size / blockAdjust ); // half block per file
00097           ++idx;
00098         }
00099       }
00100 
00101       return result;
00102     }
00103 
00105   } // namespace
00107 
00108   DiskUsageCounter::MountPointSet DiskUsageCounter::disk_usage( const ResPool & pool_r )
00109   {
00110     SatMap installedmap;
00111     // build installedmap (installed != transact)
00112     // stays installed or gets installed
00113     for_( it, pool_r.begin(), pool_r.end() )
00114     {
00115       if ( it->status().isInstalled() != it->status().transacts() )
00116       {
00117         installedmap.add( *it );
00118       }
00119     }
00120     return calcDiskUsage( mps, installedmap );
00121   }
00122 
00123   DiskUsageCounter::MountPointSet DiskUsageCounter::disk_usage( sat::Solvable solv_r )
00124   {
00125     SatMap installedmap;
00126     installedmap.add( solv_r );
00127 
00128     // temp. unset @system Repo
00129     DtorReset tmp( sat::Pool::instance().get()->installed );
00130     sat::Pool::instance().get()->installed = nullptr;
00131 
00132     return calcDiskUsage( mps, installedmap );
00133   }
00134 
00135   DiskUsageCounter::MountPointSet DiskUsageCounter::detectMountPoints(const std::string &rootdir)
00136   {
00137     DiskUsageCounter::MountPointSet ret;
00138 
00139       std::ifstream procmounts( "/proc/mounts" );
00140 
00141       if ( !procmounts ) {
00142         WAR << "Unable to read /proc/mounts" << std::endl;
00143       } else {
00144 
00145         std::string prfx;
00146         if ( rootdir != "/" )
00147           prfx = rootdir; // rootdir not /
00148 
00149         while ( procmounts ) {
00150           std::string l = str::getline( procmounts );
00151           if ( !(procmounts.fail() || procmounts.bad()) ) {
00152             // data to consume
00153 
00154             // rootfs   /               rootfs          rw 0 0
00155             // /dev/root        /               reiserfs        rw 0 0
00156             // proc     /proc           proc            rw 0 0
00157             // devpts   /dev/pts        devpts          rw 0 0
00158             // /dev/hda5        /boot           ext2            rw 0 0
00159             // shmfs    /dev/shm        shm             rw 0 0
00160             // usbdevfs         /proc/bus/usb   usbdevfs        rw 0 0
00161 
00162             std::vector<std::string> words;
00163             str::split( l, std::back_inserter(words) );
00164 
00165             if ( words.size() < 3 ) {
00166               WAR << "Suspicious entry in /proc/mounts: " << l << std::endl;
00167               continue;
00168             }
00169 
00170             //
00171             // Filter devices without '/' (proc,shmfs,..)
00172             //
00173             if ( words[0].find( '/' ) == std::string::npos ) {
00174               DBG << "Discard mount point : " << l << std::endl;
00175               continue;
00176             }
00177 
00178             // remove /proc entry
00179             if (words[0] == "/proc")
00180             {
00181               DBG << "Discard /proc filesystem: " << l << std::endl;
00182               continue;
00183             }
00184 
00185             //
00186             // Filter mountpoints not at or below _rootdir
00187             //
00188             std::string mp = words[1];
00189             if ( prfx.size() ) {
00190               if ( mp.compare( 0, prfx.size(), prfx ) != 0 ) {
00191                 // mountpoint not below rootdir
00192                 DBG << "Unwanted mount point : " << l << std::endl;
00193                 continue;
00194               }
00195               // strip prfx
00196               mp.erase( 0, prfx.size() );
00197               if ( mp.empty() ) {
00198                 mp = "/";
00199               } else if ( mp[0] != '/' ) {
00200                 // mountpoint not below rootdir
00201                 DBG << "Unwanted mount point : " << l << std::endl;
00202                 continue;
00203               }
00204             }
00205 
00206             //
00207             // Filter cdrom
00208             //
00209             if ( words[2] == "iso9660" ) {
00210               DBG << "Discard cdrom : " << l << std::endl;
00211               continue;
00212             }
00213 
00214             if ( words[2] == "vfat" || words[2] == "fat" || words[2] == "ntfs" || words[2] == "ntfs-3g")
00215             {
00216               MIL << words[1] << " contains ignored fs (" << words[2] << ')' << std::endl;
00217               continue;
00218             }
00219 
00220             //
00221             // Filter some common unwanted mountpoints
00222             //
00223             const char * mpunwanted[] = {
00224               "/mnt", "/media", "/mounts", "/floppy", "/cdrom",
00225               "/suse", "/var/tmp", "/var/adm/mount", "/var/adm/YaST",
00226               /*last*/0/*entry*/
00227             };
00228 
00229             const char ** nomp = mpunwanted;
00230             for ( ; *nomp; ++nomp ) {
00231               std::string pre( *nomp );
00232               if ( mp.compare( 0, pre.size(), pre ) == 0 // mp has prefix pre
00233                    && ( mp.size() == pre.size() || mp[pre.size()] == '/' ) ) {
00234                 break;
00235               }
00236             }
00237             if ( *nomp ) {
00238               DBG << "Filter mount point : " << l << std::endl;
00239               continue;
00240             }
00241 
00242             //
00243             // Check whether mounted readonly
00244             //
00245             bool ro = false;
00246             std::vector<std::string> flags;
00247             str::split( words[3], std::back_inserter(flags), "," );
00248 
00249             for ( unsigned i = 0; i < flags.size(); ++i ) {
00250               if ( flags[i] == "ro" ) {
00251                 ro = true;
00252                 break;
00253               }
00254             }
00255             if ( ro ) {
00256               DBG << "Filter ro mount point : " << l << std::endl;
00257               continue;
00258             }
00259 
00260             //
00261             // statvfs (full path!) and get the data
00262             //
00263             struct statvfs sb;
00264             if ( statvfs( words[1].c_str(), &sb ) != 0 ) {
00265               WAR << "Unable to statvfs(" << words[1] << "); errno " << errno << std::endl;
00266               ret.insert( DiskUsageCounter::MountPoint( mp ) );
00267             }
00268             else
00269             {
00270               //
00271               // Filter zero sized devices (bnc#769819)
00272               //
00273               if ( sb.f_blocks == 0 || sb.f_bsize == 0 )
00274               {
00275                 DBG << "Filter zero-sized mount point : " << l << std::endl;
00276                 continue;
00277               }
00278               ret.insert( DiskUsageCounter::MountPoint( mp, sb.f_bsize,
00279                 ((long long)sb.f_blocks)*sb.f_bsize/1024,
00280                 ((long long)(sb.f_blocks - sb.f_bfree))*sb.f_bsize/1024, 0LL, ro ) );
00281             }
00282           }
00283         }
00284     }
00285 
00286     return ret;
00287   }
00288 
00289   DiskUsageCounter::MountPointSet DiskUsageCounter::justRootPartition()
00290   {
00291     DiskUsageCounter::MountPointSet ret;
00292     ret.insert( DiskUsageCounter::MountPoint() );
00293     return ret;
00294   }
00295 
00296   std::ostream & operator<<( std::ostream & str, const DiskUsageCounter::MountPoint & obj )
00297   {
00298      str << "dir:[" << obj.dir << "] [ bs: " << obj.blockSize()
00299         << " ts: " << obj.totalSize()
00300         << " us: " << obj.usedSize()
00301         << " (+-: " << obj.commitDiff()
00302         << ")]";
00303     return str;
00304   }
00305 
00307 } // namespace zypp

doxygen