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/>.
32 #include "bus-error.h"
34 bool bus_error_is_dirty(sd_bus_error *e) {
38 return e->name || e->message || e->need_free;
41 _public_ void sd_bus_error_free(sd_bus_error *e) {
46 free((void*) e->name);
47 free((void*) e->message);
50 e->name = e->message = NULL;
54 _public_ int sd_bus_error_set(sd_bus_error *e, const char *name, const char *message) {
60 assert_return(!bus_error_is_dirty(e), -EINVAL);
61 assert_return(name, -EINVAL);
77 return sd_bus_error_get_errno(e);
80 int bus_error_setfv(sd_bus_error *e, const char *name, const char *format, va_list ap) {
87 assert_return(!bus_error_is_dirty(e), -EINVAL);
88 assert_return(name, -EINVAL);
95 r = vasprintf(&m, format, ap);
106 return sd_bus_error_get_errno(e);
109 _public_ int sd_bus_error_setf(sd_bus_error *e, const char *name, const char *format, ...) {
115 va_start(ap, format);
116 r = bus_error_setfv(e, name, format, ap);
122 return sd_bus_error_set(e, name, NULL);
125 _public_ int sd_bus_error_copy(sd_bus_error *dest, const sd_bus_error *e) {
130 if (!sd_bus_error_is_set(e))
133 assert_return(!bus_error_is_dirty(dest), -EINVAL);
140 y = strdup(e->message);
149 dest->need_free = true;
150 return sd_bus_error_get_errno(e);
153 _public_ int sd_bus_error_set_const(sd_bus_error *e, const char *name, const char *message) {
157 assert_return(!bus_error_is_dirty(e), -EINVAL);
158 assert_return(name, -EINVAL);
160 *e = SD_BUS_ERROR_MAKE_CONST(name, message);
161 return sd_bus_error_get_errno(e);
164 _public_ int sd_bus_error_is_set(const sd_bus_error *e) {
171 _public_ int sd_bus_error_has_name(const sd_bus_error *e, const char *name) {
175 return streq_ptr(e->name, name);
178 _public_ int sd_bus_error_get_errno(const sd_bus_error* e) {
180 /* Better replce this with a gperf table */
188 if (streq(e->name, SD_BUS_ERROR_NO_MEMORY))
191 if (streq(e->name, SD_BUS_ERROR_SERVICE_UNKNOWN))
194 if (streq(e->name, SD_BUS_ERROR_NAME_HAS_NO_OWNER))
197 if (streq(e->name, SD_BUS_ERROR_NO_REPLY) ||
198 streq(e->name, SD_BUS_ERROR_TIMEOUT) ||
199 streq(e->name, "org.freedesktop.DBus.Error.TimedOut"))
202 if (streq(e->name, SD_BUS_ERROR_IO_ERROR))
205 if (streq(e->name, SD_BUS_ERROR_BAD_ADDRESS))
206 return EADDRNOTAVAIL;
208 if (streq(e->name, SD_BUS_ERROR_NOT_SUPPORTED))
211 if (streq(e->name, SD_BUS_ERROR_LIMITS_EXCEEDED))
214 if (streq(e->name, SD_BUS_ERROR_ACCESS_DENIED) ||
215 streq(e->name, SD_BUS_ERROR_AUTH_FAILED))
218 if (streq(e->name, SD_BUS_ERROR_NO_SERVER))
221 if (streq(e->name, SD_BUS_ERROR_NO_NETWORK))
224 if (streq(e->name, SD_BUS_ERROR_ADDRESS_IN_USE))
227 if (streq(e->name, SD_BUS_ERROR_DISCONNECTED))
230 if (streq(e->name, SD_BUS_ERROR_INVALID_ARGS) ||
231 streq(e->name, SD_BUS_ERROR_INVALID_SIGNATURE) ||
232 streq(e->name, "org.freedesktop.DBus.Error.MatchRuleInvalid") ||
233 streq(e->name, "org.freedesktop.DBus.Error.InvalidFileContent"))
236 if (streq(e->name, SD_BUS_ERROR_FILE_NOT_FOUND) ||
237 streq(e->name, "org.freedesktop.DBus.Error.MatchRuleNotFound"))
240 if (streq(e->name, SD_BUS_ERROR_FILE_EXISTS))
243 if (streq(e->name, SD_BUS_ERROR_UNKNOWN_METHOD) ||
244 streq(e->name, SD_BUS_ERROR_UNKNOWN_OBJECT) ||
245 streq(e->name, SD_BUS_ERROR_UNKNOWN_INTERFACE) ||
246 streq(e->name, SD_BUS_ERROR_UNKNOWN_PROPERTY))
249 if (streq(e->name, SD_BUS_ERROR_PROPERTY_READ_ONLY))
252 if (streq(e->name, SD_BUS_ERROR_UNIX_PROCESS_ID_UNKNOWN) ||
253 streq(e->name, "org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown"))
256 if (streq(e->name, SD_BUS_ERROR_INCONSISTENT_MESSAGE))
259 if (streq(e->name, "org.freedesktop.DBus.Error.ObjectPathInUse"))
265 static int bus_error_set_strerror_or_const(sd_bus_error *e, const char *name, int error, const char *fallback) {
267 char *n = NULL, *m = NULL;
275 assert_return(!bus_error_is_dirty(e), -EINVAL);
276 assert_return(name, -EINVAL);
286 x = strerror_r(error, m, k);
287 if (errno == ERANGE || strlen(x) >= k - 1) {
301 sd_bus_error_set_const(e, name, x);
322 sd_bus_error_set_const(e, name, fallback);
326 static sd_bus_error map_from_errno(int error) {
334 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_NETWORK, "Out of memory");
338 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_ACCESS_DENIED, "Access denied");
341 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid argument");
344 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_UNIX_PROCESS_ID_UNKNOWN, "No such process");
347 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_FILE_NOT_FOUND, "File not found");
350 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_FILE_EXISTS, "File exists");
354 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_TIMEOUT, "Timed out");
357 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_IO_ERROR, "Input/output error");
362 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_DISCONNECTED, "Disconnected");
365 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NOT_SUPPORTED, "Not supported");
368 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_BAD_ADDRESS, "Address not available");
371 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_LIMITS_EXCEEDED, "Limits exceeded");
374 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_ADDRESS_IN_USE, "Address in use");
377 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INCONSISTENT_MESSAGE, "Inconsistent message");
380 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_FAILED, "Operation failed");
383 _public_ int sd_bus_error_set_errno(sd_bus_error *e, int error) {
386 x = map_from_errno(error);
388 return bus_error_set_strerror_or_const(e, x.name, error, x.message);
391 int bus_error_set_errnofv(sd_bus_error *e, int error, const char *format, va_list ap) {
401 assert_return(!bus_error_is_dirty(e), -EINVAL);
403 x = map_from_errno(error);
408 r = vasprintf(&m, format, ap);
425 return bus_error_set_strerror_or_const(e, x.name, error, x.message);
428 _public_ int sd_bus_error_set_errnof(sd_bus_error *e, int error, const char *format, ...) {
437 assert_return(!bus_error_is_dirty(e), -EINVAL);
442 va_start(ap, format);
443 r = bus_error_set_errnofv(e, error, format, ap);
449 return sd_bus_error_set_errno(e, error);
452 const char *bus_error_message(const sd_bus_error *e, int error) {
455 /* Sometimes the D-Bus server is a little bit too verbose with
456 * its error messages, so let's override them here */
457 if (sd_bus_error_has_name(e, SD_BUS_ERROR_ACCESS_DENIED))
458 return "Access denied";
467 return strerror(error);