Introduction
This Python library can assist in collecting disk information on Linux. In more details, it can:
collect information about a specific disk
explore all existing disks in the system
translate between traditional and persistent disk names
read disk temperature
read SMART attributes of a disk
read partition list of a disk
Installation
Standard installation from pypi:
pip install diskinfo
The library has the following run-time requirements:
Python version >= 3.8
for reading SMART data with
get_smart_data()
method, the smartmontools package is requiredfor reading disk temperature with
get_temperature()
method, the following dependencies needs to be considered:
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
for reading disk partition information with
get_partition_list()
method, the df command is required.optionally, for the demo Rich Python library is required
Demo
The library contains a demo application with multiple screens. In order to run demo execute the following commands:
pip install rich
The first demo screen will list the explored disks:
python -m diskinfo.demo
The second demo screen will display the attributes of a specified disk:
python -m diskinfo.demo sdb
The third demo screen will display the SMART attributes of a specified disk:
python -m diskinfo.demo nvme0n1 -s
The fourth demo screen will display the list of partitions on a specified disk:
python -m diskinfo.demo nvme0n1 -p
Persistent disk names
Please note that the traditional disk names in Linux are not persistent:
/dev/sda
/dev/sdb
It means they can refer a different physical disk after a reboot. Read more about this topic at Arch Linux wiki: Persistent block device naming.
On the other hand, there are real persistent ways to refer disk or block devices in Linux:
by-id path: it can be found in /dev/disk/by-id directory and it is constructed with disk serial numbers:
/dev/disk/by-id/ata-Samsung_SSD_850_PRO_1TB_92837A469FF876 /dev/disk/by-id/wwn-0x5002539c417223beby-path path: it can be found in /dev/disk/by-path directory and it is constructed with a physical path to the disk:
/dev/disk/by-path/pci-0000:00:17.0-ata-3
There are similar persistent constructions for disk partitions, too.
How to use
The following chapters will present the six use cases listed in the Introduction chapter above.
Use case 1: collect information about a disk
Disk attributes can be collected with the creation of a Disk
class. All disk attributes will be
collected at class creation time:
>>> from diskinfo import Disk
>>> d = Disk("sda")
and later the attributes can be accessed with the help of get functions of the class:
>>> d.get_model()
'Samsung SSD 870 QVO 8TB'
>>> d.is_ssd()
True
>>> s, u = d.get_size_in_hrf()
>>> print(f"{s:.1f} {u}")
8.0 TB
>>> d.get_serial()
'S5SXNG0MB01829M'
The Disk
class contains the following disk attributes:
Attribute |
Description |
Sample value |
---|---|---|
name |
Disk name |
sda or nvme0n1) |
path |
Disk path |
/dev/sda or /dev/nvme0n1 |
by-id path |
Persistent disk path in /dev/disk/by-id directory |
|
by-path path |
Persistent disk path in /dev/disk/by-path directory |
|
wwn |
0x5002538c307370ec |
|
model |
Disk model |
Samsung SSD 850 PRO 1TB |
serial number |
Disk serial number |
S3E2NY0J723218R |
firmware |
Disk firmware |
EXM04B6Q |
type |
Disk type |
HDD, SSD or NVME |
size |
Disk size in 512-byte blocks |
|
device id |
Disk device id, in ‘major:minor’ form |
8:0 |
physical block size |
Disk physical block size in bytes |
512 or 4096 |
logical block size |
Disk logical block size in bytes |
512 |
partition table type |
Type of the partition table on disk |
gpt or mbr |
partition table uuid |
UUID of the partition table on disk |
Use case 2: explore disks
Disks can be explored with the creation of the DiskInfo
class. During this process all disks will
identified and their attributes will be stored:
>>> from diskinfo import Disk, DiskInfo
>>> di = DiskInfo()
After that, the number of identified disks can be read with the help of get_disk_number()
method:
>>> di.get_disk_number()
4
and the list of the disks can be accessed (see more details in get_disk_list()
method):
>>> disks = di.get_disk_list(sorting=True)
>>> for d in disks:
>>> print(d.get_path())
/dev/nvme0n1
/dev/sda
/dev/sdb
/dev/sdc
The caller can also apply filters (i.e. included and excluded disk types) for both functions and can query only subset
of the disks based on one or more specific DiskType
. The list of disk can be also sorted.
Use case 3: translate between traditional and persistent disk names
Translation from traditional disk names to persistent ones can be done this way:
>>> from diskinfo import Disk
>>> d = Disk("sda")
>>> d.get_byid_path()
['/dev/disk/by-id/ata-Samsung_SSD_850_PRO_1TB_92837A469FF876', '/dev/disk/by-id/wwn-0x5002539c417223be']
>>> 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']
>>> d.get_serial_numner()
'92837A469FF876'
>>> d.get_wwn()
'0x5002539c417223be'
In the opposite direction several unique (persistent) identifier can be used to initialize Disk
class then the traditional disk path or name can be read:
>>> from diskinfo import Disk
>>> d = Disk(byid_name="ata-Samsung_SSD_850_PRO_1TB_92837A469FF876")
>>> d.get_path()
'/dev/sda'
>>> d = Disk(bypath_name="pci-0000:00:17.0-ata-3")
>>> d.get_path()
'/dev/sda'
>>> d = Disk(serial_number="92837A469FF876")
>>> d.get_path()
'/dev/sda'
>>> d = Disk(wwn="0x5002539c417223be")
>>> d.get_name()
'sda'
Use case 4: read disk temperature
After having a Disk
class instance, the disk temperature can be read in this way:
>>> from diskinfo import Disk
>>> d = Disk("sda")
>>> d.get_temperature()
28
Please note that the drivetemp kernel module should be loaded for SSDs and HDDs (available from Linux Kernel 5.6+). NVME disks do not require anything.
Use case 5: read disk SMART attributes
After having a Disk
class instance, the SMART attributes of the disk can be read with the help of
get_smart_data()
method.
>>> from diskinfo import Disk, DiskSmartData
>>> d = Disk("sda")
>>> sd = d.get_smart_data()
In case of HDDs, we can skip checking if they are in STANDBY mode:
>>> sd = d.get_smart_data(nocheck=True)
>>> if sd.standby_mode:
... print("Disk is in STANDBY mode.")
... else:
... print("Disk is ACTIVE.")
...
Disk is in STANDBY mode.
If we dont use the nocheck parameter here (when the HDD is in STANDBY mode) then the HDD will spin up and will
return to ACTIVE mode. Please note if standby_mode
is True then no other
SMART attributes are loaded.
The most important SMART information for all disk types is the health status:
>>> if sd.healthy:
... print("Disk is HEALTHY.")
... else:
... print("Disk is FAILED!")
...
Disk is HEALTHY.
In case of SSDs and HDDs the traditional SMART attributes can be accessed via
smart_attributes
list:
>>> for item in sd.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
See more details in DiskSmartData
and SmartAttribute
classes.
In case of NVME disks they have their own SMART data in nvme_attributes
attribute:
>>> if d.is_nvme():
... print(f"Power on hours: {sd.nvme_attributes.power_on_hours} h")
...
Power on hours: 1565 h
See the detailed list of the NVME attributes in NvmeAttributes
class.
Please note that the get_smart_data()
method relies on smartctl command.
It means that the caller needs to have special access rights (i.e. sudo or root).
Use case 6: read partition list
After having a Disk
class instance, the partition list can be read with the help of
get_partition_list()
method.
>>> from diskinfo import Disk, DiskSmartData
>>> d = Disk("sda")
>>> plist = d.get_partition_list()
The return value is a list of Partition
classes. This class provides several get functions to access
the partition attributes:
>>> from diskinfo import Disk
>>> disk = Disk("nvme0n1")
>>> plist = disk.get_partition_list()
>>> for item in plist:
... Disk(item.get_name())
...
nvme0n1p1
nvme0n1p2
nvme0n1p3
nvme0n1p4
nvme0n1p5
nvme0n1p6
The Partition
class contains the following partition attributes:
Attribute |
Description |
Sample value |
---|---|---|
name |
Partition name |
sda1 or nvme0n1p1 |
Path |
Partition path |
/dev/sda1 or /dev/nvme0n1p1 |
by-id path |
Persistent path in /dev/disk/by-id directory |
|
by-path path |
Persistent path in /dev/disk/by-path directory |
|
by-partuuid path |
Persistent path in /dev/disk/by-partuuid directory |
|
by-partlabel path |
Persistent path in /dev/disk/by-partlabel directory |
|
by-uuid path |
Persistent path in /dev/disk/by-uuid directory |
|
by-label path |
Persistent path in /dev/disk/by-label directory |
|
Device id |
Partition device id |
8:1 |
Partition scheme |
Partition scheme |
gtp or mbr |
Partition label |
Partition label |
Basic data partition |
Partition UUID |
Partition UUID |
acb8374d-fb60-4cb0-8ac4-273417c6f847 |
Partition type |
Partition type UUID |
|
Partition number |
Partition number in the partition table |
|
Partition offset |
Partition starting offset in 512-byte blocks |
|
Partition size |
Partition size in 512-byte blocks |
|
File system label |
File system label |
|
File system UUID |
File system UUID |
|
File system type |
File system type |
ntfs or ext4) |
File system version |
File system version |
1.0 in case of ext4) |
File system usage |
File system usage |
filesystem or other |
File system free size |
File system free size in 512-byte blocks |
|
File system mounting point |
File system mounting point |
/ or /home |