diff options
author | Lennart Poettering <lennart@poettering.net> | 2024-05-24 16:34:12 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2024-06-13 09:37:15 +0200 |
commit | 16cfe84c2495c1d9e753e2b8e21b69bea21ebaf4 (patch) | |
tree | ae88d7969029d98e6c00586310b1149347ae4ad3 /src/varlinkctl | |
parent | varlinkctl: make interface argument to "introspect" optional, and allow more ... (diff) | |
download | systemd-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.c | 52 |
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 }, |