PERFORCE change 121308 for review
Ivan Voras
ivoras at FreeBSD.org
Sat Jun 9 23:19:33 UTC 2007
http://perforce.freebsd.org/chv.cgi?CH=121308
Change 121308 by ivoras at ivoras_finstall on 2007/06/09 23:18:36
Implemented GetDrivePartitions function and supporting infrastructure
Affected files ...
.. //depot/projects/soc2007/ivoras_finstall/pybackend/conffile.py#3 edit
.. //depot/projects/soc2007/ivoras_finstall/pybackend/freebsd.py#4 edit
.. //depot/projects/soc2007/ivoras_finstall/pybackend/globals.py#4 edit
.. //depot/projects/soc2007/ivoras_finstall/pybackend/systoold.py#5 edit
.. //depot/projects/soc2007/ivoras_finstall/pybackend/systoolengine.py#5 edit
.. //depot/projects/soc2007/ivoras_finstall/pybackend/testtool/st.py#3 edit
.. //depot/projects/soc2007/ivoras_finstall/pybackend/xmldict.py#4 edit
Differences ...
==== //depot/projects/soc2007/ivoras_finstall/pybackend/conffile.py#3 (text+ko) ====
==== //depot/projects/soc2007/ivoras_finstall/pybackend/freebsd.py#4 (text+ko) ====
@@ -27,9 +27,11 @@
cmd_sysctl = "/sbin/sysctl"
cmd_geom = "/sbin/geom"
cmd_mount = "/sbin/mount"
+cmd_file = "/usr/bin/file -s"
file_dmesg = "/var/run/dmesg.boot"
+
def get_sysctl(name):
global cmd_sysctl
str = os.popen("%s -b %s" % (cmd_sysctl, name)).read().strip()
@@ -37,16 +39,47 @@
str = str[:-1]
return str
+
def get_cmd_output(name):
return os.popen(name).read().strip()
+
def get_dmesg():
global file_dmesg
return [x.strip() for x in file(file_dmesg, "r").readlines()]
+
def get_geom_xml():
return xmldict.buildxmldict(get_sysctl("kern.geom.confxml"))
+
+def guess_fs_type(dev):
+ """Try to guess what file system is on the given device."""
+ global cmd_file
+ if not dev.startswith("/dev/"):
+ dev = "/dev/%s" % dev
+ guess = get_cmd_output("%s %s" % (cmd_file, dev))
+ if guess.find("FAT (32 bit)") != -1:
+ return "FAT32"
+ elif guess.find("FAT") != -1:
+ return "FAT"
+ elif guess.find("NTFS") != -1:
+ return "NTFS"
+ elif guess.find("ext2") != -1:
+ return "ext2"
+ elif guess.find("ext3") != -1:
+ return "ext3"
+ elif guess.find("XFS") != -1:
+ return "XFS"
+ elif guess.find("ReiserFS") != -1:
+ return "ReiserFS"
+ elif guess.find("Unix Fast File system v2") != -1:
+ return "UFS2"
+ elif guess.find("Unix Fast File system") != -1:
+ return "UFS"
+ return "(unknown)"
+
+
if __name__ == "__main__":
xml = get_geom_xml()
for cls in xml["mesh"]["class"]:
==== //depot/projects/soc2007/ivoras_finstall/pybackend/globals.py#4 (text+ko) ====
@@ -34,12 +34,12 @@
# "rcconf" : Low-level functions that alter /etc/rc.conf:
# GetConf, SetConf
# "disk" : Low-level drive & file system functions:
-# GetDrives, GetMountPoints, Mount
+# GetDrives, GetDrivePartitions, GetMountPoints, Mount
# These functions are implemented in systoolengine.py
server_caps = ["systoold", "rcconf", "disk"]
# debug level. 0 = no debug
-debug_level = 0
+debug_level = 1
# if exit_syslogd becomes True, the TCP accept loop will exit
exit_systoold = False
==== //depot/projects/soc2007/ivoras_finstall/pybackend/systoold.py#5 (text+ko) ====
@@ -28,11 +28,13 @@
import os,sys
from getopt import getopt, GetoptError
from select import select
+import logging
from SimpleXMLRPCServer import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler
import globals
from systoolengine import SysToolEngine
+logging.basicConfig(level=logging.DEBUG)
bind_port = 1025
bind_host = "localhost"
@@ -75,6 +77,7 @@
server.register_function(ToUpper)
server.register_instance(engine)
+logging.info("SysToolD started")
while not globals.exit_systoold:
try:
r,w,e = select([server.fileno()], [], [], 100)
==== //depot/projects/soc2007/ivoras_finstall/pybackend/systoolengine.py#5 (text+ko) ====
@@ -22,12 +22,35 @@
# SysToolD Engine
import os, sys
+import re
+import logging
import globals
import freebsd
from conffile import ConfFile
+def logexception(func):
+ """Method call decorator that routes exceptions to the logger
+ before passing them on"""
+ def call(*args, **kwds):
+ try:
+ return func(*args, **kwds)
+ except:
+ logging.exception("Exception!")
+ raise
+ return call
+
+
+def tolist(e):
+ """Coalesce argument to list (if the argument is not list,
+ wrap it in a list of one element)."""
+ if type(e) == type([]):
+ return e
+ else:
+ return [e]
+
+
class SysToolEngine:
@@ -73,11 +96,21 @@
return True
+ @logexception
def GetDrives(self):
- """Returns an array of drives the kernel knows about.
+ """Returns information on drives the kernel knows about.
Examines "kern.drives" sysctl. This is NOT the list of
valid GEOM leaves which can be mounted, but a list of
- found hardware."""
+ found hardware.
+ RETURN VALUE:
+ The return value is a dictionary with device names
+ as keys and another dictionary as values.
+ {
+ "ad0" : {
+ "name": "ACME MegaDrive"
+ "mediasize": 300000 # (MB)
+ }
+ }"""
drive_list = freebsd.get_sysctl("kern.disks").split(" ")
dmesg = freebsd.get_dmesg()
drive_dict = {}
@@ -100,13 +133,85 @@
geomxml = freebsd.get_geom_xml()
for cls in geomxml["mesh"]["class"]:
if cls["name"].data == "DISK":
- for geom in cls["geom"]:
+ for geom in tolist(cls["geom"]):
dev_name = geom["name"].data
if dev_name in drive_dict:
drive_dict[dev_name]["mediasize"] = int(geom["provider"]["mediasize"].data) / (1024*1024) # in MB, since XML-RPC doesn't have int64
+ # do some prettyfying of device name strings
+ for drvid in drive_dict:
+ m = re.match(r"(^\d+MB)\s*(.+)", drive_dict[drvid]["name"])
+ if m != None:
+ drive_dict[drvid]["name"] = m.group(2)
return drive_dict
+ @logexception
+ def GetDrivePartitions(self, drive):
+ """Returns a list of leaf partitions created on the drive.
+ ARGUMENTS:
+ drive : The drive to inspect
+ RETURN VALUE:
+ The return value is a list of dictionaries."""
+ parts = {}
+ used_parts = []
+ geomxml = freebsd.get_geom_xml()
+ num_msdos_parts = 1
+ # enumerate MSDOS partitions
+ for cls in geomxml["mesh"]["class"]:
+ if cls["name"].data == "MBR":
+ for geom in tolist(cls["geom"]):
+ if geom["name"].data == drive:
+ for prov in tolist(geom["provider"]):
+ part = {
+ "name" : prov["name"].data,
+ "mediasize" : int(prov["mediasize"].data) / (1024*1024),
+ "sectorsize" : int(prov["sectorsize"].data),
+ "type" : "MBR"
+ }
+ parts[part["name"]] = part
+ num_msdos_parts += 1
+ # process BSDlabels, both dedicated and inside MSDOS partitions
+ for cls in geomxml["mesh"]["class"]:
+ if cls["name"].data == "BSD":
+ for geom in tolist(cls["geom"]):
+ if geom["name"].data == drive:
+ # "raw" BSD partitions directly on the drive
+ # this is not exactly possible if the drive also has MSDOS partitions on it :)
+ if num_msdos_parts != 0:
+ logging.error("The impossible has happened: drive has both MSDOS and BSD partitions directly on it")
+ continue
+ for prov in tolist(gerom["provider"]):
+ part = {
+ "name" : prov["name"].data,
+ "mediasize" : int(prov["mediasize"].data) / (1024*1024),
+ "sectorsize" : int(prov["sectorsize"].data),
+ "type" : "BSD"
+ }
+ parts[part["name"]] = part
+ if geom["name"].data in parts:
+ # bsdlabel hosted inside MSDOS partition
+ used_parts.append(geom["name"].data)
+ for prov in tolist(geom["provider"]):
+ part = {
+ "name" : prov["name"].data,
+ "mediasize" : int(prov["mediasize"].data) / (1024*1024),
+ "sectorsize" : int(prov["sectorsize"].data),
+ "type" : "BSD"
+ }
+ parts[part["name"]] = part
+ # TODO: also process GPT records
+ # Remove partitions that have been used to host other partitions from the list
+ for part in used_parts:
+ del parts[part]
+ # Try to divine file system types for the partitions
+ for part in parts:
+ parts[part]["fs_type"] = freebsd.guess_fs_type(part)
+
+ return parts
+
+
+
+
def GetMountPoints(self):
"""Returns a list of dictionaries containing information
about currently mounted file systems"""
==== //depot/projects/soc2007/ivoras_finstall/pybackend/testtool/st.py#3 (text+ko) ====
@@ -31,4 +31,12 @@
print "This is a bogus server"
sys.exit(1)
-print server.GetDrives()
+print "Connection ok"
+
+drives = server.GetDrives()
+for drive in drives:
+ print drive
+ print server.GetDrivePartitions(drive)
+
+print server.GetMountPoints()
+
==== //depot/projects/soc2007/ivoras_finstall/pybackend/xmldict.py#4 (text+ko) ====
@@ -121,7 +121,7 @@
if type(self.data) == type(''):
self.data = self.data.decode(fromencoding, 'replace')
for a in self.attrs:
- if type(self.attrs[a] == type('')):
+ if type(self.attrs[a]) == type(''):
self.attrs[a] = self.attrs[a].decode(fromencoding, 'replace')
if recurse:
for k in self.d:
More information about the p4-projects
mailing list