1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/DiskUsageCounter.cc
14 #include <sys/statvfs.h>
20 #include "zypp/base/Easy.h"
21 #include "zypp/base/Logger.h"
22 #include "zypp/base/String.h"
24 #include "zypp/DiskUsageCounter.h"
25 #include "zypp/Package.h"
29 ///////////////////////////////////////////////////////////////////
31 { /////////////////////////////////////////////////////////////////
33 ///////////////////////////////////////////////////////////////////
35 { /////////////////////////////////////////////////////////////////
37 inline void addDu( DiskUsageCounter::MountPointSet & result_r, DiskUsage & du_r )
39 // traverse mountpoints in reverse order. This is done beacuse
40 // DiskUsage::extract computes the mountpoint size, and then
41 // removes the entry. So we must process leaves first.
42 for_( mpit, result_r.rbegin(), result_r.rend() )
44 // Extract usage for the mount point
45 DiskUsage::Entry entry = du_r.extract( mpit->dir );
47 mpit->pkg_size += entry._size;
51 inline void delDu( DiskUsageCounter::MountPointSet & result_r, DiskUsage & du_r )
53 // traverse mountpoints in reverse order. This is done beacuse
54 // DiskUsage::extract computes the mountpoint size, and then
55 // removes the entry. So we must process leaves first.
56 for_( mpit, result_r.rbegin(), result_r.rend() )
58 // Extract usage for the mount point
59 DiskUsage::Entry entry = du_r.extract( mpit->dir );
61 mpit->pkg_size -= entry._size;
65 /////////////////////////////////////////////////////////////////
67 ///////////////////////////////////////////////////////////////////
69 DiskUsageCounter::MountPointSet DiskUsageCounter::disk_usage( const ResPool & pool_r )
71 DiskUsageCounter::MountPointSet result = mps;
75 // partitioning is not set
79 // set used size after commit to the current used size
80 for_( it, result.begin(), result.end() )
82 it->pkg_size = it->used_size;
85 // iterate through all items
86 for_( it, pool_r.begin(), pool_r.end() )
88 DiskUsage du( (*it)->diskusage() );
90 // skip items without du info
92 continue; // or find some substitute info
94 // skip items that do not transact
95 if ( ! it->status().transacts() )
99 if ( it->status().isUninstalled() )
101 // an uninstalled item gets installed:
104 // While there is no valid solver result, items to update
105 // are selected, but installed old versions are not yet
106 // deselected. We try to compensate this:
107 if ( ! (*it)->installOnly() )
109 // Item to update -> check the installed ones.
110 for_( nit, pool_r.byNameBegin((*it)->name()), pool_r.byNameEnd((*it)->name()) )
112 if ( (*nit)->kind() == (*it)->kind() // same kind
113 && nit->status().staysInstalled() ) // and unselected installed
115 DiskUsage ndu( (*nit)->diskusage() );
118 delDu( result, ndu );
126 // an installed item gets deleted:
133 DiskUsageCounter::MountPointSet DiskUsageCounter::detectMountPoints(const std::string &rootdir)
135 DiskUsageCounter::MountPointSet ret;
137 std::ifstream procmounts( "/proc/mounts" );
140 WAR << "Unable to read /proc/mounts" << std::endl;
144 if ( rootdir != "/" )
145 prfx = rootdir; // rootdir not /
147 while ( procmounts ) {
148 std::string l = str::getline( procmounts );
149 if ( !(procmounts.fail() || procmounts.bad()) ) {
152 // rootfs / rootfs rw 0 0
153 // /dev/root / reiserfs rw 0 0
154 // proc /proc proc rw 0 0
155 // devpts /dev/pts devpts rw 0 0
156 // /dev/hda5 /boot ext2 rw 0 0
157 // shmfs /dev/shm shm rw 0 0
158 // usbdevfs /proc/bus/usb usbdevfs rw 0 0
160 std::vector<std::string> words;
161 str::split( l, std::back_inserter(words) );
163 if ( words.size() < 3 ) {
164 WAR << "Suspicious entry in /proc/mounts: " << l << std::endl;
169 // Filter devices without '/' (proc,shmfs,..)
171 if ( words[0].find( '/' ) == std::string::npos ) {
172 DBG << "Discard mount point : " << l << std::endl;
177 // Filter mountpoints not at or below _rootdir
179 std::string mp = words[1];
181 if ( mp.compare( 0, prfx.size(), prfx ) != 0 ) {
182 // mountpoint not below rootdir
183 DBG << "Unwanted mount point : " << l << std::endl;
187 mp.erase( 0, prfx.size() );
190 } else if ( mp[0] != '/' ) {
191 // mountpoint not below rootdir
192 DBG << "Unwanted mount point : " << l << std::endl;
200 if ( words[2] == "iso9660" ) {
201 DBG << "Discard cdrom : " << l << std::endl;
206 // Filter some common unwanted mountpoints
208 const char * mpunwanted[] = {
209 "/mnt", "/media", "/mounts", "/floppy", "/cdrom",
210 "/suse", "/var/tmp", "/var/adm/mount", "/var/adm/YaST",
214 const char ** nomp = mpunwanted;
215 for ( ; *nomp; ++nomp ) {
216 std::string pre( *nomp );
217 if ( mp.compare( 0, pre.size(), pre ) == 0 // mp has prefix pre
218 && ( mp.size() == pre.size() || mp[pre.size()] == '/' ) ) {
223 DBG << "Filter mount point : " << l << std::endl;
228 // Check whether mounted readonly
231 std::vector<std::string> flags;
232 str::split( words[3], std::back_inserter(flags), "," );
234 for ( unsigned i = 0; i < flags.size(); ++i ) {
235 if ( flags[i] == "ro" ) {
241 DBG << "Filter ro mount point : " << l << std::endl;
246 // statvfs (full path!) and get the data
249 if ( statvfs( words[1].c_str(), &sb ) != 0 ) {
250 WAR << "Unable to statvfs(" << words[1] << "); errno " << errno << std::endl;
251 ret.insert( DiskUsageCounter::MountPoint( mp ) );
255 ret.insert( DiskUsageCounter::MountPoint( mp, sb.f_bsize,
256 ((long long)sb.f_blocks)*sb.f_bsize/1024,
257 ((long long)(sb.f_blocks - sb.f_bfree))*sb.f_bsize/1024, 0LL, ro ) );
266 std::ostream & operator<<( std::ostream & str, const DiskUsageCounter::MountPoint & obj )
268 str << "dir:[" << obj.dir << "] [ bs: " << obj.block_size
269 << " ts: " << obj.total_size
270 << " us: " << obj.used_size
271 << " (+-: " << (obj.pkg_size-obj.used_size)
272 << ")]" << std::endl;
277 ///////////////////////////////////////////////////////////////////