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 static int bus_error_name_to_errno(const char *name) {
42 assert_return(name, EINVAL);
44 p = startswith(name, "System.Error.");
46 r = errno_from_name(p);
53 /* Better replace this with a gperf table */
55 if (streq(name, SD_BUS_ERROR_NO_MEMORY))
58 if (streq(name, SD_BUS_ERROR_SERVICE_UNKNOWN))
61 if (streq(name, SD_BUS_ERROR_NAME_HAS_NO_OWNER))
64 if (streq(name, SD_BUS_ERROR_NO_REPLY) ||
65 streq(name, SD_BUS_ERROR_TIMEOUT) ||
66 streq(name, "org.freedesktop.DBus.Error.TimedOut"))
69 if (streq(name, SD_BUS_ERROR_IO_ERROR))
72 if (streq(name, SD_BUS_ERROR_BAD_ADDRESS))
75 if (streq(name, SD_BUS_ERROR_NOT_SUPPORTED))
78 if (streq(name, SD_BUS_ERROR_LIMITS_EXCEEDED))
81 if (streq(name, SD_BUS_ERROR_ACCESS_DENIED) ||
82 streq(name, SD_BUS_ERROR_AUTH_FAILED))
85 if (streq(name, SD_BUS_ERROR_NO_SERVER))
88 if (streq(name, SD_BUS_ERROR_NO_NETWORK))
91 if (streq(name, SD_BUS_ERROR_ADDRESS_IN_USE))
94 if (streq(name, SD_BUS_ERROR_DISCONNECTED))
97 if (streq(name, SD_BUS_ERROR_INVALID_ARGS) ||
98 streq(name, SD_BUS_ERROR_INVALID_SIGNATURE) ||
99 streq(name, "org.freedesktop.DBus.Error.MatchRuleInvalid") ||
100 streq(name, "org.freedesktop.DBus.Error.InvalidFileContent"))
103 if (streq(name, SD_BUS_ERROR_FILE_NOT_FOUND) ||
104 streq(name, "org.freedesktop.DBus.Error.MatchRuleNotFound"))
107 if (streq(name, SD_BUS_ERROR_FILE_EXISTS))
110 if (streq(name, SD_BUS_ERROR_UNKNOWN_METHOD) ||
111 streq(name, SD_BUS_ERROR_UNKNOWN_OBJECT) ||
112 streq(name, SD_BUS_ERROR_UNKNOWN_INTERFACE) ||
113 streq(name, SD_BUS_ERROR_UNKNOWN_PROPERTY))
116 if (streq(name, SD_BUS_ERROR_PROPERTY_READ_ONLY))
119 if (streq(name, SD_BUS_ERROR_UNIX_PROCESS_ID_UNKNOWN) ||
120 streq(name, "org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown"))
123 if (streq(name, SD_BUS_ERROR_INCONSISTENT_MESSAGE))
126 if (streq(name, "org.freedesktop.DBus.Error.ObjectPathInUse"))
132 static sd_bus_error errno_to_bus_error_const(int error) {
140 return BUS_ERROR_OOM;
144 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_ACCESS_DENIED, "Access denied");
147 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid argument");
150 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_UNIX_PROCESS_ID_UNKNOWN, "No such process");
153 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_FILE_NOT_FOUND, "File not found");
156 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_FILE_EXISTS, "File exists");
160 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_TIMEOUT, "Timed out");
163 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_IO_ERROR, "Input/output error");
168 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_DISCONNECTED, "Disconnected");
171 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NOT_SUPPORTED, "Not supported");
174 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_BAD_ADDRESS, "Address not available");
177 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_LIMITS_EXCEEDED, "Limits exceeded");
180 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_ADDRESS_IN_USE, "Address in use");
183 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INCONSISTENT_MESSAGE, "Inconsistent message");
186 return SD_BUS_ERROR_NULL;
189 static int errno_to_bus_error_name_new(int error, char **ret) {
196 name = errno_to_name(error);
200 n = strappend("System.Error.", name);
208 bool bus_error_is_dirty(sd_bus_error *e) {
212 return e->name || e->message || e->_need_free != 0;
215 _public_ void sd_bus_error_free(sd_bus_error *e) {
219 if (e->_need_free > 0) {
220 free((void*) e->name);
221 free((void*) e->message);
224 e->name = e->message = NULL;
228 _public_ int sd_bus_error_set(sd_bus_error *e, const char *name, const char *message) {
235 assert_return(!bus_error_is_dirty(e), -EINVAL);
237 e->name = strdup(name);
244 e->message = strdup(message);
249 return -bus_error_name_to_errno(name);
252 int bus_error_setfv(sd_bus_error *e, const char *name, const char *format, va_list ap) {
259 assert_return(!bus_error_is_dirty(e), -EINVAL);
261 e->name = strdup(name);
268 vasprintf((char**) &e->message, format, ap);
273 return -bus_error_name_to_errno(name);
276 _public_ int sd_bus_error_setf(sd_bus_error *e, const char *name, const char *format, ...) {
282 va_start(ap, format);
283 r = bus_error_setfv(e, name, format, ap);
289 return sd_bus_error_set(e, name, NULL);
292 _public_ int sd_bus_error_copy(sd_bus_error *dest, const sd_bus_error *e) {
294 if (!sd_bus_error_is_set(e))
299 assert_return(!bus_error_is_dirty(dest), -EINVAL);
302 * _need_free < 0 indicates that the error is temporarily const, needs deep copying
303 * _need_free == 0 indicates that the error is perpetually const, needs no deep copying
304 * _need_free > 0 indicates that the error is fully dynamic, needs deep copying
307 if (e->_need_free == 0)
310 dest->name = strdup(e->name);
312 *dest = BUS_ERROR_OOM;
317 dest->message = strdup(e->message);
319 dest->_need_free = 1;
323 return -bus_error_name_to_errno(e->name);
326 _public_ int sd_bus_error_set_const(sd_bus_error *e, const char *name, const char *message) {
332 assert_return(!bus_error_is_dirty(e), -EINVAL);
334 *e = SD_BUS_ERROR_MAKE_CONST(name, message);
337 return -bus_error_name_to_errno(name);
340 _public_ int sd_bus_error_is_set(const sd_bus_error *e) {
347 _public_ int sd_bus_error_has_name(const sd_bus_error *e, const char *name) {
351 return streq_ptr(e->name, name);
354 _public_ int sd_bus_error_get_errno(const sd_bus_error* e) {
358 return bus_error_name_to_errno(e->name);
361 static void bus_error_strerror(sd_bus_error *e, int error) {
375 x = strerror_r(error, m, k);
376 if (errno == ERANGE || strlen(x) >= k - 1) {
388 if (e->_need_free > 0) {
389 /* Error is already dynamic, let's just update the message */
390 free((char*) e->message);
395 /* Error was const so far, let's make it dynamic, if we can */
410 if (e->_need_free > 0) {
413 /* Error is dynamic, let's hence make the message also dynamic */
418 free((char*) e->message);
421 /* Error is const, hence we can just override */
430 _public_ int sd_bus_error_set_errno(sd_bus_error *e, int error) {
440 assert_return(!bus_error_is_dirty(e), -EINVAL);
442 /* First, try a const translation */
443 *e = errno_to_bus_error_const(error);
445 if (!sd_bus_error_is_set(e)) {
448 /* If that didn't work, try a dynamic one. */
450 k = errno_to_bus_error_name_new(error, (char**) &e->name);
457 *e = BUS_ERROR_FAILED;
460 /* Now, fill in the message from strerror() if we can */
461 bus_error_strerror(e, error);
465 int bus_error_set_errnofv(sd_bus_error *e, int error, const char *format, va_list ap) {
476 assert_return(!bus_error_is_dirty(e), -EINVAL);
478 /* First, try a const translation */
479 *e = errno_to_bus_error_const(error);
481 if (!sd_bus_error_is_set(e)) {
484 /* If that didn't work, try a dynamic one */
486 k = errno_to_bus_error_name_new(error, (char**) &e->name);
493 *e = BUS_ERROR_FAILED;
499 /* First, let's try to fill in the supplied message */
501 r = vasprintf(&m, format, ap);
504 if (e->_need_free <= 0) {
517 free((char*) e->message);
524 /* If that didn't work, use strerror() for the message */
525 bus_error_strerror(e, error);
529 _public_ int sd_bus_error_set_errnof(sd_bus_error *e, int error, const char *format, ...) {
540 assert_return(!bus_error_is_dirty(e), -EINVAL);
545 va_start(ap, format);
546 r = bus_error_set_errnofv(e, error, format, ap);
552 return sd_bus_error_set_errno(e, error);
555 const char *bus_error_message(const sd_bus_error *e, int error) {
558 /* Sometimes the D-Bus server is a little bit too verbose with
559 * its error messages, so let's override them here */
560 if (sd_bus_error_has_name(e, SD_BUS_ERROR_ACCESS_DENIED))
561 return "Access denied";
570 return strerror(error);