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/Logger.h"
00022 #include "zypp/base/String.h"
00023 
00024 #include "zypp/DiskUsageCounter.h"
00025 #include "zypp/Package.h"
00026 
00027 using std::endl;
00028 
00030 namespace zypp
00031 { 
00032 
00034   namespace
00035   { 
00036 
00037     inline void addDu( DiskUsageCounter::MountPointSet & result_r, DiskUsage & du_r )
00038     {
00039       // traverse mountpoints in reverse order. This is done beacuse
00040       // DiskUsage::extract computes the mountpoint size, and then
00041       // removes the entry. So we must process leaves first.
00042       for_( mpit, result_r.rbegin(), result_r.rend() )
00043       {
00044         // Extract usage for the mount point
00045         DiskUsage::Entry entry = du_r.extract( mpit->dir );
00046         // Adjust the data.
00047         mpit->pkg_size += entry._size;
00048       }
00049     }
00050 
00051     inline void delDu( DiskUsageCounter::MountPointSet & result_r, DiskUsage & du_r )
00052     {
00053       // traverse mountpoints in reverse order. This is done beacuse
00054       // DiskUsage::extract computes the mountpoint size, and then
00055       // removes the entry. So we must process leaves first.
00056       for_( mpit, result_r.rbegin(), result_r.rend() )
00057       {
00058         // Extract usage for the mount point
00059         DiskUsage::Entry entry = du_r.extract( mpit->dir );
00060         // Adjust the data.
00061         mpit->pkg_size -= entry._size;
00062       }
00063     }
00064 
00066   } // namespace
00068 
00069  DiskUsageCounter::MountPointSet DiskUsageCounter::disk_usage( const ResPool & pool_r )
00070   {
00071     DiskUsageCounter::MountPointSet result = mps;
00072 
00073     if ( result.empty() )
00074     {
00075       // partitioning is not set
00076       return result;
00077     }
00078 
00079     // set used size after commit to the current used size
00080     for_( it, result.begin(), result.end() )
00081     {
00082       it->pkg_size = it->used_size;
00083     }
00084 
00085     // iterate through all items
00086     for_( it, pool_r.begin(), pool_r.end() )
00087     {
00088       DiskUsage du( (*it)->diskusage() );
00089 
00090       // skip items without du info
00091       if ( du.empty() )
00092         continue; // or find some substitute info
00093 
00094       // skip items that do not transact
00095       if ( ! it->status().transacts() )
00096         continue;
00097 
00098       // Adjust the data.
00099       if ( it->status().isUninstalled() )
00100       {
00101         // an uninstalled item gets installed:
00102         addDu( result, du );
00103 
00104         // While there is no valid solver result, items to update
00105         // are selected, but installed old versions are not yet
00106         // deselected. We try to compensate this:
00107         if ( ! (*it)->installOnly() )
00108         {
00109           // Item to update -> check the installed ones.
00110           for_( nit, pool_r.byNameBegin((*it)->name()), pool_r.byNameEnd((*it)->name()) )
00111           {                                          // same name
00112             if (    (*nit)->kind() == (*it)->kind()  // same kind
00113                  && nit->status().staysInstalled() ) // and unselected installed
00114             {
00115               DiskUsage ndu( (*nit)->diskusage() );
00116               if ( ! ndu.empty() )
00117               {
00118                 delDu( result, ndu );
00119               }
00120             }
00121           }
00122         }
00123       }
00124       else
00125       {
00126         // an installed item gets deleted:
00127         delDu( result, du );
00128       }
00129     }
00130     return result;
00131   }
00132 
00133   DiskUsageCounter::MountPointSet DiskUsageCounter::detectMountPoints(const std::string &rootdir)
00134   {
00135     DiskUsageCounter::MountPointSet ret;
00136 
00137       std::ifstream procmounts( "/proc/mounts" );
00138 
00139       if ( !procmounts ) {
00140         WAR << "Unable to read /proc/mounts" << std::endl;
00141       } else {
00142 
00143         std::string prfx;
00144         if ( rootdir != "/" )
00145           prfx = rootdir; // rootdir not /
00146 
00147         while ( procmounts ) {
00148           std::string l = str::getline( procmounts );
00149           if ( !(procmounts.fail() || procmounts.bad()) ) {
00150             // data to consume
00151 
00152             // rootfs   /               rootfs          rw 0 0
00153             // /dev/root        /               reiserfs        rw 0 0
00154             // proc     /proc           proc            rw 0 0
00155             // devpts   /dev/pts        devpts          rw 0 0
00156             // /dev/hda5        /boot           ext2            rw 0 0
00157             // shmfs    /dev/shm        shm             rw 0 0
00158             // usbdevfs         /proc/bus/usb   usbdevfs        rw 0 0
00159 
00160             std::vector<std::string> words;
00161             str::split( l, std::back_inserter(words) );
00162 
00163             if ( words.size() < 3 ) {
00164               WAR << "Suspicious entry in /proc/mounts: " << l << std::endl;
00165               continue;
00166             }
00167 
00168             //
00169             // Filter devices without '/' (proc,shmfs,..)
00170             //
00171             if ( words[0].find( '/' ) == std::string::npos ) {
00172               DBG << "Discard mount point : " << l << std::endl;
00173               continue;
00174             }
00175 
00176             //
00177             // Filter mountpoints not at or below _rootdir
00178             //
00179             std::string mp = words[1];
00180             if ( prfx.size() ) {
00181               if ( mp.compare( 0, prfx.size(), prfx ) != 0 ) {
00182                 // mountpoint not below rootdir
00183                 DBG << "Unwanted mount point : " << l << std::endl;
00184                 continue;
00185               }
00186               // strip prfx
00187               mp.erase( 0, prfx.size() );
00188               if ( mp.empty() ) {
00189                 mp = "/";
00190               } else if ( mp[0] != '/' ) {
00191                 // mountpoint not below rootdir
00192                 DBG << "Unwanted mount point : " << l << std::endl;
00193                 continue;
00194               }
00195             }
00196 
00197             //
00198             // Filter cdrom
00199             //
00200             if ( words[2] == "iso9660" ) {
00201               DBG << "Discard cdrom : " << l << std::endl;
00202               continue;
00203             }
00204 
00205             //
00206             // Filter some common unwanted mountpoints
00207             //
00208             const char * mpunwanted[] = {
00209               "/mnt", "/media", "/mounts", "/floppy", "/cdrom",
00210               "/suse", "/var/tmp", "/var/adm/mount", "/var/adm/YaST",
00211               /*last*/0/*entry*/
00212             };
00213 
00214             const char ** nomp = mpunwanted;
00215             for ( ; *nomp; ++nomp ) {
00216               std::string pre( *nomp );
00217               if ( mp.compare( 0, pre.size(), pre ) == 0 // mp has prefix pre
00218                    && ( mp.size() == pre.size() || mp[pre.size()] == '/' ) ) {
00219                 break;
00220               }
00221             }
00222             if ( *nomp ) {
00223               DBG << "Filter mount point : " << l << std::endl;
00224               continue;
00225             }
00226 
00227             //
00228             // Check whether mounted readonly
00229             //
00230             bool ro = false;
00231             std::vector<std::string> flags;
00232             str::split( words[3], std::back_inserter(flags), "," );
00233 
00234             for ( unsigned i = 0; i < flags.size(); ++i ) {
00235               if ( flags[i] == "ro" ) {
00236                 ro = true;
00237                 break;
00238               }
00239             }
00240             if ( ro ) {
00241               DBG << "Filter ro mount point : " << l << std::endl;
00242               continue;
00243             }
00244 
00245             //
00246             // statvfs (full path!) and get the data
00247             //
00248             struct statvfs sb;
00249             if ( statvfs( words[1].c_str(), &sb ) != 0 ) {
00250               WAR << "Unable to statvfs(" << words[1] << "); errno " << errno << std::endl;
00251               ret.insert( DiskUsageCounter::MountPoint( mp ) );
00252             }
00253             else
00254             {
00255               ret.insert( DiskUsageCounter::MountPoint( mp, sb.f_bsize,
00256                 ((long long)sb.f_blocks)*sb.f_bsize/1024,
00257                 ((long long)(sb.f_blocks - sb.f_bfree))*sb.f_bsize/1024, 0LL, ro ) );
00258             }
00259           }
00260         }
00261     }
00262 
00263     return ret;
00264   }
00265 
00266   std::ostream & operator<<( std::ostream & str, const DiskUsageCounter::MountPoint & obj )
00267   {
00268     str << "dir:[" << obj.dir << "] [ bs: " << obj.block_size
00269         << " ts: " << obj.total_size
00270         << " us: " << obj.used_size
00271         << " (+-: " << (obj.pkg_size-obj.used_size)
00272         << ")]" << std::endl;
00273     return str;
00274   }
00275 
00276 } // namespace zypp

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