From: Lennart Poettering Date: Mon, 27 May 2024 20:32:51 +0000 (+0200) Subject: varlinkctl: add --graceful= option for optionally marking some errors as successes X-Git-Tag: v257-rc1~1085^2~1 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=da213bb5c0d766ef612fe74537792b92c257c01c;p=thirdparty%2Fsystemd.git varlinkctl: add --graceful= option for optionally marking some errors as successes This is generally useful, but in some cases particularly: when implementing enumeration calls that use the "more" flag to return multiple replies then for the first reply we need to return an error in case the list of objects to enumerate is empty, usually so form of "NoSuchXYZ" error. In many cases this shouldn't really be treated as error, as an empty list probably more than not is as valid as a list with one, two or more entries. --- diff --git a/man/varlinkctl.xml b/man/varlinkctl.xml index f21e513cb0f..2e8207cbcb3 100644 --- a/man/varlinkctl.xml +++ b/man/varlinkctl.xml @@ -250,6 +250,20 @@ + + + + + Takes a qualified Varlink error name (i.e. an interface name, suffixed by an error name, + separated by a dot; e.g. org.varlink.service.InvalidParameter). Ensures that if + a method call fails with the specified error this will be treated as success, i.e. will cause the + varlinkctl invocation to exit with a zero exit status. This option may be used more + than once in order to treat multiple different errors as successes. + + + + + diff --git a/src/varlinkctl/varlinkctl.c b/src/varlinkctl/varlinkctl.c index 02caf218e79..f4e5cc2cbff 100644 --- a/src/varlinkctl/varlinkctl.c +++ b/src/varlinkctl/varlinkctl.c @@ -22,6 +22,9 @@ static PagerFlags arg_pager_flags = 0; static VarlinkMethodFlags arg_method_flags = 0; static bool arg_collect = false; static bool arg_quiet = false; +static char **arg_graceful = NULL; + +STATIC_DESTRUCTOR_REGISTER(arg_graceful, strv_freep); static int help(void) { _cleanup_free_ char *link = NULL; @@ -58,6 +61,7 @@ static int help(void) { " --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" + " --graceful=ERROR Treat specified Varlink error as success\n" "\nSee the %2$s for details.\n", program_invocation_short_name, link, @@ -82,6 +86,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_ONEWAY, ARG_JSON, ARG_COLLECT, + ARG_GRACEFUL, }; static const struct option options[] = { @@ -93,6 +98,7 @@ static int parse_argv(int argc, char *argv[]) { { "json", required_argument, NULL, ARG_JSON }, { "collect", no_argument, NULL, ARG_COLLECT }, { "quiet", no_argument, NULL, 'q' }, + { "graceful", required_argument, NULL, ARG_GRACEFUL }, {}, }; @@ -142,6 +148,18 @@ static int parse_argv(int argc, char *argv[]) { arg_quiet = true; break; + case ARG_GRACEFUL: + r = varlink_idl_qualified_symbol_name_is_valid(optarg); + if (r < 0) + return log_error_errno(r, "Failed to validate Varlink error name '%s': %m", optarg); + if (r == 0) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Not a valid Varlink error name: %s", optarg); + + if (strv_extend(&arg_graceful, optarg) < 0) + return log_oom(); + + break; + case '?': return -EINVAL; @@ -153,6 +171,8 @@ static int parse_argv(int argc, char *argv[]) { if (FLAGS_SET(arg_method_flags, VARLINK_METHOD_MORE)) arg_json_format_flags |= SD_JSON_FORMAT_SEQ; + strv_sort_uniq(arg_graceful); + return 1; } @@ -438,7 +458,13 @@ static int reply_callback( /* Propagate the error we received via sd_notify() */ (void) sd_notifyf(/* unset_environment= */ false, "VARLINKERROR=%s", error); - r = *ret = log_error_errno(SYNTHETIC_ERRNO(EBADE), "Method call failed: %s", error); + if (strv_contains(arg_graceful, error)) { + log_full(arg_quiet ? LOG_DEBUG : LOG_INFO, + "Method call returned expected error: %s", error); + + r = 0; + } else + r = *ret = log_error_errno(SYNTHETIC_ERRNO(EBADE), "Method call failed: %s", error); } else r = 0; @@ -505,7 +531,13 @@ static int verb_call(int argc, char *argv[], void *userdata) { /* Propagate the error we received via sd_notify() */ (void) sd_notifyf(/* unset_environment= */ false, "VARLINKERROR=%s", error); - r = log_error_errno(SYNTHETIC_ERRNO(EBADE), "Method call %s() failed: %s", method, error); + if (strv_contains(arg_graceful, error)) { + log_full(arg_quiet ? LOG_DEBUG : LOG_INFO, + "Method call %s() returned expected error: %s", method, error); + + r = 0; + } else + r = log_error_errno(SYNTHETIC_ERRNO(EBADE), "Method call %s() failed: %s", method, error); } else r = 0; @@ -570,7 +602,13 @@ static int verb_call(int argc, char *argv[], void *userdata) { /* Propagate the error we received via sd_notify() */ (void) sd_notifyf(/* unset_environment= */ false, "VARLINKERROR=%s", error); - r = log_error_errno(SYNTHETIC_ERRNO(EBADE), "Method call %s() failed: %s", method, error); + if (strv_contains(arg_graceful, error)) { + log_full(arg_quiet ? LOG_DEBUG : LOG_INFO, + "Method call %s() returned expected error: %s", method, error); + + r = 0; + } else + r = log_error_errno(SYNTHETIC_ERRNO(EBADE), "Method call %s() failed: %s", method, error); } else r = 0;