summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2025-01-07 18:51:10 +0100
committerLennart Poettering <lennart@poettering.net>2025-01-10 14:05:29 +0100
commitf249cc76180864ca95ba7ca0c48d6389c47e84d5 (patch)
tree556230da7c15aecb0c8c2cf7976ec6b82e7ece01 /src
parentsd-json: make it safe to call sd_json_dispatch_full() with a NULL table (diff)
downloadsystemd-f249cc76180864ca95ba7ca0c48d6389c47e84d5.tar.xz
systemd-f249cc76180864ca95ba7ca0c48d6389c47e84d5.zip
varlink: tweak what we include in "system error" messages
We so far only included the numeric Linux errno. That's pretty Linux specific however. Hence, let's improve things and include an origin string, that clearly marks Linux as origin. Also, include the string name of the error. Take these two fields into account when translating back, too. So that we prefer going by symbolic name rather than by numeric id.
Diffstat (limited to 'src')
-rw-r--r--src/libsystemd/sd-varlink/sd-varlink.c61
-rw-r--r--src/libsystemd/sd-varlink/varlink-io.systemd.c11
2 files changed, 60 insertions, 12 deletions
diff --git a/src/libsystemd/sd-varlink/sd-varlink.c b/src/libsystemd/sd-varlink/sd-varlink.c
index 962adcb869..8658c81f67 100644
--- a/src/libsystemd/sd-varlink/sd-varlink.c
+++ b/src/libsystemd/sd-varlink/sd-varlink.c
@@ -2678,10 +2678,21 @@ _public_ int sd_varlink_error_invalid_parameter_name(sd_varlink *v, const char *
}
_public_ int sd_varlink_error_errno(sd_varlink *v, int error) {
+
+ /* This generates a system error return that includes the Linux error number, and error name. The
+ * error number is kinda Linux specific (and to some degree the error name too), hence let's indicate
+ * the origin of the system error. This way interpretation of the error should not leave questions
+ * open, even to foreign systems. */
+
+ error = abs(error);
+ const char *name = errno_to_name(error);
+
return sd_varlink_errorbo(
v,
SD_VARLINK_ERROR_SYSTEM,
- SD_JSON_BUILD_PAIR("errno", SD_JSON_BUILD_INTEGER(abs(error))));
+ SD_JSON_BUILD_PAIR_STRING("origin", "linux"),
+ SD_JSON_BUILD_PAIR_INTEGER("errno", error),
+ JSON_BUILD_PAIR_STRING_NON_EMPTY("errnoName", name));
}
_public_ int sd_varlink_notify(sd_varlink *v, sd_json_variant *parameters) {
@@ -4193,6 +4204,8 @@ _public_ int sd_varlink_error_to_errno(const char *error, sd_json_variant *param
{ SD_VARLINK_ERROR_EXPECTED_MORE, -EBADE },
};
+ int r;
+
if (!error)
return 0;
@@ -4200,20 +4213,46 @@ _public_ int sd_varlink_error_to_errno(const char *error, sd_json_variant *param
if (streq(error, t->error))
return t->value;
- if (streq(error, SD_VARLINK_ERROR_SYSTEM) && parameters) {
- sd_json_variant *e;
+ /* This following tries to reverse the operation sd_varlink_error_errno() applies to turn errnos into
+ * varlink errors */
+ if (!streq(error, SD_VARLINK_ERROR_SYSTEM))
+ return -EBADR;
- e = sd_json_variant_by_key(parameters, "errno");
- if (sd_json_variant_is_integer(e)) {
- int64_t i;
+ if (!parameters)
+ return -EBADR;
- i = sd_json_variant_integer(e);
- if (i > 0 && i < ERRNO_MAX)
- return -i;
- }
+ /* If an origin is set, check if it's Linux, otherwise don't translate */
+ sd_json_variant *e = sd_json_variant_by_key(parameters, "origin");
+ if (e && (!sd_json_variant_is_string(e) ||
+ !streq(sd_json_variant_string(e), "linux")))
+ return -EBADR;
+
+ /* If a name is specified, go by name */
+ e = sd_json_variant_by_key(parameters, "errnoName");
+ if (e) {
+ if (!sd_json_variant_is_string(e))
+ return -EBADR;
+
+ r = errno_from_name(sd_json_variant_string(e));
+ if (r < 0)
+ return -EBADR;
+
+ assert(r > 0);
+ return -r;
}
- return -EBADR; /* Catch-all */
+ /* Finally, use the provided error number, if there is one */
+ e = sd_json_variant_by_key(parameters, "errno");
+ if (!e)
+ return -EBADR;
+ if (!sd_json_variant_is_integer(e))
+ return -EBADR;
+
+ int64_t i = sd_json_variant_integer(e);
+ if (i <= 0 || i > ERRNO_MAX)
+ return -EBADR;
+
+ return (int) -i;
}
_public_ int sd_varlink_error_is_invalid_parameter(const char *error, sd_json_variant *parameter, const char *name) {
diff --git a/src/libsystemd/sd-varlink/varlink-io.systemd.c b/src/libsystemd/sd-varlink/varlink-io.systemd.c
index e2511265a3..30c9495d40 100644
--- a/src/libsystemd/sd-varlink/varlink-io.systemd.c
+++ b/src/libsystemd/sd-varlink/varlink-io.systemd.c
@@ -10,12 +10,21 @@ static SD_VARLINK_DEFINE_ERROR(Protocol);
/* This one we invented, and use for generically propagating system errors (errno) to clients */
static SD_VARLINK_DEFINE_ERROR(
System,
- SD_VARLINK_DEFINE_FIELD(errno, SD_VARLINK_INT, 0));
+ SD_VARLINK_FIELD_COMMENT("The origin of this system error, typically 'linux' to indicate Linux error numbers."),
+ SD_VARLINK_DEFINE_FIELD(origin, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
+ SD_VARLINK_FIELD_COMMENT("The Linux error name, i.e. ENOENT, EHWPOISON or similar."),
+ SD_VARLINK_DEFINE_FIELD(errnoName, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
+ SD_VARLINK_FIELD_COMMENT("The numeric Linux error number. Typically the name is preferable, if specified."),
+ SD_VARLINK_DEFINE_FIELD(errno, SD_VARLINK_STRING, SD_VARLINK_NULLABLE));
SD_VARLINK_DEFINE_INTERFACE(
io_systemd,
"io.systemd",
+ SD_VARLINK_SYMBOL_COMMENT("Local error if a Varlink connection is disconnected (this never crosses the wire and is synthesized locally only)."),
&vl_error_Disconnected,
+ SD_VARLINK_SYMBOL_COMMENT("A method call time-out has been reached (also synthesized locally, does not cross wire)"),
&vl_error_TimedOut,
+ SD_VARLINK_SYMBOL_COMMENT("Some form of protocol error (also synthesized locally, does not cross wire)"),
&vl_error_Protocol,
+ SD_VARLINK_SYMBOL_COMMENT("A generic Linux system error (\"errno\"s)."),
&vl_error_System);