]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
varlink: tweak what we include in "system error" messages
authorLennart Poettering <lennart@poettering.net>
Tue, 7 Jan 2025 17:51:10 +0000 (18:51 +0100)
committerLennart Poettering <lennart@poettering.net>
Fri, 10 Jan 2025 13:05:29 +0000 (14:05 +0100)
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.

src/libsystemd/sd-varlink/sd-varlink.c
src/libsystemd/sd-varlink/varlink-io.systemd.c

index 962adcb8697c33040df7e76cce18e9681197bbb6..8658c81f67c651ebe76e776d7b05d8aa8fa3fa34 100644 (file)
@@ -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) {
index e2511265a37310d725dc7d3a594de9dd17b8398c..30c9495d40ab4ae555665cf5135004bddf817b6b 100644 (file)
@@ -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);