1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include "bus-print-properties.h"
5 #include "cgroup-util.h"
7 #include "mountpoint-util.h"
9 #include "parse-util.h"
10 #include "stdio-util.h"
11 #include "string-util.h"
13 #include "time-util.h"
14 #include "user-util.h"
16 int bus_print_property_value(const char *name
, const char *expected_value
, BusPrintPropertyFlags flags
, const char *value
) {
19 if (expected_value
&& !streq_ptr(expected_value
, value
))
22 if (!FLAGS_SET(flags
, BUS_PRINT_PROPERTY_SHOW_EMPTY
) && isempty(value
))
25 if (FLAGS_SET(flags
, BUS_PRINT_PROPERTY_ONLY_VALUE
))
26 puts(strempty(value
));
28 printf("%s=%s\n", name
, strempty(value
));
33 int bus_print_property_valuef(const char *name
, const char *expected_value
, BusPrintPropertyFlags flags
, const char *fmt
, ...) {
34 _cleanup_free_
char *s
= NULL
;
42 r
= vasprintf(&s
, fmt
, ap
);
47 return bus_print_property_value(name
, expected_value
, flags
, s
);
50 static int bus_print_property(const char *name
, const char *expected_value
, sd_bus_message
*m
, BusPrintPropertyFlags flags
) {
58 r
= sd_bus_message_peek_type(m
, &type
, &contents
);
64 case SD_BUS_TYPE_STRING
: {
67 r
= sd_bus_message_read_basic(m
, type
, &s
);
71 if (FLAGS_SET(flags
, BUS_PRINT_PROPERTY_SHOW_EMPTY
) || !isempty(s
)) {
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');
77 bus_print_property_value(name
, expected_value
, flags
, good
? s
: "[unprintable]");
83 case SD_BUS_TYPE_BOOLEAN
: {
86 r
= sd_bus_message_read_basic(m
, type
, &b
);
90 if (expected_value
&& parse_boolean(expected_value
) != b
)
93 bus_print_property_value(name
, NULL
, flags
, yes_no(b
));
97 case SD_BUS_TYPE_UINT64
: {
100 r
= sd_bus_message_read_basic(m
, type
, &u
);
104 /* Yes, heuristics! But we can change this check
105 * should it turn out to not be sufficient */
107 if (endswith(name
, "Timestamp") ||
108 STR_IN_SET(name
, "NextElapseUSecRealtime", "LastTriggerUSec", "TimeUSec", "RTCTimeUSec"))
110 bus_print_property_value(name
, expected_value
, flags
, FORMAT_TIMESTAMP(u
));
112 else if (strstr(name
, "USec"))
113 bus_print_property_value(name
, expected_value
, flags
, FORMAT_TIMESPAN(u
, 0));
115 else if (streq(name
, "CoredumpFilter"))
116 bus_print_property_valuef(name
, expected_value
, flags
, "0x%"PRIx64
, u
);
118 else if (streq(name
, "RestrictNamespaces")) {
119 _cleanup_free_
char *s
= NULL
;
122 if ((u
& NAMESPACE_FLAGS_ALL
) == 0)
124 else if (FLAGS_SET(u
, NAMESPACE_FLAGS_ALL
))
127 r
= namespace_flags_to_string(u
, &s
);
134 bus_print_property_value(name
, expected_value
, flags
, result
);
136 } else if (streq(name
, "MountFlags")) {
139 result
= mount_propagation_flags_to_string(u
);
143 bus_print_property_value(name
, expected_value
, flags
, result
);
145 } else if (STR_IN_SET(name
, "CapabilityBoundingSet", "AmbientCapabilities")) {
146 _cleanup_free_
char *s
= NULL
;
148 r
= capability_set_to_string_alloc(u
, &s
);
152 bus_print_property_value(name
, expected_value
, flags
, s
);
154 } else if ((STR_IN_SET(name
, "CPUWeight", "StartupCPUWeight", "IOWeight", "StartupIOWeight") && u
== CGROUP_WEIGHT_INVALID
) ||
155 (STR_IN_SET(name
, "CPUShares", "StartupCPUShares") && u
== CGROUP_CPU_SHARES_INVALID
) ||
156 (STR_IN_SET(name
, "BlockIOWeight", "StartupBlockIOWeight") && u
== CGROUP_BLKIO_WEIGHT_INVALID
) ||
157 (STR_IN_SET(name
, "MemoryCurrent", "TasksCurrent") && u
== UINT64_MAX
) ||
158 (endswith(name
, "NSec") && u
== UINT64_MAX
))
160 bus_print_property_value(name
, expected_value
, flags
, "[not set]");
162 else if ((STR_IN_SET(name
, "DefaultMemoryLow", "DefaultMemoryMin", "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryLimit", "MemoryAvailable") && u
== CGROUP_LIMIT_MAX
) ||
163 (STR_IN_SET(name
, "TasksMax", "DefaultTasksMax") && u
== UINT64_MAX
) ||
164 (startswith(name
, "Limit") && u
== UINT64_MAX
) ||
165 (startswith(name
, "DefaultLimit") && u
== UINT64_MAX
))
167 bus_print_property_value(name
, expected_value
, flags
, "infinity");
168 else if (STR_IN_SET(name
, "IPIngressBytes", "IPIngressPackets", "IPEgressBytes", "IPEgressPackets") && u
== UINT64_MAX
)
169 bus_print_property_value(name
, expected_value
, flags
, "[no data]");
171 bus_print_property_valuef(name
, expected_value
, flags
, "%"PRIu64
, u
);
176 case SD_BUS_TYPE_INT64
: {
179 r
= sd_bus_message_read_basic(m
, type
, &i
);
183 bus_print_property_valuef(name
, expected_value
, flags
, "%"PRIi64
, i
);
187 case SD_BUS_TYPE_UINT32
: {
190 r
= sd_bus_message_read_basic(m
, type
, &u
);
194 if (strstr(name
, "UMask") || strstr(name
, "Mode"))
195 bus_print_property_valuef(name
, expected_value
, flags
, "%04o", u
);
197 else if (streq(name
, "UID")) {
198 if (u
== UID_INVALID
)
199 bus_print_property_value(name
, expected_value
, flags
, "[not set]");
201 bus_print_property_valuef(name
, expected_value
, flags
, "%"PRIu32
, u
);
202 } else if (streq(name
, "GID")) {
203 if (u
== GID_INVALID
)
204 bus_print_property_value(name
, expected_value
, flags
, "[not set]");
206 bus_print_property_valuef(name
, expected_value
, flags
, "%"PRIu32
, u
);
208 bus_print_property_valuef(name
, expected_value
, flags
, "%"PRIu32
, u
);
213 case SD_BUS_TYPE_INT32
: {
216 r
= sd_bus_message_read_basic(m
, type
, &i
);
220 bus_print_property_valuef(name
, expected_value
, flags
, "%"PRIi32
, i
);
224 case SD_BUS_TYPE_DOUBLE
: {
227 r
= sd_bus_message_read_basic(m
, type
, &d
);
231 bus_print_property_valuef(name
, expected_value
, flags
, "%g", d
);
235 case SD_BUS_TYPE_ARRAY
:
236 if (streq(contents
, "s")) {
240 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, contents
);
244 while ((r
= sd_bus_message_read_basic(m
, SD_BUS_TYPE_STRING
, &str
)) > 0) {
245 _cleanup_free_
char *e
= NULL
;
247 e
= shell_maybe_quote(str
, 0);
252 if (!FLAGS_SET(flags
, BUS_PRINT_PROPERTY_ONLY_VALUE
))
263 if (first
&& FLAGS_SET(flags
, BUS_PRINT_PROPERTY_SHOW_EMPTY
) && !FLAGS_SET(flags
, BUS_PRINT_PROPERTY_ONLY_VALUE
))
265 if (!first
|| FLAGS_SET(flags
, BUS_PRINT_PROPERTY_SHOW_EMPTY
))
268 r
= sd_bus_message_exit_container(m
);
274 } else if (streq(contents
, "y")) {
278 r
= sd_bus_message_read_array(m
, SD_BUS_TYPE_BYTE
, (const void**) &u
, &n
);
282 if (FLAGS_SET(flags
, BUS_PRINT_PROPERTY_SHOW_EMPTY
) || n
> 0) {
285 if (!FLAGS_SET(flags
, BUS_PRINT_PROPERTY_ONLY_VALUE
))
288 for (i
= 0; i
< n
; i
++)
289 printf("%02x", u
[i
]);
296 } else if (streq(contents
, "u")) {
300 r
= sd_bus_message_read_array(m
, SD_BUS_TYPE_UINT32
, (const void**) &u
, &n
);
304 if (FLAGS_SET(flags
, BUS_PRINT_PROPERTY_SHOW_EMPTY
) || n
> 0) {
307 if (!FLAGS_SET(flags
, BUS_PRINT_PROPERTY_ONLY_VALUE
))
310 for (i
= 0; i
< n
; i
++)
311 printf("%08x", u
[i
]);
325 int bus_message_print_all_properties(
327 bus_message_print_t func
,
329 BusPrintPropertyFlags flags
,
330 Set
**found_properties
) {
336 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "{sv}");
340 while ((r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_DICT_ENTRY
, "sv")) > 0) {
341 _cleanup_free_
char *name_with_equal
= NULL
;
342 const char *name
, *contents
, *expected_value
= NULL
;
344 r
= sd_bus_message_read_basic(m
, SD_BUS_TYPE_STRING
, &name
);
348 if (found_properties
) {
349 r
= set_ensure_put(found_properties
, &string_hash_ops
, name
);
354 name_with_equal
= strjoin(name
, "=");
355 if (!name_with_equal
)
358 if (!filter
|| strv_contains(filter
, name
) ||
359 (expected_value
= strv_find_startswith(filter
, name_with_equal
))) {
360 r
= sd_bus_message_peek_type(m
, NULL
, &contents
);
364 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_VARIANT
, contents
);
369 r
= func(name
, expected_value
, m
, flags
);
371 r
= bus_print_property(name
, expected_value
, m
, flags
);
375 if (FLAGS_SET(flags
, BUS_PRINT_PROPERTY_SHOW_EMPTY
) && !expected_value
)
376 printf("%s=[unprintable]\n", name
);
377 /* skip what we didn't read */
378 r
= sd_bus_message_skip(m
, contents
);
383 r
= sd_bus_message_exit_container(m
);
387 r
= sd_bus_message_skip(m
, "v");
392 r
= sd_bus_message_exit_container(m
);
399 r
= sd_bus_message_exit_container(m
);
406 int bus_print_all_properties(
410 bus_message_print_t func
,
412 BusPrintPropertyFlags flags
,
413 Set
**found_properties
) {
415 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
416 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
422 r
= sd_bus_call_method(bus
,
425 "org.freedesktop.DBus.Properties",
433 return bus_message_print_all_properties(reply
, func
, filter
, flags
, found_properties
);