1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/DiskUsageCounter.cc
14 #include <sys/statvfs.h>
20 #include "zypp/base/Easy.h"
21 #include "zypp/base/LogTools.h"
22 #include "zypp/base/String.h"
24 #include "zypp/DiskUsageCounter.h"
25 #include "zypp/sat/Pool.h"
26 #include "zypp/sat/detail/PoolImpl.h"
30 ///////////////////////////////////////////////////////////////////
32 { /////////////////////////////////////////////////////////////////
34 ///////////////////////////////////////////////////////////////////
36 { /////////////////////////////////////////////////////////////////
38 struct SatMap : private base::NonCopyable
40 SatMap( unsigned capacity_r = 1 )
42 ::map_init( &_installedmap, sat::Pool::instance().capacity() );
45 void add( sat::Solvable solv_r )
47 MAPSET( &_installedmap, solv_r.id() );
50 void add( const PoolItem & pi_r )
51 { add( pi_r->satSolvable() ); }
53 void add( const ResObject::constPtr & obj_r )
54 { add( obj_r->satSolvable() ); }
56 mutable ::Map _installedmap;
59 DiskUsageCounter::MountPointSet calcDiskUsage( const DiskUsageCounter::MountPointSet & mps_r, const SatMap & installedmap_r )
61 DiskUsageCounter::MountPointSet result = mps_r;
65 // partitioning is not set
69 sat::Pool satpool( sat::Pool::instance() );
70 if ( ! satpool.findSystemRepo() )
72 // take care we have at least an empty stystem repo.
73 // ::pool_calc_duchanges requires it.
78 // init satsolver result vector with mountpoints
79 static const ::DUChanges _initdu = { 0, 0, 0 };
80 std::vector< ::DUChanges> duchanges( result.size(), _initdu );
83 for_( it, result.begin(), result.end() )
85 duchanges[idx].path = it->dir.c_str();
91 ::pool_calc_duchanges( satpool.get(),
92 satpool.systemRepo().get(),
93 &installedmap_r._installedmap,
97 // and process the result
100 for_( it, result.begin(), result.end() )
102 static const ByteCount blockAdjust( 2, ByteCount::K ); // (files * blocksize) / (2 * 1K)
104 it->pkg_size = it->used_size // current usage
105 + duchanges[idx].kbytes // package data size
106 + ( duchanges[idx].files * it->block_size / blockAdjust ); // half block per file
114 /////////////////////////////////////////////////////////////////
116 ///////////////////////////////////////////////////////////////////
118 DiskUsageCounter::MountPointSet DiskUsageCounter::disk_usage( const ResPool & pool_r )
120 SatMap installedmap( sat::Pool::instance().capacity() );
121 // build installedmap (installed != transact)
122 // stays installed or gets installed
123 for_( it, pool_r.begin(), pool_r.end() )
125 if ( it->status().isInstalled() != it->status().transacts() )
127 installedmap.add( *it );
130 return calcDiskUsage( mps, installedmap );
133 DiskUsageCounter::MountPointSet DiskUsageCounter::disk_usage( sat::Solvable solv_r )
136 installedmap.add( solv_r );
137 return calcDiskUsage( mps, installedmap );
140 DiskUsageCounter::MountPointSet DiskUsageCounter::detectMountPoints(const std::string &rootdir)
142 DiskUsageCounter::MountPointSet ret;
144 std::ifstream procmounts( "/proc/mounts" );
147 WAR << "Unable to read /proc/mounts" << std::endl;
151 if ( rootdir != "/" )
152 prfx = rootdir; // rootdir not /
154 while ( procmounts ) {
155 std::string l = str::getline( procmounts );
156 if ( !(procmounts.fail() || procmounts.bad()) ) {
159 // rootfs / rootfs rw 0 0
160 // /dev/root / reiserfs rw 0 0
161 // proc /proc proc rw 0 0
162 // devpts /dev/pts devpts rw 0 0
163 // /dev/hda5 /boot ext2 rw 0 0
164 // shmfs /dev/shm shm rw 0 0
165 // usbdevfs /proc/bus/usb usbdevfs rw 0 0
167 std::vector<std::string> words;
168 str::split( l, std::back_inserter(words) );
170 if ( words.size() < 3 ) {
171 WAR << "Suspicious entry in /proc/mounts: " << l << std::endl;
176 // Filter devices without '/' (proc,shmfs,..)
178 if ( words[0].find( '/' ) == std::string::npos ) {
179 DBG << "Discard mount point : " << l << std::endl;
184 // Filter mountpoints not at or below _rootdir
186 std::string mp = words[1];
188 if ( mp.compare( 0, prfx.size(), prfx ) != 0 ) {
189 // mountpoint not below rootdir
190 DBG << "Unwanted mount point : " << l << std::endl;
194 mp.erase( 0, prfx.size() );
197 } else if ( mp[0] != '/' ) {
198 // mountpoint not below rootdir
199 DBG << "Unwanted mount point : " << l << std::endl;
207 if ( words[2] == "iso9660" ) {
208 DBG << "Discard cdrom : " << l << std::endl;
212 if ( words[2] == "vfat" || words[2] == "fat" || words[2] == "ntfs" || words[2] == "ntfs-3g")
214 MIL << words[1] << " contains ignored fs (" << words[2] << ')' << std::endl;
219 // Filter some common unwanted mountpoints
221 const char * mpunwanted[] = {
222 "/mnt", "/media", "/mounts", "/floppy", "/cdrom",
223 "/suse", "/var/tmp", "/var/adm/mount", "/var/adm/YaST",
227 const char ** nomp = mpunwanted;
228 for ( ; *nomp; ++nomp ) {
229 std::string pre( *nomp );
230 if ( mp.compare( 0, pre.size(), pre ) == 0 // mp has prefix pre
231 && ( mp.size() == pre.size() || mp[pre.size()] == '/' ) ) {
236 DBG << "Filter mount point : " << l << std::endl;
241 // Check whether mounted readonly
244 std::vector<std::string> flags;
245 str::split( words[3], std::back_inserter(flags), "," );
247 for ( unsigned i = 0; i < flags.size(); ++i ) {
248 if ( flags[i] == "ro" ) {
254 DBG << "Filter ro mount point : " << l << std::endl;
259 // statvfs (full path!) and get the data
262 if ( statvfs( words[1].c_str(), &sb ) != 0 ) {
263 WAR << "Unable to statvfs(" << words[1] << "); errno " << errno << std::endl;
264 ret.insert( DiskUsageCounter::MountPoint( mp ) );
268 ret.insert( DiskUsageCounter::MountPoint( mp, sb.f_bsize,
269 ((long long)sb.f_blocks)*sb.f_bsize/1024,
270 ((long long)(sb.f_blocks - sb.f_bfree))*sb.f_bsize/1024, 0LL, ro ) );
279 DiskUsageCounter::MountPointSet DiskUsageCounter::justRootPartition()
281 DiskUsageCounter::MountPointSet ret;
282 ret.insert( DiskUsageCounter::MountPoint() );
286 std::ostream & operator<<( std::ostream & str, const DiskUsageCounter::MountPoint & obj )
288 str << "dir:[" << obj.dir << "] [ bs: " << obj.blockSize()
289 << " ts: " << obj.totalSize()
290 << " us: " << obj.usedSize()
291 << " (+-: " << obj.commitDiff()
296 /////////////////////////////////////////////////////////////////
298 ///////////////////////////////////////////////////////////////////