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