LCOV - code coverage report
Current view: top level - libsystemd/sd-bus - bus-error.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 203 300 67.7 %
Date: 2019-08-22 15:41:25 Functions: 20 21 95.2 %

          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         115 : 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         115 :         if (!name)
      71           0 :                 return EINVAL;
      72             : 
      73         115 :         p = startswith(name, "System.Error.");
      74         115 :         if (p) {
      75           7 :                 r = errno_from_name(p);
      76           7 :                 if (r < 0)
      77           1 :                         return EIO;
      78             : 
      79           6 :                 return r;
      80             :         }
      81             : 
      82         108 :         if (additional_error_maps)
      83          15 :                 for (map = additional_error_maps; *map; map++)
      84          12 :                         for (m = *map;; m++) {
      85             :                                 /* For additional error maps the end marker is actually the end marker */
      86          30 :                                 if (m->code == BUS_ERROR_MAP_END_MARKER)
      87           8 :                                         break;
      88             : 
      89          22 :                                 if (streq(m->name, name))
      90           4 :                                         return m->code;
      91             :                         }
      92             : 
      93         104 :         m = ALIGN_TO_PTR(__start_SYSTEMD_BUS_ERROR_MAP, sizeof(void*));
      94        2914 :         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        2909 :                 if (m->code == BUS_ERROR_MAP_END_MARKER) {
     102          65 :                         m = ALIGN_TO_PTR(m + 1, sizeof(void*));
     103          65 :                         continue;
     104             :                 }
     105             : 
     106        2844 :                 if (streq(m->name, name))
     107          99 :                         return m->code;
     108             : 
     109        2745 :                 m++;
     110             :         }
     111             : 
     112           5 :         return EIO;
     113             : }
     114             : 
     115           4 : static sd_bus_error errno_to_bus_error_const(int error) {
     116             : 
     117           4 :         if (error < 0)
     118           0 :                 error = -error;
     119             : 
     120           4 :         switch (error) {
     121             : 
     122           0 :         case ENOMEM:
     123           0 :                 return BUS_ERROR_OOM;
     124             : 
     125           1 :         case EPERM:
     126             :         case EACCES:
     127           1 :                 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           1 :         case ETIMEDOUT:
     142             :         case ETIME:
     143           1 :                 return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_TIMEOUT, "Timed out");
     144             : 
     145           1 :         case EIO:
     146           1 :                 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           1 :         return SD_BUS_ERROR_NULL;
     170             : }
     171             : 
     172           1 : static int errno_to_bus_error_name_new(int error, char **ret) {
     173             :         const char *name;
     174             :         char *n;
     175             : 
     176           1 :         if (error < 0)
     177           0 :                 error = -error;
     178             : 
     179           1 :         name = errno_to_name(error);
     180           1 :         if (!name)
     181           0 :                 return 0;
     182             : 
     183           1 :         n = strjoin("System.Error.", name);
     184           1 :         if (!n)
     185           0 :                 return -ENOMEM;
     186             : 
     187           1 :         *ret = n;
     188           1 :         return 1;
     189             : }
     190             : 
     191          96 : bool bus_error_is_dirty(sd_bus_error *e) {
     192          96 :         if (!e)
     193           6 :                 return false;
     194             : 
     195          90 :         return e->name || e->message || e->_need_free != 0;
     196             : }
     197             : 
     198        2330 : _public_ void sd_bus_error_free(sd_bus_error *e) {
     199        2330 :         if (!e)
     200          36 :                 return;
     201             : 
     202        2294 :         if (e->_need_free > 0) {
     203          48 :                 free((void*) e->name);
     204          48 :                 free((void*) e->message);
     205             :         }
     206             : 
     207        2294 :         *e = SD_BUS_ERROR_NULL;
     208             : }
     209             : 
     210          19 : _public_ int sd_bus_error_set(sd_bus_error *e, const char *name, const char *message) {
     211             : 
     212          19 :         if (!name)
     213           0 :                 return 0;
     214          19 :         if (!e)
     215          18 :                 goto finish;
     216             : 
     217           1 :         assert_return(!bus_error_is_dirty(e), -EINVAL);
     218             : 
     219           1 :         e->name = strdup(name);
     220           1 :         if (!e->name) {
     221           0 :                 *e = BUS_ERROR_OOM;
     222           0 :                 return -ENOMEM;
     223             :         }
     224             : 
     225           1 :         if (message)
     226           1 :                 e->message = strdup(message);
     227             : 
     228           1 :         e->_need_free = 1;
     229             : 
     230          19 : finish:
     231          19 :         return -bus_error_name_to_errno(name);
     232             : }
     233             : 
     234          80 : int bus_error_setfv(sd_bus_error *e, const char *name, const char *format, va_list ap) {
     235             : 
     236          80 :         if (!name)
     237           1 :                 return 0;
     238             : 
     239          79 :         if (e) {
     240          39 :                 assert_return(!bus_error_is_dirty(e), -EINVAL);
     241             : 
     242          39 :                 e->name = strdup(name);
     243          39 :                 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          39 :                 if (format)
     251          39 :                         (void) vasprintf((char**) &e->message, format, ap);
     252             : 
     253          39 :                 e->_need_free = 1;
     254             :         }
     255             : 
     256          79 :         return -bus_error_name_to_errno(name);
     257             : }
     258             : 
     259          76 : _public_ int sd_bus_error_setf(sd_bus_error *e, const char *name, const char *format, ...) {
     260             : 
     261          76 :         if (format) {
     262             :                 int r;
     263             :                 va_list ap;
     264             : 
     265          76 :                 va_start(ap, format);
     266          76 :                 r = bus_error_setfv(e, name, format, ap);
     267          76 :                 va_end(ap);
     268             : 
     269          76 :                 return r;
     270             :         }
     271             : 
     272           0 :         return sd_bus_error_set(e, name, NULL);
     273             : }
     274             : 
     275           7 : _public_ int sd_bus_error_copy(sd_bus_error *dest, const sd_bus_error *e) {
     276             : 
     277           7 :         if (!sd_bus_error_is_set(e))
     278           0 :                 return 0;
     279           7 :         if (!dest)
     280           0 :                 goto finish;
     281             : 
     282           7 :         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           7 :         if (e->_need_free == 0)
     291           1 :                 *dest = *e;
     292             :         else {
     293           6 :                 dest->name = strdup(e->name);
     294           6 :                 if (!dest->name) {
     295           0 :                         *dest = BUS_ERROR_OOM;
     296           0 :                         return -ENOMEM;
     297             :                 }
     298             : 
     299           6 :                 if (e->message)
     300           6 :                         dest->message = strdup(e->message);
     301             : 
     302           6 :                 dest->_need_free = 1;
     303             :         }
     304             : 
     305           7 : finish:
     306           7 :         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           1 : _public_ int sd_bus_error_set_const(sd_bus_error *e, const char *name, const char *message) {
     332           1 :         if (!name)
     333           0 :                 return 0;
     334           1 :         if (!e)
     335           0 :                 goto finish;
     336             : 
     337           1 :         assert_return(!bus_error_is_dirty(e), -EINVAL);
     338             : 
     339           1 :         *e = SD_BUS_ERROR_MAKE_CONST(name, message);
     340             : 
     341           1 : finish:
     342           1 :         return -bus_error_name_to_errno(name);
     343             : }
     344             : 
     345         140 : _public_ int sd_bus_error_is_set(const sd_bus_error *e) {
     346         140 :         if (!e)
     347           0 :                 return 0;
     348             : 
     349         140 :         return !!e->name;
     350             : }
     351             : 
     352          50 : _public_ int sd_bus_error_has_name(const sd_bus_error *e, const char *name) {
     353          50 :         if (!e)
     354           0 :                 return 0;
     355             : 
     356          50 :         return streq_ptr(e->name, name);
     357             : }
     358             : 
     359          11 : _public_ int sd_bus_error_get_errno(const sd_bus_error* e) {
     360          11 :         if (!e)
     361           0 :                 return 0;
     362             : 
     363          11 :         if (!e->name)
     364           2 :                 return 0;
     365             : 
     366           9 :         return bus_error_name_to_errno(e->name);
     367             : }
     368             : 
     369           3 : static void bus_error_strerror(sd_bus_error *e, int error) {
     370           3 :         size_t k = 64;
     371             :         char *m;
     372             : 
     373           3 :         assert(e);
     374             : 
     375           0 :         for (;;) {
     376             :                 char *x;
     377             : 
     378           3 :                 m = new(char, k);
     379           3 :                 if (!m)
     380           0 :                         return;
     381             : 
     382           3 :                 errno = 0;
     383           3 :                 x = strerror_r(error, m, k);
     384           3 :                 if (errno == ERANGE || strlen(x) >= k - 1) {
     385           0 :                         free(m);
     386           0 :                         k *= 2;
     387           0 :                         continue;
     388             :                 }
     389             : 
     390           3 :                 if (errno) {
     391           0 :                         free(m);
     392           0 :                         return;
     393             :                 }
     394             : 
     395           3 :                 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           3 :                         free(m);
     417             : 
     418           3 :                         if (e->_need_free > 0) {
     419             :                                 char *t;
     420             : 
     421             :                                 /* Error is dynamic, let's hence make the message also dynamic */
     422           1 :                                 t = strdup(x);
     423           1 :                                 if (!t)
     424           0 :                                         return;
     425             : 
     426           1 :                                 free((char*) e->message);
     427           1 :                                 e->message = t;
     428             :                         } else {
     429             :                                 /* Error is const, hence we can just override */
     430           2 :                                 e->message = x;
     431             :                         }
     432             :                 }
     433             : 
     434           3 :                 return;
     435             :         }
     436             : }
     437             : 
     438           3 : _public_ int sd_bus_error_set_errno(sd_bus_error *e, int error) {
     439             : 
     440           3 :         if (error < 0)
     441           2 :                 error = -error;
     442             : 
     443           3 :         if (!e)
     444           0 :                 return -error;
     445           3 :         if (error == 0)
     446           0 :                 return -error;
     447             : 
     448           3 :         assert_return(!bus_error_is_dirty(e), -EINVAL);
     449             : 
     450             :         /* First, try a const translation */
     451           3 :         *e = errno_to_bus_error_const(error);
     452             : 
     453           3 :         if (!sd_bus_error_is_set(e)) {
     454             :                 int k;
     455             : 
     456             :                 /* If that didn't work, try a dynamic one. */
     457             : 
     458           1 :                 k = errno_to_bus_error_name_new(error, (char**) &e->name);
     459           1 :                 if (k > 0)
     460           1 :                         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           3 :         bus_error_strerror(e, error);
     470           3 :         return -error;
     471             : }
     472             : 
     473           1 : _public_ int sd_bus_error_set_errnofv(sd_bus_error *e, int error, const char *format, va_list ap) {
     474           1 :         PROTECT_ERRNO;
     475             :         int r;
     476             : 
     477           1 :         if (error < 0)
     478           0 :                 error = -error;
     479             : 
     480           1 :         if (!e)
     481           0 :                 return -error;
     482           1 :         if (error == 0)
     483           0 :                 return 0;
     484             : 
     485           1 :         assert_return(!bus_error_is_dirty(e), -EINVAL);
     486             : 
     487             :         /* First, try a const translation */
     488           1 :         *e = errno_to_bus_error_const(error);
     489             : 
     490           1 :         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           1 :         if (format) {
     506             :                 char *m;
     507             : 
     508             :                 /* Then, let's try to fill in the supplied message */
     509             : 
     510           1 :                 errno = error; /* Make sure that %m resolves to the specified error */
     511           1 :                 r = vasprintf(&m, format, ap);
     512           1 :                 if (r >= 0) {
     513             : 
     514           1 :                         if (e->_need_free <= 0) {
     515             :                                 char *t;
     516             : 
     517           1 :                                 t = strdup(e->name);
     518           1 :                                 if (t) {
     519           1 :                                         e->_need_free = 1;
     520           1 :                                         e->name = t;
     521           1 :                                         e->message = m;
     522           1 :                                         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           2 : _public_ int sd_bus_error_set_errnof(sd_bus_error *e, int error, const char *format, ...) {
     540             :         int r;
     541             : 
     542           2 :         if (error < 0)
     543           0 :                 error = -error;
     544             : 
     545           2 :         if (!e)
     546           0 :                 return -error;
     547           2 :         if (error == 0)
     548           1 :                 return 0;
     549             : 
     550           1 :         assert_return(!bus_error_is_dirty(e), -EINVAL);
     551             : 
     552           1 :         if (format) {
     553             :                 va_list ap;
     554             : 
     555           1 :                 va_start(ap, format);
     556           1 :                 r = sd_bus_error_set_errnofv(e, error, format, ap);
     557           1 :                 va_end(ap);
     558             : 
     559           1 :                 return r;
     560             :         }
     561             : 
     562           0 :         return sd_bus_error_set_errno(e, error);
     563             : }
     564             : 
     565          76 : const char *bus_error_message(const sd_bus_error *e, int error) {
     566             : 
     567          76 :         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          36 :                 if (sd_bus_error_has_name(e, SD_BUS_ERROR_ACCESS_DENIED))
     571           1 :                         return "Access denied";
     572             : 
     573          35 :                 if (e->message)
     574          35 :                         return e->message;
     575             :         }
     576             : 
     577          40 :         if (error < 0)
     578          40 :                 error = -error;
     579             : 
     580          40 :         return strerror_safe(error);
     581             : }
     582             : 
     583           6 : static bool map_ok(const sd_bus_error_map *map) {
     584          14 :         for (; map->code != BUS_ERROR_MAP_END_MARKER; map++)
     585          10 :                 if (!map->name || map->code <=0)
     586           2 :                         return false;
     587           4 :         return true;
     588             : }
     589             : 
     590           6 : _public_ int sd_bus_error_add_map(const sd_bus_error_map *map) {
     591           6 :         const sd_bus_error_map **maps = NULL;
     592           6 :         unsigned n = 0;
     593             : 
     594           6 :         assert_return(map, -EINVAL);
     595           6 :         assert_return(map_ok(map), -EINVAL);
     596             : 
     597           4 :         if (additional_error_maps)
     598           5 :                 for (; additional_error_maps[n] != NULL; n++)
     599           4 :                         if (additional_error_maps[n] == map)
     600           2 :                                 return 0;
     601             : 
     602           2 :         maps = reallocarray(additional_error_maps, n + 2, sizeof(struct sd_bus_error_map*));
     603           2 :         if (!maps)
     604           0 :                 return -ENOMEM;
     605             : 
     606           2 :         maps[n] = map;
     607           2 :         maps[n+1] = NULL;
     608             : 
     609           2 :         additional_error_maps = maps;
     610           2 :         return 1;
     611             : }

Generated by: LCOV version 1.14