busctl: several cleanups for introspect command (#37103)
This commit is contained in:
+101
-105
@@ -6,6 +6,7 @@
|
||||
#include "sd-json.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "bitfield.h"
|
||||
#include "build.h"
|
||||
#include "bus-dump.h"
|
||||
#include "bus-internal.h"
|
||||
@@ -23,6 +24,7 @@
|
||||
#include "glyph-util.h"
|
||||
#include "json-util.h"
|
||||
#include "log.h"
|
||||
#include "logarithm.h"
|
||||
#include "main-func.h"
|
||||
#include "memstream-util.h"
|
||||
#include "os-util.h"
|
||||
@@ -791,10 +793,6 @@ static int member_compare_func(const Member *x, const Member *y) {
|
||||
return strcmp_ptr(x->signature, y->signature);
|
||||
}
|
||||
|
||||
static int member_compare_funcp(Member * const *a, Member * const *b) {
|
||||
return member_compare_func(*a, *b);
|
||||
}
|
||||
|
||||
static Member* member_free(Member *m) {
|
||||
if (!m)
|
||||
return NULL;
|
||||
@@ -808,11 +806,6 @@ static Member* member_free(Member *m) {
|
||||
}
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(Member*, member_free);
|
||||
|
||||
static Set* member_set_free(Set *s) {
|
||||
return set_free_with_destructor(s, member_free);
|
||||
}
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, member_set_free);
|
||||
|
||||
static int on_interface(const char *interface, uint64_t flags, void *userdata) {
|
||||
_cleanup_(member_freep) Member *m = NULL;
|
||||
Set *members = ASSERT_PTR(userdata);
|
||||
@@ -829,18 +822,17 @@ static int on_interface(const char *interface, uint64_t flags, void *userdata) {
|
||||
.flags = flags,
|
||||
};
|
||||
|
||||
r = free_and_strdup(&m->interface, interface);
|
||||
r = strdup_to(&m->interface, interface);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
r = set_put(members, m);
|
||||
r = set_consume(members, TAKE_PTR(m));
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
if (r == 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EEXIST),
|
||||
"Invalid introspection data: duplicate interface '%s'.", interface);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
m = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -861,30 +853,29 @@ static int on_method(const char *interface, const char *name, const char *signat
|
||||
.flags = flags,
|
||||
};
|
||||
|
||||
r = free_and_strdup(&m->interface, interface);
|
||||
r = strdup_to(&m->interface, interface);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
r = free_and_strdup(&m->name, name);
|
||||
r = strdup_to(&m->name, name);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
r = free_and_strdup(&m->signature, signature);
|
||||
r = strdup_to(&m->signature, signature);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
r = free_and_strdup(&m->result, result);
|
||||
r = strdup_to(&m->result, result);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
r = set_put(members, m);
|
||||
r = set_consume(members, TAKE_PTR(m));
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
if (r == 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EEXIST),
|
||||
"Invalid introspection data: duplicate method '%s' on interface '%s'.", name, interface);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
m = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -905,26 +896,25 @@ static int on_signal(const char *interface, const char *name, const char *signat
|
||||
.flags = flags,
|
||||
};
|
||||
|
||||
r = free_and_strdup(&m->interface, interface);
|
||||
r = strdup_to(&m->interface, interface);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
r = free_and_strdup(&m->name, name);
|
||||
r = strdup_to(&m->name, name);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
r = free_and_strdup(&m->signature, signature);
|
||||
r = strdup_to(&m->signature, signature);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
r = set_put(members, m);
|
||||
r = set_consume(members, TAKE_PTR(m));
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
if (r == 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EEXIST),
|
||||
"Invalid introspection data: duplicate signal '%s' on interface '%s'.", name, interface);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
m = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -946,30 +936,60 @@ static int on_property(const char *interface, const char *name, const char *sign
|
||||
.writable = writable,
|
||||
};
|
||||
|
||||
r = free_and_strdup(&m->interface, interface);
|
||||
r = strdup_to(&m->interface, interface);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
r = free_and_strdup(&m->name, name);
|
||||
r = strdup_to(&m->name, name);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
r = free_and_strdup(&m->signature, signature);
|
||||
r = strdup_to(&m->signature, signature);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
r = set_put(members, m);
|
||||
r = set_consume(members, TAKE_PTR(m));
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
if (r == 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EEXIST),
|
||||
"Invalid introspection data: duplicate property '%s' on interface '%s'.", name, interface);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
m = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_PRIVATE_HASH_OPS(member_hash_ops, Member, member_hash_func, member_compare_func);
|
||||
DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
|
||||
member_hash_ops,
|
||||
Member,
|
||||
member_hash_func,
|
||||
member_compare_func,
|
||||
member_free);
|
||||
|
||||
static int members_flags_to_string(const Member *m, char **ret) {
|
||||
static const char *map[] = {
|
||||
[LOG2U(SD_BUS_VTABLE_DEPRECATED)] = "deprecated",
|
||||
[LOG2U(SD_BUS_VTABLE_METHOD_NO_REPLY)] = "no-reply",
|
||||
[LOG2U(SD_BUS_VTABLE_PROPERTY_CONST)] = "const",
|
||||
[LOG2U(SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE)] = "emits-change",
|
||||
[LOG2U(SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION)] = "emits-invalidation",
|
||||
};
|
||||
|
||||
assert(m);
|
||||
assert(ret);
|
||||
|
||||
_cleanup_free_ char *str = NULL;
|
||||
for (size_t i = 0; i < ELEMENTSOF(map); i++)
|
||||
if (BIT_SET(m->flags, i) && map[i])
|
||||
if (!strextend_with_separator(&str, " ", map[i]))
|
||||
return -ENOMEM;
|
||||
|
||||
if (m->writable)
|
||||
if (!strextend_with_separator(&str, " ", "writable"))
|
||||
return -ENOMEM;
|
||||
|
||||
*ret = TAKE_PTR(str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int introspect(int argc, char **argv, void *userdata) {
|
||||
static const XMLIntrospectOps ops = {
|
||||
@@ -982,8 +1002,7 @@ static int introspect(int argc, char **argv, void *userdata) {
|
||||
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply_xml = NULL;
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
_cleanup_(member_set_freep) Set *members = NULL;
|
||||
unsigned name_width, type_width, signature_width, result_width;
|
||||
_cleanup_set_free_ Set *members = NULL;
|
||||
Member *m;
|
||||
const char *xml;
|
||||
int r;
|
||||
@@ -1109,55 +1128,26 @@ static int introspect(int argc, char **argv, void *userdata) {
|
||||
return bus_log_parse_error(r);
|
||||
}
|
||||
|
||||
name_width = strlen("NAME");
|
||||
type_width = strlen("TYPE");
|
||||
signature_width = strlen("SIGNATURE");
|
||||
result_width = strlen("RESULT/VALUE");
|
||||
size_t n;
|
||||
_cleanup_free_ Member **sorted = NULL;
|
||||
r = set_dump_sorted(members, (void***) &sorted, &n);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
Member **sorted = newa(Member*, set_size(members));
|
||||
size_t k = 0;
|
||||
_cleanup_(table_unrefp) Table *table = table_new("name", "type", "signature", "result/value", "flags");
|
||||
if (!table)
|
||||
return log_oom();
|
||||
|
||||
SET_FOREACH(m, members) {
|
||||
if (argv[3] && !streq(argv[3], m->interface))
|
||||
continue;
|
||||
if (arg_full)
|
||||
table_set_width(table, 0);
|
||||
(void) table_set_maximum_width(table, table_get_cell(table, 0, 3), arg_full ? 100 : 40);
|
||||
table_set_header(table, arg_legend);
|
||||
table_set_ersatz_string(table, TABLE_ERSATZ_DASH);
|
||||
|
||||
if (m->interface)
|
||||
name_width = MAX(name_width, strlen(m->interface));
|
||||
if (m->name)
|
||||
name_width = MAX(name_width, strlen(m->name) + 1);
|
||||
if (m->type)
|
||||
type_width = MAX(type_width, strlen(m->type));
|
||||
if (m->signature)
|
||||
signature_width = MAX(signature_width, strlen(m->signature));
|
||||
if (m->result)
|
||||
result_width = MAX(result_width, strlen(m->result));
|
||||
if (m->value)
|
||||
result_width = MAX(result_width, strlen(m->value));
|
||||
|
||||
sorted[k++] = m;
|
||||
}
|
||||
|
||||
if (result_width > 40 && arg_full <= 0)
|
||||
result_width = 40;
|
||||
|
||||
typesafe_qsort(sorted, k, member_compare_funcp);
|
||||
|
||||
pager_open(arg_pager_flags);
|
||||
|
||||
if (arg_legend)
|
||||
printf("%-*s %-*s %-*s %-*s %s\n",
|
||||
(int) name_width, "NAME",
|
||||
(int) type_width, "TYPE",
|
||||
(int) signature_width, "SIGNATURE",
|
||||
(int) result_width, "RESULT/VALUE",
|
||||
"FLAGS");
|
||||
|
||||
for (size_t j = 0; j < k; j++) {
|
||||
_cleanup_free_ char *ellipsized = NULL;
|
||||
const char *rv;
|
||||
FOREACH_ARRAY(p, sorted, n) {
|
||||
bool is_interface;
|
||||
|
||||
m = sorted[j];
|
||||
m = *p;
|
||||
|
||||
if (argv[3] && !streq(argv[3], m->interface))
|
||||
continue;
|
||||
@@ -1167,32 +1157,38 @@ static int introspect(int argc, char **argv, void *userdata) {
|
||||
if (argv[3] && is_interface)
|
||||
continue;
|
||||
|
||||
if (m->value) {
|
||||
ellipsized = ellipsize(m->value, result_width, 100);
|
||||
if (!ellipsized)
|
||||
return log_oom();
|
||||
if (is_interface)
|
||||
r = table_add_many(
|
||||
table,
|
||||
TABLE_STRING, m->interface,
|
||||
TABLE_SET_COLOR, ansi_highlight());
|
||||
else
|
||||
r = table_add_cell_stringf(
|
||||
table, /* ret_cell = */ NULL, ".%s", m->name);
|
||||
if (r < 0)
|
||||
return table_log_add_error(r);
|
||||
|
||||
rv = ellipsized;
|
||||
} else
|
||||
rv = empty_to_dash(m->result);
|
||||
_cleanup_free_ char *flags = NULL;
|
||||
r = members_flags_to_string(m, &flags);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
printf("%s%s%-*s%s %-*s %-*s %-*s%s%s%s%s%s%s\n",
|
||||
is_interface ? ansi_highlight() : "",
|
||||
is_interface ? "" : ".",
|
||||
- !is_interface + (int) name_width,
|
||||
empty_to_dash(streq_ptr(m->type, "interface") ? m->interface : m->name),
|
||||
is_interface ? ansi_normal() : "",
|
||||
(int) type_width, empty_to_dash(m->type),
|
||||
(int) signature_width, empty_to_dash(m->signature),
|
||||
(int) result_width, rv,
|
||||
(m->flags & SD_BUS_VTABLE_DEPRECATED) ? " deprecated" : (m->flags || m->writable ? "" : " -"),
|
||||
(m->flags & SD_BUS_VTABLE_METHOD_NO_REPLY) ? " no-reply" : "",
|
||||
(m->flags & SD_BUS_VTABLE_PROPERTY_CONST) ? " const" : "",
|
||||
(m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) ? " emits-change" : "",
|
||||
(m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) ? " emits-invalidation" : "",
|
||||
m->writable ? " writable" : "");
|
||||
r = table_add_many(
|
||||
table,
|
||||
TABLE_STRING, m->type,
|
||||
TABLE_STRING, m->signature,
|
||||
TABLE_STRING, m->value ?: m->result,
|
||||
TABLE_STRING, flags);
|
||||
if (r < 0)
|
||||
return table_log_add_error(r);
|
||||
}
|
||||
|
||||
pager_open(arg_pager_flags);
|
||||
|
||||
r = table_print(table, NULL);
|
||||
if (r < 0)
|
||||
return table_log_print_error(r);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user