1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
30 #include "errno-list.h"
33 #include "bus-error.h"
35 BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_standard_errors[] = {
36 SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.Failed", EACCES),
37 SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.NoMemory", ENOMEM),
38 SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.ServiceUnknown", EHOSTUNREACH),
39 SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.NameHasNoOwner", ENXIO),
40 SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.NoReply", ETIMEDOUT),
41 SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.IOError", EIO),
42 SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.BadAddress", EADDRNOTAVAIL),
43 SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.NotSupported", ENOTSUP),
44 SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.LimitsExceeded", ENOBUFS),
45 SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.AccessDenied", EACCES),
46 SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.AuthFailed", EACCES),
47 SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.InteractiveAuthorizationRequired", EACCES),
48 SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.NoServer", EHOSTDOWN),
49 SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.Timeout", ETIMEDOUT),
50 SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.NoNetwork", ENONET),
51 SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.AddressInUse", EADDRINUSE),
52 SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.Disconnected", ECONNRESET),
53 SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.InvalidArgs", EINVAL),
54 SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.FileNotFound", ENOENT),
55 SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.FileExists", EEXIST),
56 SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.UnknownMethod", EBADR),
57 SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.UnknownObject", EBADR),
58 SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.UnknownInterface", EBADR),
59 SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.UnknownProperty", EBADR),
60 SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.PropertyReadOnly", EROFS),
61 SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.UnixProcessIdUnknown", ESRCH),
62 SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.InvalidSignature", EINVAL),
63 SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.InconsistentMessage", EBADMSG),
64 SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.TimedOut", ETIMEDOUT),
65 SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.MatchRuleInvalid", EINVAL),
66 SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.InvalidFileContent", EINVAL),
67 SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.MatchRuleNotFound", ENOENT),
68 SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown", ESRCH),
69 SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.ObjectPathInUse", EBUSY),
73 /* GCC maps this magically to the beginning and end of the BUS_ERROR_MAP section */
74 extern const sd_bus_error_map __start_BUS_ERROR_MAP[];
75 extern const sd_bus_error_map __stop_BUS_ERROR_MAP[];
77 /* Additional maps registered with sd_bus_error_add_map() are in this
78 * NULL terminated array */
79 static const sd_bus_error_map **additional_error_maps = NULL;
81 static int bus_error_name_to_errno(const char *name) {
82 const sd_bus_error_map **map, *m;
89 p = startswith(name, "System.Error.");
91 r = errno_from_name(p);
98 if (additional_error_maps) {
99 for (map = additional_error_maps; *map; map++) {
100 for (m = *map;; m++) {
101 /* For additional error maps the end marker is actually the end marker */
102 if (m->code == BUS_ERROR_MAP_END_MARKER)
105 if (streq(m->name, name))
111 m = __start_BUS_ERROR_MAP;
112 while (m < __stop_BUS_ERROR_MAP) {
113 /* For magic ELF error maps, the end marker might
114 * appear in the middle of things, since multiple maps
115 * might appear in the same section. Hence, let's skip
116 * over it, but realign the pointer to the netx 8byte
117 * boundary, which is the selected alignment for the
119 if (m->code == BUS_ERROR_MAP_END_MARKER) {
124 if (streq(m->name, name))
133 static sd_bus_error errno_to_bus_error_const(int error) {
141 return BUS_ERROR_OOM;
145 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_ACCESS_DENIED, "Access denied");
148 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid argument");
151 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_UNIX_PROCESS_ID_UNKNOWN, "No such process");
154 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_FILE_NOT_FOUND, "File not found");
157 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_FILE_EXISTS, "File exists");
161 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_TIMEOUT, "Timed out");
164 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_IO_ERROR, "Input/output error");
169 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_DISCONNECTED, "Disconnected");
172 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NOT_SUPPORTED, "Not supported");
175 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_BAD_ADDRESS, "Address not available");
178 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_LIMITS_EXCEEDED, "Limits exceeded");
181 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_ADDRESS_IN_USE, "Address in use");
184 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INCONSISTENT_MESSAGE, "Inconsistent message");
187 return SD_BUS_ERROR_NULL;
190 static int errno_to_bus_error_name_new(int error, char **ret) {
197 name = errno_to_name(error);
201 n = strappend("System.Error.", name);
209 bool bus_error_is_dirty(sd_bus_error *e) {
213 return e->name || e->message || e->_need_free != 0;
216 _public_ void sd_bus_error_free(sd_bus_error *e) {
220 if (e->_need_free > 0) {
221 free((void*) e->name);
222 free((void*) e->message);
225 e->name = e->message = NULL;
229 _public_ int sd_bus_error_set(sd_bus_error *e, const char *name, const char *message) {
236 assert_return(!bus_error_is_dirty(e), -EINVAL);
238 e->name = strdup(name);
245 e->message = strdup(message);
250 return -bus_error_name_to_errno(name);
253 int bus_error_setfv(sd_bus_error *e, const char *name, const char *format, va_list ap) {
260 assert_return(!bus_error_is_dirty(e), -EINVAL);
262 e->name = strdup(name);
268 /* If we hit OOM on formatting the pretty message, we ignore
269 * this, since we at least managed to write the error name */
271 (void) vasprintf((char**) &e->message, format, ap);
276 return -bus_error_name_to_errno(name);
279 _public_ int sd_bus_error_setf(sd_bus_error *e, const char *name, const char *format, ...) {
285 va_start(ap, format);
286 r = bus_error_setfv(e, name, format, ap);
292 return sd_bus_error_set(e, name, NULL);
295 _public_ int sd_bus_error_copy(sd_bus_error *dest, const sd_bus_error *e) {
297 if (!sd_bus_error_is_set(e))
302 assert_return(!bus_error_is_dirty(dest), -EINVAL);
305 * _need_free < 0 indicates that the error is temporarily const, needs deep copying
306 * _need_free == 0 indicates that the error is perpetually const, needs no deep copying
307 * _need_free > 0 indicates that the error is fully dynamic, needs deep copying
310 if (e->_need_free == 0)
313 dest->name = strdup(e->name);
315 *dest = BUS_ERROR_OOM;
320 dest->message = strdup(e->message);
322 dest->_need_free = 1;
326 return -bus_error_name_to_errno(e->name);
329 _public_ int sd_bus_error_set_const(sd_bus_error *e, const char *name, const char *message) {
335 assert_return(!bus_error_is_dirty(e), -EINVAL);
337 *e = SD_BUS_ERROR_MAKE_CONST(name, message);
340 return -bus_error_name_to_errno(name);
343 _public_ int sd_bus_error_is_set(const sd_bus_error *e) {
350 _public_ int sd_bus_error_has_name(const sd_bus_error *e, const char *name) {
354 return streq_ptr(e->name, name);
357 _public_ int sd_bus_error_get_errno(const sd_bus_error* e) {
364 return bus_error_name_to_errno(e->name);
367 static void bus_error_strerror(sd_bus_error *e, int error) {
381 x = strerror_r(error, m, k);
382 if (errno == ERANGE || strlen(x) >= k - 1) {
394 if (e->_need_free > 0) {
395 /* Error is already dynamic, let's just update the message */
396 free((char*) e->message);
401 /* Error was const so far, let's make it dynamic, if we can */
416 if (e->_need_free > 0) {
419 /* Error is dynamic, let's hence make the message also dynamic */
424 free((char*) e->message);
427 /* Error is const, hence we can just override */
436 _public_ int sd_bus_error_set_errno(sd_bus_error *e, int error) {
446 assert_return(!bus_error_is_dirty(e), -EINVAL);
448 /* First, try a const translation */
449 *e = errno_to_bus_error_const(error);
451 if (!sd_bus_error_is_set(e)) {
454 /* If that didn't work, try a dynamic one. */
456 k = errno_to_bus_error_name_new(error, (char**) &e->name);
463 *e = BUS_ERROR_FAILED;
466 /* Now, fill in the message from strerror() if we can */
467 bus_error_strerror(e, error);
471 int bus_error_set_errnofv(sd_bus_error *e, int error, const char *format, va_list ap) {
483 assert_return(!bus_error_is_dirty(e), -EINVAL);
485 /* First, try a const translation */
486 *e = errno_to_bus_error_const(error);
488 if (!sd_bus_error_is_set(e)) {
491 /* If that didn't work, try a dynamic one */
493 k = errno_to_bus_error_name_new(error, (char**) &e->name);
500 *e = BUS_ERROR_FAILED;
506 /* Then, let's try to fill in the supplied message */
508 errno = error; /* Make sure that %m resolves to the specified error */
509 r = vasprintf(&m, format, ap);
512 if (e->_need_free <= 0) {
525 free((char*) e->message);
532 /* If that didn't work, use strerror() for the message */
533 bus_error_strerror(e, error);
537 _public_ int sd_bus_error_set_errnof(sd_bus_error *e, int error, const char *format, ...) {
548 assert_return(!bus_error_is_dirty(e), -EINVAL);
553 va_start(ap, format);
554 r = bus_error_set_errnofv(e, error, format, ap);
560 return sd_bus_error_set_errno(e, error);
563 const char *bus_error_message(const sd_bus_error *e, int error) {
566 /* Sometimes the D-Bus server is a little bit too verbose with
567 * its error messages, so let's override them here */
568 if (sd_bus_error_has_name(e, SD_BUS_ERROR_ACCESS_DENIED))
569 return "Access denied";
578 return strerror(error);
581 _public_ int sd_bus_error_add_map(const sd_bus_error_map *map) {
582 const sd_bus_error_map **maps = NULL;
585 assert_return(map, -EINVAL);
587 if (additional_error_maps) {
589 if (additional_error_maps[n] == NULL)
592 if (additional_error_maps[n] == map)
597 maps = realloc_multiply(additional_error_maps, sizeof(struct sd_bus_error_map*), n + 2);
605 additional_error_maps = maps;