summaryrefslogtreecommitdiff
path: root/src/libsystemd
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2014-12-06 02:39:15 +0100
committerLennart Poettering <lennart@poettering.net>2014-12-08 14:55:22 +0100
commit5f86c1f4c43ee9caa120d130e9b89d3fd25124c0 (patch)
tree34908816bfd429ba578f99626eb2deabc1ed631a /src/libsystemd
parent8b5e2af10830d55b2032e6c79d0cd1f959bb5b7f (diff)
sd-bus: rework ELF error mapping table magic
The ELF magic cannot work for consumers of our shard library, since they are in a different module. Hence make all the ELF magic private, and instead introduce a public function to register additional static mapping table.
Diffstat (limited to 'src/libsystemd')
-rw-r--r--src/libsystemd/sd-bus/bus-error.c155
-rw-r--r--src/libsystemd/sd-bus/bus-error.h37
-rw-r--r--src/libsystemd/sd-bus/test-bus-error.c66
3 files changed, 193 insertions, 65 deletions
diff --git a/src/libsystemd/sd-bus/bus-error.c b/src/libsystemd/sd-bus/bus-error.c
index 47f90c26f..157b8d890 100644
--- a/src/libsystemd/sd-bus/bus-error.c
+++ b/src/libsystemd/sd-bus/bus-error.c
@@ -32,61 +32,54 @@
#include "sd-bus.h"
#include "bus-error.h"
-#define BUS_ERROR_OOM SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_MEMORY, "Out of memory")
-#define BUS_ERROR_FAILED SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_FAILED, "Operation failed")
-
-SD_BUS_ERROR_MAPPING(sd_bus_standard) = {
- {"org.freedesktop.DBus.Error.Failed", EACCES},
- {"org.freedesktop.DBus.Error.NoMemory", ENOMEM},
- {"org.freedesktop.DBus.Error.ServiceUnknown", EHOSTUNREACH},
- {"org.freedesktop.DBus.Error.NameHasNoOwner", ENXIO},
- {"org.freedesktop.DBus.Error.NoReply", ETIMEDOUT},
- {"org.freedesktop.DBus.Error.IOError", EIO},
- {"org.freedesktop.DBus.Error.BadAddress", EADDRNOTAVAIL},
- {"org.freedesktop.DBus.Error.NotSupported", ENOTSUP},
- {"org.freedesktop.DBus.Error.LimitsExceeded", ENOBUFS},
- {"org.freedesktop.DBus.Error.AccessDenied", EACCES},
- {"org.freedesktop.DBus.Error.AuthFailed", EACCES},
- {"org.freedesktop.DBus.Error.InteractiveAuthorizationRequired", EACCES},
- {"org.freedesktop.DBus.Error.NoServer", EHOSTDOWN},
- {"org.freedesktop.DBus.Error.Timeout", ETIMEDOUT},
- {"org.freedesktop.DBus.Error.NoNetwork", ENONET},
- {"org.freedesktop.DBus.Error.AddressInUse", EADDRINUSE},
- {"org.freedesktop.DBus.Error.Disconnected", ECONNRESET},
- {"org.freedesktop.DBus.Error.InvalidArgs", EINVAL},
- {"org.freedesktop.DBus.Error.FileNotFound", ENOENT},
- {"org.freedesktop.DBus.Error.FileExists", EEXIST},
- {"org.freedesktop.DBus.Error.UnknownMethod", EBADR},
- {"org.freedesktop.DBus.Error.UnknownObject", EBADR},
- {"org.freedesktop.DBus.Error.UnknownInterface", EBADR},
- {"org.freedesktop.DBus.Error.UnknownProperty", EBADR},
- {"org.freedesktop.DBus.Error.PropertyReadOnly", EROFS},
- {"org.freedesktop.DBus.Error.UnixProcessIdUnknown", ESRCH},
- {"org.freedesktop.DBus.Error.InvalidSignature", EINVAL},
- {"org.freedesktop.DBus.Error.InconsistentMessage", EBADMSG},
-
- {"org.freedesktop.DBus.Error.TimedOut", ETIMEDOUT},
- {"org.freedesktop.DBus.Error.MatchRuleInvalid", EINVAL},
- {"org.freedesktop.DBus.Error.InvalidFileContent", EINVAL},
- {"org.freedesktop.DBus.Error.MatchRuleNotFound", ENOENT},
- {"org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown", ESRCH},
- {"org.freedesktop.DBus.Error.ObjectPathInUse", EBUSY},
+BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map standard_errors[] = {
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.Failed", EACCES),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.NoMemory", ENOMEM),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.ServiceUnknown", EHOSTUNREACH),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.NameHasNoOwner", ENXIO),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.NoReply", ETIMEDOUT),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.IOError", EIO),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.BadAddress", EADDRNOTAVAIL),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.NotSupported", ENOTSUP),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.LimitsExceeded", ENOBUFS),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.AccessDenied", EACCES),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.AuthFailed", EACCES),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.InteractiveAuthorizationRequired", EACCES),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.NoServer", EHOSTDOWN),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.Timeout", ETIMEDOUT),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.NoNetwork", ENONET),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.AddressInUse", EADDRINUSE),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.Disconnected", ECONNRESET),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.InvalidArgs", EINVAL),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.FileNotFound", ENOENT),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.FileExists", EEXIST),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.UnknownMethod", EBADR),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.UnknownObject", EBADR),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.UnknownInterface", EBADR),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.UnknownProperty", EBADR),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.PropertyReadOnly", EROFS),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.UnixProcessIdUnknown", ESRCH),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.InvalidSignature", EINVAL),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.InconsistentMessage", EBADMSG),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.TimedOut", ETIMEDOUT),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.MatchRuleInvalid", EINVAL),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.InvalidFileContent", EINVAL),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.MatchRuleNotFound", ENOENT),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown", ESRCH),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.ObjectPathInUse", EBUSY),
+ SD_BUS_ERROR_MAP_END
};
-extern const sd_bus_name_error_mapping __start_sd_bus_errnomap[];
-extern const sd_bus_name_error_mapping __stop_sd_bus_errnomap[];
+/* GCC maps this magically to the beginning and end of the BUS_ERROR_MAP section */
+extern const sd_bus_error_map __start_BUS_ERROR_MAP[];
+extern const sd_bus_error_map __stop_BUS_ERROR_MAP[];
-static int bus_error_mapping_lookup(const char *name, size_t len) {
- const sd_bus_name_error_mapping *m;
-
- for (m = __start_sd_bus_errnomap; m < __stop_sd_bus_errnomap; m++)
- if (m->name && strneq(m->name, name, len))
- return m->code;
-
- return EIO;
-}
+/* Additional maps registered with sd_bus_error_add_map() are in this
+ * NULL terminated array */
+static const sd_bus_error_map **additional_error_maps = NULL;
static int bus_error_name_to_errno(const char *name) {
+ const sd_bus_error_map **map, *m;
const char *p;
int r;
@@ -102,7 +95,39 @@ static int bus_error_name_to_errno(const char *name) {
return r;
}
- return bus_error_mapping_lookup(name, strlen(name));
+ if (additional_error_maps) {
+ for (map = additional_error_maps; *map; map++) {
+ for (m = *map;; m++) {
+ /* For additional error maps the end marker is actually the end marker */
+ if (m->code == BUS_ERROR_MAP_END_MARKER)
+ break;
+
+ if (streq(m->name, name))
+ return m->code;
+ }
+ }
+ }
+
+ m = __start_BUS_ERROR_MAP;
+ while (m < __stop_BUS_ERROR_MAP) {
+ /* For magic ELF error maps, the end marker might
+ * appear in the middle of things, since multiple maps
+ * might appear in the same section. Hence, let's skip
+ * over it, but realign the pointer to the netx 8byte
+ * boundary, which is the selected alignment for the
+ * arrays. */
+ if (m->code == BUS_ERROR_MAP_END_MARKER) {
+ m = ALIGN8_PTR(m+1);
+ continue;
+ }
+
+ if (streq(m->name, name))
+ return m->code;
+
+ m++;
+ }
+
+ return EIO;
}
static sd_bus_error errno_to_bus_error_const(int error) {
@@ -552,3 +577,31 @@ const char *bus_error_message(const sd_bus_error *e, int error) {
return strerror(error);
}
+
+_public_ int sd_bus_error_add_map(const sd_bus_error_map *map) {
+ const sd_bus_error_map **maps = NULL;
+ unsigned n = 0;
+
+ assert_return(map, -EINVAL);
+
+ if (additional_error_maps) {
+ for (;; n++) {
+ if (additional_error_maps[n] == NULL)
+ break;
+
+ if (additional_error_maps[n] == map)
+ return 0;
+ }
+ }
+
+ maps = realloc_multiply(additional_error_maps, sizeof(struct sd_bus_error_map*), n + 2);
+ if (!maps)
+ return -ENOMEM;
+
+
+ maps[n] = map;
+ maps[n+1] = NULL;
+
+ additional_error_maps = maps;
+ return 1;
+}
diff --git a/src/libsystemd/sd-bus/bus-error.h b/src/libsystemd/sd-bus/bus-error.h
index 146948618..56297156a 100644
--- a/src/libsystemd/sd-bus/bus-error.h
+++ b/src/libsystemd/sd-bus/bus-error.h
@@ -26,15 +26,40 @@
#include "sd-bus.h"
#include "macro.h"
-struct name_error_mapping {
- const char* name;
- int code;
-};
-typedef struct name_error_mapping name_error_mapping;
-
bool bus_error_is_dirty(sd_bus_error *e);
const char *bus_error_message(const sd_bus_error *e, int error);
int bus_error_setfv(sd_bus_error *e, const char *name, const char *format, va_list ap) _printf_(3,0);
int bus_error_set_errnofv(sd_bus_error *e, int error, const char *format, va_list ap) _printf_(3,0);
+
+#define BUS_ERROR_OOM SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_MEMORY, "Out of memory")
+#define BUS_ERROR_FAILED SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_FAILED, "Operation failed")
+
+/*
+ * There are two ways to register error maps with the error translation
+ * logic: by using BUS_ERROR_MAP_ELF_REGISTER, which however only
+ * works when linked into the same ELF module, or via
+ * sd_bus_error_add_map() which is the official, external API, that
+ * works from any module.
+ *
+ * Note that BUS_ERROR_MAP_ELF_REGISTER has to be used as decorator in
+ * the bus error table, and BUS_ERROR_MAP_ELF_USE has to be used at
+ * least once per compilation unit (i.e. per library), to ensure that
+ * the error map is really added to the final binary.
+ */
+
+#define BUS_ERROR_MAP_ELF_REGISTER \
+ __attribute__ ((__section__("BUS_ERROR_MAP"))) \
+ __attribute__ ((__used__)) \
+ __attribute__ ((aligned(8)))
+
+#define BUS_ERROR_MAP_ELF_USE(errors) \
+ extern const sd_bus_error_map errors[]; \
+ __attribute__ ((used)) static const sd_bus_error_map * CONCATENATE(errors ## _copy_, __COUNTER__) = errors;
+
+/* We use something exotic as end marker, to ensure people build the
+ * maps using the macsd-ros. */
+#define BUS_ERROR_MAP_END_MARKER -'x'
+
+BUS_ERROR_MAP_ELF_USE(standard_errors);
diff --git a/src/libsystemd/sd-bus/test-bus-error.c b/src/libsystemd/sd-bus/test-bus-error.c
index ae894e39f..f72bcdb6b 100644
--- a/src/libsystemd/sd-bus/test-bus-error.c
+++ b/src/libsystemd/sd-bus/test-bus-error.c
@@ -22,6 +22,8 @@
#include "sd-bus.h"
#include "bus-error.h"
#include "bus-util.h"
+#include "errno-list.h"
+#include "bus-errors.h"
static void test_error(void) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL, second = SD_BUS_ERROR_NULL;
@@ -111,15 +113,24 @@ static void test_error(void) {
assert_se(sd_bus_error_is_set(&error));
}
-extern const sd_bus_name_error_mapping __start_sd_bus_errnomap[];
-extern const sd_bus_name_error_mapping __stop_sd_bus_errnomap[];
+extern const sd_bus_error_map __start_BUS_ERROR_MAP[];
+extern const sd_bus_error_map __stop_BUS_ERROR_MAP[];
static void dump_mapping_table(void) {
- const sd_bus_name_error_mapping *m;
+ const sd_bus_error_map *m;
printf("----- errno mappings ------\n");
- for (m = __start_sd_bus_errnomap; m < __stop_sd_bus_errnomap; m++)
- printf("%s -> %d\n", m->name, m->code);
+ m = __start_BUS_ERROR_MAP;
+ while (m < __stop_BUS_ERROR_MAP) {
+
+ if (m->code == BUS_ERROR_MAP_END_MARKER) {
+ m = ALIGN8_PTR(m+1);
+ continue;
+ }
+
+ printf("%s -> %i/%s\n", strna(m->name), m->code, strna(errno_to_name(m->code)));
+ m ++;
+ }
printf("---------------------------\n");
}
@@ -130,15 +141,54 @@ static void test_errno_mapping_standard(void) {
assert_se(sd_bus_error_set(NULL, "System.Error.WHATSIT", NULL) == -EIO);
}
-SD_BUS_ERROR_MAPPING(test) = {
- {"org.freedesktop.custom-dbus-error", 5},
- {"org.freedesktop.custom-dbus-error-2", 52},
+BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map test_errors[] = {
+ SD_BUS_ERROR_MAP("org.freedesktop.custom-dbus-error", 5),
+ SD_BUS_ERROR_MAP("org.freedesktop.custom-dbus-error-2", 52),
+ SD_BUS_ERROR_MAP_END
+};
+
+BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map test_errors2[] = {
+ SD_BUS_ERROR_MAP("org.freedesktop.custom-dbus-error-3", 33),
+ SD_BUS_ERROR_MAP("org.freedesktop.custom-dbus-error-4", 44),
+ SD_BUS_ERROR_MAP("org.freedesktop.custom-dbus-error-33", 333),
+ SD_BUS_ERROR_MAP_END
+};
+
+static const sd_bus_error_map test_errors3[] = {
+ SD_BUS_ERROR_MAP("org.freedesktop.custom-dbus-error-88", 888),
+ SD_BUS_ERROR_MAP("org.freedesktop.custom-dbus-error-99", 999),
+ SD_BUS_ERROR_MAP_END
+};
+
+static const sd_bus_error_map test_errors4[] = {
+ SD_BUS_ERROR_MAP("org.freedesktop.custom-dbus-error-77", 777),
+ SD_BUS_ERROR_MAP("org.freedesktop.custom-dbus-error-78", 778),
+ SD_BUS_ERROR_MAP_END
};
static void test_errno_mapping_custom(void) {
assert_se(sd_bus_error_set(NULL, "org.freedesktop.custom-dbus-error", NULL) == -5);
assert_se(sd_bus_error_set(NULL, "org.freedesktop.custom-dbus-error-2", NULL) == -52);
assert_se(sd_bus_error_set(NULL, "org.freedesktop.custom-dbus-error-x", NULL) == -EIO);
+ assert_se(sd_bus_error_set(NULL, "org.freedesktop.custom-dbus-error-33", NULL) == -333);
+
+ assert_se(sd_bus_error_set(NULL, "org.freedesktop.custom-dbus-error-88", NULL) == -EIO);
+ assert_se(sd_bus_error_set(NULL, "org.freedesktop.custom-dbus-error-99", NULL) == -EIO);
+ assert_se(sd_bus_error_set(NULL, "org.freedesktop.custom-dbus-error-77", NULL) == -EIO);
+
+ assert_se(sd_bus_error_add_map(test_errors3) > 0);
+ assert_se(sd_bus_error_set(NULL, "org.freedesktop.custom-dbus-error-88", NULL) == -888);
+ assert_se(sd_bus_error_add_map(test_errors4) > 0);
+ assert_se(sd_bus_error_add_map(test_errors4) == 0);
+ assert_se(sd_bus_error_add_map(test_errors3) == 0);
+
+ assert_se(sd_bus_error_set(NULL, "org.freedesktop.custom-dbus-error-99", NULL) == -999);
+ assert_se(sd_bus_error_set(NULL, "org.freedesktop.custom-dbus-error-77", NULL) == -777);
+ assert_se(sd_bus_error_set(NULL, "org.freedesktop.custom-dbus-error-78", NULL) == -778);
+ assert_se(sd_bus_error_set(NULL, "org.freedesktop.custom-dbus-error-2", NULL) == -52);
+ assert_se(sd_bus_error_set(NULL, "org.freedesktop.custom-dbus-error-y", NULL) == -EIO);
+
+ assert_se(sd_bus_error_set(NULL, BUS_ERROR_NO_SUCH_UNIT, NULL) == -ENOENT);
}
int main(int argc, char *argv[]) {