bus: rework sd_bus_error APIs

All calls that set a sd_bus_error structure will now return the same
error converted to a negative errno. This may be used as syntactic sugar
to return from a function and setting a bus_error structure in one go.

Also, translate all Linux Exyz (EIO, EINVAL, EUCLEAN, EPIPE, ...)
automatically into counterparts in the (new) "Posix.Error." namespace.

If we fail to allocate memory for the components of a sd_bus_error
automatically reset it to an OOM error which we always can write.
This commit is contained in:
Lennart Poettering 2013-11-22 04:01:46 +01:00
parent 6414b7c981
commit 780896a4f1
9 changed files with 579 additions and 283 deletions

View file

@ -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

View file

@ -23,7 +23,6 @@
#include <string.h>
#include "util.h"
#include "syscall-list.h"
static const struct syscall_name* lookup_syscall(register const char *str,

View file

@ -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);
}

View file

@ -27,303 +27,110 @@
#include <stdio.h>
#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);

View file

@ -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);
}

View file

@ -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 <http://www.gnu.org/licenses/>.
***/
#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;
}

4
src/shared/.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
/errno-from-name.gperf
/errno-from-name.h
/errno-list.txt
/errno-to-name.h

59
src/shared/errno-list.c Normal file
View file

@ -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 <http://www.gnu.org/licenses/>.
***/
#include <errno.h>
#include <string.h>
#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);
}

27
src/shared/errno-list.h Normal file
View file

@ -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 <http://www.gnu.org/licenses/>.
***/
const char *errno_to_name(int id);
int errno_from_name(const char *name);
int errno_max(void);