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