00001
00002
00003
00004
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
00040
00041
00042 for_( mpit, result_r.rbegin(), result_r.rend() )
00043 {
00044
00045 DiskUsage::Entry entry = du_r.extract( mpit->dir );
00046
00047 mpit->pkg_size += entry._size;
00048 }
00049 }
00050
00051 inline void delDu( DiskUsageCounter::MountPointSet & result_r, DiskUsage & du_r )
00052 {
00053
00054
00055
00056 for_( mpit, result_r.rbegin(), result_r.rend() )
00057 {
00058
00059 DiskUsage::Entry entry = du_r.extract( mpit->dir );
00060
00061 mpit->pkg_size -= entry._size;
00062 }
00063 }
00064
00066 }
00068
00069 DiskUsageCounter::MountPointSet DiskUsageCounter::disk_usage( const ResPool & pool_r )
00070 {
00071 DiskUsageCounter::MountPointSet result = mps;
00072
00073 if ( result.empty() )
00074 {
00075
00076 return result;
00077 }
00078
00079
00080 for_( it, result.begin(), result.end() )
00081 {
00082 it->pkg_size = it->used_size;
00083 }
00084
00085
00086 for_( it, pool_r.begin(), pool_r.end() )
00087 {
00088 DiskUsage du( (*it)->diskusage() );
00089
00090
00091 if ( du.empty() )
00092 continue;
00093
00094
00095 if ( ! it->status().transacts() )
00096 continue;
00097
00098
00099 if ( it->status().isUninstalled() )
00100 {
00101
00102 addDu( result, du );
00103
00104
00105
00106
00107 if ( ! (*it)->installOnly() )
00108 {
00109
00110 for_( nit, pool_r.byNameBegin((*it)->name()), pool_r.byNameEnd((*it)->name()) )
00111 {
00112 if ( (*nit)->kind() == (*it)->kind()
00113 && nit->status().staysInstalled() )
00114 {
00115 DiskUsage ndu( (*nit)->diskusage() );
00116 if ( ! ndu.empty() )
00117 {
00118 delDu( result, ndu );
00119 }
00120 }
00121 }
00122 }
00123 }
00124 else
00125 {
00126
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;
00146
00147 while ( procmounts ) {
00148 std::string l = str::getline( procmounts );
00149 if ( !(procmounts.fail() || procmounts.bad()) ) {
00150
00151
00152
00153
00154
00155
00156
00157
00158
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
00170
00171 if ( words[0].find( '/' ) == std::string::npos ) {
00172 DBG << "Discard mount point : " << l << std::endl;
00173 continue;
00174 }
00175
00176
00177
00178
00179 std::string mp = words[1];
00180 if ( prfx.size() ) {
00181 if ( mp.compare( 0, prfx.size(), prfx ) != 0 ) {
00182
00183 DBG << "Unwanted mount point : " << l << std::endl;
00184 continue;
00185 }
00186
00187 mp.erase( 0, prfx.size() );
00188 if ( mp.empty() ) {
00189 mp = "/";
00190 } else if ( mp[0] != '/' ) {
00191
00192 DBG << "Unwanted mount point : " << l << std::endl;
00193 continue;
00194 }
00195 }
00196
00197
00198
00199
00200 if ( words[2] == "iso9660" ) {
00201 DBG << "Discard cdrom : " << l << std::endl;
00202 continue;
00203 }
00204
00205
00206
00207
00208 const char * mpunwanted[] = {
00209 "/mnt", "/media", "/mounts", "/floppy", "/cdrom",
00210 "/suse", "/var/tmp", "/var/adm/mount", "/var/adm/YaST",
00211 0
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
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
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
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 }