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")) {
109 char timestamp
[FORMAT_TIMESTAMP_MAX
];
112 t
= format_timestamp(timestamp
, sizeof(timestamp
), u
);
113 bus_print_property_value(name
, expected_value
, flags
, t
);
115 } else if (strstr(name
, "USec")) {
116 char timespan
[FORMAT_TIMESPAN_MAX
];
118 (void) format_timespan(timespan
, sizeof(timespan
), u
, 0);
119 bus_print_property_value(name
, expected_value
, flags
, timespan
);
121 } else if (streq(name
, "CoredumpFilter"))
122 bus_print_property_valuef(name
, expected_value
, flags
, "0x%"PRIx64
, u
);
124 else if (streq(name
, "RestrictNamespaces")) {
125 _cleanup_free_
char *s
= NULL
;
128 if ((u
& NAMESPACE_FLAGS_ALL
) == 0)
130 else if (FLAGS_SET(u
, NAMESPACE_FLAGS_ALL
))
133 r
= namespace_flags_to_string(u
, &s
);
140 bus_print_property_value(name
, expected_value
, flags
, result
);
142 } else if (streq(name
, "MountFlags")) {
145 result
= mount_propagation_flags_to_string(u
);
149 bus_print_property_value(name
, expected_value
, flags
, result
);
151 } else if (STR_IN_SET(name
, "CapabilityBoundingSet", "AmbientCapabilities")) {
152 _cleanup_free_
char *s
= NULL
;
154 r
= capability_set_to_string_alloc(u
, &s
);
158 bus_print_property_value(name
, expected_value
, flags
, s
);
160 } else if ((STR_IN_SET(name
, "CPUWeight", "StartupCPUWeight", "IOWeight", "StartupIOWeight") && u
== CGROUP_WEIGHT_INVALID
) ||
161 (STR_IN_SET(name
, "CPUShares", "StartupCPUShares") && u
== CGROUP_CPU_SHARES_INVALID
) ||
162 (STR_IN_SET(name
, "BlockIOWeight", "StartupBlockIOWeight") && u
== CGROUP_BLKIO_WEIGHT_INVALID
) ||
163 (STR_IN_SET(name
, "MemoryCurrent", "TasksCurrent") && u
== UINT64_MAX
) ||
164 (endswith(name
, "NSec") && u
== UINT64_MAX
))
166 bus_print_property_value(name
, expected_value
, flags
, "[not set]");
168 else if ((STR_IN_SET(name
, "DefaultMemoryLow", "DefaultMemoryMin", "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryLimit") && u
== CGROUP_LIMIT_MAX
) ||
169 (STR_IN_SET(name
, "TasksMax", "DefaultTasksMax") && u
== UINT64_MAX
) ||
170 (startswith(name
, "Limit") && u
== UINT64_MAX
) ||
171 (startswith(name
, "DefaultLimit") && u
== UINT64_MAX
))
173 bus_print_property_value(name
, expected_value
, flags
, "infinity");
174 else if (STR_IN_SET(name
, "IPIngressBytes", "IPIngressPackets", "IPEgressBytes", "IPEgressPackets") && u
== UINT64_MAX
)
175 bus_print_property_value(name
, expected_value
, flags
, "[no data]");
177 bus_print_property_valuef(name
, expected_value
, flags
, "%"PRIu64
, u
);
182 case SD_BUS_TYPE_INT64
: {
185 r
= sd_bus_message_read_basic(m
, type
, &i
);
189 bus_print_property_valuef(name
, expected_value
, flags
, "%"PRIi64
, i
);
193 case SD_BUS_TYPE_UINT32
: {
196 r
= sd_bus_message_read_basic(m
, type
, &u
);
200 if (strstr(name
, "UMask") || strstr(name
, "Mode"))
201 bus_print_property_valuef(name
, expected_value
, flags
, "%04o", u
);
203 else if (streq(name
, "UID")) {
204 if (u
== UID_INVALID
)
205 bus_print_property_value(name
, expected_value
, flags
, "[not set]");
207 bus_print_property_valuef(name
, expected_value
, flags
, "%"PRIu32
, u
);
208 } else if (streq(name
, "GID")) {
209 if (u
== GID_INVALID
)
210 bus_print_property_value(name
, expected_value
, flags
, "[not set]");
212 bus_print_property_valuef(name
, expected_value
, flags
, "%"PRIu32
, u
);
214 bus_print_property_valuef(name
, expected_value
, flags
, "%"PRIu32
, u
);
219 case SD_BUS_TYPE_INT32
: {
222 r
= sd_bus_message_read_basic(m
, type
, &i
);
226 bus_print_property_valuef(name
, expected_value
, flags
, "%"PRIi32
, i
);
230 case SD_BUS_TYPE_DOUBLE
: {
233 r
= sd_bus_message_read_basic(m
, type
, &d
);
237 bus_print_property_valuef(name
, expected_value
, flags
, "%g", d
);
241 case SD_BUS_TYPE_ARRAY
:
242 if (streq(contents
, "s")) {
246 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, contents
);
250 while ((r
= sd_bus_message_read_basic(m
, SD_BUS_TYPE_STRING
, &str
)) > 0) {
251 _cleanup_free_
char *e
= NULL
;
253 e
= shell_maybe_quote(str
, 0);
258 if (!FLAGS_SET(flags
, BUS_PRINT_PROPERTY_ONLY_VALUE
))
269 if (first
&& FLAGS_SET(flags
, BUS_PRINT_PROPERTY_SHOW_EMPTY
) && !FLAGS_SET(flags
, BUS_PRINT_PROPERTY_ONLY_VALUE
))
271 if (!first
|| FLAGS_SET(flags
, BUS_PRINT_PROPERTY_SHOW_EMPTY
))
274 r
= sd_bus_message_exit_container(m
);
280 } else if (streq(contents
, "y")) {
284 r
= sd_bus_message_read_array(m
, SD_BUS_TYPE_BYTE
, (const void**) &u
, &n
);
288 if (FLAGS_SET(flags
, BUS_PRINT_PROPERTY_SHOW_EMPTY
) || n
> 0) {
291 if (!FLAGS_SET(flags
, BUS_PRINT_PROPERTY_ONLY_VALUE
))
294 for (i
= 0; i
< n
; i
++)
295 printf("%02x", u
[i
]);
302 } else if (streq(contents
, "u")) {
306 r
= sd_bus_message_read_array(m
, SD_BUS_TYPE_UINT32
, (const void**) &u
, &n
);
310 if (FLAGS_SET(flags
, BUS_PRINT_PROPERTY_SHOW_EMPTY
) || n
> 0) {
313 if (!FLAGS_SET(flags
, BUS_PRINT_PROPERTY_ONLY_VALUE
))
316 for (i
= 0; i
< n
; i
++)
317 printf("%08x", u
[i
]);
331 int bus_message_print_all_properties(
333 bus_message_print_t func
,
335 BusPrintPropertyFlags flags
,
336 Set
**found_properties
) {
342 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "{sv}");
346 while ((r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_DICT_ENTRY
, "sv")) > 0) {
347 _cleanup_free_
char *name_with_equal
= NULL
;
348 const char *name
, *contents
, *expected_value
= NULL
;
350 r
= sd_bus_message_read_basic(m
, SD_BUS_TYPE_STRING
, &name
);
354 if (found_properties
) {
355 r
= set_ensure_put(found_properties
, &string_hash_ops
, name
);
360 name_with_equal
= strjoin(name
, "=");
361 if (!name_with_equal
)
364 if (!filter
|| strv_find(filter
, name
) ||
365 (expected_value
= strv_find_startswith(filter
, name_with_equal
))) {
366 r
= sd_bus_message_peek_type(m
, NULL
, &contents
);
370 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_VARIANT
, contents
);
375 r
= func(name
, expected_value
, m
, flags
);
377 r
= bus_print_property(name
, expected_value
, m
, flags
);
381 if (FLAGS_SET(flags
, BUS_PRINT_PROPERTY_SHOW_EMPTY
) && !expected_value
)
382 printf("%s=[unprintable]\n", name
);
383 /* skip what we didn't read */
384 r
= sd_bus_message_skip(m
, contents
);
389 r
= sd_bus_message_exit_container(m
);
393 r
= sd_bus_message_skip(m
, "v");
398 r
= sd_bus_message_exit_container(m
);
405 r
= sd_bus_message_exit_container(m
);
412 int bus_print_all_properties(
416 bus_message_print_t func
,
418 BusPrintPropertyFlags flags
,
419 Set
**found_properties
) {
421 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
422 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
428 r
= sd_bus_call_method(bus
,
431 "org.freedesktop.DBus.Properties",
439 return bus_message_print_all_properties(reply
, func
, filter
, flags
, found_properties
);