]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
varlinkctl: add new list-methods verb
authorLennart Poettering <lennart@poettering.net>
Fri, 24 May 2024 14:34:12 +0000 (16:34 +0200)
committerLennart Poettering <lennart@poettering.net>
Thu, 13 Jun 2024 07:37:15 +0000 (09:37 +0200)
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.

man/varlinkctl.xml
src/varlinkctl/varlinkctl.c

index 5a3e1d0050416e6bf4863d480df3ffa55820117d..0dedc1e4db5e05e7e8db6e3ada53c77f8e051cec 100644 (file)
         <xi:include href="version-info.xml" xpointer="v255"/></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><command>list-methods</command> <replaceable>ADDRESS</replaceable> [<replaceable>INTERFACE…</replaceable>]</term>
+
+        <listitem><para>Show list of methods implemented by the specified service. Expects a service address
+        in one of the formats described above as well as one or more interface names. If no interface name is
+        specified, lists all methods of all interfaces implemented by the service, otherwise just the methods
+        in the specified services.</para>
+
+        <xi:include href="version-info.xml" xpointer="v257"/></listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><command>introspect</command> <replaceable>ADDRESS</replaceable> [<replaceable>INTERFACE…</replaceable>]</term>
 
index 6d9a6a972102d809fdfc5e7ac97ba4ea608f831c..739770d2961ebe81ef43f473fca1ec2d5acfd34f 100644 (file)
@@ -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         },