Skip to content

Instantly share code, notes, and snippets.

@leecardona
Created August 31, 2017 01:15
Show Gist options
  • Save leecardona/583d7137d8b6b9a7aead28091ed9fca9 to your computer and use it in GitHub Desktop.
Save leecardona/583d7137d8b6b9a7aead28091ed9fca9 to your computer and use it in GitHub Desktop.
#Copyright (C) 2014 Marc Herndon
#
#This program is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public License,
#version 2, as published by the Free Software Foundation.
#
#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License
#along with this program; if not, write to the Free Software
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
"""
This module contains the definition of the `DeviceList` class, used to
represent all physical storage devices connected to the system.
Once initialized, the sole member `devices` will contain a list of `Device`
objects.
This class has no public methods. All interaction should be through the
`Device` class API.
"""
# Python built-ins
from subprocess import Popen, PIPE
# pySMART module imports
from .device import Device
from .utils import OS, rescan_device_busses
class DeviceList(object):
"""
Represents a list of all the storage devices connected to this computer.
"""
def __init__(self, init=True):
"""
Instantiates and optionally initializes the `DeviceList`.
###Args:
* **init (bool):** By default, `pySMART.device_list.DeviceList.devices`
is populated with `Device` objects during instantiation. Setting init to
False will skip initialization and create an empty
`pySMART.device_list.DeviceList` object instead.
"""
self.devices = []
"""
**(list of `Device`):** Contains all storage devices detected during
instantiation, as `Device` objects.
"""
if init:
self._initialize()
def __repr__(self):
"""Define a basic representation of the class object."""
rep = "<DeviceList contents:\n"
for device in self.devices:
rep += str(device) + '\n'
return rep + '>'
#return "<DeviceList contents:%r>" % (self.devices)
def _cleanup(self):
"""
Removes duplicate ATA devices that correspond to an existing CSMI
device. Also removes any device with no capacity value, as this
indicates removable storage, ie: CD/DVD-ROM, ZIP, etc.
"""
# We can't operate directly on the list while we're iterating
# over it, so we collect indeces to delete and remove them later
to_delete = []
# Enumerate the list to get tuples containing indeces and values
for index, device in enumerate(self.devices):
if device.interface == 'csmi':
for otherindex, otherdevice in enumerate(self.devices):
if (otherdevice.interface == 'ata' or
otherdevice.interface == 'sata'):
if device.serial == otherdevice.serial:
to_delete.append(otherindex)
device._sd_name = otherdevice.name
if device.capacity == None and index not in to_delete:
to_delete.append(index)
# Recreate the self.devices list without the marked indeces
self.devices[:] = [v for i, v in enumerate(self.devices)
if i not in to_delete]
def _initialize(self):
"""
Scans system busses for attached devices and add them to the
`DeviceList` as `Device` objects.
"""
# On Windows machines we should re-initialize the system busses
# before scanning for disks
if OS == 'Windows':
rescan_device_busses()
cmd = Popen('smartctl --scan-open', shell=True,
stdout=PIPE, stderr=PIPE)
_stdout, _stderr = cmd.communicate()
for line in _stdout.split('\n'):
if not ('failed:' in line or line == '' or 'scsi' in line):
raid_drive = line.split(' ')[2].replace('\n', '')
name = line.split(' ')[0].replace('/dev/', '')
# CSMI devices are explicitly of the 'csmi' type and do not
# require further disambiguation
if name[0:4] == 'csmi':
self.devices.append(Device(name, interface='csmi'))
# Other device types will be disambiguated by Device.__init__
else:
self.devices.append(Device(name, raid_drive, interface=None))
# Remove duplicates and unwanted devices (optical, etc.) from the list
self._cleanup()
# Sort the list alphabetically by device name
self.devices.sort(key=lambda device: device.name)
__all__ = ['DeviceList']
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment