summaryrefslogtreecommitdiffstats
path: root/src/varlinkctl
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2024-05-24 16:34:12 +0200
committerLennart Poettering <lennart@poettering.net>2024-06-13 09:37:15 +0200
commit16cfe84c2495c1d9e753e2b8e21b69bea21ebaf4 (patch)
treeae88d7969029d98e6c00586310b1149347ae4ad3 /src/varlinkctl
parentvarlinkctl: make interface argument to "introspect" optional, and allow more ... (diff)
downloadsystemd-16cfe84c2495c1d9e753e2b8e21b69bea21ebaf4.tar.xz
systemd-16cfe84c2495c1d9e753e2b8e21b69bea21ebaf4.zip
varlinkctl: add new list-methods verb
For putting together "varlinkctl call" command lines it's useful to quickly enumerate all methods implemented by a service. Hence, let's add a new "list-methods" which uses the introspection data of a service to quickly list methods. This is implemented as a special flavour of the "introspect" logic, and just suppresses all output except for the method names.
Diffstat (limited to 'src/varlinkctl')
-rw-r--r--src/varlinkctl/varlinkctl.c52
1 files changed, 46 insertions, 6 deletions
diff --git a/src/varlinkctl/varlinkctl.c b/src/varlinkctl/varlinkctl.c
index 6d9a6a9721..739770d296 100644
--- a/src/varlinkctl/varlinkctl.c
+++ b/src/varlinkctl/varlinkctl.c
@@ -38,6 +38,9 @@ static int help(void) {
" info ADDRESS Show service information\n"
" list-interfaces ADDRESS\n"
" List interfaces implemented by service\n"
+ " list-methods ADDRESS [INTERFACE…]\n"
+ " List methods implemented by services or specific\n"
+ " interfaces\n"
" introspect ADDRESS [INTERFACE…]\n"
" Show interface definition\n"
" call ADDRESS METHOD [PARAMS]\n"
@@ -293,9 +296,11 @@ static int verb_introspect(int argc, char *argv[], void *userdata) {
_cleanup_strv_free_ char **auto_interfaces = NULL;
char **interfaces;
const char *url;
+ bool list_methods;
int r;
assert(argc >= 2);
+ list_methods = streq(argv[0], "list-methods");
url = argv[1];
interfaces = strv_skip(argv, 2);
@@ -328,9 +333,11 @@ static int verb_introspect(int argc, char *argv[], void *userdata) {
}
/* Automatically switch on JSON_SEQ if we output multiple JSON objects */
- if (strv_length(interfaces) > 1)
+ if (!list_methods && strv_length(interfaces) > 1)
arg_json_format_flags |= SD_JSON_FORMAT_SEQ;
+ _cleanup_strv_free_ char **methods = NULL;
+
STRV_FOREACH(i, interfaces) {
sd_json_variant *reply = NULL;
r = varlink_callb_and_log(
@@ -341,9 +348,7 @@ static int verb_introspect(int argc, char *argv[], void *userdata) {
if (r < 0)
return r;
- pager_open(arg_pager_flags);
-
- if (FLAGS_SET(arg_json_format_flags, SD_JSON_FORMAT_OFF)) {
+ if (FLAGS_SET(arg_json_format_flags, SD_JSON_FORMAT_OFF) || list_methods) {
static const struct sd_json_dispatch_field dispatch_table[] = {
{ "description", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, 0, SD_JSON_MANDATORY },
{}
@@ -356,22 +361,56 @@ static int verb_introspect(int argc, char *argv[], void *userdata) {
if (r < 0)
return r;
- if (i > interfaces)
+ if (!list_methods && i > interfaces)
print_separator();
/* Try to parse the returned description, so that we can add syntax highlighting */
r = varlink_idl_parse(ASSERT_PTR(description), &line, &column, &vi);
if (r < 0) {
+ if (list_methods)
+ return log_error_errno(r, "Failed to parse returned interface description at %u:%u: %m", line, column);
+
log_warning_errno(r, "Failed to parse returned interface description at %u:%u, showing raw interface description: %m", line, column);
+ pager_open(arg_pager_flags);
fputs_with_newline(description, stdout);
+ } else if (list_methods) {
+ for (const VarlinkSymbol *const *y = vi->symbols, *symbol; (symbol = *y); y++) {
+ if (symbol->symbol_type != VARLINK_METHOD)
+ continue;
+
+ r = strv_extendf(&methods, "%s.%s", vi->name, symbol->name);
+ if (r < 0)
+ return log_oom();
+ }
} else {
+ pager_open(arg_pager_flags);
r = varlink_idl_dump(stdout, /* use_colors= */ -1, vi);
if (r < 0)
return log_error_errno(r, "Failed to format parsed interface description: %m");
}
- } else
+ } else {
+ pager_open(arg_pager_flags);
sd_json_variant_dump(reply, arg_json_format_flags, stdout, NULL);
+ }
+ }
+
+ if (list_methods) {
+ pager_open(arg_pager_flags);
+
+ strv_sort(strv_uniq(methods));
+
+ if (FLAGS_SET(arg_json_format_flags, SD_JSON_FORMAT_OFF))
+ strv_print(methods);
+ else {
+ _cleanup_(sd_json_variant_unrefp) sd_json_variant *j = NULL;
+
+ r = sd_json_build(&j, SD_JSON_BUILD_STRV(methods));
+ if (r < 0)
+ return log_error_errno(r, "Failed to build JSON array: %m");
+
+ sd_json_variant_dump(j, arg_json_format_flags, stdout, NULL);
+ }
}
return 0;
@@ -573,6 +612,7 @@ static int varlinkctl_main(int argc, char *argv[]) {
{ "info", 2, 2, 0, verb_info },
{ "list-interfaces", 2, 2, 0, verb_info },
{ "introspect", 2, VERB_ANY, 0, verb_introspect },
+ { "list-methods", 2, VERB_ANY, 0, verb_introspect },
{ "call", 3, 4, 0, verb_call },
{ "validate-idl", 1, 2, 0, verb_validate_idl },
{ "help", VERB_ANY, VERB_ANY, 0, verb_help },