11from labgrid .protocol import CommandProtocol
2+ import json
23import re
34
45def get_systemd_version (command ):
@@ -21,39 +22,81 @@ def get_systemd_version(command):
2122 return int (parsed .group ("version" ))
2223
2324def get_systemd_status (command ):
25+ """Returns parsed output of systemd Manager's ListUnits DBus command
26+
27+ Args:
28+ command (CommandProtocol): An instance of a Driver implementing the CommandProtocol
29+
30+ Returns:
31+ dict: dictionary of service names to their properties
32+ """
2433 assert isinstance (command , CommandProtocol ), "command must be a CommandProtocol"
25- # TODO: Use busctl --json if systemd>239
2634 array_notation = "a(ssssssouso)"
27- out = command .run_check (
28- "busctl call --no-pager org.freedesktop.systemd1 \
29- /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager ListUnits"
30- )
3135
32- out = out [0 ]
33- if array_notation not in out :
34- raise ValueError ("Systemd ListUnits output changed" )
35- out = out [len (array_notation ):]
36- array_length = int (out [:out .index ('"' )].strip (" " ))
37- out = out [out .index ('"' )+ 1 :- 1 ]
38- out = out .split ('\" \" ' )
39- data = iter (out )
40- services = {}
41- for _ in range (array_length ):
42- name = next (data )
43- services [name ] = {}
44- services [name ]["description" ] = next (data )
45- services [name ]["load" ] = next (data )
46- services [name ]["active" ] = next (data )
47- services [name ]["sub" ] = next (data )
48- services [name ]["follow" ] = next (data )
49- path_and_id = next (data )
50- pos = path_and_id .index ('"' )
51- services [name ]["path" ] = path_and_id [:pos ]
52- services [name ]["id" ] = int (path_and_id [pos + 1 :- 1 ].strip (" " ))
53- services [name ]["type" ] = path_and_id [path_and_id .rfind ('"' ):]
54- services [name ]["objpath" ] = next (data )
55-
56- return services
36+ def get_systemd_status_json (command ):
37+ out = command .run_check (
38+ "busctl call --json=short --no-pager org.freedesktop.systemd1 \
39+ /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager ListUnits"
40+ )
41+ out = out [0 ]
42+ out = json .loads (out )
43+ if out ["type" ] != array_notation :
44+ raise ValueError ("Systemd ListUnits output changed" )
45+
46+ services = {}
47+ for record in out ["data" ][0 ]:
48+ data = iter (record )
49+ name = next (data )
50+ services [name ] = {}
51+ services [name ]["description" ] = next (data )
52+ services [name ]["load" ] = next (data )
53+ services [name ]["active" ] = next (data )
54+ services [name ]["sub" ] = next (data )
55+ services [name ]["follow" ] = next (data )
56+ services [name ]["path" ] = next (data )
57+ services [name ]["id" ] = int (next (data ))
58+ services [name ]["type" ] = next (data )
59+ services [name ]["objpath" ] = next (data )
60+
61+ return services
62+
63+ def get_systemd_status_raw (command ):
64+ out = command .run_check (
65+ "busctl call --no-pager org.freedesktop.systemd1 \
66+ /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager ListUnits"
67+ )
68+
69+ out = out [0 ]
70+ if array_notation not in out :
71+ raise ValueError ("Systemd ListUnits output changed" )
72+ out = out [len (array_notation ):]
73+ array_length = int (out [:out .index ('"' )].strip (" " ))
74+ out = out [out .index ('"' )+ 1 :- 1 ]
75+ out = out .split ('\" \" ' )
76+ data = iter (out )
77+ services = {}
78+ for _ in range (array_length ):
79+ name = next (data )
80+ services [name ] = {}
81+ services [name ]["description" ] = next (data )
82+ services [name ]["load" ] = next (data )
83+ services [name ]["active" ] = next (data )
84+ services [name ]["sub" ] = next (data )
85+ services [name ]["follow" ] = next (data )
86+ path_and_id = next (data )
87+ pos = path_and_id .index ('"' )
88+ services [name ]["path" ] = path_and_id [:pos ]
89+ services [name ]["id" ] = int (path_and_id [pos + 1 :- 1 ].strip (" " ))
90+ services [name ]["type" ] = path_and_id [path_and_id .rfind ('"' ):]
91+ services [name ]["objpath" ] = next (data )
92+
93+ return services
94+
95+ if get_systemd_version (command ) > 239 :
96+ return get_systemd_status_json (command )
97+ else :
98+ return get_systemd_status_raw (command )
99+
57100
58101def get_commands (command , directories = None ):
59102 """Returns the commands of a running linux system
0 commit comments