summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy Grover <andy@groveronline.com>2015-12-11 10:59:34 -0800
committerAndy Grover <andy@groveronline.com>2015-12-11 10:59:34 -0800
commitd2de7ae9d97d67522a17d4835391cf12c1d6b274 (patch)
treef7d4451742ec674b5ad4d5595fe4a2485a664132
parent690d1905066e4e880891496648d5f42befa707bb (diff)
parentba2badbc40aa1798ee667b6b4b31f5733b50611a (diff)
downloadrtslib-fb-d2de7ae9d97d67522a17d4835391cf12c1d6b274.tar.gz
Merge pull request #67 from mulkieran/master-pyudev-maybe
Make use of pyudev package as much as possible in utils module.
-rw-r--r--rtslib/utils.py117
1 files changed, 77 insertions, 40 deletions
diff --git a/rtslib/utils.py b/rtslib/utils.py
index 4cee7a5..e5f1c4d 100644
--- a/rtslib/utils.py
+++ b/rtslib/utils.py
@@ -27,6 +27,10 @@ import subprocess
import uuid
from contextlib import contextmanager
+import pyudev
+
+_CONTEXT = pyudev.Context()
+
class RTSLibError(Exception):
'''
Generic rtslib error.
@@ -111,22 +115,36 @@ def is_dev_in_use(path):
os.close(file_fd)
return False
+def _get_size_for_dev(device):
+ '''
+ @param device: the device
+ @type device: pyudev.Device
+ @return: the size in logical blocks, 0 if none found
+ @rtype: int
+ '''
+ attributes = device.attributes
+ try:
+ sect_size = attributes.asint('size')
+ except (KeyError, UnicodeDecodeError, ValueError):
+ return 0
+
+ try:
+ logical_block_size = attributes.asint('queue/logical_block_size')
+ except (KeyError, UnicodeDecodeError, ValueError):
+ return 0
+
+ return (sect_size * 512) // logical_block_size
+
def get_size_for_blk_dev(path):
'''
@param path: The path to a block device
@type path: string
@return: The size in logical blocks of the device
+ @raises: DeviceNotFoundError if corresponding device not found
+ @raises: EnvironmentError, ValueError in some situations
'''
- path = os.path.realpath(str(path))
- rdev = os.lstat(path).st_rdev
- maj, min = os.major(rdev), os.minor(rdev)
-
- for line in list(open("/proc/partitions"))[2:]:
- xmaj, xmin, size, name = line.split()
- if (maj, min) == (int(xmaj), int(xmin)):
- return get_size_for_disk_name(name)
- else:
- return 0
+ device = Device.from_device_file(_CONTEXT, os.path.realpath(str(path)))
+ return _get_size_for_dev(device)
get_block_size = get_size_for_blk_dev
@@ -135,23 +153,26 @@ def get_size_for_disk_name(name):
@param name: a kernel disk name, as found in /proc/partitions
@type name: string
@return: The size in logical blocks of a disk-type block device.
+ @raises: DeviceNotFoundError
'''
# size is in 512-byte sectors, we want to return number of logical blocks
- def get_size(path, is_partition=False):
- sect_size = int(fread("%s/size" % path))
- if is_partition:
- path = os.path.split(path)[0]
- logical_block_size = int(fread("%s/queue/logical_block_size" % path))
- return sect_size / (logical_block_size / 512)
+ def get_size(name):
+ """
+ :param str name: name of block device
+ :raises DeviceNotFoundError: if device not found
+ """
+ device = pyudev.Device.from_name(_CONTEXT, 'block', name)
+ return _get_size_for_dev(device)
# Disk names can include '/' (e.g. 'cciss/c0d0') but these are changed to
# '!' when listed in /sys/block.
+ # in pyudev 0.19 it should no longer be necessary to swap '/'s in name
name = name.replace("/", "!")
try:
- return get_size("/sys/block/%s" % name)
- except IOError:
+ return get_size(name)
+ except pyudev.DeviceNotFoundError:
# Maybe it's a partition?
m = re.search(r'^([a-z0-9_\-!]+?)(\d+)$', name)
if m:
@@ -160,7 +181,7 @@ def get_size_for_disk_name(name):
disk = m.groups()[0]
if disk[-1] == 'p' and disk[-2].isdigit():
disk = disk[:-1]
- return get_size("/sys/block/%s/%s" % (disk, m.group()), True)
+ return get_size(m.group())
else:
raise
@@ -184,26 +205,41 @@ def get_blockdev_type(path):
@type path: string
@return: An int for the block device type, or None if not a block device.
'''
- dev = os.path.realpath(path)
-
- # is dev a block device?
try:
- mode = os.stat(dev)
- except OSError:
+ device = pyudev.Device.from_device_file(_CONTEXT, path)
+ except (pyudev.DeviceNotFoundError, EnvironmentError, ValueError):
return None
- if not stat.S_ISBLK(mode[stat.ST_MODE]):
+ if device.subsystem != u'block':
return None
- # assume disk if device/type is missing
- disk_type = 0
- with ignored(IOError):
- disk_type = int(fread("/sys/block/%s/device/type" % os.path.basename(dev)))
+ attributes = device.attributes
+ disk_type = 0
+ try:
+ disk_type = attributes.asint('device/type')
+ except (KeyError, UnicodeDecodeError, ValueError):
+ pass
return disk_type
get_block_type = get_blockdev_type
+def _hctl_from_dev(device):
+ '''
+ @param device: the device
+ @type device: pyudev.Device
+ @returns: H:C:T:L specifier or None if not found
+ @rtype: list of int * 4 or NoneType
+ '''
+ parent = device.parent
+ if parent is None or parent.subsystem != 'scsi':
+ return None
+
+ try:
+ return [int(data) for data in parent.sys_name.split(':')]
+ except (ValueError, TypeError):
+ return None
+
def convert_scsi_path_to_hctl(path):
'''
This function returns the SCSI ID in H:C:T:L form for the block
@@ -229,14 +265,11 @@ def convert_scsi_path_to_hctl(path):
values representing the SCSI ID of the device, or None if no
match is found.
'''
- devname = os.path.basename(os.path.realpath(path))
try:
- hctl = os.listdir("/sys/block/%s/device/scsi_device"
- % devname)[0].split(':')
- except:
+ device = pyudev.Device.from_device_file(context, os.path.realpath(path))
+ except (pyudev.DeviceNotFoundError, EnvironmentError, ValueError):
return None
-
- return [int(data) for data in hctl]
+ return _hctl_from_dev(device)
def convert_scsi_hctl_to_path(host, controller, target, lun):
'''
@@ -270,11 +303,15 @@ def convert_scsi_hctl_to_path(host, controller, target, lun):
raise RTSLibError(
"The host, controller, target and lun parameter must be integers")
- for devname in os.listdir("/sys/block"):
- path = "/dev/%s" % devname
- hctl = [host, controller, target, lun]
- if convert_scsi_path_to_hctl(path) == hctl:
- return os.path.realpath(path)
+ hctl = [host, controller, target, lun]
+ try:
+ scsi_device = pyudev.Device.from_name(_CONTEXT, 'scsi', ':'.join(hctl))
+ except DeviceNotFoundError:
+ return ''
+
+ for device in context.list_devices(subsystem='block'):
+ if device.parent == scsi_device:
+ return device.device_node
return ''
def generate_wwn(wwn_type):