1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
5 #include "alloc-util.h"
7 #include "errno-list.h"
8 #include "errno-util.h"
9 #include "string-util.h"
11 BUS_ERROR_MAP_ELF_REGISTER
const sd_bus_error_map bus_standard_errors
[] = {
12 SD_BUS_ERROR_MAP(SD_BUS_ERROR_FAILED
, EACCES
),
13 SD_BUS_ERROR_MAP(SD_BUS_ERROR_NO_MEMORY
, ENOMEM
),
14 SD_BUS_ERROR_MAP(SD_BUS_ERROR_SERVICE_UNKNOWN
, EHOSTUNREACH
),
15 SD_BUS_ERROR_MAP(SD_BUS_ERROR_NAME_HAS_NO_OWNER
, ENXIO
),
16 SD_BUS_ERROR_MAP(SD_BUS_ERROR_NO_REPLY
, ETIMEDOUT
),
17 SD_BUS_ERROR_MAP(SD_BUS_ERROR_IO_ERROR
, EIO
),
18 SD_BUS_ERROR_MAP(SD_BUS_ERROR_BAD_ADDRESS
, EADDRNOTAVAIL
),
19 SD_BUS_ERROR_MAP(SD_BUS_ERROR_NOT_SUPPORTED
, EOPNOTSUPP
),
20 SD_BUS_ERROR_MAP(SD_BUS_ERROR_LIMITS_EXCEEDED
, ENOBUFS
),
21 SD_BUS_ERROR_MAP(SD_BUS_ERROR_ACCESS_DENIED
, EACCES
),
22 SD_BUS_ERROR_MAP(SD_BUS_ERROR_AUTH_FAILED
, EACCES
),
23 SD_BUS_ERROR_MAP(SD_BUS_ERROR_NO_SERVER
, EHOSTDOWN
),
24 SD_BUS_ERROR_MAP(SD_BUS_ERROR_TIMEOUT
, ETIMEDOUT
),
25 SD_BUS_ERROR_MAP(SD_BUS_ERROR_NO_NETWORK
, ENONET
),
26 SD_BUS_ERROR_MAP(SD_BUS_ERROR_ADDRESS_IN_USE
, EADDRINUSE
),
27 SD_BUS_ERROR_MAP(SD_BUS_ERROR_DISCONNECTED
, ECONNRESET
),
28 SD_BUS_ERROR_MAP(SD_BUS_ERROR_INVALID_ARGS
, EINVAL
),
29 SD_BUS_ERROR_MAP(SD_BUS_ERROR_FILE_NOT_FOUND
, ENOENT
),
30 SD_BUS_ERROR_MAP(SD_BUS_ERROR_FILE_EXISTS
, EEXIST
),
31 SD_BUS_ERROR_MAP(SD_BUS_ERROR_UNKNOWN_METHOD
, EBADR
),
32 SD_BUS_ERROR_MAP(SD_BUS_ERROR_UNKNOWN_OBJECT
, EBADR
),
33 SD_BUS_ERROR_MAP(SD_BUS_ERROR_UNKNOWN_INTERFACE
, EBADR
),
34 SD_BUS_ERROR_MAP(SD_BUS_ERROR_UNKNOWN_PROPERTY
, EBADR
),
35 SD_BUS_ERROR_MAP(SD_BUS_ERROR_PROPERTY_READ_ONLY
, EROFS
),
36 SD_BUS_ERROR_MAP(SD_BUS_ERROR_UNIX_PROCESS_ID_UNKNOWN
, ESRCH
),
37 SD_BUS_ERROR_MAP(SD_BUS_ERROR_INVALID_SIGNATURE
, EINVAL
),
38 SD_BUS_ERROR_MAP(SD_BUS_ERROR_INCONSISTENT_MESSAGE
, EBADMSG
),
39 SD_BUS_ERROR_MAP(SD_BUS_ERROR_TIMED_OUT
, ETIMEDOUT
),
40 SD_BUS_ERROR_MAP(SD_BUS_ERROR_MATCH_RULE_NOT_FOUND
, ENOENT
),
41 SD_BUS_ERROR_MAP(SD_BUS_ERROR_MATCH_RULE_INVALID
, EINVAL
),
42 SD_BUS_ERROR_MAP(SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED
, EACCES
),
43 SD_BUS_ERROR_MAP(SD_BUS_ERROR_INVALID_FILE_CONTENT
, EINVAL
),
44 SD_BUS_ERROR_MAP(SD_BUS_ERROR_SELINUX_SECURITY_CONTEXT_UNKNOWN
, ESRCH
),
45 SD_BUS_ERROR_MAP(SD_BUS_ERROR_OBJECT_PATH_IN_USE
, EBUSY
),
49 /* GCC maps this magically to the beginning and end of the BUS_ERROR_MAP section */
50 extern const sd_bus_error_map __start_SYSTEMD_BUS_ERROR_MAP
[];
51 extern const sd_bus_error_map __stop_SYSTEMD_BUS_ERROR_MAP
[];
53 /* Additional maps registered with sd_bus_error_add_map() are in this
54 * NULL terminated array */
55 static const sd_bus_error_map
**additional_error_maps
= NULL
;
57 static int bus_error_name_to_errno(const char *name
) {
61 assert_return(name
, EINVAL
);
63 p
= startswith(name
, "System.Error.");
65 r
= errno_from_name(p
);
72 if (additional_error_maps
)
73 for (const sd_bus_error_map
**map
= additional_error_maps
; *map
; map
++)
74 for (const sd_bus_error_map
*m
= *map
;; m
++) {
75 /* For additional error maps the end marker is actually the end marker */
76 if (m
->code
== BUS_ERROR_MAP_END_MARKER
)
79 if (streq(m
->name
, name
)) {
85 const sd_bus_error_map
*elf_map
= ALIGN_PTR(__start_SYSTEMD_BUS_ERROR_MAP
);
86 while (elf_map
< __stop_SYSTEMD_BUS_ERROR_MAP
) {
87 /* For magic ELF error maps, the end marker might appear in the middle of things, since
88 * multiple maps might appear in the same section. Hence, let's skip over it, but realign
89 * the pointer to the next 8 byte boundary, which is the selected alignment for the arrays. */
90 if (elf_map
->code
== BUS_ERROR_MAP_END_MARKER
) {
91 elf_map
= ALIGN_PTR(elf_map
+ 1);
95 if (streq(elf_map
->name
, name
)) {
96 assert(elf_map
->code
> 0);
106 static sd_bus_error
errno_to_bus_error_const(int error
) {
114 return BUS_ERROR_OOM
;
118 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_ACCESS_DENIED
, "Access denied");
121 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS
, "Invalid argument");
124 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_UNIX_PROCESS_ID_UNKNOWN
, "No such process");
127 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_FILE_NOT_FOUND
, "File not found");
130 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_FILE_EXISTS
, "File exists");
134 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_TIMEOUT
, "Timed out");
137 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_IO_ERROR
, "Input/output error");
142 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_DISCONNECTED
, "Disconnected");
145 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NOT_SUPPORTED
, "Not supported");
148 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_BAD_ADDRESS
, "Address not available");
151 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_LIMITS_EXCEEDED
, "Limits exceeded");
154 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_ADDRESS_IN_USE
, "Address in use");
157 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INCONSISTENT_MESSAGE
, "Inconsistent message");
160 return SD_BUS_ERROR_NULL
;
163 static int errno_to_bus_error_name_new(int error
, char **ret
) {
170 name
= errno_to_name(error
);
174 n
= strjoin("System.Error.", name
);
182 bool bus_error_is_dirty(sd_bus_error
*e
) {
186 return e
->name
|| e
->message
|| e
->_need_free
!= 0;
189 _public_
void sd_bus_error_free(sd_bus_error
*e
) {
193 if (e
->_need_free
> 0) {
194 free((void*) e
->name
);
195 free((void*) e
->message
);
198 *e
= SD_BUS_ERROR_NULL
;
201 _public_
int sd_bus_error_set(sd_bus_error
*e
, const char *name
, const char *message
) {
208 assert_return(!bus_error_is_dirty(e
), -EINVAL
);
210 e
->name
= strdup(name
);
217 e
->message
= strdup(message
);
222 r
= bus_error_name_to_errno(name
);
227 _public_
int sd_bus_error_setfv(sd_bus_error
*e
, const char *name
, const char *format
, va_list ap
) {
234 assert_return(!bus_error_is_dirty(e
), -EINVAL
);
236 e
->name
= strdup(name
);
243 _cleanup_free_
char *mesg
= NULL
;
245 /* If we hit OOM on formatting the pretty message, we ignore
246 * this, since we at least managed to write the error name */
248 if (vasprintf(&mesg
, format
, ap
) >= 0)
249 e
->message
= TAKE_PTR(mesg
);
255 r
= bus_error_name_to_errno(name
);
260 _public_
int sd_bus_error_setf(sd_bus_error
*e
, const char *name
, const char *format
, ...) {
266 va_start(ap
, format
);
267 r
= sd_bus_error_setfv(e
, name
, format
, ap
);
275 r
= sd_bus_error_set(e
, name
, NULL
);
281 _public_
int sd_bus_error_copy(sd_bus_error
*dest
, const sd_bus_error
*e
) {
283 if (!sd_bus_error_is_set(e
))
288 assert_return(!bus_error_is_dirty(dest
), -EINVAL
);
291 * _need_free < 0 indicates that the error is temporarily const, needs deep copying
292 * _need_free == 0 indicates that the error is perpetually const, needs no deep copying
293 * _need_free > 0 indicates that the error is fully dynamic, needs deep copying
296 if (e
->_need_free
== 0)
299 dest
->name
= strdup(e
->name
);
301 *dest
= BUS_ERROR_OOM
;
306 dest
->message
= strdup(e
->message
);
308 dest
->_need_free
= 1;
312 return -bus_error_name_to_errno(e
->name
);
315 _public_
int sd_bus_error_move(sd_bus_error
*dest
, sd_bus_error
*e
) {
318 if (!sd_bus_error_is_set(e
)) {
321 *dest
= SD_BUS_ERROR_NULL
;
326 r
= -bus_error_name_to_errno(e
->name
);
330 *e
= SD_BUS_ERROR_NULL
;
332 sd_bus_error_free(e
);
337 _public_
int sd_bus_error_set_const(sd_bus_error
*e
, const char *name
, const char *message
) {
343 assert_return(!bus_error_is_dirty(e
), -EINVAL
);
345 *e
= SD_BUS_ERROR_MAKE_CONST(name
, message
);
348 return -bus_error_name_to_errno(name
);
351 _public_
int sd_bus_error_is_set(const sd_bus_error
*e
) {
358 _public_
int sd_bus_error_has_name(const sd_bus_error
*e
, const char *name
) {
362 return streq_ptr(e
->name
, name
);
365 _public_
int sd_bus_error_has_names_sentinel(const sd_bus_error
*e
, ...) {
373 while ((p
= va_arg(ap
, const char *)))
374 if (streq(p
, e
->name
))
380 _public_
int sd_bus_error_get_errno(const sd_bus_error
*e
) {
384 return bus_error_name_to_errno(e
->name
);
387 static void bus_error_strerror(sd_bus_error
*e
, int error
) {
401 x
= strerror_r(error
, m
, k
);
402 if (errno
== ERANGE
|| strlen(x
) >= k
- 1) {
414 if (e
->_need_free
> 0) {
415 /* Error is already dynamic, let's just update the message */
416 free((char*) e
->message
);
421 /* Error was const so far, let's make it dynamic, if we can */
436 if (e
->_need_free
> 0) {
439 /* Error is dynamic, let's hence make the message also dynamic */
444 free((char*) e
->message
);
447 /* Error is const, hence we can just override */
456 _public_
int sd_bus_error_set_errno(sd_bus_error
*e
, int error
) {
466 assert_return(!bus_error_is_dirty(e
), -EINVAL
);
468 /* First, try a const translation */
469 *e
= errno_to_bus_error_const(error
);
471 if (!sd_bus_error_is_set(e
)) {
474 /* If that didn't work, try a dynamic one. */
476 k
= errno_to_bus_error_name_new(error
, (char**) &e
->name
);
483 *e
= BUS_ERROR_FAILED
;
486 /* Now, fill in the message from strerror_r() if we can */
487 bus_error_strerror(e
, error
);
491 _public_
int sd_bus_error_set_errnofv(sd_bus_error
*e
, int error
, const char *format
, va_list ap
) {
502 assert_return(!bus_error_is_dirty(e
), -EINVAL
);
504 /* First, try a const translation */
505 *e
= errno_to_bus_error_const(error
);
507 if (!sd_bus_error_is_set(e
)) {
510 /* If that didn't work, try a dynamic one */
512 k
= errno_to_bus_error_name_new(error
, (char**) &e
->name
);
519 *e
= BUS_ERROR_FAILED
;
523 _cleanup_free_
char *m
= NULL
;
525 /* Then, let's try to fill in the supplied message */
527 errno
= error
; /* Make sure that %m resolves to the specified error */
528 if (vasprintf(&m
, format
, ap
) < 0)
531 if (e
->_need_free
<= 0) {
542 e
->message
= TAKE_PTR(m
);
547 /* If that didn't work, use strerror_r() for the message */
548 bus_error_strerror(e
, error
);
552 _public_
int sd_bus_error_set_errnof(sd_bus_error
*e
, int error
, const char *format
, ...) {
563 assert_return(!bus_error_is_dirty(e
), -EINVAL
);
568 va_start(ap
, format
);
569 r
= sd_bus_error_set_errnofv(e
, error
, format
, ap
);
575 return sd_bus_error_set_errno(e
, error
);
578 const char* _bus_error_message(const sd_bus_error
*e
, int error
, char buf
[static ERRNO_BUF_LEN
]) {
579 /* Sometimes, the D-Bus server is a little bit too verbose with
580 * its error messages, so let's override them here */
581 if (sd_bus_error_has_name(e
, SD_BUS_ERROR_ACCESS_DENIED
))
582 return "Access denied";
587 return strerror_r(ABS(error
), buf
, ERRNO_BUF_LEN
);
590 static bool map_ok(const sd_bus_error_map
*map
) {
591 for (; map
->code
!= BUS_ERROR_MAP_END_MARKER
; map
++)
592 if (!map
->name
|| map
->code
<= 0)
597 _public_
int sd_bus_error_add_map(const sd_bus_error_map
*map
) {
600 assert_return(map
, -EINVAL
);
601 assert_return(map_ok(map
), -EINVAL
);
603 if (additional_error_maps
)
604 for (; additional_error_maps
[n
] != NULL
; n
++)
605 if (additional_error_maps
[n
] == map
)
608 if (!GREEDY_REALLOC(additional_error_maps
, n
+ 2))
611 additional_error_maps
[n
] = map
;
612 additional_error_maps
[n
+1] = NULL
;