You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
427 lines
15 KiB
427 lines
15 KiB
#-*- 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)
|