diff --git a/Makefile.am b/Makefile.am index fa215e8e09..06d4fcf233 100644 --- a/Makefile.am +++ b/Makefile.am @@ -177,6 +177,7 @@ AM_CPPFLAGS = \ -DQUOTACHECK=\"$(QUOTACHECK)\" \ -DKEXEC=\"$(KEXEC)\" \ -I $(top_srcdir)/src \ + -I $(top_builddir)/src/shared \ -I $(top_srcdir)/src/shared \ -I $(top_srcdir)/src/network \ -I $(top_srcdir)/src/login \ @@ -761,7 +762,13 @@ libsystemd_shared_la_SOURCES = \ src/shared/ptyfwd.c \ src/shared/ptyfwd.h \ src/shared/net-util.c \ - src/shared/net-util.h + src/shared/net-util.h \ + src/shared/errno-list.c \ + src/shared/errno-list.h + +nodist_libsystemd_shared_la_SOURCES = \ + src/shared/errno-from-name.h \ + src/shared/errno-to-name.h # ------------------------------------------------------------------------------ noinst_LTLIBRARIES += \ @@ -1031,11 +1038,15 @@ CLEANFILES += \ src/core/load-fragment-gperf.c \ src/core/load-fragment-gperf-nulstr.c \ src/core/syscall-list.txt \ - src/core/syscall-from-name.gperf + src/core/syscall-from-name.gperf \ + src/shared/errno-list.txt \ + src/shared/errno-from-name.gperf BUILT_SOURCES += \ src/core/syscall-from-name.h \ - src/core/syscall-to-name.h + src/core/syscall-to-name.h \ + src/shared/errno-from-name.h \ + src/shared/errno-to-name.h src/core/syscall-list.txt: Makefile $(AM_V_at)$(MKDIR_P) $(dir $@) @@ -1051,7 +1062,23 @@ src/core/syscall-from-name.h: src/core/syscall-from-name.gperf Makefile src/core/syscall-to-name.h: src/core/syscall-list.txt Makefile $(AM_V_at)$(MKDIR_P) $(dir $@) - $(AM_V_GEN)$(AWK) 'BEGIN{ print "const char* const syscall_names[] = { "} { printf "[SYSCALL_TO_INDEX(__NR_%s)] = \"%s\",\n", $$1, $$1 } END{print "};"}' < $< > $@ + $(AM_V_GEN)$(AWK) 'BEGIN{ print "static const char* const syscall_names[] = { "} { printf "[SYSCALL_TO_INDEX(__NR_%s)] = \"%s\",\n", $$1, $$1 } END{print "};"}' < $< > $@ + +src/shared/errno-list.txt: Makefile + $(AM_V_at)$(MKDIR_P) $(dir $@) + $(AM_V_GEN)$(CPP) $(CFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) -dM -include errno.h - < /dev/null | $(AWK) '/^#define[ \t]+E[^ _]+[ \t]+[0-9]/ { print $$2; }' > $@ + +src/shared/errno-from-name.gperf: src/shared/errno-list.txt Makefile + $(AM_V_at)$(MKDIR_P) $(dir $@) + $(AM_V_GEN)$(AWK) 'BEGIN{ print "struct errno_name { const char* name; int id; };"; print "%null-strings"; print "%%";} { printf "%s, %s\n", $$1, $$1 }' < $< > $@ + +src/shared/errno-from-name.h: src/shared/errno-from-name.gperf Makefile + $(AM_V_at)$(MKDIR_P) $(dir $@) + $(AM_V_GPERF)$(GPERF) -L ANSI-C -t --ignore-case -N lookup_errno -H hash_errno_name -p -C < $< > $@ + +src/shared/errno-to-name.h: src/shared/errno-list.txt Makefile + $(AM_V_at)$(MKDIR_P) $(dir $@) + $(AM_V_GEN)$(AWK) 'BEGIN{ print "static const char* const errno_names[] = { "} { printf "[%s] = \"%s\",\n", $$1, $$1 } END{print "};"}' < $< > $@ # ------------------------------------------------------------------------------ systemd_SOURCES = \ @@ -2004,6 +2031,7 @@ tests += \ test-bus-zero-copy \ test-bus-introspect \ test-bus-objects \ + test-bus-error \ test-event bin_PROGRAMS += \ @@ -2079,6 +2107,15 @@ test_bus_objects_LDADD = \ libsystemd-capability.la \ $(CAP_LIBS) +test_bus_error_SOURCES = \ + src/libsystemd-bus/test-bus-error.c + +test_bus_error_LDADD = \ + libsystemd-bus-internal.la \ + libsystemd-id128-internal.la \ + libsystemd-daemon-internal.la \ + libsystemd-shared.la + test_bus_match_SOURCES = \ src/libsystemd-bus/test-bus-match.c diff --git a/src/core/syscall-list.c b/src/core/syscall-list.c index 35216b2a88..dc84dca8fe 100644 --- a/src/core/syscall-list.c +++ b/src/core/syscall-list.c @@ -23,7 +23,6 @@ #include #include "util.h" - #include "syscall-list.h" static const struct syscall_name* lookup_syscall(register const char *str, diff --git a/src/libsystemd-bus/bus-convenience.c b/src/libsystemd-bus/bus-convenience.c index 6446874713..e765ddb21d 100644 --- a/src/libsystemd-bus/bus-convenience.c +++ b/src/libsystemd-bus/bus-convenience.c @@ -155,7 +155,6 @@ _public_ int sd_bus_reply_method_errorf( _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; va_list ap; - int r; assert_return(call, -EINVAL); assert_return(call->sealed, -EPERM); @@ -167,12 +166,9 @@ _public_ int sd_bus_reply_method_errorf( return 0; va_start(ap, format); - r = bus_error_setfv(&error, name, format, ap); + bus_error_setfv(&error, name, format, ap); va_end(ap); - if (r < 0) - return r; - return sd_bus_reply_method_error(call, &error); } diff --git a/src/libsystemd-bus/bus-error.c b/src/libsystemd-bus/bus-error.c index 7fef681413..968e80df7d 100644 --- a/src/libsystemd-bus/bus-error.c +++ b/src/libsystemd-bus/bus-error.c @@ -27,303 +27,110 @@ #include #include "util.h" +#include "errno-list.h" #include "sd-bus.h" #include "bus-error.h" -bool bus_error_is_dirty(sd_bus_error *e) { - if (!e) - return 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") - return e->name || e->message || e->need_free; -} - -_public_ void sd_bus_error_free(sd_bus_error *e) { - if (!e) - return; - - if (e->need_free) { - free((void*) e->name); - free((void*) e->message); - } - - e->name = e->message = NULL; - e->need_free = false; -} - -_public_ int sd_bus_error_set(sd_bus_error *e, const char *name, const char *message) { - char *n, *m = NULL; - - if (!e) - return 0; - - assert_return(!bus_error_is_dirty(e), -EINVAL); - assert_return(name, -EINVAL); - - n = strdup(name); - if (!n) - return -ENOMEM; - - if (message) { - m = strdup(message); - if (!m) - return -ENOMEM; - } - - e->name = n; - e->message = m; - e->need_free = true; - - return sd_bus_error_get_errno(e); -} - -int bus_error_setfv(sd_bus_error *e, const char *name, const char *format, va_list ap) { - char *n, *m = NULL; +static int bus_error_name_to_errno(const char *name) { + const char *p; int r; - if (!e) - return 0; + if (!name) + return EINVAL; - assert_return(!bus_error_is_dirty(e), -EINVAL); - assert_return(name, -EINVAL); - - n = strdup(name); - if (!n) - return -ENOMEM; - - if (format) { - r = vasprintf(&m, format, ap); - if (r < 0) { - free(n); - return -ENOMEM; - } - } - - e->name = n; - e->message = m; - e->need_free = true; - - return sd_bus_error_get_errno(e); -} - -_public_ int sd_bus_error_setf(sd_bus_error *e, const char *name, const char *format, ...) { - - if (format) { - int r; - va_list ap; - - va_start(ap, format); - r = bus_error_setfv(e, name, format, ap); - va_end(ap); + p = startswith(name, "Posix.Error."); + if (p) { + r = errno_from_name(p); + if (r <= 0) + return EIO; return r; } - return sd_bus_error_set(e, name, NULL); -} + /* Better replace this with a gperf table */ -_public_ int sd_bus_error_copy(sd_bus_error *dest, const sd_bus_error *e) { - char *x, *y = NULL; - - if (!dest) - return 0; - if (!sd_bus_error_is_set(e)) - return 0; - - assert_return(!bus_error_is_dirty(dest), -EINVAL); - - x = strdup(e->name); - if (!x) - return -ENOMEM; - - if (e->message) { - y = strdup(e->message); - if (!y) { - free(x); - return -ENOMEM; - } - } - - dest->name = x; - dest->message = y; - dest->need_free = true; - return sd_bus_error_get_errno(e); -} - -_public_ int sd_bus_error_set_const(sd_bus_error *e, const char *name, const char *message) { - if (!e) - return 0; - - assert_return(!bus_error_is_dirty(e), -EINVAL); - assert_return(name, -EINVAL); - - *e = SD_BUS_ERROR_MAKE_CONST(name, message); - return sd_bus_error_get_errno(e); -} - -_public_ int sd_bus_error_is_set(const sd_bus_error *e) { - if (!e) - return 0; - - return !!e->name; -} - -_public_ int sd_bus_error_has_name(const sd_bus_error *e, const char *name) { - if (!e) - return 0; - - return streq_ptr(e->name, name); -} - -_public_ int sd_bus_error_get_errno(const sd_bus_error* e) { - - /* Better replce this with a gperf table */ - - if (!e) - return EIO; - - if (!e->name) - return EIO; - - if (streq(e->name, SD_BUS_ERROR_NO_MEMORY)) + if (streq(name, SD_BUS_ERROR_NO_MEMORY)) return ENOMEM; - if (streq(e->name, SD_BUS_ERROR_SERVICE_UNKNOWN)) + if (streq(name, SD_BUS_ERROR_SERVICE_UNKNOWN)) return EHOSTUNREACH; - if (streq(e->name, SD_BUS_ERROR_NAME_HAS_NO_OWNER)) + if (streq(name, SD_BUS_ERROR_NAME_HAS_NO_OWNER)) return ENXIO; - if (streq(e->name, SD_BUS_ERROR_NO_REPLY) || - streq(e->name, SD_BUS_ERROR_TIMEOUT) || - streq(e->name, "org.freedesktop.DBus.Error.TimedOut")) + if (streq(name, SD_BUS_ERROR_NO_REPLY) || + streq(name, SD_BUS_ERROR_TIMEOUT) || + streq(name, "org.freedesktop.DBus.Error.TimedOut")) return ETIMEDOUT; - if (streq(e->name, SD_BUS_ERROR_IO_ERROR)) + if (streq(name, SD_BUS_ERROR_IO_ERROR)) return EIO; - if (streq(e->name, SD_BUS_ERROR_BAD_ADDRESS)) + if (streq(name, SD_BUS_ERROR_BAD_ADDRESS)) return EADDRNOTAVAIL; - if (streq(e->name, SD_BUS_ERROR_NOT_SUPPORTED)) + if (streq(name, SD_BUS_ERROR_NOT_SUPPORTED)) return ENOTSUP; - if (streq(e->name, SD_BUS_ERROR_LIMITS_EXCEEDED)) + if (streq(name, SD_BUS_ERROR_LIMITS_EXCEEDED)) return ENOBUFS; - if (streq(e->name, SD_BUS_ERROR_ACCESS_DENIED) || - streq(e->name, SD_BUS_ERROR_AUTH_FAILED)) + if (streq(name, SD_BUS_ERROR_ACCESS_DENIED) || + streq(name, SD_BUS_ERROR_AUTH_FAILED)) return EACCES; - if (streq(e->name, SD_BUS_ERROR_NO_SERVER)) + if (streq(name, SD_BUS_ERROR_NO_SERVER)) return EHOSTDOWN; - if (streq(e->name, SD_BUS_ERROR_NO_NETWORK)) + if (streq(name, SD_BUS_ERROR_NO_NETWORK)) return ENONET; - if (streq(e->name, SD_BUS_ERROR_ADDRESS_IN_USE)) + if (streq(name, SD_BUS_ERROR_ADDRESS_IN_USE)) return EADDRINUSE; - if (streq(e->name, SD_BUS_ERROR_DISCONNECTED)) + if (streq(name, SD_BUS_ERROR_DISCONNECTED)) return ECONNRESET; - if (streq(e->name, SD_BUS_ERROR_INVALID_ARGS) || - streq(e->name, SD_BUS_ERROR_INVALID_SIGNATURE) || - streq(e->name, "org.freedesktop.DBus.Error.MatchRuleInvalid") || - streq(e->name, "org.freedesktop.DBus.Error.InvalidFileContent")) + if (streq(name, SD_BUS_ERROR_INVALID_ARGS) || + streq(name, SD_BUS_ERROR_INVALID_SIGNATURE) || + streq(name, "org.freedesktop.DBus.Error.MatchRuleInvalid") || + streq(name, "org.freedesktop.DBus.Error.InvalidFileContent")) return EINVAL; - if (streq(e->name, SD_BUS_ERROR_FILE_NOT_FOUND) || - streq(e->name, "org.freedesktop.DBus.Error.MatchRuleNotFound")) + if (streq(name, SD_BUS_ERROR_FILE_NOT_FOUND) || + streq(name, "org.freedesktop.DBus.Error.MatchRuleNotFound")) return ENOENT; - if (streq(e->name, SD_BUS_ERROR_FILE_EXISTS)) + if (streq(name, SD_BUS_ERROR_FILE_EXISTS)) return EEXIST; - if (streq(e->name, SD_BUS_ERROR_UNKNOWN_METHOD) || - streq(e->name, SD_BUS_ERROR_UNKNOWN_OBJECT) || - streq(e->name, SD_BUS_ERROR_UNKNOWN_INTERFACE) || - streq(e->name, SD_BUS_ERROR_UNKNOWN_PROPERTY)) + if (streq(name, SD_BUS_ERROR_UNKNOWN_METHOD) || + streq(name, SD_BUS_ERROR_UNKNOWN_OBJECT) || + streq(name, SD_BUS_ERROR_UNKNOWN_INTERFACE) || + streq(name, SD_BUS_ERROR_UNKNOWN_PROPERTY)) return EBADR; - if (streq(e->name, SD_BUS_ERROR_PROPERTY_READ_ONLY)) + if (streq(name, SD_BUS_ERROR_PROPERTY_READ_ONLY)) return EROFS; - if (streq(e->name, SD_BUS_ERROR_UNIX_PROCESS_ID_UNKNOWN) || - streq(e->name, "org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown")) + if (streq(name, SD_BUS_ERROR_UNIX_PROCESS_ID_UNKNOWN) || + streq(name, "org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown")) return ESRCH; - if (streq(e->name, SD_BUS_ERROR_INCONSISTENT_MESSAGE)) + if (streq(name, SD_BUS_ERROR_INCONSISTENT_MESSAGE)) return EBADMSG; - if (streq(e->name, "org.freedesktop.DBus.Error.ObjectPathInUse")) + if (streq(name, "org.freedesktop.DBus.Error.ObjectPathInUse")) return EBUSY; return EIO; } -static int bus_error_set_strerror_or_const(sd_bus_error *e, const char *name, int error, const char *fallback) { - size_t k = 64; - char *n = NULL, *m = NULL; - - if (error < 0) - error = -error; - - if (!e) - return -error; - - assert_return(!bus_error_is_dirty(e), -EINVAL); - assert_return(name, -EINVAL); - - for (;;) { - char *x; - - m = new(char, k); - if (!m) - goto use_fallback; - - errno = 0; - x = strerror_r(error, m, k); - if (errno == ERANGE || strlen(x) >= k - 1) { - free(m); - k *= 2; - continue; - } - - if (!x || errno) { - free(m); - goto use_fallback; - } - - - if (x != m) { - free(m); - sd_bus_error_set_const(e, name, x); - return -error; - } - - break; - } - - - n = strdup(name); - if (!n) { - free(m); - goto use_fallback; - } - - e->name = n; - e->message = m; - e->need_free = true; - - return -error; - -use_fallback: - sd_bus_error_set_const(e, name, fallback); - return -error; -} - -static sd_bus_error map_from_errno(int error) { +static sd_bus_error errno_to_bus_error_const(int error) { if (error < 0) error = -error; @@ -331,7 +138,7 @@ static sd_bus_error map_from_errno(int error) { switch (error) { case ENOMEM: - return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_NETWORK, "Out of memory"); + return BUS_ERROR_OOM; case EPERM: case EACCES: @@ -377,19 +184,280 @@ static sd_bus_error map_from_errno(int error) { return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INCONSISTENT_MESSAGE, "Inconsistent message"); } - return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_FAILED, "Operation failed"); + return SD_BUS_ERROR_NULL; +} + +static int errno_to_bus_error_name_new(int error, char **ret) { + const char *name; + char *n; + + if (error < 0) + error = -error; + + name = errno_to_name(error); + if (!name) + return 0; + + n = strappend("Posix.Error.", name); + if (!n) + return -ENOMEM; + + *ret = n; + return 1; +} + +bool bus_error_is_dirty(sd_bus_error *e) { + if (!e) + return false; + + return e->name || e->message || e->need_free; +} + +_public_ void sd_bus_error_free(sd_bus_error *e) { + if (!e) + return; + + if (e->need_free) { + free((void*) e->name); + free((void*) e->message); + } + + e->name = e->message = NULL; + e->need_free = false; +} + +_public_ int sd_bus_error_set(sd_bus_error *e, const char *name, const char *message) { + + if (!name) + return 0; + if (!e) + goto finish; + + assert_return(!bus_error_is_dirty(e), -EINVAL); + + e->name = strdup(name); + if (!e->name) { + *e = BUS_ERROR_OOM; + return -ENOMEM; + } + + if (message) + e->message = strdup(message); + + e->need_free = true; + +finish: + return -bus_error_name_to_errno(name); +} + +int bus_error_setfv(sd_bus_error *e, const char *name, const char *format, va_list ap) { + + if (!name) + return 0; + if (!e) + goto finish; + + assert_return(!bus_error_is_dirty(e), -EINVAL); + + e->name = strdup(name); + if (!e->name) { + *e = BUS_ERROR_OOM; + return -ENOMEM; + } + + if (format) + vasprintf((char**) &e->message, format, ap); + + e->need_free = true; + +finish: + return -bus_error_name_to_errno(name); +} + +_public_ int sd_bus_error_setf(sd_bus_error *e, const char *name, const char *format, ...) { + + if (format) { + int r; + va_list ap; + + va_start(ap, format); + r = bus_error_setfv(e, name, format, ap); + va_end(ap); + + return r; + } + + return sd_bus_error_set(e, name, NULL); +} + +_public_ int sd_bus_error_copy(sd_bus_error *dest, const sd_bus_error *e) { + + if (!sd_bus_error_is_set(e)) + return 0; + if (!dest) + goto finish; + + assert_return(!bus_error_is_dirty(dest), -EINVAL); + + if (!e->need_free) + *dest = *e; + else { + dest->name = strdup(e->name); + if (!dest->name) { + *dest = BUS_ERROR_OOM; + return -ENOMEM; + } + + if (e->message) + dest->message = strdup(e->message); + + dest->need_free = true; + } + +finish: + return -bus_error_name_to_errno(e->name); +} + +_public_ int sd_bus_error_set_const(sd_bus_error *e, const char *name, const char *message) { + if (!name) + return 0; + if (!e) + goto finish; + + assert_return(!bus_error_is_dirty(e), -EINVAL); + + *e = SD_BUS_ERROR_MAKE_CONST(name, message); + +finish: + return -bus_error_name_to_errno(name); +} + +_public_ int sd_bus_error_is_set(const sd_bus_error *e) { + if (!e) + return 0; + + return !!e->name; +} + +_public_ int sd_bus_error_has_name(const sd_bus_error *e, const char *name) { + if (!e) + return 0; + + return streq_ptr(e->name, name); +} + +_public_ int sd_bus_error_get_errno(const sd_bus_error* e) { + if (!e) + return 0; + + return bus_error_name_to_errno(e->name); +} + +static void bus_error_strerror(sd_bus_error *e, int error) { + size_t k = 64; + char *m; + + assert(e); + + for (;;) { + char *x; + + m = new(char, k); + if (!m) + return; + + errno = 0; + x = strerror_r(error, m, k); + if (errno == ERANGE || strlen(x) >= k - 1) { + free(m); + k *= 2; + continue; + } + + if (!x || errno) { + free(m); + return; + } + + if (x == m) { + if (e->need_free) { + /* Error is already dynamic, let's just update the message */ + free((char*) e->message); + e->message = x; + + } else { + char *t; + /* Error was const so far, let's make it dynamic, if we can */ + + t = strdup(e->name); + if (!t) { + free(m); + return; + } + + e->need_free = true; + e->name = t; + e->message = x; + } + } else { + free(m); + + if (e->need_free) { + char *t; + + /* Error is dynamic, let's hence make the message also dynamic */ + t = strdup(x); + if (!t) + return; + + free((char*) e->message); + e->message = t; + } else { + /* Error is const, hence we can just override */ + e->message = x; + } + } + + return; + } } _public_ int sd_bus_error_set_errno(sd_bus_error *e, int error) { - sd_bus_error x; - x = map_from_errno(error); + if (error < 0) + error = -error; - return bus_error_set_strerror_or_const(e, x.name, error, x.message); + if (!e) + return -error; + if (error == 0) + return -error; + + assert_return(!bus_error_is_dirty(e), -EINVAL); + + /* First, try a const translation */ + *e = errno_to_bus_error_const(error); + + if (!sd_bus_error_is_set(e)) { + int k; + + /* If that didn't work, try a dynamic one. */ + + k = errno_to_bus_error_name_new(error, (char**) &e->name); + if (k > 0) + e->need_free = true; + else if (k < 0) { + *e = BUS_ERROR_OOM; + return -error; + } else + *e = BUS_ERROR_FAILED; + } + + /* Now, fill in the message from strerror() if we can */ + bus_error_strerror(e, error); + return -error; } int bus_error_set_errnofv(sd_bus_error *e, int error, const char *format, va_list ap) { - sd_bus_error x; int r; if (error < 0) @@ -397,32 +465,60 @@ int bus_error_set_errnofv(sd_bus_error *e, int error, const char *format, va_lis if (!e) return -error; + if (error == 0) + return 0; assert_return(!bus_error_is_dirty(e), -EINVAL); - x = map_from_errno(error); + /* First, try a const translation */ + *e = errno_to_bus_error_const(error); - if (format) { - char *n, *m; + if (!sd_bus_error_is_set(e)) { + int k; - r = vasprintf(&m, format, ap); - if (r < 0) - goto fallback; + /* If that didn't work, try a dynamic one */ - n = strdup(x.name); - if (!n) { - free(m); - goto fallback; - } - - e->name = n; - e->message = m; - e->need_free = true; - return -error; + k = errno_to_bus_error_name_new(error, (char**) &e->name); + if (k > 0) + e->need_free = true; + else if (k < 0) { + *e = BUS_ERROR_OOM; + return -ENOMEM; + } else + *e = BUS_ERROR_FAILED; } -fallback: - return bus_error_set_strerror_or_const(e, x.name, error, x.message); + if (format) { + char *m; + + /* First, let's try to fill in the supplied message */ + + r = vasprintf(&m, format, ap); + if (r >= 0) { + + if (!e->need_free) { + char *t; + + t = strdup(e->name); + if (t) { + e->need_free = true; + e->name = t; + e->message = m; + return -error; + } + + free(m); + } else { + free((char*) e->message); + e->message = m; + return -error; + } + } + } + + /* If that didn't work, use strerror() for the message */ + bus_error_strerror(e, error); + return -error; } _public_ int sd_bus_error_set_errnof(sd_bus_error *e, int error, const char *format, ...) { @@ -433,6 +529,8 @@ _public_ int sd_bus_error_set_errnof(sd_bus_error *e, int error, const char *for if (!e) return -error; + if (error == 0) + return 0; assert_return(!bus_error_is_dirty(e), -EINVAL); diff --git a/src/libsystemd-bus/bus-message.c b/src/libsystemd-bus/bus-message.c index 538a28af9e..132426f6fd 100644 --- a/src/libsystemd-bus/bus-message.c +++ b/src/libsystemd-bus/bus-message.c @@ -624,18 +624,14 @@ _public_ int sd_bus_message_new_method_errorf( _cleanup_free_ sd_bus_error error = SD_BUS_ERROR_NULL; va_list ap; - int r; assert_return(name, -EINVAL); assert_return(m, -EINVAL); va_start(ap, format); - r = bus_error_setfv(&error, name, format, ap); + bus_error_setfv(&error, name, format, ap); va_end(ap); - if (r < 0) - return r; - return sd_bus_message_new_method_error(call, &error, m); } @@ -664,15 +660,11 @@ _public_ int sd_bus_message_new_method_errnof( _cleanup_free_ sd_bus_error berror = SD_BUS_ERROR_NULL; va_list ap; - int r; va_start(ap, format); - r = bus_error_set_errnofv(&berror, error, format, ap); + bus_error_set_errnofv(&berror, error, format, ap); va_end(ap); - if (r < 0) - return r; - return sd_bus_message_new_method_error(call, &berror, m); } diff --git a/src/libsystemd-bus/test-bus-error.c b/src/libsystemd-bus/test-bus-error.c new file mode 100644 index 0000000000..9c0f4e0158 --- /dev/null +++ b/src/libsystemd-bus/test-bus-error.c @@ -0,0 +1,84 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "sd-bus.h" +#include "bus-error.h" +#include "bus-util.h" + +int main(int argc, char *argv[]) { + + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL, second = SD_BUS_ERROR_NULL; + + assert_se(!sd_bus_error_is_set(&error)); + assert_se(sd_bus_error_set(&error, SD_BUS_ERROR_NOT_SUPPORTED, "xxx") == -ENOTSUP); + assert_se(streq(error.name, SD_BUS_ERROR_NOT_SUPPORTED)); + assert_se(streq(error.message, "xxx")); + assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_NOT_SUPPORTED)); + assert_se(sd_bus_error_get_errno(&error) == ENOTSUP); + assert_se(sd_bus_error_is_set(&error)); + sd_bus_error_free(&error); + + assert_se(!sd_bus_error_is_set(&error)); + assert_se(sd_bus_error_setf(&error, SD_BUS_ERROR_FILE_NOT_FOUND, "yyy %i", -1) == -ENOENT); + assert_se(streq(error.name, SD_BUS_ERROR_FILE_NOT_FOUND)); + assert_se(streq(error.message, "yyy -1")); + assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_FILE_NOT_FOUND)); + assert_se(sd_bus_error_get_errno(&error) == ENOENT); + assert_se(sd_bus_error_is_set(&error)); + + assert_se(!sd_bus_error_is_set(&second)); + assert_se(sd_bus_error_copy(&second, &error) == -ENOENT); + assert_se(streq(error.name, second.name)); + assert_se(streq(error.message, second.message)); + assert_se(sd_bus_error_get_errno(&second) == ENOENT); + assert_se(sd_bus_error_has_name(&second, SD_BUS_ERROR_FILE_NOT_FOUND)); + assert_se(sd_bus_error_is_set(&second)); + + sd_bus_error_free(&error); + + assert_se(!sd_bus_error_is_set(&error)); + assert_se(sd_bus_error_set_const(&error, "Posix.Error.EUCLEAN", "Hallo") == -EUCLEAN); + assert_se(streq(error.name, "Posix.Error.EUCLEAN")); + assert_se(streq(error.message, "Hallo")); + assert_se(sd_bus_error_has_name(&error, "Posix.Error.EUCLEAN")); + assert_se(sd_bus_error_get_errno(&error) == EUCLEAN); + assert_se(sd_bus_error_is_set(&error)); + sd_bus_error_free(&error); + + assert_se(!sd_bus_error_is_set(&error)); + assert_se(sd_bus_error_set_errno(&error, EBUSY) == -EBUSY); + assert_se(streq(error.name, "Posix.Error.EBUSY")); + assert_se(streq(error.message, strerror(EBUSY))); + assert_se(sd_bus_error_has_name(&error, "Posix.Error.EBUSY")); + assert_se(sd_bus_error_get_errno(&error) == EBUSY); + assert_se(sd_bus_error_is_set(&error)); + sd_bus_error_free(&error); + + assert_se(!sd_bus_error_is_set(&error)); + assert_se(sd_bus_error_set_errnof(&error, EIO, "Waldi %c", 'X') == -EIO); + assert_se(streq(error.name, SD_BUS_ERROR_IO_ERROR)); + assert_se(streq(error.message, "Waldi X")); + assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_IO_ERROR)); + assert_se(sd_bus_error_get_errno(&error) == EIO); + assert_se(sd_bus_error_is_set(&error)); + + return 0; +} diff --git a/src/shared/.gitignore b/src/shared/.gitignore new file mode 100644 index 0000000000..c9b5f81719 --- /dev/null +++ b/src/shared/.gitignore @@ -0,0 +1,4 @@ +/errno-from-name.gperf +/errno-from-name.h +/errno-list.txt +/errno-to-name.h diff --git a/src/shared/errno-list.c b/src/shared/errno-list.c new file mode 100644 index 0000000000..c63296f292 --- /dev/null +++ b/src/shared/errno-list.c @@ -0,0 +1,59 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "util.h" +#include "errno-list.h" + +static const struct errno_name* lookup_errno(register const char *str, + register unsigned int len); + +#include "errno-to-name.h" +#include "errno-from-name.h" + +const char *errno_to_name(int id) { + + if (id < 0) + id = -id; + + if (id >= (int) ELEMENTSOF(errno_names)) + return NULL; + + return errno_names[id]; +} + +int errno_from_name(const char *name) { + const struct errno_name *sc; + + assert(name); + + sc = lookup_errno(name, strlen(name)); + if (!sc) + return 0; + + return sc->id; +} + +int errno_max(void) { + return ELEMENTSOF(errno_names); +} diff --git a/src/shared/errno-list.h b/src/shared/errno-list.h new file mode 100644 index 0000000000..ba533294e6 --- /dev/null +++ b/src/shared/errno-list.h @@ -0,0 +1,27 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +const char *errno_to_name(int id); +int errno_from_name(const char *name); + +int errno_max(void);