libzypp  11.13.5
DiskUsageCounter.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
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/DtorReset.h"
23 #include "zypp/base/String.h"
24 
25 #include "zypp/DiskUsageCounter.h"
26 #include "zypp/sat/Pool.h"
28 
29 using std::endl;
30 
32 namespace zypp
33 {
34 
36  namespace
37  {
38 
39  struct SatMap : private base::NonCopyable
40  {
41  SatMap()
42  {
43  ::map_init( &_installedmap, sat::Pool::instance().capacity() );
44  }
45 
46  void add( sat::Solvable solv_r )
47  {
48  MAPSET( &_installedmap, solv_r.id() );
49  }
50 
51  void add( const PoolItem & pi_r )
52  { add( pi_r->satSolvable() ); }
53 
54  void add( const ResObject::constPtr & obj_r )
55  { add( obj_r->satSolvable() ); }
56 
57  mutable ::Map _installedmap;
58  };
59 
60  DiskUsageCounter::MountPointSet calcDiskUsage( DiskUsageCounter::MountPointSet result, const SatMap & installedmap_r )
61  {
62  if ( result.empty() )
63  {
64  // partitioning is not set
65  return result;
66  }
67 
68  sat::Pool satpool( sat::Pool::instance() );
69 
70  // init libsolv result vector with mountpoints
71  static const ::DUChanges _initdu = { 0, 0, 0 };
72  std::vector< ::DUChanges> duchanges( result.size(), _initdu );
73  {
74  unsigned idx = 0;
75  for_( it, result.begin(), result.end() )
76  {
77  duchanges[idx].path = it->dir.c_str();
78  ++idx;
79  }
80  }
81 
82  // now calc...
83  ::pool_calc_duchanges( satpool.get(),
84  &installedmap_r._installedmap,
85  &duchanges[0],
86  duchanges.size() );
87 
88  // and process the result
89  {
90  unsigned idx = 0;
91  for_( it, result.begin(), result.end() )
92  {
93  static const ByteCount blockAdjust( 2, ByteCount::K ); // (files * blocksize) / (2 * 1K)
94  it->pkg_size = it->used_size // current usage
95  + duchanges[idx].kbytes // package data size
96  + ( duchanges[idx].files * it->block_size / blockAdjust ); // half block per file
97  ++idx;
98  }
99  }
100 
101  return result;
102  }
103 
105  } // namespace
107 
109  {
110  SatMap installedmap;
111  // build installedmap (installed != transact)
112  // stays installed or gets installed
113  for_( it, pool_r.begin(), pool_r.end() )
114  {
115  if ( it->status().isInstalled() != it->status().transacts() )
116  {
117  installedmap.add( *it );
118  }
119  }
120  return calcDiskUsage( mps, installedmap );
121  }
122 
124  {
125  SatMap installedmap;
126  installedmap.add( solv_r );
127 
128  // temp. unset @system Repo
129  DtorReset tmp( sat::Pool::instance().get()->installed );
130  sat::Pool::instance().get()->installed = nullptr;
131 
132  return calcDiskUsage( mps, installedmap );
133  }
134 
136  {
138 
139  std::ifstream procmounts( "/proc/mounts" );
140 
141  if ( !procmounts ) {
142  WAR << "Unable to read /proc/mounts" << std::endl;
143  } else {
144 
145  std::string prfx;
146  if ( rootdir != "/" )
147  prfx = rootdir; // rootdir not /
148 
149  while ( procmounts ) {
150  std::string l = str::getline( procmounts );
151  if ( !(procmounts.fail() || procmounts.bad()) ) {
152  // data to consume
153 
154  // rootfs / rootfs rw 0 0
155  // /dev/root / reiserfs rw 0 0
156  // proc /proc proc rw 0 0
157  // devpts /dev/pts devpts rw 0 0
158  // /dev/hda5 /boot ext2 rw 0 0
159  // shmfs /dev/shm shm rw 0 0
160  // usbdevfs /proc/bus/usb usbdevfs rw 0 0
161 
162  std::vector<std::string> words;
163  str::split( l, std::back_inserter(words) );
164 
165  if ( words.size() < 3 ) {
166  WAR << "Suspicious entry in /proc/mounts: " << l << std::endl;
167  continue;
168  }
169 
170  //
171  // Filter devices without '/' (proc,shmfs,..)
172  //
173  if ( words[0].find( '/' ) == std::string::npos ) {
174  DBG << "Discard mount point : " << l << std::endl;
175  continue;
176  }
177 
178  // remove /proc entry
179  if (words[0] == "/proc")
180  {
181  DBG << "Discard /proc filesystem: " << l << std::endl;
182  continue;
183  }
184 
185  //
186  // Filter mountpoints not at or below _rootdir
187  //
188  std::string mp = words[1];
189  if ( prfx.size() ) {
190  if ( mp.compare( 0, prfx.size(), prfx ) != 0 ) {
191  // mountpoint not below rootdir
192  DBG << "Unwanted mount point : " << l << std::endl;
193  continue;
194  }
195  // strip prfx
196  mp.erase( 0, prfx.size() );
197  if ( mp.empty() ) {
198  mp = "/";
199  } else if ( mp[0] != '/' ) {
200  // mountpoint not below rootdir
201  DBG << "Unwanted mount point : " << l << std::endl;
202  continue;
203  }
204  }
205 
206  //
207  // Filter cdrom
208  //
209  if ( words[2] == "iso9660" ) {
210  DBG << "Discard cdrom : " << l << std::endl;
211  continue;
212  }
213 
214  if ( words[2] == "vfat" || words[2] == "fat" || words[2] == "ntfs" || words[2] == "ntfs-3g")
215  {
216  MIL << words[1] << " contains ignored fs (" << words[2] << ')' << std::endl;
217  continue;
218  }
219 
220  //
221  // Filter some common unwanted mountpoints
222  //
223  const char * mpunwanted[] = {
224  "/mnt", "/media", "/mounts", "/floppy", "/cdrom",
225  "/suse", "/var/tmp", "/var/adm/mount", "/var/adm/YaST",
226  /*last*/0/*entry*/
227  };
228 
229  const char ** nomp = mpunwanted;
230  for ( ; *nomp; ++nomp ) {
231  std::string pre( *nomp );
232  if ( mp.compare( 0, pre.size(), pre ) == 0 // mp has prefix pre
233  && ( mp.size() == pre.size() || mp[pre.size()] == '/' ) ) {
234  break;
235  }
236  }
237  if ( *nomp ) {
238  DBG << "Filter mount point : " << l << std::endl;
239  continue;
240  }
241 
242  //
243  // Check whether mounted readonly
244  //
245  bool ro = false;
246  std::vector<std::string> flags;
247  str::split( words[3], std::back_inserter(flags), "," );
248 
249  for ( unsigned i = 0; i < flags.size(); ++i ) {
250  if ( flags[i] == "ro" ) {
251  ro = true;
252  break;
253  }
254  }
255  if ( ro ) {
256  DBG << "Filter ro mount point : " << l << std::endl;
257  continue;
258  }
259 
260  //
261  // statvfs (full path!) and get the data
262  //
263  struct statvfs sb;
264  if ( statvfs( words[1].c_str(), &sb ) != 0 ) {
265  WAR << "Unable to statvfs(" << words[1] << "); errno " << errno << std::endl;
266  ret.insert( DiskUsageCounter::MountPoint( mp ) );
267  }
268  else
269  {
270  //
271  // Filter zero sized devices (bnc#769819)
272  //
273  if ( sb.f_blocks == 0 || sb.f_bsize == 0 )
274  {
275  DBG << "Filter zero-sized mount point : " << l << std::endl;
276  continue;
277  }
278  ret.insert( DiskUsageCounter::MountPoint( mp, sb.f_bsize,
279  ((long long)sb.f_blocks)*sb.f_bsize/1024,
280  ((long long)(sb.f_blocks - sb.f_bfree))*sb.f_bsize/1024, 0LL, ro ) );
281  }
282  }
283  }
284  }
285 
286  return ret;
287  }
288 
290  {
292  ret.insert( DiskUsageCounter::MountPoint() );
293  return ret;
294  }
295 
296  std::ostream & operator<<( std::ostream & str, const DiskUsageCounter::MountPoint & obj )
297  {
298  str << "dir:[" << obj.dir << "] [ bs: " << obj.blockSize()
299  << " ts: " << obj.totalSize()
300  << " us: " << obj.usedSize()
301  << " (+-: " << obj.commitDiff()
302  << ")]";
303  return str;
304  }
305 
307 } // namespace zypp