diff --git a/man/varlinkctl.xml b/man/varlinkctl.xml index 0dedc1e4db..f21e513cb0 100644 --- a/man/varlinkctl.xml +++ b/man/varlinkctl.xml @@ -239,6 +239,17 @@ + + + + + + Suppress output of method call replies. + + + + + diff --git a/src/libsystemd/sd-json/sd-json.c b/src/libsystemd/sd-json/sd-json.c index 3a0b838c51..2c5c0a35c9 100644 --- a/src/libsystemd/sd-json/sd-json.c +++ b/src/libsystemd/sd-json/sd-json.c @@ -3378,6 +3378,9 @@ _public_ int sd_json_parse_with_source( _cleanup_(json_source_unrefp) JsonSource *s = NULL; + if (isempty(input)) + return -ENODATA; + if (source) { s = json_source_new(source); if (!s) @@ -3447,9 +3450,6 @@ _public_ int sd_json_parse_file_at( if (r < 0) return r; - if (isempty(text)) - return -ENODATA; - return sd_json_parse_with_source(text, path, flags, ret, reterr_line, reterr_column); } diff --git a/src/varlinkctl/varlinkctl.c b/src/varlinkctl/varlinkctl.c index 5d3a2f4c0a..3057c0542c 100644 --- a/src/varlinkctl/varlinkctl.c +++ b/src/varlinkctl/varlinkctl.c @@ -21,6 +21,7 @@ static sd_json_format_flags_t arg_json_format_flags = SD_JSON_FORMAT_OFF; static PagerFlags arg_pager_flags = 0; static VarlinkMethodFlags arg_method_flags = 0; static bool arg_collect = false; +static bool arg_quiet = false; static int help(void) { _cleanup_free_ char *link = NULL; @@ -56,6 +57,7 @@ static int help(void) { " --oneway Do not request response\n" " --json=MODE Output as JSON\n" " -j Same as --json=pretty on tty, --json=short otherwise\n" + " -q --quiet Do not output method reply\n" "\nSee the %2$s for details.\n", program_invocation_short_name, link, @@ -90,6 +92,7 @@ static int parse_argv(int argc, char *argv[]) { { "oneway", no_argument, NULL, ARG_ONEWAY }, { "json", required_argument, NULL, ARG_JSON }, { "collect", no_argument, NULL, ARG_COLLECT }, + { "quiet", no_argument, NULL, 'q' }, {}, }; @@ -98,7 +101,7 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); - while ((c = getopt_long(argc, argv, "hj", options, NULL)) >= 0) + while ((c = getopt_long(argc, argv, "hjq", options, NULL)) >= 0) switch (c) { @@ -135,6 +138,10 @@ static int parse_argv(int argc, char *argv[]) { arg_json_format_flags = SD_JSON_FORMAT_PRETTY_AUTO|SD_JSON_FORMAT_COLOR_AUTO; break; + case 'q': + arg_quiet = true; + break; + case '?': return -EINVAL; @@ -435,14 +442,16 @@ static int reply_callback( } else r = 0; - sd_json_variant_dump(parameters, arg_json_format_flags, stdout, NULL); + if (!arg_quiet) + sd_json_variant_dump(parameters, arg_json_format_flags, stdout, NULL); + return r; } static int verb_call(int argc, char *argv[], void *userdata) { _cleanup_(sd_json_variant_unrefp) sd_json_variant *jp = NULL; _cleanup_(varlink_unrefp) Varlink *vl = NULL; - const char *url, *method, *parameter; + const char *url, *method, *parameter, *source; unsigned line = 0, column = 0; int r; @@ -461,15 +470,25 @@ static int verb_call(int argc, char *argv[], void *userdata) { arg_json_format_flags |= SD_JSON_FORMAT_NEWLINE; if (parameter) { + source = ""; + /* is correct, as dispatch_verb() shifts arguments by one for the verb. */ - r = sd_json_parse_with_source(parameter, "", 0, &jp, &line, &column); - if (r < 0) - return log_error_errno(r, "Failed to parse parameters at :%u:%u: %m", line, column); + r = sd_json_parse_with_source(parameter, source, 0, &jp, &line, &column); } else { - r = sd_json_parse_file_at(stdin, AT_FDCWD, "", 0, &jp, &line, &column); - if (r < 0) - return log_error_errno(r, "Failed to parse parameters at :%u:%u: %m", line, column); + if (isatty(STDIN_FILENO) > 0 && !arg_quiet) + log_notice("Expecting method call parameter JSON object on standard input. (Provide empty string or {} for no parameters.)"); + + source = ""; + + r = sd_json_parse_file_at(stdin, AT_FDCWD, source, 0, &jp, &line, &column); } + if (r < 0 && r != -ENODATA) + return log_error_errno(r, "Failed to parse parameters at %s:%u:%u: %m", source, line, column); + + /* If parsing resulted in ENODATA the provided string was empty. As convenience to users we'll accept + * that and treat it as equivalent to an empty object: as a call with empty set of parameters. This + * mirrors how we do this in our C APIs too, where we are happy to accept NULL instead of a proper + * JsonVariant object for method calls. */ r = varlink_connect_auto(&vl, url); if (r < 0) @@ -490,6 +509,9 @@ static int verb_call(int argc, char *argv[], void *userdata) { } else r = 0; + if (arg_quiet) + return r; + pager_open(arg_pager_flags); sd_json_variant_dump(reply, arg_json_format_flags, stdout, NULL); return r; @@ -552,6 +574,9 @@ static int verb_call(int argc, char *argv[], void *userdata) { } else r = 0; + if (arg_quiet) + return r; + pager_open(arg_pager_flags); sd_json_variant_dump(reply, arg_json_format_flags, stdout, NULL); @@ -598,6 +623,9 @@ static int verb_validate_idl(int argc, char *argv[], void *userdata) { if (r < 0) return log_error_errno(r, "Failed to check interface for consistency: %m"); + if (arg_quiet) + return 0; + pager_open(arg_pager_flags); r = varlink_idl_dump(stdout, /* use_colors= */ -1, vi); diff --git a/test/units/TEST-74-AUX-UTILS.varlinkctl.sh b/test/units/TEST-74-AUX-UTILS.varlinkctl.sh index 9de014bdad..030f077c85 100755 --- a/test/units/TEST-74-AUX-UTILS.varlinkctl.sh +++ b/test/units/TEST-74-AUX-UTILS.varlinkctl.sh @@ -40,9 +40,11 @@ varlinkctl introspect -j /run/systemd/journal/io.systemd.journal io.systemd.Jour if command -v userdbctl >/dev/null; then systemctl start systemd-userdbd varlinkctl call /run/systemd/userdb/io.systemd.Multiplexer io.systemd.UserDatabase.GetUserRecord '{ "userName" : "testuser", "service" : "io.systemd.Multiplexer" }' + varlinkctl call -q /run/systemd/userdb/io.systemd.Multiplexer io.systemd.UserDatabase.GetUserRecord '{ "userName" : "testuser", "service" : "io.systemd.Multiplexer" }' varlinkctl call -j /run/systemd/userdb/io.systemd.Multiplexer io.systemd.UserDatabase.GetUserRecord '{ "userName" : "testuser", "service" : "io.systemd.Multiplexer" }' | jq . # We ignore the return value of the following two calls, since if no memberships are defined at all this will return a NotFound error, which is OK (varlinkctl call --more /run/systemd/userdb/io.systemd.Multiplexer io.systemd.UserDatabase.GetMemberships '{ "service" : "io.systemd.Multiplexer" }' ||:) + (varlinkctl call --quiet --more /run/systemd/userdb/io.systemd.Multiplexer io.systemd.UserDatabase.GetMemberships '{ "service" : "io.systemd.Multiplexer" }' ||:) (varlinkctl call --more -j /run/systemd/userdb/io.systemd.Multiplexer io.systemd.UserDatabase.GetMemberships '{ "service" : "io.systemd.Multiplexer" }' ||:) | jq --seq . varlinkctl call --oneway /run/systemd/userdb/io.systemd.Multiplexer io.systemd.UserDatabase.GetMemberships '{ "service" : "io.systemd.Multiplexer" }' (! varlinkctl call --oneway /run/systemd/userdb/io.systemd.Multiplexer io.systemd.UserDatabase.GetMemberships '{ "service" : "io.systemd.Multiplexer" }' | grep .)