]>
git.ipfire.org Git - people/ms/pakfire.git/blob - src/pakfire/system.py
2 ###############################################################################
4 # Pakfire - The IPFire package management system #
5 # Copyright (C) 2011 Pakfire development team #
7 # This program is free software: you can redistribute it and/or modify #
8 # it under the terms of the GNU General Public License as published by #
9 # the Free Software Foundation, either version 3 of the License, or #
10 # (at your option) any later version. #
12 # This program is distributed in the hope that it will be useful, #
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15 # GNU General Public License for more details. #
17 # You should have received a copy of the GNU General Public License #
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
20 ###############################################################################
22 from __future__
import division
24 import multiprocessing
36 Class that grants access to several information about
37 the system this software is running on.
41 hn
= socket
.gethostname()
43 # If a host has got no domain part, we add one.
45 hn
= "%s.localdomain" % hn
51 if not hasattr(self
, "_distro"):
52 self
._distro
= distro
.Distribution()
57 def native_arch(self
):
59 Return the native architecture of the host we
67 Return the architecture of the host we are running on.
69 if self
.supported_arches
and not self
.native_arch
in self
.supported_arches
:
70 return self
.supported_arches
[0]
72 return self
.native_arch
75 def supported_arches(self
):
77 Check what architectures can be built on this host.
80 # Host arch : Can build these arches.
83 "x86_64" : ["x86_64", "i686",],
87 "armv5tel" : ["armv5tel",],
88 "armv5tejl" : ["armv5tel",],
89 "armv6l" : ["armv5tel",],
90 "armv7l" : ["armv7hl", "armv5tel",],
91 "armv7hl" : ["armv7hl", "armv5tel",],
93 "aarch64" : ["aarch64", "armv7hl", "armv5tel"],
97 return host_can_build
[self
.native_arch
]
101 def host_supports_arch(self
, arch
):
103 Check if this host can build for the target architecture "arch".
105 return arch
in self
.supported_arches
110 Count the number of CPU cores.
112 return multiprocessing
.cpu_count()
114 def parse_cpuinfo(self
):
117 with
open("/proc/cpuinfo") as f
:
118 for line
in f
.readlines():
120 # Split the lines by colons.
121 a
, b
= line
.split(":")
135 cpuinfo
= self
.parse_cpuinfo()
137 ret
= cpuinfo
.get("model name", None)
139 # Some ARM platforms do not provide "model name", so we
143 ret
= "%(Hardware)s - %(Processor)s" % cpuinfo
147 # Remove too many spaces.
149 ret
= " ".join(ret
.split())
151 return ret
or _("Could not be determined")
154 def cpu_bogomips(self
):
155 cpuinfo
= self
.parse_cpuinfo()
157 for key
in ("bogomips", "BogoMIPS"):
158 bogomips
= cpuinfo
.get(key
, None)
163 return float(bogomips
) * self
.cpu_count
165 def get_loadavg(self
):
166 return os
.getloadavg()
170 return self
.get_loadavg()[0]
174 return self
.get_loadavg()[1]
178 return self
.get_loadavg()[2]
180 def has_overload(self
):
182 Checks, if the load average is not too high.
184 On this is to be decided if a new job is taken.
186 # If there are more than 2 processes in the process queue per CPU
187 # core we will assume that the system has heavy load and to not request
189 return self
.loadavg5
>= self
.cpu_count
* 2
191 def parse_meminfo(self
):
194 with
open("/proc/meminfo") as f
:
195 for line
in f
.readlines():
197 a
, b
, c
= line
.split()
200 a
= a
.replace(":", "")
210 def memory_total(self
):
211 meminfo
= self
.parse_meminfo()
213 return meminfo
.get("MemTotal", None)
216 memory
= memory_total
219 def memory_free(self
):
220 meminfo
= self
.parse_meminfo()
222 free
= meminfo
.get("MemFree", None)
224 buffers
= meminfo
.get("Buffers")
225 cached
= meminfo
.get("Cached")
227 return free
+ buffers
+ cached
230 def swap_total(self
):
231 meminfo
= self
.parse_meminfo()
233 return meminfo
.get("SwapTotal", None)
237 meminfo
= self
.parse_meminfo()
239 return meminfo
.get("SwapFree", None)
241 def get_mountpoint(self
, path
):
242 return Mountpoint(path
)
245 def parallelism(self
):
247 Calculates how many processes should be run
248 simulatneously when compiling.
250 # Check how many processes would fit into the
251 # memory when each process takes up to 192MB.
252 multiplicator
= self
.memory
/ (192 * 1024 * 1024)
253 multiplicator
= round(multiplicator
)
255 # Count the number of online CPU cores.
256 cpucount
= os
.sysconf("SC_NPROCESSORS_CONF") * 2
259 return min(multiplicator
, cpucount
)
262 # Create an instance of this class to only keep it once in memory.
265 class Mountpoints(object):
266 def __init__(self
, root
="/"):
267 self
._mountpoints
= []
269 # Scan for all mountpoints on the system.
273 return iter(self
._mountpoints
)
275 def _scan(self
, root
):
276 # Get the real path of root.
277 root
= os
.path
.realpath(root
)
279 # If root is not equal to /, we are in a chroot and
280 # our root must be a mountpoint to count files.
282 mp
= Mountpoint("/", root
=root
)
283 self
._mountpoints
.append(mp
)
285 f
= open("/proc/mounts")
287 for line
in f
.readlines():
290 # The mountpoint is the second argument.
293 # Skip all mountpoints that are not in our root directory.
294 if not mountpoint
.startswith(root
):
297 mountpoint
= os
.path
.relpath(mountpoint
, root
)
298 if mountpoint
== ".":
301 mountpoint
= os
.path
.join("/", mountpoint
)
303 mp
= Mountpoint(mountpoint
, root
=root
)
305 if not mp
in self
._mountpoints
:
306 self
._mountpoints
.append(mp
)
310 # Sort all mountpoints for better searching.
311 self
._mountpoints
.sort()
313 def add_pkg(self
, pkg
):
314 for file in pkg
.filelist
:
317 def rem_pkg(self
, pkg
):
318 for file in pkg
.filelist
:
322 for mp
in reversed(self
._mountpoints
):
323 # Check if the file is located on this mountpoint.
324 if not file.name
.startswith(mp
.path
):
327 # Add file to this mountpoint.
332 for mp
in reversed(self
._mountpoints
):
333 # Check if the file is located on this mountpoint.
334 if not file.name
.startswith(mp
.path
):
337 # Remove file from this mountpoint.
342 class Mountpoint(object):
343 def __init__(self
, path
, root
="/"):
347 # Cache the statvfs call of the mountpoint.
350 # Save the amount of data that is used or freed.
354 return "<%s %s>" % (self
.__class
__.__name
__, self
.fullpath
)
356 def __cmp__(self
, other
):
357 return cmp(self
.fullpath
, other
.fullpath
)
362 while path
.startswith("/"):
365 return os
.path
.join(self
.root
, path
)
369 if self
.__stat
is None:
370 # Find the next mountpoint, because we cannot
371 # statvfs any path in the FS.
372 path
= os
.path
.realpath(self
.fullpath
)
374 # Walk to root until we find a mountpoint.
375 while not os
.path
.ismount(path
):
376 path
= os
.path
.dirname(path
)
378 # See what we can get.
379 self
.__stat
= os
.statvfs(path
)
385 return self
.stat
.f_bavail
* self
.stat
.f_bsize
388 def space_needed(self
):
389 if self
.disk_usage
> 0:
390 return self
.disk_usage
395 def space_left(self
):
396 return self
.free
- self
.space_needed
399 assert file.name
.startswith(self
.path
)
401 # Round filesize to 4k blocks.
404 blocks
= file.size
// block_size
405 if file.size
% block_size
:
408 self
.disk_usage
+= blocks
* block_size
411 assert file.name
.startswith(self
.path
)
413 self
.disk_usage
-= file.size
415 def is_readonly(self
):
417 Returns True if the mountpoint is mounted read-only.
420 # Using the statvfs output does not really work, so we use
421 # a very naive approach here, were we just try to create a
422 # new file. If that works, it's writable.
425 handle
, path
= tempfile
.mkstemp(prefix
="ro-test-", dir=self
.fullpath
)
427 # Read-only file system.
431 # Raise all other exceptions.
434 # Close the file and remove it.
440 def remount(self
, rorw
=None):
442 if rorw
in ("ro", "rw"):
443 options
= "%s,%s" % (options
, rorw
)
446 shellenv
= shell
.ShellExecuteEnvironment(
447 ["mount", "-o", options
, self
.fullpath
],
451 except ShellEnvironmentError
, e
:
455 if __name__
== "__main__":
456 print "Hostname", system
.hostname
457 print "Arch", system
.arch
458 print "Supported arches", system
.supported_arches
460 print "CPU Model", system
.cpu_model
461 print "CPU count", system
.cpu_count
462 print "Memory", system
.memory