From owner-p4-projects@FreeBSD.ORG Sat Jun 9 23:19:32 2007 Return-Path: X-Original-To: p4-projects@freebsd.org Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id A2ED016A469; Sat, 9 Jun 2007 23:19:32 +0000 (UTC) X-Original-To: perforce@FreeBSD.org Delivered-To: perforce@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 7376616A421 for ; Sat, 9 Jun 2007 23:19:32 +0000 (UTC) (envelope-from ivoras@FreeBSD.org) Received: from repoman.freebsd.org (repoman.freebsd.org [69.147.83.41]) by mx1.freebsd.org (Postfix) with ESMTP id 6356C13C44C for ; Sat, 9 Jun 2007 23:19:32 +0000 (UTC) (envelope-from ivoras@FreeBSD.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.13.8/8.13.8) with ESMTP id l59NJWDD015875 for ; Sat, 9 Jun 2007 23:19:32 GMT (envelope-from ivoras@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.13.8/8.13.8/Submit) id l59NJWIW015863 for perforce@freebsd.org; Sat, 9 Jun 2007 23:19:32 GMT (envelope-from ivoras@FreeBSD.org) Date: Sat, 9 Jun 2007 23:19:32 GMT Message-Id: <200706092319.l59NJWIW015863@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to ivoras@FreeBSD.org using -f From: Ivan Voras To: Perforce Change Reviews Cc: Subject: PERFORCE change 121308 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 09 Jun 2007 23:19:33 -0000 http://perforce.freebsd.org/chv.cgi?CH=121308 Change 121308 by ivoras@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: