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