]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
9176326b LP |
2 | |
3 | #include "bus-print-properties.h" | |
4 | #include "cap-list.h" | |
5 | #include "cgroup-util.h" | |
6 | #include "escape.h" | |
7 | #include "mountpoint-util.h" | |
8 | #include "nsflags.h" | |
9 | #include "parse-util.h" | |
10 | #include "stdio-util.h" | |
11 | #include "string-util.h" | |
12 | #include "strv.h" | |
13 | #include "time-util.h" | |
14 | #include "user-util.h" | |
15 | ||
255b1fc8 | 16 | int bus_print_property_value(const char *name, const char *expected_value, BusPrintPropertyFlags flags, const char *value) { |
9176326b LP |
17 | assert(name); |
18 | ||
19 | if (expected_value && !streq_ptr(expected_value, value)) | |
20 | return 0; | |
21 | ||
255b1fc8 YW |
22 | if (!FLAGS_SET(flags, BUS_PRINT_PROPERTY_SHOW_EMPTY) && isempty(value)) |
23 | return 0; | |
24 | ||
25 | if (FLAGS_SET(flags, BUS_PRINT_PROPERTY_ONLY_VALUE)) | |
26 | puts(strempty(value)); | |
9176326b | 27 | else |
255b1fc8 | 28 | printf("%s=%s\n", name, strempty(value)); |
9176326b LP |
29 | |
30 | return 0; | |
31 | } | |
32 | ||
255b1fc8 YW |
33 | int bus_print_property_valuef(const char *name, const char *expected_value, BusPrintPropertyFlags flags, const char *fmt, ...) { |
34 | _cleanup_free_ char *s = NULL; | |
9176326b LP |
35 | va_list ap; |
36 | int r; | |
37 | ||
38 | assert(name); | |
39 | assert(fmt); | |
40 | ||
9176326b | 41 | va_start(ap, fmt); |
255b1fc8 | 42 | r = vasprintf(&s, fmt, ap); |
9176326b | 43 | va_end(ap); |
255b1fc8 YW |
44 | if (r < 0) |
45 | return -ENOMEM; | |
9176326b | 46 | |
255b1fc8 | 47 | return bus_print_property_value(name, expected_value, flags, s); |
9176326b LP |
48 | } |
49 | ||
255b1fc8 | 50 | static int bus_print_property(const char *name, const char *expected_value, sd_bus_message *m, BusPrintPropertyFlags flags) { |
9176326b LP |
51 | char type; |
52 | const char *contents; | |
53 | int r; | |
54 | ||
55 | assert(name); | |
56 | assert(m); | |
57 | ||
58 | r = sd_bus_message_peek_type(m, &type, &contents); | |
59 | if (r < 0) | |
60 | return r; | |
61 | ||
62 | switch (type) { | |
63 | ||
64 | case SD_BUS_TYPE_STRING: { | |
65 | const char *s; | |
66 | ||
67 | r = sd_bus_message_read_basic(m, type, &s); | |
68 | if (r < 0) | |
69 | return r; | |
70 | ||
255b1fc8 | 71 | if (FLAGS_SET(flags, BUS_PRINT_PROPERTY_SHOW_EMPTY) || !isempty(s)) { |
9176326b LP |
72 | bool good; |
73 | ||
74 | /* This property has a single value, so we need to take | |
75 | * care not to print a new line, everything else is OK. */ | |
76 | good = !strchr(s, '\n'); | |
255b1fc8 | 77 | bus_print_property_value(name, expected_value, flags, good ? s : "[unprintable]"); |
9176326b LP |
78 | } |
79 | ||
80 | return 1; | |
81 | } | |
82 | ||
83 | case SD_BUS_TYPE_BOOLEAN: { | |
84 | int b; | |
85 | ||
86 | r = sd_bus_message_read_basic(m, type, &b); | |
87 | if (r < 0) | |
88 | return r; | |
89 | ||
90 | if (expected_value && parse_boolean(expected_value) != b) | |
91 | return 1; | |
92 | ||
255b1fc8 | 93 | bus_print_property_value(name, NULL, flags, yes_no(b)); |
9176326b LP |
94 | return 1; |
95 | } | |
96 | ||
97 | case SD_BUS_TYPE_UINT64: { | |
98 | uint64_t u; | |
99 | ||
100 | r = sd_bus_message_read_basic(m, type, &u); | |
101 | if (r < 0) | |
102 | return r; | |
103 | ||
104 | /* Yes, heuristics! But we can change this check | |
105 | * should it turn out to not be sufficient */ | |
106 | ||
107 | if (endswith(name, "Timestamp") || | |
04f5c018 | 108 | STR_IN_SET(name, "NextElapseUSecRealtime", "LastTriggerUSec", "TimeUSec", "RTCTimeUSec")) |
9176326b | 109 | |
04f5c018 | 110 | bus_print_property_value(name, expected_value, flags, FORMAT_TIMESTAMP(u)); |
9176326b | 111 | |
5291f26d ZJS |
112 | else if (strstr(name, "USec")) |
113 | bus_print_property_value(name, expected_value, flags, FORMAT_TIMESPAN(u, 0)); | |
9176326b | 114 | |
5291f26d | 115 | else if (streq(name, "CoredumpFilter")) |
255b1fc8 | 116 | bus_print_property_valuef(name, expected_value, flags, "0x%"PRIx64, u); |
9176326b | 117 | |
255b1fc8 | 118 | else if (streq(name, "RestrictNamespaces")) { |
9176326b LP |
119 | _cleanup_free_ char *s = NULL; |
120 | const char *result; | |
121 | ||
122 | if ((u & NAMESPACE_FLAGS_ALL) == 0) | |
123 | result = "yes"; | |
124 | else if (FLAGS_SET(u, NAMESPACE_FLAGS_ALL)) | |
125 | result = "no"; | |
126 | else { | |
127 | r = namespace_flags_to_string(u, &s); | |
128 | if (r < 0) | |
129 | return r; | |
130 | ||
255b1fc8 | 131 | result = s; |
9176326b LP |
132 | } |
133 | ||
255b1fc8 | 134 | bus_print_property_value(name, expected_value, flags, result); |
9176326b LP |
135 | |
136 | } else if (streq(name, "MountFlags")) { | |
137 | const char *result; | |
138 | ||
b205e59a | 139 | result = mount_propagation_flag_to_string(u); |
9176326b LP |
140 | if (!result) |
141 | return -EINVAL; | |
142 | ||
255b1fc8 | 143 | bus_print_property_value(name, expected_value, flags, result); |
9176326b LP |
144 | |
145 | } else if (STR_IN_SET(name, "CapabilityBoundingSet", "AmbientCapabilities")) { | |
146 | _cleanup_free_ char *s = NULL; | |
147 | ||
8142d735 | 148 | r = capability_set_to_string(u, &s); |
9176326b LP |
149 | if (r < 0) |
150 | return r; | |
151 | ||
255b1fc8 | 152 | bus_print_property_value(name, expected_value, flags, s); |
9176326b | 153 | |
c8340822 | 154 | } else if (STR_IN_SET(name, "CPUWeight", "StartupCPUWeight") && u == CGROUP_WEIGHT_IDLE) |
155 | bus_print_property_value(name, expected_value, flags, "idle"); | |
156 | ||
157 | else if ((STR_IN_SET(name, "CPUWeight", "StartupCPUWeight", "IOWeight", "StartupIOWeight") && u == CGROUP_WEIGHT_INVALID) || | |
9176326b LP |
158 | (STR_IN_SET(name, "CPUShares", "StartupCPUShares") && u == CGROUP_CPU_SHARES_INVALID) || |
159 | (STR_IN_SET(name, "BlockIOWeight", "StartupBlockIOWeight") && u == CGROUP_BLKIO_WEIGHT_INVALID) || | |
3565c709 | 160 | (STR_IN_SET(name, "MemoryCurrent", "MemoryAvailable", "TasksCurrent") && u == UINT64_MAX) || |
3f362012 | 161 | (startswith(name, "Memory") && ENDSWITH_SET(name, "Current", "Peak") && u == CGROUP_LIMIT_MAX) || |
bfb6b121 | 162 | (startswith(name, "IO") && ENDSWITH_SET(name, "Bytes", "Operations") && u == UINT64_MAX) || |
f5fbe71d | 163 | (endswith(name, "NSec") && u == UINT64_MAX)) |
9176326b | 164 | |
255b1fc8 | 165 | bus_print_property_value(name, expected_value, flags, "[not set]"); |
9176326b | 166 | |
4fb0d2dc MK |
167 | else if ((ENDSWITH_SET(name, "MemoryLow", "MemoryMin", |
168 | "MemoryHigh", "MemoryMax", | |
169 | "MemorySwapMax", "MemoryZSwapMax", "MemoryLimit") && | |
bfb6b121 | 170 | u == CGROUP_LIMIT_MAX) || |
4fb0d2dc | 171 | (endswith(name, "TasksMax") && u == UINT64_MAX) || |
f5fbe71d YW |
172 | (startswith(name, "Limit") && u == UINT64_MAX) || |
173 | (startswith(name, "DefaultLimit") && u == UINT64_MAX)) | |
9176326b | 174 | |
255b1fc8 | 175 | bus_print_property_value(name, expected_value, flags, "infinity"); |
f5fbe71d | 176 | else if (STR_IN_SET(name, "IPIngressBytes", "IPIngressPackets", "IPEgressBytes", "IPEgressPackets") && u == UINT64_MAX) |
255b1fc8 | 177 | bus_print_property_value(name, expected_value, flags, "[no data]"); |
9176326b | 178 | else |
255b1fc8 | 179 | bus_print_property_valuef(name, expected_value, flags, "%"PRIu64, u); |
9176326b LP |
180 | |
181 | return 1; | |
182 | } | |
183 | ||
184 | case SD_BUS_TYPE_INT64: { | |
185 | int64_t i; | |
186 | ||
187 | r = sd_bus_message_read_basic(m, type, &i); | |
188 | if (r < 0) | |
189 | return r; | |
190 | ||
255b1fc8 | 191 | bus_print_property_valuef(name, expected_value, flags, "%"PRIi64, i); |
9176326b LP |
192 | return 1; |
193 | } | |
194 | ||
195 | case SD_BUS_TYPE_UINT32: { | |
196 | uint32_t u; | |
197 | ||
198 | r = sd_bus_message_read_basic(m, type, &u); | |
199 | if (r < 0) | |
200 | return r; | |
201 | ||
202 | if (strstr(name, "UMask") || strstr(name, "Mode")) | |
255b1fc8 | 203 | bus_print_property_valuef(name, expected_value, flags, "%04o", u); |
9176326b LP |
204 | |
205 | else if (streq(name, "UID")) { | |
206 | if (u == UID_INVALID) | |
255b1fc8 | 207 | bus_print_property_value(name, expected_value, flags, "[not set]"); |
9176326b | 208 | else |
255b1fc8 | 209 | bus_print_property_valuef(name, expected_value, flags, "%"PRIu32, u); |
9176326b LP |
210 | } else if (streq(name, "GID")) { |
211 | if (u == GID_INVALID) | |
255b1fc8 | 212 | bus_print_property_value(name, expected_value, flags, "[not set]"); |
9176326b | 213 | else |
255b1fc8 | 214 | bus_print_property_valuef(name, expected_value, flags, "%"PRIu32, u); |
9176326b | 215 | } else |
255b1fc8 | 216 | bus_print_property_valuef(name, expected_value, flags, "%"PRIu32, u); |
9176326b LP |
217 | |
218 | return 1; | |
219 | } | |
220 | ||
221 | case SD_BUS_TYPE_INT32: { | |
222 | int32_t i; | |
223 | ||
224 | r = sd_bus_message_read_basic(m, type, &i); | |
225 | if (r < 0) | |
226 | return r; | |
227 | ||
255b1fc8 | 228 | bus_print_property_valuef(name, expected_value, flags, "%"PRIi32, i); |
9176326b LP |
229 | return 1; |
230 | } | |
231 | ||
232 | case SD_BUS_TYPE_DOUBLE: { | |
233 | double d; | |
234 | ||
235 | r = sd_bus_message_read_basic(m, type, &d); | |
236 | if (r < 0) | |
237 | return r; | |
238 | ||
255b1fc8 | 239 | bus_print_property_valuef(name, expected_value, flags, "%g", d); |
9176326b LP |
240 | return 1; |
241 | } | |
242 | ||
243 | case SD_BUS_TYPE_ARRAY: | |
244 | if (streq(contents, "s")) { | |
245 | bool first = true; | |
246 | const char *str; | |
247 | ||
248 | r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, contents); | |
249 | if (r < 0) | |
250 | return r; | |
251 | ||
252 | while ((r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &str)) > 0) { | |
253 | _cleanup_free_ char *e = NULL; | |
254 | ||
9e53c10a | 255 | e = shell_maybe_quote(str, 0); |
9176326b LP |
256 | if (!e) |
257 | return -ENOMEM; | |
258 | ||
259 | if (first) { | |
255b1fc8 | 260 | if (!FLAGS_SET(flags, BUS_PRINT_PROPERTY_ONLY_VALUE)) |
9176326b LP |
261 | printf("%s=", name); |
262 | first = false; | |
263 | } else | |
264 | fputs(" ", stdout); | |
265 | ||
266 | fputs(e, stdout); | |
267 | } | |
268 | if (r < 0) | |
269 | return r; | |
270 | ||
255b1fc8 | 271 | if (first && FLAGS_SET(flags, BUS_PRINT_PROPERTY_SHOW_EMPTY) && !FLAGS_SET(flags, BUS_PRINT_PROPERTY_ONLY_VALUE)) |
9176326b | 272 | printf("%s=", name); |
255b1fc8 | 273 | if (!first || FLAGS_SET(flags, BUS_PRINT_PROPERTY_SHOW_EMPTY)) |
9176326b LP |
274 | puts(""); |
275 | ||
276 | r = sd_bus_message_exit_container(m); | |
277 | if (r < 0) | |
278 | return r; | |
279 | ||
280 | return 1; | |
281 | ||
282 | } else if (streq(contents, "y")) { | |
283 | const uint8_t *u; | |
284 | size_t n; | |
285 | ||
286 | r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, (const void**) &u, &n); | |
287 | if (r < 0) | |
288 | return r; | |
289 | ||
255b1fc8 | 290 | if (FLAGS_SET(flags, BUS_PRINT_PROPERTY_SHOW_EMPTY) || n > 0) { |
9176326b LP |
291 | unsigned i; |
292 | ||
255b1fc8 | 293 | if (!FLAGS_SET(flags, BUS_PRINT_PROPERTY_ONLY_VALUE)) |
9176326b LP |
294 | printf("%s=", name); |
295 | ||
296 | for (i = 0; i < n; i++) | |
297 | printf("%02x", u[i]); | |
298 | ||
299 | puts(""); | |
300 | } | |
301 | ||
302 | return 1; | |
303 | ||
304 | } else if (streq(contents, "u")) { | |
305 | uint32_t *u; | |
306 | size_t n; | |
307 | ||
308 | r = sd_bus_message_read_array(m, SD_BUS_TYPE_UINT32, (const void**) &u, &n); | |
309 | if (r < 0) | |
310 | return r; | |
311 | ||
255b1fc8 | 312 | if (FLAGS_SET(flags, BUS_PRINT_PROPERTY_SHOW_EMPTY) || n > 0) { |
9176326b LP |
313 | unsigned i; |
314 | ||
255b1fc8 | 315 | if (!FLAGS_SET(flags, BUS_PRINT_PROPERTY_ONLY_VALUE)) |
9176326b LP |
316 | printf("%s=", name); |
317 | ||
318 | for (i = 0; i < n; i++) | |
319 | printf("%08x", u[i]); | |
320 | ||
321 | puts(""); | |
322 | } | |
323 | ||
324 | return 1; | |
325 | } | |
326 | ||
327 | break; | |
328 | } | |
329 | ||
330 | return 0; | |
331 | } | |
332 | ||
333 | int bus_message_print_all_properties( | |
334 | sd_bus_message *m, | |
335 | bus_message_print_t func, | |
336 | char **filter, | |
255b1fc8 | 337 | BusPrintPropertyFlags flags, |
9176326b LP |
338 | Set **found_properties) { |
339 | ||
340 | int r; | |
341 | ||
342 | assert(m); | |
343 | ||
344 | r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}"); | |
345 | if (r < 0) | |
346 | return r; | |
347 | ||
348 | while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) { | |
349 | _cleanup_free_ char *name_with_equal = NULL; | |
350 | const char *name, *contents, *expected_value = NULL; | |
351 | ||
352 | r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &name); | |
353 | if (r < 0) | |
354 | return r; | |
355 | ||
356 | if (found_properties) { | |
357 | r = set_ensure_put(found_properties, &string_hash_ops, name); | |
358 | if (r < 0) | |
359 | return log_oom(); | |
360 | } | |
361 | ||
362 | name_with_equal = strjoin(name, "="); | |
363 | if (!name_with_equal) | |
364 | return log_oom(); | |
365 | ||
d29cc4d6 | 366 | if (!filter || strv_contains(filter, name) || |
9176326b LP |
367 | (expected_value = strv_find_startswith(filter, name_with_equal))) { |
368 | r = sd_bus_message_peek_type(m, NULL, &contents); | |
369 | if (r < 0) | |
370 | return r; | |
371 | ||
372 | r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents); | |
373 | if (r < 0) | |
374 | return r; | |
375 | ||
376 | if (func) | |
255b1fc8 | 377 | r = func(name, expected_value, m, flags); |
9176326b | 378 | if (!func || r == 0) |
255b1fc8 | 379 | r = bus_print_property(name, expected_value, m, flags); |
9176326b LP |
380 | if (r < 0) |
381 | return r; | |
382 | if (r == 0) { | |
255b1fc8 | 383 | if (FLAGS_SET(flags, BUS_PRINT_PROPERTY_SHOW_EMPTY) && !expected_value) |
9176326b LP |
384 | printf("%s=[unprintable]\n", name); |
385 | /* skip what we didn't read */ | |
386 | r = sd_bus_message_skip(m, contents); | |
387 | if (r < 0) | |
388 | return r; | |
389 | } | |
390 | ||
391 | r = sd_bus_message_exit_container(m); | |
392 | if (r < 0) | |
393 | return r; | |
394 | } else { | |
395 | r = sd_bus_message_skip(m, "v"); | |
396 | if (r < 0) | |
397 | return r; | |
398 | } | |
399 | ||
400 | r = sd_bus_message_exit_container(m); | |
401 | if (r < 0) | |
402 | return r; | |
403 | } | |
404 | if (r < 0) | |
405 | return r; | |
406 | ||
407 | r = sd_bus_message_exit_container(m); | |
408 | if (r < 0) | |
409 | return r; | |
410 | ||
411 | return 0; | |
412 | } | |
413 | ||
414 | int bus_print_all_properties( | |
415 | sd_bus *bus, | |
416 | const char *dest, | |
417 | const char *path, | |
418 | bus_message_print_t func, | |
419 | char **filter, | |
255b1fc8 | 420 | BusPrintPropertyFlags flags, |
9176326b LP |
421 | Set **found_properties) { |
422 | ||
423 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; | |
424 | _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; | |
425 | int r; | |
426 | ||
427 | assert(bus); | |
428 | assert(path); | |
429 | ||
430 | r = sd_bus_call_method(bus, | |
431 | dest, | |
432 | path, | |
433 | "org.freedesktop.DBus.Properties", | |
434 | "GetAll", | |
435 | &error, | |
436 | &reply, | |
437 | "s", ""); | |
438 | if (r < 0) | |
439 | return r; | |
440 | ||
255b1fc8 | 441 | return bus_message_print_all_properties(reply, func, filter, flags, found_properties); |
9176326b | 442 | } |