1
+ import enum
2
+
1
3
import dbus
4
+ from sdbus import sd_bus_open_system , DbusInterfaceCommon
2
5
from yunohost .utils .system import binary_to_human
3
6
7
+ __all__ = ["info" , "do_list" ]
4
8
5
- __all__ = [ "info" , "list" ]
9
+ from yunohost . utils . udisks2_interfaces import Udisks2Manager
6
10
7
11
8
12
UDISK_DRIVE_PATH = "/org/freedesktop/UDisks2/drives/"
9
13
UDISK_DRIVE_IFC = "org.freedesktop.UDisks2.Drive"
10
-
11
-
12
- def _query_udisks () -> list [tuple [str , dict ]]:
13
- bus = dbus .SystemBus ()
14
- manager = dbus .Interface (
15
- bus .get_object ("org.freedesktop.UDisks2" , "/org/freedesktop/UDisks2" ),
16
- "org.freedesktop.DBus.ObjectManager" ,
17
- )
18
-
19
- return sorted (
20
- (
21
- (name .removeprefix (UDISK_DRIVE_PATH ), dev [UDISK_DRIVE_IFC ])
22
- for name , dev in manager .GetManagedObjects ().items ()
23
- if name .startswith (UDISK_DRIVE_PATH )
24
- ),
25
- key = lambda item : item [1 ]["SortKey" ],
26
- )
14
+ UDISK_DRIVE_ATA_IFC = "org.freedesktop.UDisks2.Drive.Ata"
15
+ UDISK_DRIVE_NVME_IFC = "org.freedesktop.UDisks2.Manager.NVMe"
16
+
17
+
18
+ class DiskState (enum .StrEnum ):
19
+ @staticmethod
20
+ def _generate_next_value_ (name , start , count , last_values ):
21
+ return name .upper ()
22
+
23
+ TEST_SANE = enum .auto ()
24
+ TEST_IN_PROGRESS = enum .auto ()
25
+ TEST_FAILURE = enum .auto ()
26
+ """Test result is unavailable for some reason"""
27
+ TEST_UNKNOWN = enum .auto ()
28
+ """No data. Either because not run or previously aborted"""
29
+ UNKNOWN = enum .auto ()
30
+
31
+ @staticmethod
32
+ def parse (status : str | None ):
33
+ """
34
+ https://storaged.org/doc/udisks2-api/latest/gdbus-org.freedesktop.UDisks2.Drive.Ata.html#gdbus-property-org-freedesktop-UDisks2-Drive-Ata.SmartSelftestStatus
35
+ https://storaged.org/doc/udisks2-api/latest/gdbus-org.freedesktop.UDisks2.NVMe.Controller.html#gdbus-property-org-freedesktop-UDisks2-NVMe-Controller.SmartSelftestStatus
36
+ """
37
+ if not status :
38
+ return DiskState .UNKNOWN
39
+
40
+ match status :
41
+ case "success" :
42
+ return DiskState .TEST_SANE
43
+ case "inprogress" :
44
+ return DiskState .TEST_IN_PROGRESS
45
+ case (
46
+ "fatal_error"
47
+ | "known_seg_fail"
48
+ | "unknown_seg_fail"
49
+ | "fatal"
50
+ | "error_unknown"
51
+ | "error_electrical"
52
+ | "error_servo"
53
+ | "error_read"
54
+ | "error_handling"
55
+ ):
56
+ return DiskState .TEST_FAILURE
57
+ case _:
58
+ return DiskState .UNKNOWN
27
59
28
60
29
61
def _disk_infos (name : str , drive : dict , human_readable = False ):
30
62
result = {
31
63
"name" : name ,
32
- "model" : drive ["Model" ],
33
- "serial" : drive ["Serial" ],
34
- "removable" : bool (drive ["MediaRemovable" ]),
35
- "size" : binary_to_human (drive ["Size" ]) if human_readable else drive ["Size" ],
64
+ "model" : drive ["model" ],
65
+ "serial" : drive ["serial" ],
66
+ "removable" : bool (drive ["media_removable" ]),
67
+ "size" : binary_to_human (drive ["size" ]) if human_readable else drive ["size" ],
68
+ "smartStatus" : DiskState .parse (drive .get ("smart_selftest_status" )),
36
69
}
37
70
38
- if connection_bus := drive [ "ConnectionBus" ] :
39
- result ["connection_bus " ] = connection_bus
71
+ if " connection_bus" in drive :
72
+ result ["connectionBus " ] = drive [ " connection_bus" ]
40
73
41
- if (rotation_rate := drive ["RotationRate " ]) == - 1 :
74
+ if (rotation_rate := drive ["rotation_rate " ]) == - 1 :
42
75
result .update (
43
76
{
44
77
"type" : "HDD" ,
@@ -58,25 +91,24 @@ def _disk_infos(name: str, drive: dict, human_readable=False):
58
91
return result
59
92
60
93
61
- def list (with_info = False , human_readable = False ):
94
+ def do_list (with_info = False , human_readable = False ):
95
+ bus = sd_bus_open_system ()
96
+ disks = Udisks2Manager (bus ).get_disks ()
62
97
if not with_info :
63
- return [ name for name , _ in _query_udisks ()]
98
+ return list ( disks . keys ())
64
99
65
- result = []
66
-
67
- for name , drive in _query_udisks ():
68
- result .append (_disk_infos (name , drive , human_readable ))
100
+ result = [
101
+ _disk_infos (name , disk .props , human_readable ) for name , disk in disks .items ()
102
+ ]
69
103
70
104
return {"disks" : result }
71
105
72
106
73
107
def info (name , human_readable = False ):
74
- bus = dbus .SystemBus ()
75
- drive = dbus .Interface (
76
- bus .get_object (
77
- "org.freedesktop.UDisks2" , f"/org/freedesktop/UDisks2/drives/{ name } "
78
- ),
79
- dbus .PROPERTIES_IFACE ,
80
- ).GetAll ("org.freedesktop.UDisks2.Drive" )
81
-
82
- return _disk_infos (name , drive , human_readable )
108
+ bus = sd_bus_open_system ()
109
+ disk = Udisks2Manager (bus ).get_disks ().get (name )
110
+
111
+ if not disk :
112
+ return f"Unknown disk with name { name } " if human_readable else None
113
+
114
+ return _disk_infos (name , disk .props , human_readable )
0 commit comments