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.
calculate-utils-3-lib/pym/calculate/lib/utils/device.py

388 lines
13 KiB

# -*- coding: utf-8 -*-
# Copyright 2008-2016 Mir Calculate. 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
from os import path
from calculate.lib.cl_lang import setLocalTranslate
setLocalTranslate('cl_lib3', sys.modules[__name__])
# используется для кэша функции getLvmPartitions()
_lvm_partitions_cache = []
def getUUIDDict(revers=False, devs=()):
"""Get dict UUID -> dev"""
blkidProcess = process("/sbin/blkid", "-s", "UUID", "-c", "/dev/null",
*list(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, process)
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=None):
"""Get lvm partitions"""
if cache is None:
cache = _lvm_partitions_cache
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"""
if not syspath.startswith('/sys'):
syspath = pathJoin('/sys', syspath)
prop = getUdevDeviceInfo(path=syspath)
# real device
if (prop.get('DEVTYPE', "") == "disk" and
(prop.get('ID_TYPE', "") == "disk" or
path.exists(path.join(syspath, "device")))):
return prop.get('DEVNAME', "")
# partition
if prop.get('DEVTYPE') == "partition":
return getPartitionDevice(path.dirname(syspath))
# md raid
if prop.get('MD_LEVEL', "").startswith("raid"):
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(object):
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 keyCache not 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"))))
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 /= 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 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 OSError:
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)