diff options
author | Lennart Poettering <lennart@poettering.net> | 2013-10-16 06:10:04 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2013-10-16 06:15:02 +0200 |
commit | 40ca29a1370379d43e44c0ed425eecc7218dcbca (patch) | |
tree | 39cde46c8166bd79471b0111251693edddfae3c4 /src/libsystemd-bus/bus-error.c | |
parent | 7a37d62501c97eb3b48a418ef764d0308e0c3fb9 (diff) |
timedated: use libsystemd-bus instead of libdbus for bus communication
Among other things this also adds a few things necessary for the change:
- Considerably more powerful error returning APIs in libsystemd-bus
- Adapter for connecting an sd_bus to an sd_event
- As I reworked the PolicyKit logic to the new library I also made it
asynchronous, so that PolicyKit requests of one user cannot block out
another user anymore.
- We always use the macro names for common bus error. That way it is
harder to mistype them since the compiler will notice
Diffstat (limited to 'src/libsystemd-bus/bus-error.c')
-rw-r--r-- | src/libsystemd-bus/bus-error.c | 352 |
1 files changed, 270 insertions, 82 deletions
diff --git a/src/libsystemd-bus/bus-error.c b/src/libsystemd-bus/bus-error.c index 28fe15467f..c347b101bc 100644 --- a/src/libsystemd-bus/bus-error.c +++ b/src/libsystemd-bus/bus-error.c @@ -56,10 +56,9 @@ int sd_bus_error_set(sd_bus_error *e, const char *name, const char *message) { if (!e) return 0; - if (bus_error_is_dirty(e)) - return -EINVAL; - if (!name) - return -EINVAL; + + assert_return(!bus_error_is_dirty(e), -EINVAL); + assert_return(name, -EINVAL); n = strdup(name); if (!n) @@ -78,27 +77,22 @@ int sd_bus_error_set(sd_bus_error *e, const char *name, const char *message) { return 0; } -int sd_bus_error_setf(sd_bus_error *e, const char *name, const char *format, ...) { +int bus_error_setfv(sd_bus_error *e, const char *name, const char *format, va_list ap) { char *n, *m = NULL; - va_list ap; int r; if (!e) return 0; - if (bus_error_is_dirty(e)) - return -EINVAL; - 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) { - va_start(ap, format); r = vasprintf(&m, format, ap); - va_end(ap); - if (r < 0) { free(n); return -ENOMEM; @@ -112,16 +106,32 @@ int sd_bus_error_setf(sd_bus_error *e, const char *name, const char *format, ... return 0; } +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); +} + int sd_bus_error_copy(sd_bus_error *dest, const sd_bus_error *e) { char *x, *y = NULL; if (!dest) return 0; - if (bus_error_is_dirty(dest)) - return -EINVAL; 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; @@ -140,13 +150,15 @@ int sd_bus_error_copy(sd_bus_error *dest, const sd_bus_error *e) { return 0; } -void sd_bus_error_set_const(sd_bus_error *e, const char *name, const char *message) { +int sd_bus_error_set_const(sd_bus_error *e, const char *name, const char *message) { if (!e) - return; - if (bus_error_is_dirty(e)) - return; + return 0; + + assert_return(!bus_error_is_dirty(e), -EINVAL); + assert_return(name, -EINVAL); *e = SD_BUS_ERROR_MAKE(name, message); + return 0; } int sd_bus_error_is_set(const sd_bus_error *e) { @@ -163,106 +175,282 @@ int sd_bus_error_has_name(const sd_bus_error *e, const char *name) { return streq_ptr(e->name, name); } -int bus_error_to_errno(const sd_bus_error* e) { +int sd_bus_error_get_errno(const sd_bus_error* e) { /* Better replce this with a gperf table */ if (!e) - return -EIO; + return EIO; if (!e->name) - return -EIO; + return EIO; - if (streq(e->name, "org.freedesktop.DBus.Error.NoMemory")) - return -ENOMEM; + if (streq(e->name, SD_BUS_ERROR_NO_MEMORY)) + return ENOMEM; + + if (streq(e->name, SD_BUS_ERROR_SERVICE_UNKNOWN)) + return EHOSTUNREACH; + + if (streq(e->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")) + return ETIMEDOUT; + + if (streq(e->name, SD_BUS_ERROR_IO_ERROR)) + return EIO; + + if (streq(e->name, SD_BUS_ERROR_BAD_ADDRESS)) + return EADDRNOTAVAIL; - if (streq(e->name, "org.freedesktop.DBus.Error.AuthFailed") || - streq(e->name, "org.freedesktop.DBus.Error.AccessDenied")) - return -EPERM; + if (streq(e->name, SD_BUS_ERROR_NOT_SUPPORTED)) + return ENOTSUP; - if (streq(e->name, "org.freedesktop.DBus.Error.InvalidArgs")) - return -EINVAL; + if (streq(e->name, SD_BUS_ERROR_LIMITS_EXCEEDED)) + return ENOBUFS; - if (streq(e->name, "org.freedesktop.DBus.Error.UnixProcessIdUnknown")) - return -ESRCH; + if (streq(e->name, SD_BUS_ERROR_ACCESS_DENIED) || + streq(e->name, SD_BUS_ERROR_AUTH_FAILED)) + return EACCES; - if (streq(e->name, "org.freedesktop.DBus.Error.FileNotFound")) - return -ENOENT; + if (streq(e->name, SD_BUS_ERROR_NO_SERVER)) + return EHOSTDOWN; - if (streq(e->name, "org.freedesktop.DBus.Error.FileExists")) - return -EEXIST; + if (streq(e->name, SD_BUS_ERROR_NO_NETWORK)) + return ENONET; - if (streq(e->name, "org.freedesktop.DBus.Error.Timeout")) - return -ETIMEDOUT; + if (streq(e->name, SD_BUS_ERROR_ADDRESS_IN_USE)) + return EADDRINUSE; - if (streq(e->name, "org.freedesktop.DBus.Error.IOError")) - return -EIO; + if (streq(e->name, SD_BUS_ERROR_DISCONNECTED)) + return ECONNRESET; - if (streq(e->name, "org.freedesktop.DBus.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")) + return EINVAL; - if (streq(e->name, "org.freedesktop.DBus.Error.NotSupported")) - return -ENOTSUP; + if (streq(e->name, SD_BUS_ERROR_FILE_NOT_FOUND) || + streq(e->name, "org.freedesktop.DBus.Error.MatchRuleNotFound")) + return ENOENT; - return -EIO; + if (streq(e->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)) + return EBADR; + + if (streq(e->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")) + return ESRCH; + + if (streq(e->name, SD_BUS_ERROR_INCONSISTENT_MESSAGE)) + return EBADMSG; + + if (streq(e->name, "org.freedesktop.DBus.Error.ObjectPathInUse")) + return EBUSY; + + return EIO; } -int bus_error_from_errno(sd_bus_error *e, int error) { +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; + return -error; - switch (error) { + assert_return(!bus_error_is_dirty(e), -EINVAL); + assert_return(name, -EINVAL); - case -ENOMEM: - sd_bus_error_set_const(e, "org.freedesktop.DBus.Error.NoMemory", "Out of memory"); - break; + for (;;) { + char *x; - case -EPERM: - case -EACCES: - sd_bus_error_set_const(e, "org.freedesktop.DBus.Error.AccessDenied", "Access denied"); - break; + 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; + } - case -EINVAL: - sd_bus_error_set_const(e, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid argument"); - break; + if (!x || errno) { + free(m); + goto use_fallback; + } - case -ESRCH: - sd_bus_error_set_const(e, "org.freedesktop.DBus.Error.UnixProcessIdUnknown", "No such process"); - break; - case -ENOENT: - sd_bus_error_set_const(e, "org.freedesktop.DBus.Error.FileNotFound", "File not found"); - break; + if (x != m) { + free(m); + sd_bus_error_set_const(e, name, x); + return -error; + } - case -EEXIST: - sd_bus_error_set_const(e, "org.freedesktop.DBus.Error.FileExists", "File exists"); break; + } - case -ETIMEDOUT: - case -ETIME: - sd_bus_error_set_const(e, "org.freedesktop.DBus.Error.Timeout", "Timed out"); - break; - case -EIO: - sd_bus_error_set_const(e, "org.freedesktop.DBus.Error.IOError", "Input/output error"); - break; + n = strdup(name); + if (!n) { + free(m); + goto use_fallback; + } - case -ENETRESET: - case -ECONNABORTED: - case -ECONNRESET: - sd_bus_error_set_const(e, "org.freedesktop.DBus.Error.Disconnected", "Disconnected"); - break; + e->name = n; + e->message = m; + e->need_free = true; - case -ENOTSUP: - sd_bus_error_set_const(e, "org.freedesktop.DBus.Error.NotSupported", "Not supported"); - break; + return -error; + +use_fallback: + sd_bus_error_set_const(e, name, fallback); + return -error; +} + +static sd_bus_error map_from_errno(int error) { + + if (error < 0) + error = -error; + + switch (error) { + + case ENOMEM: + return SD_BUS_ERROR_MAKE(SD_BUS_ERROR_NO_NETWORK, "Out of memory"); + + case EPERM: + case EACCES: + return SD_BUS_ERROR_MAKE(SD_BUS_ERROR_ACCESS_DENIED, "Access denied"); + + case EINVAL: + return SD_BUS_ERROR_MAKE(SD_BUS_ERROR_INVALID_ARGS, "Invalid argument"); + + case ESRCH: + return SD_BUS_ERROR_MAKE(SD_BUS_ERROR_UNIX_PROCESS_ID_UNKNOWN, "No such process"); + + case ENOENT: + return SD_BUS_ERROR_MAKE(SD_BUS_ERROR_FILE_NOT_FOUND, "File not found"); + + case EEXIST: + return SD_BUS_ERROR_MAKE(SD_BUS_ERROR_FILE_EXISTS, "File exists"); + + case ETIMEDOUT: + case ETIME: + return SD_BUS_ERROR_MAKE(SD_BUS_ERROR_TIMEOUT, "Timed out"); + + case EIO: + return SD_BUS_ERROR_MAKE(SD_BUS_ERROR_IO_ERROR, "Input/output error"); + + case ENETRESET: + case ECONNABORTED: + case ECONNRESET: + return SD_BUS_ERROR_MAKE(SD_BUS_ERROR_DISCONNECTED, "Disconnected"); + + case ENOTSUP: + return SD_BUS_ERROR_MAKE(SD_BUS_ERROR_NOT_SUPPORTED, "Not supported"); + + case EADDRNOTAVAIL: + return SD_BUS_ERROR_MAKE(SD_BUS_ERROR_BAD_ADDRESS, "Address not available"); + + case ENOBUFS: + return SD_BUS_ERROR_MAKE(SD_BUS_ERROR_LIMITS_EXCEEDED, "Limits exceeded"); + + case EADDRINUSE: + return SD_BUS_ERROR_MAKE(SD_BUS_ERROR_ADDRESS_IN_USE, "Address in use"); + + case EBADMSG: + return SD_BUS_ERROR_MAKE(SD_BUS_ERROR_INCONSISTENT_MESSAGE, "Inconsistent message"); + } + + return SD_BUS_ERROR_MAKE(SD_BUS_ERROR_FAILED, "Operation failed"); +} + +int sd_bus_error_set_errno(sd_bus_error *e, int error) { + sd_bus_error x; + + x = map_from_errno(error); + + return bus_error_set_strerror_or_const(e, x.name, error, x.message); +} + +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) + error = -error; + + if (!e) + return 0; + + assert_return(!bus_error_is_dirty(e), -EINVAL); + + x = map_from_errno(error); + + if (format) { + char *n, *m; + + r = vasprintf(&m, format, ap); + if (r < 0) + goto fallback; + + n = strdup(x.name); + if (!n) { + free(m); + goto fallback; + } + + e->name = n; + e->message = m; + e->need_free = true; + return -error; } - sd_bus_error_set_const(e, "org.freedesktop.DBus.Error.Failed", "Operation failed"); - return error; +fallback: + return bus_error_set_strerror_or_const(e, x.name, error, x.message); +} + +int sd_bus_error_set_errnof(sd_bus_error *e, int error, const char *format, ...) { + int r; + + if (!e) + return 0; + + assert_return(!bus_error_is_dirty(e), -EINVAL); + + if (format) { + va_list ap; + + va_start(ap, format); + r = bus_error_set_errnofv(e, error, format, ap); + va_end(ap); + + return r; + } + + return sd_bus_error_set_errno(e, error); } const char *bus_error_message(const sd_bus_error *e, int error) { + + if (error < 0) + error = -error; + if (e && e->message) return e->message; |