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/Logger.h"
00021 #include "zypp/base/String.h"
00022 
00023 #include "zypp/DiskUsageCounter.h"
00024 #include "zypp/Package.h"
00025 
00026 
00028 namespace zypp
00029 { 
00030 
00031   DiskUsageCounter::MountPointSet DiskUsageCounter::disk_usage(const ResPool &pool)
00032   {
00033     MountPointSet result = mps;
00034 
00035     if (mps.empty())
00036     {
00037       // partitioning is not set
00038       return result;
00039     }
00040 
00041     // set used size after commit to the current used size
00042     for (MountPointSet::iterator mpit = result.begin();
00043       mpit != result.end();
00044       mpit++)
00045     {
00046       mpit->pkg_size = mpit->used_size;
00047     }
00048 
00049     // iterate through all packages
00050     for (ResPool::byKind_iterator it = pool.byKindBegin(ResTraits<Package>::kind);
00051       it != pool.byKindEnd(ResTraits<Package>::kind);
00052       ++it)
00053     {
00054       bool inst = it->status().isToBeInstalled();
00055       bool rem = it->status().isToBeUninstalled();
00056 
00057       // if the package is not selected for installation or removing
00058       // it can't affect disk usage
00059       if (inst || rem)
00060       {
00061         Package::constPtr pkg = boost::dynamic_pointer_cast<const Package>( it->resolvable() );
00062         DiskUsage du = pkg->diskusage();
00063         DiskUsage du_another_package;
00064         Edition edition_another_package;
00065 
00066         // the same package has been selected for installation
00067         bool found_installed = false;
00068         // the same package has been selected for uninstallation
00069         bool found_to_install = false;
00070 
00071         // the du is empty or the package is selected for installation (check whether the package is already installed)
00072         if (du.size() == 0 || inst)
00073         {
00074             // disk usage is unknown for already installed packages
00075             // find the same package from any installation source
00076             std::string name = (*it)->name();
00077 
00078             for (ResPool::byName_iterator nameit = pool.byNameBegin(name);
00079               nameit != pool.byNameEnd(name);
00080               ++nameit)
00081             {
00082                 // is version and architecture same?
00083                 if (isKind<Package>(nameit->resolvable()))
00084                 {
00085                     // found a package
00086                     Package::constPtr pkg_from_source = boost::dynamic_pointer_cast<const Package>( nameit->resolvable() );
00087 
00088                     if (nameit->status().isToBeInstalled())
00089                     {
00090                         found_to_install = true;
00091                     }
00092 
00093                     // check the version
00094                     if ((*it)->edition() == (*nameit)->edition() && (*it)->arch() == (*nameit)->arch())
00095                     {
00096                         if (inst)
00097                         {
00098                             if (nameit->status().isInstalled())
00099                             {
00100                                 found_installed = true;
00101                                 XXX << name << '-' << (*it)->edition() << ": found already installed package (" << (*nameit)->edition() << ")" << std::endl;
00102                             }
00103                         }
00104                         else
00105                         {
00106                             // the package will be uninstalled and du is empty, try to use du from another object
00107                             du = pkg_from_source->diskusage();
00108                             if (du.size() > 0)
00109                             {
00110                                 XXX << name << '-' << (*it)->edition() << ": using DiskUsage from another Package object (" << (*nameit)->edition() << ")" << std::endl;
00111                                 break;
00112                             }
00113                         }
00114                     }
00115                     else
00116                     {
00117                         if (inst && nameit->status().isInstalled())
00118                         {
00119                             // just freshen the package, don't change du statistics
00120                             found_installed = true;
00121                             XXX << name << '-' << (*it)->edition() << ": found already installed package (" << (*nameit)->edition() << ")" << std::endl;
00122                         }
00123                         else if (pkg_from_source->diskusage().size() > 0)
00124                         {
00125                             // found different version of the package, remember the disk usage
00126                             // it will be used the same version is not found
00127                             du_another_package = pkg_from_source->diskusage();
00128                             edition_another_package = (*nameit)->edition();
00129                         }
00130                     }
00131                 }
00132             }
00133 
00134             // don't subtract the disk usage for updated package
00135             if (du.size() == 0 && du_another_package.size() > 0 && !(rem && found_to_install))
00136             {
00137                 XXX << name << '-' << (*it)->edition() << ": using DU info from version " << edition_another_package << std::endl;
00138                 du = du_another_package;
00139             }
00140         }
00141 
00142         // don't modify du if the installed package is already installed (freshening)
00143         if (du.size() > 0 && !(inst && found_installed))
00144         {
00145           // iterate trough all mount points, add usage to each directory
00146           // directory tree must be processed from leaves to the root directory
00147           // so iterate in reverse order so e.g. /usr is used before /
00148           for (MountPointSet::reverse_iterator mpit = result.rbegin();
00149             mpit != result.rend();
00150             mpit++)
00151           {
00152             // get usage for the mount point
00153             DiskUsage::Entry entry = du.extract(mpit->dir);
00154 
00155             // add or subtract it to the current value
00156             if (inst)
00157             {
00158                 mpit->pkg_size += entry._size;
00159             }
00160             else // the package will be uninstalled
00161             {
00162                 mpit->pkg_size -= entry._size;
00163             }
00164           }
00165         }
00166       }
00167     }
00168 
00169     return result;
00170   }
00171 
00172 
00173   DiskUsageCounter::MountPointSet DiskUsageCounter::detectMountPoints(const std::string &rootdir)
00174   {
00175     DiskUsageCounter::MountPointSet ret;
00176 
00177       std::ifstream procmounts( "/proc/mounts" );
00178 
00179       if ( !procmounts ) {
00180         WAR << "Unable to read /proc/mounts" << std::endl;
00181       } else {
00182 
00183         std::string prfx;
00184         if ( rootdir != "/" )
00185           prfx = rootdir; // rootdir not /
00186 
00187         while ( procmounts ) {
00188           std::string l = str::getline( procmounts );
00189           if ( !(procmounts.fail() || procmounts.bad()) ) {
00190             // data to consume
00191 
00192             // rootfs   /               rootfs          rw 0 0
00193             // /dev/root        /               reiserfs        rw 0 0
00194             // proc     /proc           proc            rw 0 0
00195             // devpts   /dev/pts        devpts          rw 0 0
00196             // /dev/hda5        /boot           ext2            rw 0 0
00197             // shmfs    /dev/shm        shm             rw 0 0
00198             // usbdevfs         /proc/bus/usb   usbdevfs        rw 0 0
00199 
00200             std::vector<std::string> words;
00201             str::split( l, std::back_inserter(words) );
00202 
00203             if ( words.size() < 3 ) {
00204               WAR << "Suspicious entry in /proc/mounts: " << l << std::endl;
00205               continue;
00206             }
00207 
00208             //
00209             // Filter devices without '/' (proc,shmfs,..)
00210             //
00211             if ( words[0].find( '/' ) == std::string::npos ) {
00212               DBG << "Discard mount point : " << l << std::endl;
00213               continue;
00214             }
00215 
00216             //
00217             // Filter mountpoints not at or below _rootdir
00218             //
00219             std::string mp = words[1];
00220             if ( prfx.size() ) {
00221               if ( mp.compare( 0, prfx.size(), prfx ) != 0 ) {
00222                 // mountpoint not below rootdir
00223                 DBG << "Unwanted mount point : " << l << std::endl;
00224                 continue;
00225               }
00226               // strip prfx
00227               mp.erase( 0, prfx.size() );
00228               if ( mp.empty() ) {
00229                 mp = "/";
00230               } else if ( mp[0] != '/' ) {
00231                 // mountpoint not below rootdir
00232                 DBG << "Unwanted mount point : " << l << std::endl;
00233                 continue;
00234               }
00235             }
00236 
00237             //
00238             // Filter cdrom
00239             //
00240             if ( words[2] == "iso9660" ) {
00241               DBG << "Discard cdrom : " << l << std::endl;
00242               continue;
00243             }
00244 
00245             //
00246             // Filter some common unwanted mountpoints
00247             //
00248             char * mpunwanted[] = {
00249               "/mnt", "/media", "/mounts", "/floppy", "/cdrom",
00250               "/suse", "/var/tmp", "/var/adm/mount", "/var/adm/YaST",
00251               /*last*/0/*entry*/
00252             };
00253 
00254             char ** nomp = mpunwanted;
00255             for ( ; *nomp; ++nomp ) {
00256               std::string pre( *nomp );
00257               if ( mp.compare( 0, pre.size(), pre ) == 0 // mp has prefix pre
00258                    && ( mp.size() == pre.size() || mp[pre.size()] == '/' ) ) {
00259                 break;
00260               }
00261             }
00262             if ( *nomp ) {
00263               DBG << "Filter mount point : " << l << std::endl;
00264               continue;
00265             }
00266 
00267             //
00268             // Check whether mounted readonly
00269             //
00270             bool ro = false;
00271             std::vector<std::string> flags;
00272             str::split( words[3], std::back_inserter(flags), "," );
00273 
00274             for ( unsigned i = 0; i < flags.size(); ++i ) {
00275               if ( flags[i] == "ro" ) {
00276                 ro = true;
00277                 break;
00278               }
00279             }
00280 
00281             //
00282             // statvfs (full path!) and get the data
00283             //
00284             struct statvfs sb;
00285             if ( statvfs( words[1].c_str(), &sb ) != 0 ) {
00286               WAR << "Unable to statvfs(" << words[1] << "); errno " << errno << std::endl;
00287               ret.insert( DiskUsageCounter::MountPoint( mp ) );
00288             }
00289             else
00290             {
00291               ret.insert( DiskUsageCounter::MountPoint( mp, sb.f_bsize,
00292                 ((long long)sb.f_blocks)*sb.f_bsize/1024,
00293                 ((long long)(sb.f_blocks - sb.f_bfree))*sb.f_bsize/1024, 0LL, ro ) );
00294             }
00295           }
00296         }
00297     }
00298 
00299     return ret;
00300   }
00301 
00302 } // namespace zypp

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