#-*- coding: utf-8 -*- # Copyright 2008-2013 Calculate Ltd. http://www.calculate-linux.org # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import sys import re import os import time import os from os import path from calculate.lib.cl_lang import setLocalTranslate setLocalTranslate('cl_lib3',sys.modules[__name__]) def getUUIDDict(revers=False,devs=[]): """Get dict UUID -> dev""" blkidProcess = process("/sbin/blkid","-s","UUID","-c","/dev/null",*devs) if revers: datafunc = lambda x,y: (y,x) else: datafunc = lambda x,y: (x,y) DEV,UUID = 0,1 reSplit = re.compile('^([^:]+):.*UUID="([^"]+)"',re.S) return dict( map(lambda x:datafunc("UUID=%s"%x[UUID], getUdevDeviceInfo(name=x[DEV]).get('DEVNAME',x[DEV])), map(lambda x:x.groups(), filter(lambda x:x, map(reSplit.search, blkidProcess))))) from files import (getProgPath,pathJoin,listDirectory, checkUtils,readFile,process) from common import getpathenv def detectDeviceForPartition(dev): """Detect parent device for partition by udev and return property""" prop = getUdevDeviceInfo(name=dev) if prop.get('DEVTYPE','') != 'partition': return '' parentpath = path.dirname(prop.get('DEVPATH','')) if parentpath: devProp = getUdevDeviceInfo(path=parentpath) return devProp.get('DEVNAME','') return None def countPartitions(devname): """Count partition for specified device""" syspath = getUdevDeviceInfo(name=devname).get('DEVPATH','') if not syspath: return 0 deviceName = path.basename(syspath) if not syspath.startswith("/sys"): syspath = pathJoin("/sys",syspath) return len(filter(lambda x:x.startswith(deviceName), listDirectory(syspath))) def getLvmGroups(): """Get LVM groups""" pvdisplayCmd = getProgPath('/sbin/pvdisplay') pvdata = process(pvdisplayCmd,"-C","-o", "vg_name","--noh") return filter(lambda x:x,pvdata.read().split()) def getLvmPartitions(vg_name,lv_name,cache=[]): """Get lvm partitions""" if not cache: pvdisplayCmd = getProgPath('/sbin/pvdisplay') pvdata = process(pvdisplayCmd,"-C","-o", "vg_name,lv_name,pv_name","--noh") if pvdata.success(): cache.extend( filter(lambda x:x and len(x)==3, map(lambda x:x.split(), pvdata.read().split('\n')))) if cache: res = map(lambda x:x[2], filter(lambda x:x[0]==vg_name and x[1]==lv_name,cache)) if res: return res return [] def getPartitionDevice(syspath): """Get real parent device by partition,lvm,mdraid""" prop = getUdevDeviceInfo(path=syspath) # real device if prop.get('ID_TYPE',"") == "disk" and \ prop.get('DEVTYPE',"") == "disk": return prop.get('DEVNAME',"") # partition if prop.get('DEVTYPE') == "partition": return getPartitionDevice(path.dirname(syspath)) # md raid if prop.get('MD_LEVEL',"").startswith("raid"): if not syspath.startswith('/sys'): syspath = pathJoin('/sys',syspath) syspath = pathJoin(syspath,"md") for rd in filter(lambda x:path.basename(x).startswith('rd'), listDirectory(syspath,fullPath=True)): rdBlockPath = path.join(rd,"block") if path.exists(rdBlockPath): return getPartitionDevice(path.realpath(rdBlockPath)) else: return "" # lvm if prop.get('DM_LV_NAME',"") != "": parts = getLvmPartitions(prop.get('DM_VG_NAME',''), prop.get('DM_LV_NAME','')) if parts: propPartLvm = getUdevDeviceInfo(name=parts[0]) if 'DEVPATH' in propPartLvm: return getPartitionDevice(propPartLvm['DEVPATH']) return "" def lspci(filtername=None,shortInfo=False): """Get hash of lspci, filtred by filtername. If shortInfo, then type,vendor and name get only first word pcidata(domain,bus,slot,func) 'type' 'vendor' 'name'""" reData = re.compile(r'(\S+)\s"([^"]+)"\s+"([^"]+)"\s+"([^"]+)"',re.S) if filtername: if hasattr(filtername,'__call__'): filterfunc = filtername else: filterfunc = lambda x: filtername in x else: filterfunc = lambda x:x if shortInfo: sfunc = lambda x:x.partition(" ")[0] else: sfunc = lambda x:x lspciProg = checkUtils('/usr/sbin/lspci') processLsPci = process(lspciProg,"-m") retData = {} for device in map(lambda x:x.groups(), filter(lambda x:x, map(reData.search, filter(filterfunc, processLsPci)))): retData[device[0]] = {'type':sfunc(device[1]),\ 'vendor':sfunc(device[2]),\ 'name':sfunc(device[3])} return retData class getUdevDeviceInfo: cache = {} udevadmCmd = "" def clearCache(self): self.cache = {} def __call__(self,path="",name=""): """Get device info by syspath of name""" typeQuery = "--name" if name else "--path" value = name or os.path.realpath(path) keyCache = "%s=%s"%(typeQuery,value) if not self.cache: refreshUdev(onlyTrigger=True) if not keyCache in self.cache: if not self.udevadmCmd: self.udevadmCmd = getProgPath('/sbin/udevadm') data = \ dict( filter(lambda x:x[0], map(lambda x:x.partition("=")[0::2], process(self.udevadmCmd,"info","--query","property", typeQuery,value).read().split("\n")))) tm = time.time() keyNameCache = data.get('DEVNAME','') keyPathCache = data.get('DEVPATH','') if keyNameCache: keyNameCache = "--name="+keyNameCache if keyPathCache: keyPathCache = "--path=/sys"+keyPathCache if "DEVNAME" in data and not keyNameCache in self.cache: self.cache[keyNameCache] = data if "DEVPATH" in data and not keyPathCache in self.cache: self.cache[keyPathCache] = data return data else: #print "fromCache",keyCache return self.cache[keyCache] getUdevDeviceInfo = getUdevDeviceInfo() def convertNameToSyspath(name): dev = getUdevDeviceInfo(name=name).get('DEVPATH',"") if dev and not dev.startswith('/sys'): dev = pathJoin('/sys',dev) return dev def humanreadableSize(size): """ Human readable size (1024 -> 1K and etc) """ try: size = int(size) except ValueError: return "" suffix = (((1024**0),"",False), ((1024**1),"K",False), ((1024**2),"M",False), ((1024**3),"G",True), ((1024**4),"T",True), ((1024**5),"P",True)) suffix = filter(lambda x:size >x[0],suffix) if suffix: suffix = suffix[-1] printSize = int(size / (float(suffix[0])/10)) printSizeTail = printSize % 10 printSize = printSize / 10 if suffix[2] and printSizeTail: return "%d.%d%s"%(printSize,printSizeTail,suffix[1]) else: return "%d%s"%(printSize,suffix[1]) return str(size) def getPartitionSize(syspath=None,name=None,inBytes=False): """ Get partition size """ if name: dev = convertNameToSyspath(name) else: dev = syspath SECTORSIZE=512 sizeFile = pathJoin(dev,"size") if path.exists(sizeFile): size = int(open(sizeFile,'r').read().strip())*SECTORSIZE if inBytes: return str(size) else: return humanreadableSize(size) return "" def getDeviceType(syspath=None,name=None): """Get device type (disk,partition,lvm,raid)""" if name: prop = getUdevDeviceInfo(name=name) syspath = prop.get('DEVPATH','') else: prop = getUdevDeviceInfo(path=syspath) # real device if prop.get('ID_CDROM',""): return "cdrom" if prop.get('ID_TYPE',"") == "disk" and \ prop.get('DEVTYPE',"") == "disk": return "disk" # partition if prop.get('DEVTYPE') == "partition": return getDeviceType(path.dirname(syspath))+"-partition" # md raid if prop.get('MD_LEVEL',"").startswith("raid"): if not syspath.startswith('/sys'): syspath = pathJoin('/sys',syspath) syspath = pathJoin(syspath,"md") for rd in filter(lambda x:path.basename(x).startswith('rd'), listDirectory(syspath,fullPath=True)): rdBlockPath = path.join(rd,"block") if path.exists(rdBlockPath): return getDeviceType(path.realpath(rdBlockPath))+"-raid" else: return "loop" # lvm if prop.get('DM_LV_NAME',"") != "": parts = getLvmPartitions(prop.get('DM_VG_NAME',''), prop.get('DM_LV_NAME','')) if parts: propPartLvm = getUdevDeviceInfo(name=parts[0]) if 'DEVPATH' in propPartLvm: return getDeviceType(propPartLvm['DEVPATH'])+"-lvm" return "loop" def getRaidPartitions(raidpath): """Get raid partitions""" prop = getUdevDeviceInfo(path=raidpath) raidParts = [] if prop.get('MD_LEVEL',"").startswith("raid"): if not raidpath.startswith('/sys'): raidpath = pathJoin('/sys',raidpath) raidpath = pathJoin(raidpath,"md") for rd in filter(lambda x:path.basename(x).startswith('rd'), listDirectory(raidpath,fullPath=True)): rdpath = path.join(raidpath,rd,"block") if path.exists(rdpath): raidParts.append( getUdevDeviceInfo(path=path.realpath(rdpath)).get( "DEVNAME",'')) return filter(lambda x:x,raidParts) def getPartitionType(prop): """Get type of dos part table (primary,extended or logical)""" if prop.get('ID_PART_ENTRY_SCHEME') == 'dos': partId = prop.get('ID_PART_ENTRY_TYPE','') partNumber = prop.get('ID_PART_ENTRY_NUMBER','') if partId and partNumber: if partId == "0x5": return "extended" elif int(partNumber)>4: return "logical" else: return "primary" return prop.get('ID_PART_TABLE_TYPE','') def detectBuild(pathname,dictInfo): """Detect build by root passwd 'root'""" shadowPath = pathJoin(pathname,'/etc/shadow') if r"root:$1$JMvNh5xg$VnV1DyJdTcwuZ0hp5YiJG0:14349:0:::::" in \ readFile(shadowPath): dictInfo['type'] = ' assemble' elif path.exists(pathJoin(pathname,"delta")) and \ path.exists(pathJoin(pathname,"workspace")): dictInfo['type'] = " builder" issue = readFile(pathJoin(pathname,'etc/gentoo-release')) if "Server" in issue: if "Scratch" in issue: dictInfo['name'] = "CSS" else: dictInfo['name'] = "CDS" elif "Desktop" in issue: if "XFCE" in issue: dictInfo['name'] = "CLDX" elif "KDE" in issue: dictInfo['name'] = "CLD" elif "GNOME" in issue: dictInfo['name'] = "CLDG" elif "Scratch" in issue: dictInfo['name'] = "CLS" else: dictInfo['type'] = '' return dictInfo def getOsProberHash(getContentFunc=None): """Get partition content by os-prober""" os_prober = getProgPath('/usr/bin/os-prober') if os_prober: DEV,LONG,SHORT,TYPE = 0,1,2,3 osProberList = \ map(lambda x:[getUdevDeviceInfo(name=x[DEV]).get('DEVNAME',''), x[LONG],x[SHORT],x[TYPE]], filter(lambda x:len(x)>=4, map(lambda x:x.split(":"), process(os_prober)))) for osRecord in osProberList: if "Gentoo" in osRecord[SHORT] and getContentFunc: osDescr = getContentFunc(osRecord[DEV],addFunc=detectBuild) if "name" in osDescr and "march" in osDescr and \ "build" in osDescr and "ver" in osDescr and \ (osDescr["ver"] != "0" or osDescr["build"]): if osDescr['build']: osDescr['build'] = "-%s"%osDescr['build'] else: osDescr['build'] = "-%s"%osDescr['ver'] osRecord[SHORT] = \ "{name}-{march}{build}{type}".format(**osDescr) else: osRecord[SHORT] = "Gentoo" elif "Gentoo" in osRecord[SHORT] and "Calculate" in osRecord[LONG]: osRecord[SHORT] = "Calculate" osProberHash = \ dict( map(lambda x:(x[DEV],x[SHORT]), osProberList)) else: osProberHash = {} return osProberHash def refreshLVM(): """Run command which refresh information about LVM""" vgscan = getProgPath('/sbin/vgscan') vgchange = getProgPath('/sbin/vgchange') lvchange = getProgPath('/sbin/lvchange') if vgscan and vgchange and lvchange: process(vgscan).success() process(vgchange,'-ay').success() process(vgchange,'--refresh').success() for group in getLvmGroups(): if not os.environ.get('EBUILD_PHASE'): process(lvchange,'-ay',group).success() process(lvchange,'--refresh',group).success() def loadEfiVars(): """ Load module with efivars """ modprobe = getProgPath('/sbin/modprobe') if not path.exists('/sys/firmware/efi') and modprobe: process(modprobe,'efivars').success() def refreshUdev(onlyTrigger=False): """Run command which refresh information about device in udev""" if not onlyTrigger: getUdevDeviceInfo.clearCache() udevadm = getProgPath('/bin/udevadm') if udevadm: blkidFile = '/etc/blkid.tab' try: if path.exists(blkidFile): os.unlink(blkidFile) except: pass if not os.environ.get('EBUILD_PHASE'): process(udevadm,"trigger","--subsystem-match","block").success() process(udevadm,"settle","--timeout=15").success() def getCommonDeviceName(dev): """ Get common device name (example: LVM -> /dev/dm- and etc) """ return getUdevDeviceInfo(name=dev).get('DEVNAME',dev)