#
# Module `disk`: implements classes `DiskType` and `Disk`.
# Peter Sulyok (C) 2022-2024.
#
import glob
import os
import re
from typing import List, Tuple, Union
from pySMART import Device, SMARTCTL
from diskinfo.utils import _read_file, _read_udev_property, _read_udev_path, size_in_hrf
from diskinfo.disktype import DiskType
from diskinfo.partition import Partition
from diskinfo.disksmart import DiskSmartData, SmartAttribute, NvmeAttributes
[docs]
class Disk:
"""The Disk class contains all disk related information. The class can be initialized with specifying one of the
five unique identifiers of the disk:
* a disk name (e.g. `sda` or `nvme0n1`) located in `/dev/` directory.
* a disk serial number (e.g. `"92837A469FF876"`)
* a disk `wwn identifier <https://en.wikipedia.org/wiki/World_Wide_Name>`_ (e.g. `"0x5002638c807270be"`)
* a `by-id` name of the disk (e.g. `"ata-Samsung_SSD_850_PRO_1TB_92837A469FF876"`) located in `/dev/disk/by-id/`
directory
* a `by-path` name of the disk (e.g. `"pci-0000:00:17.0-ata-3"`) located in `/dev/disk/by-path/` directory
Based on the specified input parameter the disk will be identified and its attributes will be collected and
stored. A :py:obj:`ValueError` exception will be raised in case of missing or invalid disk identifier.
Encoding parameter will be used for processing disk attribute strings.
Operators (``<``, ``>`` and ``==``) are also implemented for this class to compare different class instances,
they use the disk name for comparison.
.. note::
During the class initialization the disk will not be physically accessed.
Args:
disk_name (str): the disk name
serial_number (str): serial number of the disk
wwn (str): wwn identifier of the disk
byid_name (str): by-id name of the disk
bypath_name (str): by-path name of the disk
encoding (str): encoding (default is `utf-8`)
Raises:
ValueError: in case of missing or invalid parameters
RuntimeError: in case of any system error
Example:
This example shows how to create a :class:`~diskinfo.Disk` class then how to get its path and serial number::
>>> from diskinfo import Disk
>>> d = Disk("sda")
>>> d.get_path()
'/dev/sda'
>>> d.get_serial_number()
'S3D2NY0J819210S'
and here are additional ways how the :class:`~diskinfo.Disk` class can be initialized::
>>> d = Disk(serial_number="92837A469FF876")
>>> d.get_name()
'sdc'
>>> d = Disk(wwn="0x5002539c417223be")
>>> d.get_name()
'sdc'
>>> d = Disk(byid_name="ata-Samsung_SSD_850_PRO_1TB_92837A469FF876")
>>> d.get_name()
'sdc'
>>> d = Disk(bypath_name="pci-0000:00:17.0-ata-3")
>>> d.get_name()
'sdc'
"""
# Disk attributes:
__name: str # Disk name (e.g. sda)
__path: str # Disk path (e.g. /dev/sda)
__byid_path: List[str] # Disk by-byid paths (e.g. /dev/disk/by-byid/ata-WDC_WD80FLAX...)
__bypath_path: List[str] # Disk by-path paths (e.g. /dev/disk/by-path/pci-0000:00:17.0-ata-1)
__wwn: str # Disk WWN
__model: str # Disk model
__serial_number: str # Disk serial number
__firmware: str # Disk firmware
__type: int # Disk type (HDD, SSD or NVME)
__size: int # Disk size (number of 512-byte blocks)
__device_id: str # Disk device id (e.g. 8:0)
__physical_block_size: int # Disk physical block size
__logical_block_size: int # Disk logical block size
__part_table_type: str # Disk partition table type
__part_table_uuid: str # Disk partition table UUID
__hwmon_path: str # Path for the /sys/HWMON temperature file
__encoding: str # Character encoding
def __init__(self, disk_name: str = None, serial_number: str = None, wwn: str = None,
byid_name: str = None, bypath_name: str = None, encoding="utf-8") -> None:
"""See class definition docstring above."""
# Save encoding.
self.__encoding = encoding
# Initialization 1: disk name.
if disk_name:
self.__name = disk_name
# Initialization 2: disk serial number.
elif serial_number:
name = ""
for file in os.listdir("/sys/block/"):
self.__device_id = _read_file("/sys/block/" + file + "/dev", self.__encoding)
dev_path = "/run/udev/data/b" + self.__device_id
self.__serial_number = _read_udev_property(dev_path, "ID_SERIAL_SHORT=", self.__encoding)
if serial_number == self.__serial_number:
name = file
break
if name == "":
raise ValueError(f"Invalid serial number ({serial_number})!")
self.__name = name
# Initialization 3: disk WWN name.
elif wwn:
name = ""
for file in os.listdir("/sys/block/"):
self.__device_id = _read_file("/sys/block/" + file + "/dev", self.__encoding)
dev_path = "/run/udev/data/b" + self.__device_id
self.__wwn = _read_udev_property(dev_path, "ID_WWN=", self.__encoding)
if wwn in self.__wwn:
name = file
break
if name == "":
raise ValueError(f"Invalid wwn identifier ({wwn})!")
self.__name = name
# Initialization 4: disk `by-id` name.
elif byid_name:
self.__name = os.path.basename(os.readlink("/dev/disk/by-id/" + byid_name))
# Initialization 5: disk `by-path` name.
elif bypath_name:
self.__name = os.path.basename(os.readlink("/dev/disk/by-path/" + bypath_name))
# Initialization error (none of them was specified).
else:
raise ValueError("Missing disk identifier, Disk() class cannot be initialized.")
# Check the existence of disk name in /dev and /sys/block folders.
self.__path = "/dev/" + self.__name
if not os.path.exists(self.__path):
raise ValueError(f"Disk path ({self.__path}) does not exist!")
path = "/sys/block/" + self.__name
if not os.path.exists(path):
raise ValueError(f"Disk path ({self.__path}) does not exist!")
# Read disk attributes from /sys filesystem.
self.__size = int(_read_file("/sys/block/" + self.__name + "/size", self.__encoding))
self.__model = _read_file("/sys/block/" + self.__name + "/device/model", self.__encoding)
self.__device_id = _read_file("/sys/block/" + self.__name + "/dev", self.__encoding)
self.__physical_block_size = int(_read_file("/sys/block/" + self.__name + "/queue/physical_block_size",
self.__encoding))
self.__logical_block_size = int(_read_file("/sys/block/" + self.__name + "/queue/logical_block_size",
self.__encoding))
# Determination of the disk type (HDD, SSD, NVME or LOOP)
# Type: LOOP
if re.match(r'^7:', self.__device_id):
self.__type = DiskType.LOOP
# Type: NVME
elif "nvme" in self.__name:
self.__type = DiskType.NVME
# Type: SSD or HDD
else:
path = "/sys/block/" + self.__name + "/queue/rotational"
result = _read_file(path, self.__encoding)
if result == "1":
self.__type = DiskType.HDD
elif result == "0":
self.__type = DiskType.SSD
else:
raise RuntimeError(f"Disk type cannot be determined based on this value ({path}={result}).")
# Read attributes from udev data.
dev_path = "/run/udev/data/b" + self.__device_id
self.__serial_number = _read_udev_property(dev_path, "ID_SERIAL_SHORT=", self.__encoding)
self.__firmware = _read_udev_property(dev_path, "ID_REVISION=", self.__encoding)
self.__wwn = _read_udev_property(dev_path, "ID_WWN=", self.__encoding)
self.__part_table_type = _read_udev_property(dev_path, "ID_PART_TABLE_TYPE=", self.__encoding)
self.__part_table_uuid = _read_udev_property(dev_path, "ID_PART_TABLE_UUID=", self.__encoding)
model = _read_udev_property(dev_path, "ID_MODEL_ENC=", self.__encoding)
if model:
self.__model = model
# Read `/dev/disk/by-byid/` path elements from udev and check their existence.
self.__byid_path = _read_udev_path(dev_path, 0, self.__encoding)
for file_name in self.__byid_path:
if not os.path.exists(file_name):
raise RuntimeError(f"Disk by-id path ({file_name}) does not exist!")
# Read `/dev/disk/by-path/` path elements from udev and check their existence.
self.__bypath_path = _read_udev_path(dev_path, 1, self.__encoding)
for file_name in self.__bypath_path:
if not os.path.exists(file_name):
raise RuntimeError(f"Disk by-path path ({file_name}) does not exist!")
# Find the path for HWMON file of the disk.
# Step 1: Check typical HWMON path for HDD, SSD disks
path = "/sys/block/" + self.__name + "/device/hwmon/hwmon*/temp1_input"
file_names = glob.glob(path)
if file_names and os.path.exists(file_names[0]):
self.__hwmon_path = file_names[0]
else:
# Step 2: Check HWMON path for NVME disks in Linux kernel 5.10-5.18?
path = "/sys/block/" + self.__name + "/device/device/hwmon/hwmon*/temp1_input"
file_names = glob.glob(path)
if file_names and os.path.exists(file_names[0]):
self.__hwmon_path = file_names[0]
else:
# Step 3: Check HWMON path for NVME disks in Linux kernel 5.19+?
path = "/sys/block/" + self.__name + "/device/hwmon*/temp1_input"
file_names = glob.glob(path)
if file_names and os.path.exists(file_names[0]):
self.__hwmon_path = file_names[0]
[docs]
def get_name(self) -> str:
"""Returns the disk name.
Example:
An example about the use of this function::
>>> from diskinfo import Disk
>>> d = Disk(serial_number="92837A469FF876")
>>> d.get_name()
'sdc'
"""
return self.__name
[docs]
def get_path(self) -> str:
"""Returns the disk path.
Example:
An example about the use of this function::
>>> from diskinfo import Disk
>>> d = Disk(serial_number="92837A469FF876")
>>> d.get_path()
'/dev/sdc'
.. note::
Please note this path is not persistent (i.e. it may refer different physical disk after a reboot).
"""
return self.__path
[docs]
def get_byid_path(self) -> List[str]:
"""Returns disk path in a persistent ``/dev/disk/by-byid/...`` form.
The result could be one or more path elements in a list.
Example:
An example about the use of this function::
>>> from diskinfo import Disk
>>> d = Disk("sdc")
>>> d.get_byid_path()
['/dev/disk/by-id/ata-Samsung_SSD_850_PRO_1TB_92837A469FF876', '/dev/disk/by-id/wwn-0x5002539c417223be']
"""
return self.__byid_path
[docs]
def get_bypath_path(self) -> List[str]:
"""Returns disk path in a persistent ``/dev/disk/by-path/...`` form.
The result could be one or more path elements in a list.
Example:
An example about the use of this function::
>>> from diskinfo import Disk
>>> d = Disk("sdc")
>>> d.get_bypath_path()
['/dev/disk/by-path/pci-0000:00:17.0-ata-3', '/dev/disk/by-path/pci-0000:00:17.0-ata-3.0']
"""
return self.__bypath_path
[docs]
def get_wwn(self) -> str:
"""Returns the world-wide name (WWN) of the disk. Read more about
`WWN here <https://en.wikipedia.org/wiki/World_Wide_Name>`_.
.. note::
This is a unique and persistent identifier of
the disk.
Example:
An example about the use of this function::
>>> from diskinfo import Disk
>>> d = Disk("sdc")
>>> d.get_wwn()
'0x5002539c417223be'
"""
return self.__wwn
[docs]
def get_model(self) -> str:
"""Returns the disk model string.
Example:
An example about the use of this function::
>>> from diskinfo import Disk
>>> d = Disk("sdc")
>>> d.get_model()
'Samsung SSD 850 PRO 1TB'
"""
return self.__model
[docs]
def get_serial_number(self) -> str:
"""Returns the disk serial number .
.. note::
This is a unique and persistent identifier of
the disk.
Example:
An example about the use of this function::
>>> from diskinfo import Disk
>>> d = Disk("sdc")
>>> d.get_serial_number()
'92837A469FF876'
"""
return self.__serial_number
[docs]
def get_firmware(self) -> str:
"""Returns the disk firmware string.
Example:
An example about the use of this function::
>>> from diskinfo import Disk
>>> d = Disk("sdc")
>>> d.get_firmware()
'EXM04B6Q'
"""
return self.__firmware
[docs]
def get_type(self) -> int:
"""Returns the type of the disk. One of the constants in :class:`~diskinfo.DiskType` class:
- ``DiskType.HDD`` for hard disks (with spinning platters)
- ``DiskType.SSD`` for SDDs on SATA or USB interface
- ``DiskType.NVME`` for NVME disks
- ``DiskType.LOOP`` for LOOP disks
Example:
An example about the use of this function::
>>> from diskinfo import Disk
>>> d = Disk("sdc")
>>> d.get_type()
2
"""
return self.__type
[docs]
def is_ssd(self) -> bool:
"""Returns `True` if the disk type is SSD, otherwise `False`.
Example:
An example about the use of this function::
>>> from diskinfo import Disk
>>> d = Disk("sdc")
>>> d.is_ssd()
True
"""
return bool(self.__type == DiskType.SSD)
[docs]
def is_nvme(self) -> bool:
"""Returns `True` if the disk type is NVME, otherwise `False`.
Example:
An example about the use of this function::
>>> from diskinfo import Disk
>>> d = Disk("sdc")
>>> d.is_nvme()
False
"""
return bool(self.__type == DiskType.NVME)
[docs]
def is_hdd(self) -> bool:
"""Returns `True` if the disk type is HDD, otherwise `False`.
Example:
An example about the use of this function::
>>> from diskinfo import Disk
>>> d = Disk("sdc")
>>> d.is_hdd()
False
"""
return bool(self.__type == DiskType.HDD)
[docs]
def is_loop(self) -> bool:
"""Returns `True` if the disk type is LOOP, otherwise `False`.
Example:
An example about the use of this function::
>>> from diskinfo import Disk
>>> d = Disk("loop0")
>>> d.is_loop()
True
"""
return bool(self.__type == DiskType.LOOP)
[docs]
def get_type_str(self) -> str:
"""Returns the name of the disk type. See the return values in :class:`~diskinfo.DiskType` class:
- ``DiskType.HDD_STR`` for hard disks (with spinning platters)
- ``DiskType.SSD_STR`` for SDDs on SATA or USB interface
- ``DiskType.NVME_STR`` for NVME disks
- ``DiskType.LOOP_STR`` for LOOP disks
Raises:
RuntimeError: in case of unknown disk type.
Example:
An example about the use of this function::
>>> from diskinfo import Disk
>>> d = Disk("sdc")
>>> d.get_type_str()
'SSD'
"""
if self.is_nvme():
return DiskType.NVME_STR
if self.is_ssd():
return DiskType.SSD_STR
if self.is_hdd():
return DiskType.HDD_STR
if self.is_loop():
return DiskType.LOOP_STR
raise RuntimeError(f'Unknown disk type (type={self.__type})')
[docs]
def get_size(self) -> int:
"""Returns the size of the disk in 512-byte units.
Example:
An example about the use of this function::
>>> from diskinfo import Disk
>>> d = Disk("sdc")
>>> s = d.get_size()
>>> print(f"Disk size: { s * 512 } bytes.")
Disk size: 1024209543168 bytes.
"""
return self.__size
[docs]
def get_size_in_hrf(self, units: int = 0) -> Tuple[float, str]:
"""Returns the size of the disk in a human-readable form.
Args:
units (int): unit system will be used in result:
- 0 metric units (default)
- 1 IEC units
- 2 legacy units
Read more about `units here <https://en.wikipedia.org/wiki/Byte>`_.
Returns:
Tuple[float, str]: size of the disk, proper unit
Example:
An example about the use of this function::
>>> from diskinfo import Disk
>>> d = Disk("sdc")
>>> s,u = d.get_size_in_hrf()
>>> print(f"{s:.1f} {u}")
1.0 TB
"""
return size_in_hrf(self.__size * 512, units)
[docs]
def get_device_id(self) -> str:
"""Returns the disk device id in `'major:minor'` form.
Example:
An example about the use of this function::
>>> from diskinfo import Disk
>>> d = Disk("sdc")
>>> d.get_device_id()
'8:32'
"""
return self.__device_id
[docs]
def get_physical_block_size(self) -> int:
"""Returns the physical block size of the disk in bytes. Typically, it is 512 bytes for SSDs and NVMEs, and
it could be 4096 bytes for HDDs.
Example:
An example about the use of this function::
>>> from diskinfo import Disk
>>> d = Disk("sdc")
>>> d.get_physical_block_size()
512
"""
return self.__physical_block_size
[docs]
def get_logical_block_size(self) -> int:
"""Returns the logical block size of the disk in bytes. Typically, it is 512 bytes.
Example:
An example about the use of this function::
>>> from diskinfo import Disk
>>> d = Disk("sdc")
>>> d.get_logical_block_size()
512
"""
return self.__logical_block_size
[docs]
def get_partition_table_type(self) -> str:
"""Returns the type of the partition table on the disk (e.g. `mbr` or `gpt`).
Example:
An example about the use of this function::
>>> from diskinfo import Disk
>>> d = Disk("sdc")
>>> d.get_partition_table_type()
'gpt'
"""
return self.__part_table_type
[docs]
def get_partition_table_uuid(self) -> str:
"""Returns the UUID of the partition table on the disk.
Example:
An example about the use of this function::
>>> from diskinfo import Disk
>>> d = Disk("sdc")
>>> d.get_partition_table_uuid()
'd3f932e0-7107-455e-a569-9acd5b60d204'
"""
return self.__part_table_uuid
[docs]
def get_temperature(self, sudo: bool = False, smartctl_path: str = "/usr/sbin/smartctl") -> Union[float, None]:
"""Returns the current disk temperature. The method will try to read disk temperature from the Linux kernel
HWMON interface first then will try to execure the `smartctl` command. The method has the following
requirements:
.. list-table::
:header-rows: 1
* - Disk type
- Requirement
* - SATA HDD/SSD
- `drivetemp` kernel module (Linux kernel version `5.6+`) has to be loaded
* - SCSI/ATA HDD
- `smartmontools` has to be installed
* - NVME
- none
.. note::
Please note that reading disk temperature from HWMON kernel interface will not access the disk and
will not change its power state (e.g. HDD can be in STANDBY state) but reading disk temperature with
`smartctl` will do.
Args:
sudo (bool): ``sudo`` command should be used for ``smartctl``, default value is ``False``
smartctl_path (str): Path for ``smartctl`` command, default value is ``/usr/sbin/smartctl``
Returns:
float: disk temperature in C degree or None if the temperature cannot be determined
Example:
An example about the use of this function::
>>> from diskinfo import Disk
>>> d = Disk("sdc")
>>> d.get_temperature(sudo=True)
28.5
"""
temp: float
sd: Device
# Read disk temperature from HWMON system of the Linux kernel.
if hasattr(self, '_Disk__hwmon_path') and \
self.__hwmon_path and \
os.path.exists(self.__hwmon_path):
try:
return float(_read_file(self.__hwmon_path, self.__encoding)) / 1000.0
except ValueError:
pass
# Read disk temperature from `smartctl` command.
SMARTCTL.options = []
SMARTCTL.smartctl_path = smartctl_path
if sudo:
SMARTCTL.sudo = True
else:
SMARTCTL.sudo = False
sd = Device(self.__path)
temp = sd.temperature
if not temp:
return None
return float(temp)
[docs]
def get_smart_data(self, nocheck: bool = False, sudo: bool = False, smartctl_path: str = "/usr/sbin/smartctl") \
-> Union[DiskSmartData, None]:
"""Returns SMART data of the disk. This function will execute ``smartctl`` command from `smartmontools
<https://www.smartmontools.org/>`_ package, it needs to be installed.
.. note::
``smartctl`` command needs root priviledge for reading device SMART attributes. This function has
to be used as `root` user or called with ``sudo=True`` parameter.
In case of HDDs, the ``smartctl`` command will access the disk directly and the HDD could be woken up. If
the ``nocheck=True`` parameter is used then the current power state of the disk will be preserved.
Args:
nocheck (bool): No check should be applied for a HDDs (``"-n standby"`` argument will be used)
sudo (bool): ``sudo`` command should be used, default value is ``False``
smartctl_path (str): Path for ``smartctl`` command, default value is ``/usr/sbin/smartctl``
Returns:
DiskSmartData: SMART information of the disk (see more details at
:class:`~diskinfo.DiskSmartData` class) or None if `smartctl` cannot be executed
Example:
The example show the use of the function::
>>> from diskinfo import Disk, DiskSmartData
>>> d = Disk("sda")
>>> d = d.get_smart_data()
In case of SSDs and HDDs the traditional SMART attributes can be accessed via
:attr:`~diskinfo.DiskSmartData.smart_attributes` list::
>>> for item in d.smart_attributes:
... print(f"{item.id:>3d} {item.attribute_name}: {item.raw_value}")
...
5 Reallocated_Sector_Ct: 0
9 Power_On_Hours: 6356
12 Power_Cycle_Count: 2308
177 Wear_Leveling_Count: 2
179 Used_Rsvd_Blk_Cnt_Tot: 0
181 Program_Fail_Cnt_Total: 0
182 Erase_Fail_Count_Total: 0
183 Runtime_Bad_Block: 0
187 Uncorrectable_Error_Cnt: 0
190 Airflow_Temperature_Cel: 28
195 ECC_Error_Rate: 0
199 CRC_Error_Count: 0
235 POR_Recovery_Count: 67
241 Total_LBAs_Written: 9869978356
In case of NVME disks they have their own SMART data in :attr:`~diskinfo.DiskSmartData.nvme_attributes`
field::
>>> if d.is_nvme():
... print(f"Power on hours: {d.nvme_attributes.power_on_hours} h")
...
Power on hours: 1565 h
"""
sd: Device # Device class created by pySMART
rv: DiskSmartData # return value
# Ignore loop disks.
if self.is_loop():
return None
rv = DiskSmartData()
rv.standby_mode = False
SMARTCTL.options = []
SMARTCTL.smartctl_path = smartctl_path
# If sudo command should be used
if sudo:
SMARTCTL.sudo = True
else:
SMARTCTL.sudo = False
# If no check should be applied in standby power mode of an HDD
if nocheck:
SMARTCTL.add_options(["-n", "standby"])
# Check if `smartctl` can be executed.
output = SMARTCTL.info(self.__path)
if not output:
return None
# Check if the disk is in STANDBY mode
if "Device is in STANDBY mode" in output[3]:
rv.standby_mode = True
return rv
# Get SMART data from pySMART.
sd = Device(self.__path)
# Check if the device interface was not identified (i.e. unknown device).
if not sd.interface:
return None
# Save SMART flags.
rv.smart_enabled = sd.smart_enabled
rv.smart_capable = sd.smart_capable
# Find overall-health status
if sd.assessment == "PASS":
rv.healthy = True
else:
rv.healthy = False
# Read and store of NVME attributes
if self.is_nvme():
if hasattr(sd, "if_attributes"):
rv.nvme_attributes = NvmeAttributes(
sd.if_attributes.criticalWarning
if hasattr(sd.if_attributes, "criticalWarning") else None,
sd.if_attributes._temperature
if hasattr(sd.if_attributes, "_temperature") else None,
sd.if_attributes.availableSpare
if hasattr(sd.if_attributes, "availableSpare") else None,
sd.if_attributes.availableSpareThreshold
if hasattr(sd.if_attributes, "availableSpareThreshold") else None,
sd.if_attributes.percentageUsed
if hasattr(sd.if_attributes, "percentageUsed") else None,
sd.if_attributes.dataUnitsRead
if hasattr(sd.if_attributes, "dataUnitsRead") else None,
sd.if_attributes.dataUnitsWritten
if hasattr(sd.if_attributes, "dataUnitsWritten") else None,
sd.if_attributes.hostReadCommands
if hasattr(sd.if_attributes, "hostReadCommands") else None,
sd.if_attributes.hostWriteCommands
if hasattr(sd.if_attributes, "hostWriteCommands") else None,
sd.if_attributes.controllerBusyTime
if hasattr(sd.if_attributes, "controllerBusyTime") else None,
sd.if_attributes.powerCycles
if hasattr(sd.if_attributes, "powerCycles") else None,
sd.if_attributes.powerOnHours
if hasattr(sd.if_attributes, "powerOnHours") else None,
sd.if_attributes.unsafeShutdowns
if hasattr(sd.if_attributes, "unsafeShutdowns") else None,
sd.if_attributes.integrityErrors
if hasattr(sd.if_attributes, "integrityErrors") else None,
sd.if_attributes.errorEntries
if hasattr(sd.if_attributes, "errorEntries") else None,
sd.if_attributes.warningTemperatureTime
if hasattr(sd.if_attributes, "warningTemperatureTime") else None,
sd.if_attributes.criticalTemperatureTime
if hasattr(sd.if_attributes, "criticalTemperatureTime") else None
)
# Read and save SATA attributes
else:
if hasattr(sd, "if_attributes") and hasattr(sd.if_attributes, "legacyAttributes"):
rv.smart_attributes = []
for i in sd.if_attributes.legacyAttributes:
if i:
rv.smart_attributes.append(SmartAttribute(
i.num, i.name, i.flags, i.value_int, i.worst, i.thresh, i.type, i.updated,
i.when_failed, i.raw_int)
)
return rv
[docs]
def get_partition_list(self) -> List[Partition]:
"""Reads partition information of the disk and returns the list of partitions. See
:class:`~diskinfo.Partition` class for more details for a partition entry.
Returns:
List[Partition]: list of partitions
Example:
>>> from diskinfo import *
>>> disk=Disk("nvme0n1")
>>> plist=disk.get_partition_list()
>>> for item in plist:
... print(item.get_name())
...
nvme0n1p1
nvme0n1p2
nvme0n1p3
nvme0n1p4
nvme0n1p5
nvme0n1p6
"""
result: List[Partition] = []
index = 1
while True:
path = "/sys/block/" + self.__name + "/" + self.__name
if self.is_nvme():
path += "p"
path += str(index)
if not os.path.exists(path):
break # If partition path dos not exists.
result.append(Partition(os.path.basename(path), _read_file(path + "/dev", self.__encoding)))
index += 1
return result
def __gt__(self, other) -> bool:
"""Implementation of '>' operator for Disk class."""
return bool(self.__name > other.__name)
def __lt__(self, other) -> bool:
"""Implementation of '<' operator for Disk class."""
return bool(self.__name < other.__name)
def __eq__(self, other) -> bool:
"""Implementation of '==' operator for Disk class."""
return bool(self.__name == other.__name)
def __repr__(self):
"""String representation of the Disk class."""
return (f"Disk(name={self.__name}, "
f"path={self.__path}, "
f"byid_path={self.__byid_path}, "
f"by_path={self.__bypath_path}, "
f"wwn={self.__wwn}, "
f"model={self.__model}, "
f"serial={self.__serial_number}, "
f"firmware={self.__firmware}, "
f"type={self.get_type_str()}, "
f"size={self.__size}, "
f"device_id={self.__device_id}, "
f"physical_block_size={self.__physical_block_size}, "
f"logical_block_size={self.__logical_block_size}, "
f"partition_table_type={self.__part_table_type}, "
f"partition_table_uuid={self.__part_table_uuid})")
# End.