- Reenable diskusage calculation (bnc #395051)
[platform/upstream/libzypp.git] / zypp / DiskUsageCounter.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/DiskUsageCounter.cc
10  *
11  */
12 extern "C"
13 {
14 #include <sys/statvfs.h>
15 }
16
17 #include <iostream>
18 #include <fstream>
19
20 #include "zypp/base/Easy.h"
21 #include "zypp/base/LogTools.h"
22 #include "zypp/base/String.h"
23
24 #include "zypp/DiskUsageCounter.h"
25 #include "zypp/sat/Pool.h"
26 #include "zypp/sat/detail/PoolImpl.h"
27
28 using std::endl;
29
30 ///////////////////////////////////////////////////////////////////
31 namespace zypp
32 { /////////////////////////////////////////////////////////////////
33
34   DiskUsageCounter::MountPointSet DiskUsageCounter::disk_usage( const ResPool & pool_r )
35   {
36     DiskUsageCounter::MountPointSet result = mps;
37
38     if ( result.empty() )
39     {
40       // partitioning is not set
41       return result;
42     }
43
44     sat::Pool satpool( sat::Pool::instance() );
45
46     // init satsolver result vector with mountpoints
47     static const ::DUChanges _initdu = { 0, 0, 0 };
48     std::vector< ::DUChanges> duchanges( result.size(), _initdu );
49     {
50       unsigned idx = 0;
51       for_( it, result.begin(), result.end() )
52       {
53         duchanges[idx].path = it->dir.c_str();
54         ++idx;
55       }
56     }
57
58     // build installedmap (installed != transact)
59     // stays installed or gets installed
60     ::Map installedmap;
61     ::map_init( &installedmap, satpool.capacity() );
62     for_( it, pool_r.begin(), pool_r.end() )
63     {
64       if ( it->status().isInstalled() != it->status().transacts() )
65       {
66         MAPSET( &installedmap, it->satSolvable().id() );
67       }
68     }
69
70     // now calc...
71     ::pool_calc_duchanges( satpool.get(),
72                            satpool.systemRepo().get(),
73                            &installedmap,
74                            &duchanges[0],
75                            duchanges.size() );
76
77     // and process the result
78     {
79       unsigned idx = 0;
80       for_( it, result.begin(), result.end() )
81       {
82         static const ByteCount blockAdjust( 2, ByteCount::K ); // (files * blocksize) / (2 * 1K)
83
84         it->pkg_size = it->used_size          // current usage
85                      + duchanges[idx].kbytes  // package data size
86                      + ( duchanges[idx].files * it->block_size / blockAdjust ); // half block per file
87         ++idx;
88       }
89     }
90
91     return result;
92   }
93
94   DiskUsageCounter::MountPointSet DiskUsageCounter::detectMountPoints(const std::string &rootdir)
95   {
96     DiskUsageCounter::MountPointSet ret;
97
98       std::ifstream procmounts( "/proc/mounts" );
99
100       if ( !procmounts ) {
101         WAR << "Unable to read /proc/mounts" << std::endl;
102       } else {
103
104         std::string prfx;
105         if ( rootdir != "/" )
106           prfx = rootdir; // rootdir not /
107
108         while ( procmounts ) {
109           std::string l = str::getline( procmounts );
110           if ( !(procmounts.fail() || procmounts.bad()) ) {
111             // data to consume
112
113             // rootfs   /               rootfs          rw 0 0
114             // /dev/root        /               reiserfs        rw 0 0
115             // proc     /proc           proc            rw 0 0
116             // devpts   /dev/pts        devpts          rw 0 0
117             // /dev/hda5        /boot           ext2            rw 0 0
118             // shmfs    /dev/shm        shm             rw 0 0
119             // usbdevfs         /proc/bus/usb   usbdevfs        rw 0 0
120
121             std::vector<std::string> words;
122             str::split( l, std::back_inserter(words) );
123
124             if ( words.size() < 3 ) {
125               WAR << "Suspicious entry in /proc/mounts: " << l << std::endl;
126               continue;
127             }
128
129             //
130             // Filter devices without '/' (proc,shmfs,..)
131             //
132             if ( words[0].find( '/' ) == std::string::npos ) {
133               DBG << "Discard mount point : " << l << std::endl;
134               continue;
135             }
136
137             //
138             // Filter mountpoints not at or below _rootdir
139             //
140             std::string mp = words[1];
141             if ( prfx.size() ) {
142               if ( mp.compare( 0, prfx.size(), prfx ) != 0 ) {
143                 // mountpoint not below rootdir
144                 DBG << "Unwanted mount point : " << l << std::endl;
145                 continue;
146               }
147               // strip prfx
148               mp.erase( 0, prfx.size() );
149               if ( mp.empty() ) {
150                 mp = "/";
151               } else if ( mp[0] != '/' ) {
152                 // mountpoint not below rootdir
153                 DBG << "Unwanted mount point : " << l << std::endl;
154                 continue;
155               }
156             }
157
158             //
159             // Filter cdrom
160             //
161             if ( words[2] == "iso9660" ) {
162               DBG << "Discard cdrom : " << l << std::endl;
163               continue;
164             }
165
166             if ( words[2] == "vfat" || words[2] == "fat" || words[2] == "ntfs" || words[2] == "ntfs-3g")
167             {
168               MIL << words[1] << " contains ignored fs (" << words[2] << ')' << std::endl;
169               continue;
170             }
171
172             //
173             // Filter some common unwanted mountpoints
174             //
175             const char * mpunwanted[] = {
176               "/mnt", "/media", "/mounts", "/floppy", "/cdrom",
177               "/suse", "/var/tmp", "/var/adm/mount", "/var/adm/YaST",
178               /*last*/0/*entry*/
179             };
180
181             const char ** nomp = mpunwanted;
182             for ( ; *nomp; ++nomp ) {
183               std::string pre( *nomp );
184               if ( mp.compare( 0, pre.size(), pre ) == 0 // mp has prefix pre
185                    && ( mp.size() == pre.size() || mp[pre.size()] == '/' ) ) {
186                 break;
187               }
188             }
189             if ( *nomp ) {
190               DBG << "Filter mount point : " << l << std::endl;
191               continue;
192             }
193
194             //
195             // Check whether mounted readonly
196             //
197             bool ro = false;
198             std::vector<std::string> flags;
199             str::split( words[3], std::back_inserter(flags), "," );
200
201             for ( unsigned i = 0; i < flags.size(); ++i ) {
202               if ( flags[i] == "ro" ) {
203                 ro = true;
204                 break;
205               }
206             }
207             if ( ro ) {
208               DBG << "Filter ro mount point : " << l << std::endl;
209               continue;
210             }
211
212             //
213             // statvfs (full path!) and get the data
214             //
215             struct statvfs sb;
216             if ( statvfs( words[1].c_str(), &sb ) != 0 ) {
217               WAR << "Unable to statvfs(" << words[1] << "); errno " << errno << std::endl;
218               ret.insert( DiskUsageCounter::MountPoint( mp ) );
219             }
220             else
221             {
222               ret.insert( DiskUsageCounter::MountPoint( mp, sb.f_bsize,
223                 ((long long)sb.f_blocks)*sb.f_bsize/1024,
224                 ((long long)(sb.f_blocks - sb.f_bfree))*sb.f_bsize/1024, 0LL, ro ) );
225             }
226           }
227         }
228     }
229
230     return ret;
231   }
232
233   std::ostream & operator<<( std::ostream & str, const DiskUsageCounter::MountPoint & obj )
234   {
235     str << "dir:[" << obj.dir << "] [ bs: " << obj.block_size
236         << " ts: " << obj.total_size
237         << " us: " << obj.used_size
238         << " (+-: " << (obj.pkg_size-obj.used_size)
239         << ")]";
240     return str;
241   }
242
243 } // namespace zypp
244 ///////////////////////////////////////////////////////////////////