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 #define BUS_ERROR_OOM SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_MEMORY, "Out of memory")
36 #define BUS_ERROR_FAILED SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_FAILED, "Operation failed")
38 SD_BUS_ERROR_MAPPING(sd_bus_standard) = {
39 {"org.freedesktop.DBus.Error.Failed", EACCES},
40 {"org.freedesktop.DBus.Error.NoMemory", ENOMEM},
41 {"org.freedesktop.DBus.Error.ServiceUnknown", EHOSTUNREACH},
42 {"org.freedesktop.DBus.Error.NameHasNoOwner", ENXIO},
43 {"org.freedesktop.DBus.Error.NoReply", ETIMEDOUT},
44 {"org.freedesktop.DBus.Error.IOError", EIO},
45 {"org.freedesktop.DBus.Error.BadAddress", EADDRNOTAVAIL},
46 {"org.freedesktop.DBus.Error.NotSupported", ENOTSUP},
47 {"org.freedesktop.DBus.Error.LimitsExceeded", ENOBUFS},
48 {"org.freedesktop.DBus.Error.AccessDenied", EACCES},
49 {"org.freedesktop.DBus.Error.AuthFailed", EACCES},
50 {"org.freedesktop.DBus.Error.InteractiveAuthorizationRequired", EACCES},
51 {"org.freedesktop.DBus.Error.NoServer", EHOSTDOWN},
52 {"org.freedesktop.DBus.Error.Timeout", ETIMEDOUT},
53 {"org.freedesktop.DBus.Error.NoNetwork", ENONET},
54 {"org.freedesktop.DBus.Error.AddressInUse", EADDRINUSE},
55 {"org.freedesktop.DBus.Error.Disconnected", ECONNRESET},
56 {"org.freedesktop.DBus.Error.InvalidArgs", EINVAL},
57 {"org.freedesktop.DBus.Error.FileNotFound", ENOENT},
58 {"org.freedesktop.DBus.Error.FileExists", EEXIST},
59 {"org.freedesktop.DBus.Error.UnknownMethod", EBADR},
60 {"org.freedesktop.DBus.Error.UnknownObject", EBADR},
61 {"org.freedesktop.DBus.Error.UnknownInterface", EBADR},
62 {"org.freedesktop.DBus.Error.UnknownProperty", EBADR},
63 {"org.freedesktop.DBus.Error.PropertyReadOnly", EROFS},
64 {"org.freedesktop.DBus.Error.UnixProcessIdUnknown", ESRCH},
65 {"org.freedesktop.DBus.Error.InvalidSignature", EINVAL},
66 {"org.freedesktop.DBus.Error.InconsistentMessage", EBADMSG},
68 {"org.freedesktop.DBus.Error.TimedOut", ETIMEDOUT},
69 {"org.freedesktop.DBus.Error.MatchRuleInvalid", EINVAL},
70 {"org.freedesktop.DBus.Error.InvalidFileContent", EINVAL},
71 {"org.freedesktop.DBus.Error.MatchRuleNotFound", ENOENT},
72 {"org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown", ESRCH},
73 {"org.freedesktop.DBus.Error.ObjectPathInUse", EBUSY},
76 extern const sd_bus_name_error_mapping __start_sd_bus_errnomap[];
77 extern const sd_bus_name_error_mapping __stop_sd_bus_errnomap[];
79 static int bus_error_mapping_lookup(const char *name, size_t len) {
80 const sd_bus_name_error_mapping *m;
82 for (m = __start_sd_bus_errnomap; m < __stop_sd_bus_errnomap; m++)
83 if (m->name && strneq(m->name, name, len))
89 static int bus_error_name_to_errno(const char *name) {
96 p = startswith(name, "System.Error.");
98 r = errno_from_name(p);
105 return bus_error_mapping_lookup(name, strlen(name));
108 static sd_bus_error errno_to_bus_error_const(int error) {
116 return BUS_ERROR_OOM;
120 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_ACCESS_DENIED, "Access denied");
123 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid argument");
126 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_UNIX_PROCESS_ID_UNKNOWN, "No such process");
129 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_FILE_NOT_FOUND, "File not found");
132 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_FILE_EXISTS, "File exists");
136 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_TIMEOUT, "Timed out");
139 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_IO_ERROR, "Input/output error");
144 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_DISCONNECTED, "Disconnected");
147 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NOT_SUPPORTED, "Not supported");
150 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_BAD_ADDRESS, "Address not available");
153 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_LIMITS_EXCEEDED, "Limits exceeded");
156 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_ADDRESS_IN_USE, "Address in use");
159 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INCONSISTENT_MESSAGE, "Inconsistent message");
162 return SD_BUS_ERROR_NULL;
165 static int errno_to_bus_error_name_new(int error, char **ret) {
172 name = errno_to_name(error);
176 n = strappend("System.Error.", name);
184 bool bus_error_is_dirty(sd_bus_error *e) {
188 return e->name || e->message || e->_need_free != 0;
191 _public_ void sd_bus_error_free(sd_bus_error *e) {
195 if (e->_need_free > 0) {
196 free((void*) e->name);
197 free((void*) e->message);
200 e->name = e->message = NULL;
204 _public_ int sd_bus_error_set(sd_bus_error *e, const char *name, const char *message) {
211 assert_return(!bus_error_is_dirty(e), -EINVAL);
213 e->name = strdup(name);
220 e->message = strdup(message);
225 return -bus_error_name_to_errno(name);
228 int bus_error_setfv(sd_bus_error *e, const char *name, const char *format, va_list ap) {
235 assert_return(!bus_error_is_dirty(e), -EINVAL);
237 e->name = strdup(name);
243 /* Of we hit OOM on formatting the pretty message, we ignore
244 * this, since we at least managed to write the error name */
246 (void) vasprintf((char**) &e->message, format, ap);
251 return -bus_error_name_to_errno(name);
254 _public_ int sd_bus_error_setf(sd_bus_error *e, const char *name, const char *format, ...) {
260 va_start(ap, format);
261 r = bus_error_setfv(e, name, format, ap);
267 return sd_bus_error_set(e, name, NULL);
270 _public_ int sd_bus_error_copy(sd_bus_error *dest, const sd_bus_error *e) {
272 if (!sd_bus_error_is_set(e))
277 assert_return(!bus_error_is_dirty(dest), -EINVAL);
280 * _need_free < 0 indicates that the error is temporarily const, needs deep copying
281 * _need_free == 0 indicates that the error is perpetually const, needs no deep copying
282 * _need_free > 0 indicates that the error is fully dynamic, needs deep copying
285 if (e->_need_free == 0)
288 dest->name = strdup(e->name);
290 *dest = BUS_ERROR_OOM;
295 dest->message = strdup(e->message);
297 dest->_need_free = 1;
301 return -bus_error_name_to_errno(e->name);
304 _public_ int sd_bus_error_set_const(sd_bus_error *e, const char *name, const char *message) {
310 assert_return(!bus_error_is_dirty(e), -EINVAL);
312 *e = SD_BUS_ERROR_MAKE_CONST(name, message);
315 return -bus_error_name_to_errno(name);
318 _public_ int sd_bus_error_is_set(const sd_bus_error *e) {
325 _public_ int sd_bus_error_has_name(const sd_bus_error *e, const char *name) {
329 return streq_ptr(e->name, name);
332 _public_ int sd_bus_error_get_errno(const sd_bus_error* e) {
339 return bus_error_name_to_errno(e->name);
342 static void bus_error_strerror(sd_bus_error *e, int error) {
356 x = strerror_r(error, m, k);
357 if (errno == ERANGE || strlen(x) >= k - 1) {
369 if (e->_need_free > 0) {
370 /* Error is already dynamic, let's just update the message */
371 free((char*) e->message);
376 /* Error was const so far, let's make it dynamic, if we can */
391 if (e->_need_free > 0) {
394 /* Error is dynamic, let's hence make the message also dynamic */
399 free((char*) e->message);
402 /* Error is const, hence we can just override */
411 _public_ int sd_bus_error_set_errno(sd_bus_error *e, int error) {
421 assert_return(!bus_error_is_dirty(e), -EINVAL);
423 /* First, try a const translation */
424 *e = errno_to_bus_error_const(error);
426 if (!sd_bus_error_is_set(e)) {
429 /* If that didn't work, try a dynamic one. */
431 k = errno_to_bus_error_name_new(error, (char**) &e->name);
438 *e = BUS_ERROR_FAILED;
441 /* Now, fill in the message from strerror() if we can */
442 bus_error_strerror(e, error);
446 int bus_error_set_errnofv(sd_bus_error *e, int error, const char *format, va_list ap) {
457 assert_return(!bus_error_is_dirty(e), -EINVAL);
459 /* First, try a const translation */
460 *e = errno_to_bus_error_const(error);
462 if (!sd_bus_error_is_set(e)) {
465 /* If that didn't work, try a dynamic one */
467 k = errno_to_bus_error_name_new(error, (char**) &e->name);
474 *e = BUS_ERROR_FAILED;
480 /* First, let's try to fill in the supplied message */
482 r = vasprintf(&m, format, ap);
485 if (e->_need_free <= 0) {
498 free((char*) e->message);
505 /* If that didn't work, use strerror() for the message */
506 bus_error_strerror(e, error);
510 _public_ int sd_bus_error_set_errnof(sd_bus_error *e, int error, const char *format, ...) {
521 assert_return(!bus_error_is_dirty(e), -EINVAL);
526 va_start(ap, format);
527 r = bus_error_set_errnofv(e, error, format, ap);
533 return sd_bus_error_set_errno(e, error);
536 const char *bus_error_message(const sd_bus_error *e, int error) {
539 /* Sometimes the D-Bus server is a little bit too verbose with
540 * its error messages, so let's override them here */
541 if (sd_bus_error_has_name(e, SD_BUS_ERROR_ACCESS_DENIED))
542 return "Access denied";
551 return strerror(error);