chiark / gitweb /
bus: add sd_bus_message_read_strv()
[elogind.git] / src / libsystemd-bus / bus-message.c
index 0d565ddf9c0a476d068b872f6f6fc760bec30fc8..96d177823584f1fb32fecd9842c913b26d700ec5 100644 (file)
@@ -2642,8 +2642,8 @@ static bool validate_object_path(const char *s, size_t l) {
 
 int sd_bus_message_read_basic(sd_bus_message *m, char type, void *p) {
         struct bus_container *c;
-        int r;
         void *q;
+        int r;
 
         if (!m)
                 return -EINVAL;
@@ -2651,8 +2651,6 @@ int sd_bus_message_read_basic(sd_bus_message *m, char type, void *p) {
                 return -EPERM;
         if (!bus_type_is_basic(type))
                 return -EINVAL;
-        if (!p)
-                return -EINVAL;
 
         c = message_get_container(m);
 
@@ -2693,7 +2691,9 @@ int sd_bus_message_read_basic(sd_bus_message *m, char type, void *p) {
                 }
 
                 m->rindex = rindex;
-                *(const char**) p = q;
+                if (p)
+                        *(const char**) p = q;
+
                 break;
         }
 
@@ -2717,7 +2717,9 @@ int sd_bus_message_read_basic(sd_bus_message *m, char type, void *p) {
                         return -EBADMSG;
 
                 m->rindex = rindex;
-                *(const char**) p = q;
+
+                if (p)
+                        *(const char**) p = q;
                 break;
         }
 
@@ -2737,27 +2739,32 @@ int sd_bus_message_read_basic(sd_bus_message *m, char type, void *p) {
                 switch (type) {
 
                 case SD_BUS_TYPE_BYTE:
-                        *(uint8_t*) p = *(uint8_t*) q;
+                        if (p)
+                                *(uint8_t*) p = *(uint8_t*) q;
                         break;
 
                 case SD_BUS_TYPE_BOOLEAN:
-                        *(unsigned*) p = !!*(uint32_t*) q;
+                        if (p)
+                                *(unsigned*) p = !!*(uint32_t*) q;
                         break;
 
                 case SD_BUS_TYPE_INT16:
                 case SD_BUS_TYPE_UINT16:
-                        *(uint16_t*) p = BUS_MESSAGE_BSWAP16(m, *(uint16_t*) q);
+                        if (p)
+                                *(uint16_t*) p = BUS_MESSAGE_BSWAP16(m, *(uint16_t*) q);
                         break;
 
                 case SD_BUS_TYPE_INT32:
                 case SD_BUS_TYPE_UINT32:
-                        *(uint32_t*) p = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
+                        if (p)
+                                *(uint32_t*) p = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
                         break;
 
                 case SD_BUS_TYPE_INT64:
                 case SD_BUS_TYPE_UINT64:
                 case SD_BUS_TYPE_DOUBLE:
-                        *(uint64_t*) p = BUS_MESSAGE_BSWAP64(m, *(uint64_t*) q);
+                        if (p)
+                                *(uint64_t*) p = BUS_MESSAGE_BSWAP64(m, *(uint64_t*) q);
                         break;
 
                 case SD_BUS_TYPE_UNIX_FD: {
@@ -2767,7 +2774,8 @@ int sd_bus_message_read_basic(sd_bus_message *m, char type, void *p) {
                         if (j >= m->n_fds)
                                 return -EBADMSG;
 
-                        *(int*) p = m->fds[j];
+                        if (p)
+                                *(int*) p = m->fds[j];
                         break;
                 }
 
@@ -2974,12 +2982,28 @@ int sd_bus_message_enter_container(sd_bus_message *m, char type, const char *con
         size_t before;
         int r;
 
-        if (!m)
-                return -EINVAL;
-        if (!m->sealed)
-                return -EPERM;
-        if (!contents)
-                return -EINVAL;
+        assert_return(m, -EINVAL);
+        assert_return(m->sealed, -EPERM);
+        assert_return(type != 0 || !contents, -EINVAL);
+
+        if (type == 0 || !contents) {
+                const char *cc;
+                char tt;
+
+                /* Allow entering into anonymous containers */
+                r = sd_bus_message_peek_type(m, &tt, &cc);
+                if (r <= 0)
+                        return r;
+
+                if (type != 0 && type != tt)
+                        return -ENXIO;
+
+                if (contents && !streq(contents, cc))
+                        return -ENXIO;
+
+                type = tt;
+                contents = cc;
+        }
 
         /*
          * We enforce a global limit on container depth, that is much
@@ -3316,7 +3340,6 @@ static int message_read_ap(
                         r = sd_bus_message_read_basic(m, *t, p);
                         if (r < 0)
                                 return r;
-
                         if (r == 0) {
                                 if (n_loop <= 1)
                                         return 0;
@@ -3445,12 +3468,9 @@ int sd_bus_message_read(sd_bus_message *m, const char *types, ...) {
         va_list ap;
         int r;
 
-        if (!m)
-                return -EINVAL;
-        if (!m->sealed)
-                return -EPERM;
-        if (!types)
-                return -EINVAL;
+        assert_return(m, -EINVAL);
+        assert_return(m->sealed, -EPERM);
+        assert_return(types, -EINVAL);
 
         va_start(ap, types);
         r = message_read_ap(m, types, ap);
@@ -3459,6 +3479,148 @@ int sd_bus_message_read(sd_bus_message *m, const char *types, ...) {
         return r;
 }
 
+int sd_bus_message_skip(sd_bus_message *m, const char *types) {
+        int r;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->sealed, -EPERM);
+        assert_return(types, -EINVAL);
+
+        if (isempty(types))
+                return 0;
+
+        switch (*types) {
+
+        case SD_BUS_TYPE_BYTE:
+        case SD_BUS_TYPE_BOOLEAN:
+        case SD_BUS_TYPE_INT16:
+        case SD_BUS_TYPE_UINT16:
+        case SD_BUS_TYPE_INT32:
+        case SD_BUS_TYPE_UINT32:
+        case SD_BUS_TYPE_INT64:
+        case SD_BUS_TYPE_UINT64:
+        case SD_BUS_TYPE_DOUBLE:
+        case SD_BUS_TYPE_STRING:
+        case SD_BUS_TYPE_OBJECT_PATH:
+        case SD_BUS_TYPE_SIGNATURE:
+        case SD_BUS_TYPE_UNIX_FD:
+
+                r = sd_bus_message_read_basic(m, *types, NULL);
+                if (r <= 0)
+                        return r;
+
+                r = sd_bus_message_skip(m, types + 1);
+                if (r < 0)
+                        return r;
+
+                return 1;
+
+        case SD_BUS_TYPE_ARRAY: {
+                size_t k;
+
+                r = signature_element_length(types + 1, &k);
+                if (r < 0)
+                        return r;
+
+                {
+                        char s[k+1];
+                        memcpy(s, types+1, k);
+                        s[k] = 0;
+
+                        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, s);
+                        if (r <= 0)
+                                return r;
+
+                        for (;;) {
+                                r = sd_bus_message_skip(m, s);
+                                if (r < 0)
+                                        return r;
+                                if (r == 0)
+                                        break;
+                        }
+
+                        r = sd_bus_message_exit_container(m);
+                        if (r < 0)
+                                return r;
+                }
+
+                r = sd_bus_message_skip(m, types + 1 + k);
+                if (r < 0)
+                        return r;
+
+                return 1;
+        }
+
+        case SD_BUS_TYPE_VARIANT: {
+                const char *contents;
+                char x;
+
+                r = sd_bus_message_peek_type(m, &x, &contents);
+                if (r <= 0)
+                        return r;
+
+                if (x != SD_BUS_TYPE_VARIANT)
+                        return -ENXIO;
+
+                r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
+                if (r <= 0)
+                        return r;
+
+                r = sd_bus_message_skip(m, contents);
+                if (r < 0)
+                        return r;
+                assert(r != 0);
+
+                r = sd_bus_message_exit_container(m);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_skip(m, types + 1);
+                if (r < 0)
+                        return r;
+
+                return 1;
+        }
+
+        case SD_BUS_TYPE_STRUCT_BEGIN:
+        case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
+                size_t k;
+
+                r = signature_element_length(types, &k);
+                if (r < 0)
+                        return r;
+
+                {
+                        char s[k-1];
+                        memcpy(s, types+1, k-2);
+                        s[k-2] = 0;
+
+                        r = sd_bus_message_enter_container(m, *types == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
+                        if (r <= 0)
+                                return r;
+
+                        r = sd_bus_message_skip(m, s);
+                        if (r < 0)
+                                return r;
+                        assert(r != 0);
+
+                        r = sd_bus_message_exit_container(m);
+                        if (r < 0)
+                                return r;
+                }
+
+                r = sd_bus_message_skip(m, types + k);
+                if (r < 0)
+                        return r;
+
+                return 1;
+        }
+
+        default:
+                return -EINVAL;
+        }
+}
+
 int sd_bus_message_read_array(sd_bus_message *m, char type, const void **ptr, size_t *size) {
         struct bus_container *c;
         void *p;
@@ -4047,8 +4209,6 @@ int bus_message_dump(sd_bus_message *m, FILE *f, bool with_header) {
                         "\tsender=%s\n"
                         "\tsignature=%s\n"
                         "\treply_serial=%u\n"
-                        "\terror.name=%s\n"
-                        "\terror.message=%s\n"
                         "\tsealed=%s\n"
                         "\tn_body_parts=%u\n",
                         m,
@@ -4067,11 +4227,16 @@ int bus_message_dump(sd_bus_message *m, FILE *f, bool with_header) {
                         strna(m->sender),
                         strna(m->root_container.signature),
                         m->reply_serial,
-                        strna(m->error.name),
-                        strna(m->error.message),
                         yes_no(m->sealed),
                         m->n_body_parts);
 
+                if (sd_bus_error_is_set(&m->error))
+                        fprintf(f,
+                                "\terror.name=%s\n"
+                                "\terror.message=%s\n",
+                                strna(m->error.name),
+                                strna(m->error.message));
+
                 if (m->pid != 0)
                         fprintf(f, "\tpid=%lu\n", (unsigned long) m->pid);
                 if (m->tid != 0)
@@ -4113,7 +4278,9 @@ int bus_message_dump(sd_bus_message *m, FILE *f, bool with_header) {
                 if (sd_bus_message_get_audit_sessionid(m, &audit_sessionid) >= 0)
                         fprintf(f, "\taudit_sessionid=%lu\n", (unsigned long) audit_sessionid);
 
-                fprintf(f, "\tCAP_KILL=%i\n", sd_bus_message_has_effective_cap(m, 5));
+                r = sd_bus_message_has_effective_cap(m, 5);
+                if (r >= 0)
+                        fprintf(f, "\tCAP_KILL=%s\n", yes_no(r));
 
                 if (sd_bus_message_get_cmdline(m, &cmdline) >= 0) {
                         char **c;
@@ -4319,7 +4486,7 @@ int bus_message_read_strv_extend(sd_bus_message *m, char ***l) {
         assert(l);
 
         r = sd_bus_message_enter_container(m, 'a', "s");
-        if (r < 0)
+        if (r <= 0)
                 return r;
 
         for (;;) {
@@ -4343,6 +4510,24 @@ int bus_message_read_strv_extend(sd_bus_message *m, char ***l) {
         return 0;
 }
 
+int sd_bus_message_read_strv(sd_bus_message *m, char ***l) {
+        char **strv = NULL;
+        int r;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->sealed, -EPERM);
+        assert_return(l, -EINVAL);
+
+        r = bus_message_read_strv_extend(m, &strv);
+        if (r <= 0) {
+                strv_free(strv);
+                return r;
+        }
+
+        *l = strv;
+        return 1;
+}
+
 const char* bus_message_get_arg(sd_bus_message *m, unsigned i) {
         int r;
         const char *t = NULL;
@@ -4431,6 +4616,11 @@ int sd_bus_message_copy(sd_bus_message *m, sd_bus_message *source, int all) {
         bool done_something = false;
         int r;
 
+        assert_return(m, -EINVAL);
+        assert_return(source, -EINVAL);
+        assert_return(!m->sealed, -EPERM);
+        assert_return(source->sealed, -EPERM);
+
         do {
                 const char *contents;
                 char type;