]>
git.ipfire.org Git - oddments/fireinfo.git/blob - fireinfo/system.py
2 ###############################################################################
5 # Copyright (C) 2010, 2011 IPFire Team (www.ipfire.org) #
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 ###############################################################################
36 SYS_CLASS_DMI
= "/sys/class/dmi/id"
37 SECRET_ID_FILE
= "/etc/fireinfo-id"
39 INVALID_ID_STRINGS
= (
40 "OEM", "O.E.M.", "o.e.m.",
42 "12345", "54321", "202020",
44 "00020003-0004-0005-0006-000700080009",
48 class Singleton(type):
49 def __init__(cls
, name
, bases
, dict):
50 super(Singleton
, cls
).__init
__(name
, bases
, dict)
53 def __call__(cls
, *args
, **kw
):
54 if cls
.instance
is None:
55 cls
.instance
= super(Singleton
, cls
).__call
__(*args
, **kw
)
60 def read_from_file(filename
):
62 Read all data from filename.
64 if not os
.path
.exists(filename
):
68 with
open(filename
) as f
:
69 return f
.read().strip()
74 __metaclass__
= Singleton
81 self
.hypervisor
= hypervisor
.Hypervisor()
88 "vendor" : self
.vendor
,
90 # Indicator if the system is running in a
91 # virtual environment.
92 "virtual" : self
.virtual
,
95 "language" : self
.language
,
98 "release" : self
.release
,
99 "kernel_release" : self
.kernel_release
,
101 "memory" : self
.memory
,
102 "root_size" : self
.root_size
,
106 for device
in self
.devices
:
108 "subsystem" : device
.subsystem
.lower(),
109 "vendor" : device
.vendor
.lower(),
110 "model" : device
.model
.lower(),
111 "deviceclass" : device
.deviceclass
,
112 "driver" : device
.driver
,
115 # PCI devices provide subsystem information, USB don't.
116 if d
["subsystem"] == "pci":
117 d
["sub_model"] = device
.sub_model
118 d
["sub_vendor"] = device
.sub_vendor
120 p
["devices"].append(d
)
124 "vendor" : self
.cpu
.vendor
,
125 "model" : self
.cpu
.model
,
126 "model_string" : self
.cpu
.model_string
,
127 "stepping" : self
.cpu
.stepping
,
128 "flags" : self
.cpu
.flags
,
129 "bogomips" : self
.cpu
.bogomips
,
130 "speed" : self
.cpu
.speed
,
131 "family" : self
.cpu
.family
,
132 "count" : self
.cpu
.count
136 "green" : self
.network
.has_green(),
137 "blue" : self
.network
.has_blue(),
138 "orange" : self
.network
.has_orange(),
139 "red" : self
.network
.has_red(),
142 # Only append hypervisor information if we are virtualized.
145 "type" : self
.hypervisor
.type,
146 "vendor" : self
.hypervisor
.vendor
,
151 "profile_version" : PROFILE_VERSION
,
153 # Identification and authorization codes
154 "public_id" : self
.public_id
,
155 "private_id" : self
.private_id
,
157 # Actual profile data
169 This returns a globally (hopefully) ID to identify the host
170 later (by request) in the database.
172 public_id
= self
.secret_id
176 return hashlib
.sha1(public_id
).hexdigest()
179 def private_id(self
):
181 The private ID is built out of the _unique_id and used to
182 permit a host to do changes on the database.
184 No one could ever guess this without access to the host.
187 for i
in reversed(self
.secret_id
):
193 return hashlib
.sha1(private_id
).hexdigest()
198 Read a "secret" ID from a file if available
199 or calculate it from the hardware.
201 if os
.path
.exists(SECRET_ID_FILE
):
202 return read_from_file(SECRET_ID_FILE
)
204 return hashlib
.sha1(self
._unique
_id
).hexdigest()
207 def _unique_id(self
):
209 This is a helper ID which is generated out of some hardware information
210 that is considered to be constant over a PC's lifetime.
212 None of the data here is ever sent to the server.
216 # Virtual machines (for example) and some boards have a UUID
217 # which is globally unique.
218 for file in ("product_uuid", "product_serial", "chassis_serial"):
219 id = read_from_file(os
.path
.join(SYS_CLASS_DMI
, file))
222 # Sort out all bogous or invalid strings from the list.
228 for i
in INVALID_ID_STRINGS
:
238 # Use serial number from root disk (if available) and if
239 # no other ID was found, yet.
241 root_disk_serial
= self
.root_disk_serial
242 if root_disk_serial
and not root_disk_serial
.startswith("QM000"):
243 ids
.append(root_disk_serial
)
245 # As last resort, we use the UUID from pakfire.
247 id = read_from_file("/opt/pakfire/db/uuid")
255 Return the language code of IPFire or "unknown" if we cannot get it.
257 # Return "unknown" if settings file does not exist.
258 filename
= "/var/ipfire/main/settings"
259 if not os
.path
.exists(filename
):
262 with
open(filename
, "r") as f
:
263 for line
in f
.readlines():
264 key
, val
= line
.split("=", 1)
265 if key
== "LANGUAGE":
271 Return the system release string.
273 return read_from_file("/etc/system-release")
276 def bios_vendor(self
):
278 Return the bios vendor name.
280 return read_from_file("/sys/class/dmi/id/bios_vendor")
285 Return the vendor string of this system (if any).
288 for file in ("sys_vendor", "board_vendor", "chassis_vendor",):
289 ret
= read_from_file(os
.path
.join(SYS_CLASS_DMI
, file))
298 Return the model string of this system (if any).
301 for file in ("product_name", "board_model", "chassis_model",):
302 ret
= read_from_file(os
.path
.join(SYS_CLASS_DMI
, file))
311 Return the amount of memory in kilobytes.
313 with
open("/proc/meminfo", "r") as f
:
314 firstline
= f
.readline().strip()
315 return int(firstline
.split()[1])
318 def kernel_release(self
):
320 Return the kernel release string.
327 Return the dev node of the root disk.
329 with
open("/etc/mtab", "r") as f
:
330 dev
, mountpoint
, rest
= f
.readline().split(" ", 2)
331 if mountpoint
== "/":
334 # Cut off all digits at end of string
335 while dev
[-1] in string
.digits
:
343 Return the size of the root disk in kilobytes.
345 path
= "/sys/block/%s/size" % self
.root_disk
346 if not os
.path
.exists(path
):
349 with
open(path
, "r") as f
:
350 return int(f
.readline()) * 512 / 1024
353 def root_disk_serial(self
):
355 Return the serial number of the root disk (if any).
357 serial
= _fireinfo
.get_harddisk_serial("/dev/%s" % self
.root_disk
)
361 return serial
.strip()
365 Scan for all devices (PCI/USB) in the system and append them
371 ("/sys/bus/pci/devices", device
.PCIDevice
),
372 ("/sys/bus/usb/devices", device
.USBDevice
)
374 for path
, cls
in toscan
:
375 if not os
.path
.exists(path
):
378 dirlist
= os
.listdir(path
)
380 self
.devices
.append(cls(os
.path
.join(path
, dir)))
385 Say if the host is running in a virtual environment.
387 return self
.hypervisor
.virtual
392 Reference to the network class.
394 return network
.Network()
397 if __name__
== "__main__":
407 print "------------\n", s
.devices
, "\n------------\n"
408 print json
.dumps(s
.profile(), sort_keys
=True, indent
=4)