Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #include <errno.h>
4 : : #include <stdarg.h>
5 : : #include <stdbool.h>
6 : : #include <stdio.h>
7 : : #include <stdlib.h>
8 : : #include <string.h>
9 : :
10 : : #include "sd-bus.h"
11 : :
12 : : #include "alloc-util.h"
13 : : #include "bus-error.h"
14 : : #include "errno-list.h"
15 : : #include "errno-util.h"
16 : : #include "string-util.h"
17 : : #include "util.h"
18 : :
19 : : BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_standard_errors[] = {
20 : : SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.Failed", EACCES),
21 : : SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.NoMemory", ENOMEM),
22 : : SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.ServiceUnknown", EHOSTUNREACH),
23 : : SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.NameHasNoOwner", ENXIO),
24 : : SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.NoReply", ETIMEDOUT),
25 : : SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.IOError", EIO),
26 : : SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.BadAddress", EADDRNOTAVAIL),
27 : : SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.NotSupported", EOPNOTSUPP),
28 : : SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.LimitsExceeded", ENOBUFS),
29 : : SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.AccessDenied", EACCES),
30 : : SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.AuthFailed", EACCES),
31 : : SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.InteractiveAuthorizationRequired", EACCES),
32 : : SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.NoServer", EHOSTDOWN),
33 : : SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.Timeout", ETIMEDOUT),
34 : : SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.NoNetwork", ENONET),
35 : : SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.AddressInUse", EADDRINUSE),
36 : : SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.Disconnected", ECONNRESET),
37 : : SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.InvalidArgs", EINVAL),
38 : : SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.FileNotFound", ENOENT),
39 : : SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.FileExists", EEXIST),
40 : : SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.UnknownMethod", EBADR),
41 : : SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.UnknownObject", EBADR),
42 : : SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.UnknownInterface", EBADR),
43 : : SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.UnknownProperty", EBADR),
44 : : SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.PropertyReadOnly", EROFS),
45 : : SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.UnixProcessIdUnknown", ESRCH),
46 : : SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.InvalidSignature", EINVAL),
47 : : SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.InconsistentMessage", EBADMSG),
48 : : SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.TimedOut", ETIMEDOUT),
49 : : SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.MatchRuleInvalid", EINVAL),
50 : : SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.InvalidFileContent", EINVAL),
51 : : SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.MatchRuleNotFound", ENOENT),
52 : : SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown", ESRCH),
53 : : SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.ObjectPathInUse", EBUSY),
54 : : SD_BUS_ERROR_MAP_END
55 : : };
56 : :
57 : : /* GCC maps this magically to the beginning and end of the BUS_ERROR_MAP section */
58 : : extern const sd_bus_error_map __start_SYSTEMD_BUS_ERROR_MAP[];
59 : : extern const sd_bus_error_map __stop_SYSTEMD_BUS_ERROR_MAP[];
60 : :
61 : : /* Additional maps registered with sd_bus_error_add_map() are in this
62 : : * NULL terminated array */
63 : : static const sd_bus_error_map **additional_error_maps = NULL;
64 : :
65 : 460 : static int bus_error_name_to_errno(const char *name) {
66 : : const sd_bus_error_map **map, *m;
67 : : const char *p;
68 : : int r;
69 : :
70 [ - + ]: 460 : if (!name)
71 : 0 : return EINVAL;
72 : :
73 : 460 : p = startswith(name, "System.Error.");
74 [ + + ]: 460 : if (p) {
75 : 28 : r = errno_from_name(p);
76 [ + + ]: 28 : if (r < 0)
77 : 4 : return EIO;
78 : :
79 : 24 : return r;
80 : : }
81 : :
82 [ + + ]: 432 : if (additional_error_maps)
83 [ + + ]: 60 : for (map = additional_error_maps; *map; map++)
84 : 48 : for (m = *map;; m++) {
85 : : /* For additional error maps the end marker is actually the end marker */
86 [ + + ]: 120 : if (m->code == BUS_ERROR_MAP_END_MARKER)
87 : 32 : break;
88 : :
89 [ + + ]: 88 : if (streq(m->name, name))
90 : 16 : return m->code;
91 : : }
92 : :
93 : 416 : m = ALIGN_TO_PTR(__start_SYSTEMD_BUS_ERROR_MAP, sizeof(void*));
94 [ + + ]: 11656 : while (m < __stop_SYSTEMD_BUS_ERROR_MAP) {
95 : : /* For magic ELF error maps, the end marker might
96 : : * appear in the middle of things, since multiple maps
97 : : * might appear in the same section. Hence, let's skip
98 : : * over it, but realign the pointer to the next 8 byte
99 : : * boundary, which is the selected alignment for the
100 : : * arrays. */
101 [ + + ]: 11636 : if (m->code == BUS_ERROR_MAP_END_MARKER) {
102 : 260 : m = ALIGN_TO_PTR(m + 1, sizeof(void*));
103 : 260 : continue;
104 : : }
105 : :
106 [ + + ]: 11376 : if (streq(m->name, name))
107 : 396 : return m->code;
108 : :
109 : 10980 : m++;
110 : : }
111 : :
112 : 20 : return EIO;
113 : : }
114 : :
115 : 16 : static sd_bus_error errno_to_bus_error_const(int error) {
116 : :
117 [ - + ]: 16 : if (error < 0)
118 : 0 : error = -error;
119 : :
120 [ - + - - : 16 : switch (error) {
- - + + -
- - - - -
+ ]
121 : :
122 : 0 : case ENOMEM:
123 : 0 : return BUS_ERROR_OOM;
124 : :
125 : 4 : case EPERM:
126 : : case EACCES:
127 : 4 : return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_ACCESS_DENIED, "Access denied");
128 : :
129 : 0 : case EINVAL:
130 : 0 : return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid argument");
131 : :
132 : 0 : case ESRCH:
133 : 0 : return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_UNIX_PROCESS_ID_UNKNOWN, "No such process");
134 : :
135 : 0 : case ENOENT:
136 : 0 : return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_FILE_NOT_FOUND, "File not found");
137 : :
138 : 0 : case EEXIST:
139 : 0 : return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_FILE_EXISTS, "File exists");
140 : :
141 : 4 : case ETIMEDOUT:
142 : : case ETIME:
143 : 4 : return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_TIMEOUT, "Timed out");
144 : :
145 : 4 : case EIO:
146 : 4 : return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_IO_ERROR, "Input/output error");
147 : :
148 : 0 : case ENETRESET:
149 : : case ECONNABORTED:
150 : : case ECONNRESET:
151 : 0 : return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_DISCONNECTED, "Disconnected");
152 : :
153 : 0 : case EOPNOTSUPP:
154 : 0 : return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NOT_SUPPORTED, "Not supported");
155 : :
156 : 0 : case EADDRNOTAVAIL:
157 : 0 : return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_BAD_ADDRESS, "Address not available");
158 : :
159 : 0 : case ENOBUFS:
160 : 0 : return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_LIMITS_EXCEEDED, "Limits exceeded");
161 : :
162 : 0 : case EADDRINUSE:
163 : 0 : return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_ADDRESS_IN_USE, "Address in use");
164 : :
165 : 0 : case EBADMSG:
166 : 0 : return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INCONSISTENT_MESSAGE, "Inconsistent message");
167 : : }
168 : :
169 : 4 : return SD_BUS_ERROR_NULL;
170 : : }
171 : :
172 : 4 : static int errno_to_bus_error_name_new(int error, char **ret) {
173 : : const char *name;
174 : : char *n;
175 : :
176 [ - + ]: 4 : if (error < 0)
177 : 0 : error = -error;
178 : :
179 : 4 : name = errno_to_name(error);
180 [ - + ]: 4 : if (!name)
181 : 0 : return 0;
182 : :
183 : 4 : n = strjoin("System.Error.", name);
184 [ - + ]: 4 : if (!n)
185 : 0 : return -ENOMEM;
186 : :
187 : 4 : *ret = n;
188 : 4 : return 1;
189 : : }
190 : :
191 : 384 : bool bus_error_is_dirty(sd_bus_error *e) {
192 [ + + ]: 384 : if (!e)
193 : 24 : return false;
194 : :
195 [ + - + - : 360 : return e->name || e->message || e->_need_free != 0;
- + ]
196 : : }
197 : :
198 : 9208 : _public_ void sd_bus_error_free(sd_bus_error *e) {
199 [ + + ]: 9208 : if (!e)
200 : 144 : return;
201 : :
202 [ + + ]: 9064 : if (e->_need_free > 0) {
203 : 192 : free((void*) e->name);
204 : 192 : free((void*) e->message);
205 : : }
206 : :
207 : 9064 : *e = SD_BUS_ERROR_NULL;
208 : : }
209 : :
210 : 76 : _public_ int sd_bus_error_set(sd_bus_error *e, const char *name, const char *message) {
211 : :
212 [ - + ]: 76 : if (!name)
213 : 0 : return 0;
214 [ + + ]: 76 : if (!e)
215 : 72 : goto finish;
216 : :
217 [ - + - + ]: 4 : assert_return(!bus_error_is_dirty(e), -EINVAL);
218 : :
219 : 4 : e->name = strdup(name);
220 [ - + ]: 4 : if (!e->name) {
221 : 0 : *e = BUS_ERROR_OOM;
222 : 0 : return -ENOMEM;
223 : : }
224 : :
225 [ + - ]: 4 : if (message)
226 : 4 : e->message = strdup(message);
227 : :
228 : 4 : e->_need_free = 1;
229 : :
230 : 76 : finish:
231 : 76 : return -bus_error_name_to_errno(name);
232 : : }
233 : :
234 : 320 : int bus_error_setfv(sd_bus_error *e, const char *name, const char *format, va_list ap) {
235 : :
236 [ + + ]: 320 : if (!name)
237 : 4 : return 0;
238 : :
239 [ + + ]: 316 : if (e) {
240 [ - + - + ]: 156 : assert_return(!bus_error_is_dirty(e), -EINVAL);
241 : :
242 : 156 : e->name = strdup(name);
243 [ - + ]: 156 : if (!e->name) {
244 : 0 : *e = BUS_ERROR_OOM;
245 : 0 : return -ENOMEM;
246 : : }
247 : :
248 : : /* If we hit OOM on formatting the pretty message, we ignore
249 : : * this, since we at least managed to write the error name */
250 [ + - ]: 156 : if (format)
251 : 156 : (void) vasprintf((char**) &e->message, format, ap);
252 : :
253 : 156 : e->_need_free = 1;
254 : : }
255 : :
256 : 316 : return -bus_error_name_to_errno(name);
257 : : }
258 : :
259 : 304 : _public_ int sd_bus_error_setf(sd_bus_error *e, const char *name, const char *format, ...) {
260 : :
261 [ + - ]: 304 : if (format) {
262 : : int r;
263 : : va_list ap;
264 : :
265 : 304 : va_start(ap, format);
266 : 304 : r = bus_error_setfv(e, name, format, ap);
267 : 304 : va_end(ap);
268 : :
269 : 304 : return r;
270 : : }
271 : :
272 : 0 : return sd_bus_error_set(e, name, NULL);
273 : : }
274 : :
275 : 28 : _public_ int sd_bus_error_copy(sd_bus_error *dest, const sd_bus_error *e) {
276 : :
277 [ - + ]: 28 : if (!sd_bus_error_is_set(e))
278 : 0 : return 0;
279 [ - + ]: 28 : if (!dest)
280 : 0 : goto finish;
281 : :
282 [ - + - + ]: 28 : assert_return(!bus_error_is_dirty(dest), -EINVAL);
283 : :
284 : : /*
285 : : * _need_free < 0 indicates that the error is temporarily const, needs deep copying
286 : : * _need_free == 0 indicates that the error is perpetually const, needs no deep copying
287 : : * _need_free > 0 indicates that the error is fully dynamic, needs deep copying
288 : : */
289 : :
290 [ + + ]: 28 : if (e->_need_free == 0)
291 : 4 : *dest = *e;
292 : : else {
293 : 24 : dest->name = strdup(e->name);
294 [ - + ]: 24 : if (!dest->name) {
295 : 0 : *dest = BUS_ERROR_OOM;
296 : 0 : return -ENOMEM;
297 : : }
298 : :
299 [ + - ]: 24 : if (e->message)
300 : 24 : dest->message = strdup(e->message);
301 : :
302 : 24 : dest->_need_free = 1;
303 : : }
304 : :
305 : 28 : finish:
306 : 28 : return -bus_error_name_to_errno(e->name);
307 : : }
308 : :
309 : 0 : _public_ int sd_bus_error_move(sd_bus_error *dest, sd_bus_error *e) {
310 : : int r;
311 : :
312 [ # # ]: 0 : if (!sd_bus_error_is_set(e)) {
313 : :
314 [ # # ]: 0 : if (dest)
315 : 0 : *dest = SD_BUS_ERROR_NULL;
316 : :
317 : 0 : return 0;
318 : : }
319 : :
320 : 0 : r = -bus_error_name_to_errno(e->name);
321 : :
322 [ # # ]: 0 : if (dest) {
323 : 0 : *dest = *e;
324 : 0 : *e = SD_BUS_ERROR_NULL;
325 : : } else
326 : 0 : sd_bus_error_free(e);
327 : :
328 : 0 : return r;
329 : : }
330 : :
331 : 4 : _public_ int sd_bus_error_set_const(sd_bus_error *e, const char *name, const char *message) {
332 [ - + ]: 4 : if (!name)
333 : 0 : return 0;
334 [ - + ]: 4 : if (!e)
335 : 0 : goto finish;
336 : :
337 [ - + - + ]: 4 : assert_return(!bus_error_is_dirty(e), -EINVAL);
338 : :
339 : 4 : *e = SD_BUS_ERROR_MAKE_CONST(name, message);
340 : :
341 : 4 : finish:
342 : 4 : return -bus_error_name_to_errno(name);
343 : : }
344 : :
345 : 511 : _public_ int sd_bus_error_is_set(const sd_bus_error *e) {
346 [ - + ]: 511 : if (!e)
347 : 0 : return 0;
348 : :
349 : 511 : return !!e->name;
350 : : }
351 : :
352 : 200 : _public_ int sd_bus_error_has_name(const sd_bus_error *e, const char *name) {
353 [ - + ]: 200 : if (!e)
354 : 0 : return 0;
355 : :
356 : 200 : return streq_ptr(e->name, name);
357 : : }
358 : :
359 : 44 : _public_ int sd_bus_error_get_errno(const sd_bus_error* e) {
360 [ - + ]: 44 : if (!e)
361 : 0 : return 0;
362 : :
363 [ + + ]: 44 : if (!e->name)
364 : 8 : return 0;
365 : :
366 : 36 : return bus_error_name_to_errno(e->name);
367 : : }
368 : :
369 : 12 : static void bus_error_strerror(sd_bus_error *e, int error) {
370 : 12 : size_t k = 64;
371 : : char *m;
372 : :
373 [ - + ]: 12 : assert(e);
374 : :
375 : 0 : for (;;) {
376 : : char *x;
377 : :
378 : 12 : m = new(char, k);
379 [ - + ]: 12 : if (!m)
380 : 0 : return;
381 : :
382 : 12 : errno = 0;
383 : 12 : x = strerror_r(error, m, k);
384 [ + - - + ]: 12 : if (errno == ERANGE || strlen(x) >= k - 1) {
385 : 0 : free(m);
386 : 0 : k *= 2;
387 : 0 : continue;
388 : : }
389 : :
390 [ - + ]: 12 : if (errno) {
391 : 0 : free(m);
392 : 0 : return;
393 : : }
394 : :
395 [ - + ]: 12 : if (x == m) {
396 [ # # ]: 0 : if (e->_need_free > 0) {
397 : : /* Error is already dynamic, let's just update the message */
398 : 0 : free((char*) e->message);
399 : 0 : e->message = x;
400 : :
401 : : } else {
402 : : char *t;
403 : : /* Error was const so far, let's make it dynamic, if we can */
404 : :
405 : 0 : t = strdup(e->name);
406 [ # # ]: 0 : if (!t) {
407 : 0 : free(m);
408 : 0 : return;
409 : : }
410 : :
411 : 0 : e->_need_free = 1;
412 : 0 : e->name = t;
413 : 0 : e->message = x;
414 : : }
415 : : } else {
416 : 12 : free(m);
417 : :
418 [ + + ]: 12 : if (e->_need_free > 0) {
419 : : char *t;
420 : :
421 : : /* Error is dynamic, let's hence make the message also dynamic */
422 : 4 : t = strdup(x);
423 [ - + ]: 4 : if (!t)
424 : 0 : return;
425 : :
426 : 4 : free((char*) e->message);
427 : 4 : e->message = t;
428 : : } else {
429 : : /* Error is const, hence we can just override */
430 : 8 : e->message = x;
431 : : }
432 : : }
433 : :
434 : 12 : return;
435 : : }
436 : : }
437 : :
438 : 12 : _public_ int sd_bus_error_set_errno(sd_bus_error *e, int error) {
439 : :
440 [ + + ]: 12 : if (error < 0)
441 : 8 : error = -error;
442 : :
443 [ - + ]: 12 : if (!e)
444 : 0 : return -error;
445 [ - + ]: 12 : if (error == 0)
446 : 0 : return -error;
447 : :
448 [ - + - + ]: 12 : assert_return(!bus_error_is_dirty(e), -EINVAL);
449 : :
450 : : /* First, try a const translation */
451 : 12 : *e = errno_to_bus_error_const(error);
452 : :
453 [ + + ]: 12 : if (!sd_bus_error_is_set(e)) {
454 : : int k;
455 : :
456 : : /* If that didn't work, try a dynamic one. */
457 : :
458 : 4 : k = errno_to_bus_error_name_new(error, (char**) &e->name);
459 [ + - ]: 4 : if (k > 0)
460 : 4 : e->_need_free = 1;
461 [ # # ]: 0 : else if (k < 0) {
462 : 0 : *e = BUS_ERROR_OOM;
463 : 0 : return -error;
464 : : } else
465 : 0 : *e = BUS_ERROR_FAILED;
466 : : }
467 : :
468 : : /* Now, fill in the message from strerror() if we can */
469 : 12 : bus_error_strerror(e, error);
470 : 12 : return -error;
471 : : }
472 : :
473 : 4 : _public_ int sd_bus_error_set_errnofv(sd_bus_error *e, int error, const char *format, va_list ap) {
474 : 4 : PROTECT_ERRNO;
475 : : int r;
476 : :
477 [ - + ]: 4 : if (error < 0)
478 : 0 : error = -error;
479 : :
480 [ - + ]: 4 : if (!e)
481 : 0 : return -error;
482 [ - + ]: 4 : if (error == 0)
483 : 0 : return 0;
484 : :
485 [ - + - + ]: 4 : assert_return(!bus_error_is_dirty(e), -EINVAL);
486 : :
487 : : /* First, try a const translation */
488 : 4 : *e = errno_to_bus_error_const(error);
489 : :
490 [ - + ]: 4 : if (!sd_bus_error_is_set(e)) {
491 : : int k;
492 : :
493 : : /* If that didn't work, try a dynamic one */
494 : :
495 : 0 : k = errno_to_bus_error_name_new(error, (char**) &e->name);
496 [ # # ]: 0 : if (k > 0)
497 : 0 : e->_need_free = 1;
498 [ # # ]: 0 : else if (k < 0) {
499 : 0 : *e = BUS_ERROR_OOM;
500 : 0 : return -ENOMEM;
501 : : } else
502 : 0 : *e = BUS_ERROR_FAILED;
503 : : }
504 : :
505 [ + - ]: 4 : if (format) {
506 : : char *m;
507 : :
508 : : /* Then, let's try to fill in the supplied message */
509 : :
510 : 4 : errno = error; /* Make sure that %m resolves to the specified error */
511 : 4 : r = vasprintf(&m, format, ap);
512 [ + - ]: 4 : if (r >= 0) {
513 : :
514 [ + - ]: 4 : if (e->_need_free <= 0) {
515 : : char *t;
516 : :
517 : 4 : t = strdup(e->name);
518 [ + - ]: 4 : if (t) {
519 : 4 : e->_need_free = 1;
520 : 4 : e->name = t;
521 : 4 : e->message = m;
522 : 4 : return -error;
523 : : }
524 : :
525 : 0 : free(m);
526 : : } else {
527 : 0 : free((char*) e->message);
528 : 0 : e->message = m;
529 : 0 : return -error;
530 : : }
531 : : }
532 : : }
533 : :
534 : : /* If that didn't work, use strerror() for the message */
535 : 0 : bus_error_strerror(e, error);
536 : 0 : return -error;
537 : : }
538 : :
539 : 8 : _public_ int sd_bus_error_set_errnof(sd_bus_error *e, int error, const char *format, ...) {
540 : : int r;
541 : :
542 [ - + ]: 8 : if (error < 0)
543 : 0 : error = -error;
544 : :
545 [ - + ]: 8 : if (!e)
546 : 0 : return -error;
547 [ + + ]: 8 : if (error == 0)
548 : 4 : return 0;
549 : :
550 [ - + - + ]: 4 : assert_return(!bus_error_is_dirty(e), -EINVAL);
551 : :
552 [ + - ]: 4 : if (format) {
553 : : va_list ap;
554 : :
555 : 4 : va_start(ap, format);
556 : 4 : r = sd_bus_error_set_errnofv(e, error, format, ap);
557 : 4 : va_end(ap);
558 : :
559 : 4 : return r;
560 : : }
561 : :
562 : 0 : return sd_bus_error_set_errno(e, error);
563 : : }
564 : :
565 : 304 : const char *bus_error_message(const sd_bus_error *e, int error) {
566 : :
567 [ + + ]: 304 : if (e) {
568 : : /* Sometimes, the D-Bus server is a little bit too verbose with
569 : : * its error messages, so let's override them here */
570 [ + + ]: 144 : if (sd_bus_error_has_name(e, SD_BUS_ERROR_ACCESS_DENIED))
571 : 4 : return "Access denied";
572 : :
573 [ + - ]: 140 : if (e->message)
574 : 140 : return e->message;
575 : : }
576 : :
577 [ + - ]: 160 : if (error < 0)
578 : 160 : error = -error;
579 : :
580 : 160 : return strerror_safe(error);
581 : : }
582 : :
583 : 24 : static bool map_ok(const sd_bus_error_map *map) {
584 [ + + ]: 56 : for (; map->code != BUS_ERROR_MAP_END_MARKER; map++)
585 [ + - + + ]: 40 : if (!map->name || map->code <=0)
586 : 8 : return false;
587 : 16 : return true;
588 : : }
589 : :
590 : 24 : _public_ int sd_bus_error_add_map(const sd_bus_error_map *map) {
591 : 24 : const sd_bus_error_map **maps = NULL;
592 : 24 : unsigned n = 0;
593 : :
594 [ - + - + ]: 24 : assert_return(map, -EINVAL);
595 [ + + + + ]: 24 : assert_return(map_ok(map), -EINVAL);
596 : :
597 [ + + ]: 16 : if (additional_error_maps)
598 [ + + ]: 20 : for (; additional_error_maps[n] != NULL; n++)
599 [ + + ]: 16 : if (additional_error_maps[n] == map)
600 : 8 : return 0;
601 : :
602 : 8 : maps = reallocarray(additional_error_maps, n + 2, sizeof(struct sd_bus_error_map*));
603 [ - + ]: 8 : if (!maps)
604 : 0 : return -ENOMEM;
605 : :
606 : 8 : maps[n] = map;
607 : 8 : maps[n+1] = NULL;
608 : :
609 : 8 : additional_error_maps = maps;
610 : 8 : return 1;
611 : : }
|