mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-02-02 09:47:03 +03:00
libsystemd-bus: add lightweight object vtable implementation for exposing objects on the bus
This adds a lightweight scheme how to define interfaces in static fixed arrays which then can be easily registered on a bus connection. This makes it much easier to write bus services. This automatically handles implementation of the Properties, ObjectManager, and Introspection bus interfaces.
This commit is contained in:
parent
8d1a280204
commit
29ddb38fea
2
.gitignore
vendored
2
.gitignore
vendored
@ -87,12 +87,14 @@
|
||||
/tags
|
||||
/test-boot-timestamp
|
||||
/test-bus-chat
|
||||
/test-bus-introspect
|
||||
/test-bus-kernel
|
||||
/test-bus-kernel-bloom
|
||||
/test-bus-kernel-benchmark
|
||||
/test-bus-marshal
|
||||
/test-bus-match
|
||||
/test-bus-memfd
|
||||
/test-bus-objects
|
||||
/test-bus-signature
|
||||
/test-bus-server
|
||||
/test-bus-zero-copy
|
||||
|
28
Makefile.am
28
Makefile.am
@ -1956,6 +1956,8 @@ libsystemd_bus_la_SOURCES = \
|
||||
src/libsystemd-bus/bus-match.h \
|
||||
src/libsystemd-bus/bus-bloom.c \
|
||||
src/libsystemd-bus/bus-bloom.h \
|
||||
src/libsystemd-bus/bus-introspect.c \
|
||||
src/libsystemd-bus/bus-introspect.h \
|
||||
src/libsystemd-bus/kdbus.h \
|
||||
src/libsystemd-bus/sd-memfd.c
|
||||
|
||||
@ -1981,7 +1983,9 @@ tests += \
|
||||
test-bus-kernel-bloom \
|
||||
test-bus-kernel-benchmark \
|
||||
test-bus-memfd \
|
||||
test-bus-zero-copy
|
||||
test-bus-zero-copy \
|
||||
test-bus-introspect \
|
||||
test-bus-objects
|
||||
|
||||
noinst_PROGRAMS += \
|
||||
busctl
|
||||
@ -2031,6 +2035,18 @@ test_bus_server_LDADD = \
|
||||
libsystemd-bus.la \
|
||||
libsystemd-id128-internal.la
|
||||
|
||||
test_bus_objects_SOURCES = \
|
||||
src/libsystemd-bus/test-bus-objects.c
|
||||
|
||||
test_bus_objects_CFLAGS = \
|
||||
$(AM_CFLAGS) \
|
||||
-pthread
|
||||
|
||||
test_bus_objects_LDADD = \
|
||||
libsystemd-shared.la \
|
||||
libsystemd-bus.la \
|
||||
libsystemd-id128-internal.la
|
||||
|
||||
test_bus_match_SOURCES = \
|
||||
src/libsystemd-bus/test-bus-match.c
|
||||
|
||||
@ -2095,6 +2111,16 @@ test_bus_zero_copy_LDADD = \
|
||||
libsystemd-shared.la \
|
||||
libsystemd-bus.la
|
||||
|
||||
test_bus_introspect_SOURCES = \
|
||||
src/libsystemd-bus/test-bus-introspect.c
|
||||
|
||||
test_bus_introspect_CFLAGS = \
|
||||
$(AM_CFLAGS)
|
||||
|
||||
test_bus_introspect_LDADD = \
|
||||
libsystemd-shared.la \
|
||||
libsystemd-bus.la
|
||||
|
||||
busctl_SOURCES = \
|
||||
src/libsystemd-bus/busctl.c
|
||||
|
||||
|
2
TODO
2
TODO
@ -54,6 +54,8 @@ Features:
|
||||
|
||||
* tmpfiles: when applying ownership to /run/log/journal also do this for the journal fails contained in it
|
||||
|
||||
* rework list.h to use typeof() and thus simplify most linked list macros by not requring the type to be specified
|
||||
|
||||
* we probably should replace the left-over uses of strv_append() and replace them by strv_push() or strv_extend()
|
||||
|
||||
* move config_parse_path_strv() out of conf-parser.c
|
||||
|
@ -51,7 +51,34 @@ void sd_bus_error_free(sd_bus_error *e) {
|
||||
e->need_free = false;
|
||||
}
|
||||
|
||||
int sd_bus_error_set(sd_bus_error *e, const char *name, const char *format, ...) {
|
||||
int sd_bus_error_set(sd_bus_error *e, const char *name, const char *message) {
|
||||
char *n, *m = NULL;
|
||||
|
||||
if (!e)
|
||||
return 0;
|
||||
if (bus_error_is_dirty(e))
|
||||
return -EINVAL;
|
||||
if (!name)
|
||||
return -EINVAL;
|
||||
|
||||
n = strdup(name);
|
||||
if (!n)
|
||||
return -ENOMEM;
|
||||
|
||||
if (message) {
|
||||
m = strdup(message);
|
||||
if (!m)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
e->name = n;
|
||||
e->message = m;
|
||||
e->need_free = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_bus_error_setf(sd_bus_error *e, const char *name, const char *format, ...) {
|
||||
char *n, *m = NULL;
|
||||
va_list ap;
|
||||
int r;
|
||||
@ -119,9 +146,7 @@ void sd_bus_error_set_const(sd_bus_error *e, const char *name, const char *messa
|
||||
if (bus_error_is_dirty(e))
|
||||
return;
|
||||
|
||||
e->name = name;
|
||||
e->message = message;
|
||||
e->need_free = false;
|
||||
*e = SD_BUS_ERROR_MAKE(name, message);
|
||||
}
|
||||
|
||||
int sd_bus_error_is_set(const sd_bus_error *e) {
|
||||
|
@ -61,6 +61,29 @@ bool object_path_is_valid(const char *p) {
|
||||
return true;
|
||||
}
|
||||
|
||||
char* object_path_startswith(const char *a, const char *b) {
|
||||
const char *p;
|
||||
|
||||
if (!object_path_is_valid(a) ||
|
||||
!object_path_is_valid(b))
|
||||
return NULL;
|
||||
|
||||
if (streq(b, "/"))
|
||||
return (char*) a + 1;
|
||||
|
||||
p = startswith(a, b);
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
if (*p == 0)
|
||||
return (char*) p;
|
||||
|
||||
if (*p == '/')
|
||||
return (char*) p + 1;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool interface_name_is_valid(const char *p) {
|
||||
const char *q;
|
||||
bool dot, found_dot = false;
|
||||
|
@ -54,14 +54,63 @@ struct filter_callback {
|
||||
LIST_FIELDS(struct filter_callback, callbacks);
|
||||
};
|
||||
|
||||
struct object_callback {
|
||||
struct node {
|
||||
char *path;
|
||||
struct node *parent;
|
||||
LIST_HEAD(struct node, child);
|
||||
LIST_FIELDS(struct node, siblings);
|
||||
|
||||
LIST_HEAD(struct node_callback, callbacks);
|
||||
LIST_HEAD(struct node_vtable, vtables);
|
||||
LIST_HEAD(struct node_enumerator, enumerators);
|
||||
|
||||
bool object_manager;
|
||||
};
|
||||
|
||||
struct node_callback {
|
||||
struct node *node;
|
||||
|
||||
bool is_fallback;
|
||||
sd_bus_message_handler_t callback;
|
||||
void *userdata;
|
||||
|
||||
char *path;
|
||||
bool is_fallback;
|
||||
unsigned last_iteration;
|
||||
|
||||
LIST_FIELDS(struct node_callback, callbacks);
|
||||
};
|
||||
|
||||
struct node_enumerator {
|
||||
struct node *node;
|
||||
|
||||
sd_bus_node_enumerator_t callback;
|
||||
void *userdata;
|
||||
|
||||
unsigned last_iteration;
|
||||
|
||||
LIST_FIELDS(struct node_enumerator, enumerators);
|
||||
};
|
||||
|
||||
struct node_vtable {
|
||||
struct node *node;
|
||||
|
||||
char *interface;
|
||||
bool is_fallback;
|
||||
const sd_bus_vtable *vtable;
|
||||
void *userdata;
|
||||
sd_bus_object_find_t find;
|
||||
|
||||
unsigned last_iteration;
|
||||
|
||||
LIST_FIELDS(struct node_vtable, vtables);
|
||||
};
|
||||
|
||||
struct vtable_member {
|
||||
const char *path;
|
||||
const char *interface;
|
||||
const char *member;
|
||||
struct node_vtable *parent;
|
||||
unsigned last_iteration;
|
||||
const sd_bus_vtable *vtable;
|
||||
};
|
||||
|
||||
enum bus_state {
|
||||
@ -109,7 +158,7 @@ struct sd_bus {
|
||||
bool processing:1;
|
||||
bool match_callbacks_modified:1;
|
||||
bool filter_callbacks_modified:1;
|
||||
bool object_callbacks_modified:1;
|
||||
bool nodes_modified:1;
|
||||
|
||||
int use_memfd;
|
||||
|
||||
@ -131,7 +180,12 @@ struct sd_bus {
|
||||
Prioq *reply_callbacks_prioq;
|
||||
Hashmap *reply_callbacks;
|
||||
LIST_HEAD(struct filter_callback, filter_callbacks);
|
||||
Hashmap *object_callbacks;
|
||||
|
||||
Hashmap *nodes;
|
||||
|
||||
|
||||
Hashmap *vtable_methods;
|
||||
Hashmap *vtable_properties;
|
||||
|
||||
union {
|
||||
struct sockaddr sa;
|
||||
@ -213,10 +267,11 @@ static inline void bus_unrefp(sd_bus **b) {
|
||||
|
||||
#define BUS_EXEC_ARGV_MAX 256
|
||||
|
||||
bool object_path_is_valid(const char *p);
|
||||
bool interface_name_is_valid(const char *p);
|
||||
bool service_name_is_valid(const char *p);
|
||||
bool member_name_is_valid(const char *p);
|
||||
bool object_path_is_valid(const char *p);
|
||||
char *object_path_startswith(const char *a, const char *b);
|
||||
|
||||
bool namespace_complex_pattern(const char *pattern, const char *value);
|
||||
bool path_complex_pattern(const char *pattern, const char *value);
|
||||
|
200
src/libsystemd-bus/bus-introspect.c
Normal file
200
src/libsystemd-bus/bus-introspect.c
Normal file
@ -0,0 +1,200 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2013 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include "util.h"
|
||||
#include "sd-bus-protocol.h"
|
||||
#include "bus-introspect.h"
|
||||
#include "bus-signature.h"
|
||||
#include "bus-internal.h"
|
||||
|
||||
int introspect_begin(struct introspect *i) {
|
||||
assert(i);
|
||||
|
||||
zero(*i);
|
||||
|
||||
i->f = open_memstream(&i->introspection, &i->size);
|
||||
if (!i->f)
|
||||
return -ENOMEM;
|
||||
|
||||
fputs(SD_BUS_INTROSPECT_DOCTYPE
|
||||
"<node>\n", i->f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int introspect_write_default_interfaces(struct introspect *i, bool object_manager) {
|
||||
assert(i);
|
||||
|
||||
fputs(SD_BUS_INTROSPECT_INTERFACE_PEER
|
||||
SD_BUS_INTROSPECT_INTERFACE_INTROSPECTABLE
|
||||
SD_BUS_INTROSPECT_INTERFACE_PROPERTIES, i->f);
|
||||
|
||||
if (object_manager)
|
||||
fputs(SD_BUS_INTROSPECT_INTERFACE_OBJECT_MANAGER, i->f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int introspect_write_child_nodes(struct introspect *i, Set *s, const char *prefix) {
|
||||
char *node;
|
||||
|
||||
assert(i);
|
||||
assert(prefix);
|
||||
|
||||
while ((node = set_steal_first(s))) {
|
||||
const char *e;
|
||||
|
||||
e = object_path_startswith(node, prefix);
|
||||
if (e)
|
||||
fprintf(i->f, " <node name=\"%s\"/>\n", e);
|
||||
|
||||
free(node);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void introspect_write_flags(struct introspect *i, int type, int flags) {
|
||||
if (flags & SD_BUS_VTABLE_DEPRECATED)
|
||||
fputs(" <annotation name=\"org.freedesktop.DBus.Deprecated\" value=\"true\"/>\n", i->f);
|
||||
|
||||
if (type == _SD_BUS_VTABLE_METHOD && flags & SD_BUS_VTABLE_METHOD_NO_REPLY)
|
||||
fputs(" <annotation name=\"org.freedesktop.DBus.Method.NoReply\" value=\"true\"/>\n", i->f);
|
||||
|
||||
if (type == _SD_BUS_VTABLE_PROPERTY || type == _SD_BUS_VTABLE_WRITABLE_PROPERTY) {
|
||||
if (!(flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE))
|
||||
fputs(" <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"false\"/>\n", i->f);
|
||||
else if (flags & SD_BUS_VTABLE_PROPERTY_INVALIDATE_ONLY)
|
||||
fputs(" <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"invalidates\"/>\n", i->f);
|
||||
}
|
||||
}
|
||||
|
||||
static int introspect_write_arguments(struct introspect *i, const char *signature, const char *direction) {
|
||||
int r;
|
||||
|
||||
for (;;) {
|
||||
size_t l;
|
||||
|
||||
if (!*signature)
|
||||
return 0;
|
||||
|
||||
r = signature_element_length(signature, &l);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
fprintf(i->f, " <arg type=\"%.*s\"", (int) l, signature);
|
||||
|
||||
if (direction)
|
||||
fprintf(i->f, " direction=\"%s\">\n", direction);
|
||||
else
|
||||
fputs(">\n", i->f);
|
||||
|
||||
signature += l;
|
||||
}
|
||||
}
|
||||
|
||||
int introspect_write_interface(struct introspect *i, const char *interface, const sd_bus_vtable *v) {
|
||||
assert(i);
|
||||
assert(interface);
|
||||
assert(v);
|
||||
|
||||
fprintf(i->f, " <interface name=\"%s\">\n", interface);
|
||||
|
||||
for (; v->type != _SD_BUS_VTABLE_END; v++) {
|
||||
|
||||
switch (v->type) {
|
||||
|
||||
case _SD_BUS_VTABLE_START:
|
||||
if (v->flags & SD_BUS_VTABLE_DEPRECATED)
|
||||
fputs(" <annotation name=\"org.freedesktop.DBus.Deprecated\" value=\"true\"/>\n", i->f);
|
||||
break;
|
||||
|
||||
case _SD_BUS_VTABLE_METHOD:
|
||||
fprintf(i->f, " <method name=\"%s\">\n", v->method.member);
|
||||
introspect_write_arguments(i, v->method.signature, "in");
|
||||
introspect_write_arguments(i, v->method.result, "out");
|
||||
introspect_write_flags(i, v->type, v->flags);
|
||||
fputs(" </method>\n", i->f);
|
||||
break;
|
||||
|
||||
case _SD_BUS_VTABLE_PROPERTY:
|
||||
case _SD_BUS_VTABLE_WRITABLE_PROPERTY:
|
||||
fprintf(i->f, " <property name=\"%s\" type=\"%s\" access=\"%s\">\n",
|
||||
v->property.member,
|
||||
v->property.signature,
|
||||
v->type == _SD_BUS_VTABLE_WRITABLE_PROPERTY ? "readwrite" : "read");
|
||||
introspect_write_flags(i, v->type, v->flags);
|
||||
fputs(" </property>\n", i->f);
|
||||
break;
|
||||
|
||||
case _SD_BUS_VTABLE_SIGNAL:
|
||||
fprintf(i->f, " <signal name=\"%s\">\n", v->signal.member);
|
||||
introspect_write_arguments(i, v->signal.signature, NULL);
|
||||
introspect_write_flags(i, v->type, v->flags);
|
||||
fputs(" </signal>\n", i->f);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fputs(" </interface>\n", i->f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int introspect_finish(struct introspect *i, sd_bus *bus, sd_bus_message *m, sd_bus_message **reply) {
|
||||
sd_bus_message *q;
|
||||
int r;
|
||||
|
||||
assert(i);
|
||||
assert(m);
|
||||
assert(reply);
|
||||
|
||||
fputs("</node>\n", i->f);
|
||||
fflush(i->f);
|
||||
|
||||
if (ferror(i->f))
|
||||
return -ENOMEM;
|
||||
|
||||
r = sd_bus_message_new_method_return(bus, m, &q);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_append(q, "s", i->introspection);
|
||||
if (r < 0) {
|
||||
sd_bus_message_unref(q);
|
||||
return r;
|
||||
}
|
||||
|
||||
*reply = q;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void introspect_free(struct introspect *i) {
|
||||
assert(i);
|
||||
|
||||
if (i->f)
|
||||
fclose(i->f);
|
||||
|
||||
if (i->introspection)
|
||||
free(i->introspection);
|
||||
|
||||
zero(*i);
|
||||
}
|
41
src/libsystemd-bus/bus-introspect.h
Normal file
41
src/libsystemd-bus/bus-introspect.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2013 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "sd-bus.h"
|
||||
#include "set.h"
|
||||
|
||||
struct introspect {
|
||||
FILE *f;
|
||||
char *introspection;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
int introspect_begin(struct introspect *i);
|
||||
int introspect_write_default_interfaces(struct introspect *i, bool object_manager);
|
||||
int introspect_write_child_nodes(struct introspect *i, Set *s, const char *prefix);
|
||||
int introspect_write_interface(struct introspect *i, const char *interface, const sd_bus_vtable *v);
|
||||
int introspect_finish(struct introspect *i, sd_bus *bus, sd_bus_message *m, sd_bus_message **reply);
|
||||
void introspect_free(struct introspect *i);
|
@ -496,9 +496,13 @@ int sd_bus_message_new_method_call(
|
||||
sd_bus_message *t;
|
||||
int r;
|
||||
|
||||
if (!path)
|
||||
if (destination && !service_name_is_valid(destination))
|
||||
return -EINVAL;
|
||||
if (!member)
|
||||
if (!object_path_is_valid(path))
|
||||
return -EINVAL;
|
||||
if (interface && !interface_name_is_valid(interface))
|
||||
return -EINVAL;
|
||||
if (!member_name_is_valid(member))
|
||||
return -EINVAL;
|
||||
if (!m)
|
||||
return -EINVAL;
|
||||
@ -627,6 +631,58 @@ fail:
|
||||
return r;
|
||||
}
|
||||
|
||||
int sd_bus_message_new_method_errorf(
|
||||
sd_bus *bus,
|
||||
sd_bus_message *call,
|
||||
sd_bus_message **m,
|
||||
const char *name,
|
||||
const char *format,
|
||||
...) {
|
||||
|
||||
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
sd_bus_message *t;
|
||||
va_list ap;
|
||||
int r;
|
||||
|
||||
if (!name)
|
||||
return -EINVAL;
|
||||
if (!m)
|
||||
return -EINVAL;
|
||||
|
||||
r = message_new_reply(bus, call, SD_BUS_MESSAGE_TYPE_METHOD_ERROR, &t);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = message_append_field_string(t, SD_BUS_MESSAGE_HEADER_ERROR_NAME, SD_BUS_TYPE_STRING, name, &t->error.name);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
if (format) {
|
||||
_cleanup_free_ char *message = NULL;
|
||||
|
||||
va_start(ap, format);
|
||||
r = vasprintf(&message, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (r < 0) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = message_append_basic(t, SD_BUS_TYPE_STRING, message, (const void**) &t->error.message);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
*m = t;
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
message_free(t);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
int bus_message_new_synthetic_error(
|
||||
sd_bus *bus,
|
||||
uint64_t serial,
|
||||
@ -1558,7 +1614,7 @@ static int bus_message_open_array(
|
||||
assert(contents);
|
||||
assert(array_size);
|
||||
|
||||
if (!signature_is_single(contents))
|
||||
if (!signature_is_single(contents, true))
|
||||
return -EINVAL;
|
||||
|
||||
alignment = bus_type_get_alignment(contents[0]);
|
||||
@ -1629,7 +1685,7 @@ static int bus_message_open_variant(
|
||||
assert(c);
|
||||
assert(contents);
|
||||
|
||||
if (!signature_is_single(contents))
|
||||
if (!signature_is_single(contents, false))
|
||||
return -EINVAL;
|
||||
|
||||
if (*contents == SD_BUS_TYPE_DICT_ENTRY_BEGIN)
|
||||
@ -2704,7 +2760,7 @@ static int bus_message_enter_array(
|
||||
assert(contents);
|
||||
assert(array_size);
|
||||
|
||||
if (!signature_is_single(contents))
|
||||
if (!signature_is_single(contents, true))
|
||||
return -EINVAL;
|
||||
|
||||
alignment = bus_type_get_alignment(contents[0]);
|
||||
@ -2758,7 +2814,7 @@ static int bus_message_enter_variant(
|
||||
assert(c);
|
||||
assert(contents);
|
||||
|
||||
if (!signature_is_single(contents))
|
||||
if (!signature_is_single(contents, false))
|
||||
return -EINVAL;
|
||||
|
||||
if (*contents == SD_BUS_TYPE_DICT_ENTRY_BEGIN)
|
||||
@ -4290,3 +4346,16 @@ int bus_message_to_errno(sd_bus_message *m) {
|
||||
|
||||
return bus_error_to_errno(&m->error);
|
||||
}
|
||||
|
||||
int sd_bus_message_get_signature(sd_bus_message *m, int complete, const char **signature) {
|
||||
struct bus_container *c;
|
||||
|
||||
if (!m)
|
||||
return -EINVAL;
|
||||
if (!signature)
|
||||
return -EINVAL;
|
||||
|
||||
c = complete ? &m->root_container : message_get_container(m);
|
||||
*signature = c->signature ?: "";
|
||||
return 0;
|
||||
}
|
||||
|
@ -110,13 +110,13 @@ int signature_element_length(const char *s, size_t *l) {
|
||||
return signature_element_length_internal(s, true, 0, 0, l);
|
||||
}
|
||||
|
||||
bool signature_is_single(const char *s) {
|
||||
bool signature_is_single(const char *s, bool allow_dict_entry) {
|
||||
int r;
|
||||
size_t t;
|
||||
|
||||
assert(s);
|
||||
|
||||
r = signature_element_length(s, &t);
|
||||
r = signature_element_length_internal(s, allow_dict_entry, 0, 0, &t);
|
||||
if (r < 0)
|
||||
return false;
|
||||
|
||||
@ -129,7 +129,7 @@ bool signature_is_pair(const char *s) {
|
||||
if (!bus_type_is_basic(*s))
|
||||
return false;
|
||||
|
||||
return signature_is_single(s + 1);
|
||||
return signature_is_single(s + 1, false);
|
||||
}
|
||||
|
||||
bool signature_is_valid(const char *s, bool allow_dict_entry) {
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include <stdbool.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
bool signature_is_single(const char *s);
|
||||
bool signature_is_single(const char *s, bool allow_dict_entry);
|
||||
bool signature_is_pair(const char *s);
|
||||
bool signature_is_valid(const char *s, bool allow_dict_entry);
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
63
src/libsystemd-bus/test-bus-introspect.c
Normal file
63
src/libsystemd-bus/test-bus-introspect.c
Normal file
@ -0,0 +1,63 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2013 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include "util.h"
|
||||
#include "log.h"
|
||||
#include "bus-introspect.h"
|
||||
|
||||
static int prop_get(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, sd_bus_error *error, void *userdata) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int prop_set(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, sd_bus_error *error, void *userdata) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const sd_bus_vtable vtable[] = {
|
||||
SD_BUS_VTABLE_START(0),
|
||||
SD_BUS_METHOD("Hello", "ssas", "a(uu)", 0, NULL),
|
||||
SD_BUS_METHOD("DeprecatedHello", "", "", SD_BUS_VTABLE_DEPRECATED, NULL),
|
||||
SD_BUS_METHOD("DeprecatedHelloNoReply", "", "", SD_BUS_VTABLE_DEPRECATED|SD_BUS_VTABLE_METHOD_NO_REPLY, NULL),
|
||||
SD_BUS_SIGNAL("Wowza", "sss", 0),
|
||||
SD_BUS_SIGNAL("DeprecatedWowza", "ut", SD_BUS_VTABLE_DEPRECATED),
|
||||
SD_BUS_WRITABLE_PROPERTY("AProperty", "s", prop_get, prop_set, 0, 0),
|
||||
SD_BUS_PROPERTY("AReadOnlyDeprecatedProperty", "(ut)", prop_get, 0, SD_BUS_VTABLE_DEPRECATED),
|
||||
SD_BUS_PROPERTY("ChangingProperty", "t", prop_get, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
SD_BUS_PROPERTY("Invalidating", "t", prop_get, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE|SD_BUS_VTABLE_PROPERTY_INVALIDATE_ONLY),
|
||||
SD_BUS_VTABLE_END
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
struct introspect intro;
|
||||
|
||||
log_set_max_level(LOG_DEBUG);
|
||||
|
||||
assert_se(introspect_begin(&intro) >= 0);
|
||||
|
||||
assert_se(introspect_write_interface(&intro, "org.foo", vtable) >= 0);
|
||||
|
||||
fflush(intro.f);
|
||||
fputs(intro.introspection, stdout);
|
||||
|
||||
introspect_free(&intro);
|
||||
|
||||
return 0;
|
||||
}
|
374
src/libsystemd-bus/test-bus-objects.c
Normal file
374
src/libsystemd-bus/test-bus-objects.c
Normal file
@ -0,0 +1,374 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2013 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
#include "macro.h"
|
||||
#include "strv.h"
|
||||
|
||||
#include "sd-bus.h"
|
||||
#include "bus-internal.h"
|
||||
#include "bus-message.h"
|
||||
|
||||
/* Test:
|
||||
*
|
||||
* sd_bus_add_object_manager()
|
||||
* sd_bus_emit_properties_changed()
|
||||
*
|
||||
* Add in:
|
||||
*
|
||||
* automatic properties
|
||||
* node hierarchy updates during dispatching
|
||||
* emit_interfaces_added/emit_interfaces_removed
|
||||
*
|
||||
*/
|
||||
|
||||
struct context {
|
||||
int fds[2];
|
||||
bool quit;
|
||||
char *something;
|
||||
};
|
||||
|
||||
static int something_handler(sd_bus *bus, sd_bus_message *m, void *userdata) {
|
||||
struct context *c = userdata;
|
||||
const char *s;
|
||||
char *n = NULL;
|
||||
int r;
|
||||
|
||||
r = sd_bus_message_read(m, "s", &s);
|
||||
assert_se(r > 0);
|
||||
|
||||
n = strjoin("<<<", s, ">>>", NULL);
|
||||
assert_se(n);
|
||||
|
||||
free(c->something);
|
||||
c->something = n;
|
||||
|
||||
log_info("AlterSomething() called, got %s, returning %s", s, n);
|
||||
|
||||
r = sd_bus_reply_method_return(bus, m, "s", n);
|
||||
assert_se(r >= 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int exit_handler(sd_bus *bus, sd_bus_message *m, void *userdata) {
|
||||
struct context *c = userdata;
|
||||
int r;
|
||||
|
||||
c->quit = true;
|
||||
|
||||
log_info("Exit called");
|
||||
|
||||
r = sd_bus_reply_method_return(bus, m, "");
|
||||
assert_se(r >= 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int get_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, sd_bus_error *error, void *userdata) {
|
||||
struct context *c = userdata;
|
||||
int r;
|
||||
|
||||
log_info("property get for %s called", property);
|
||||
|
||||
r = sd_bus_message_append(reply, "s", c->something);
|
||||
assert_se(r >= 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int set_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *value, sd_bus_error *error, void *userdata) {
|
||||
struct context *c = userdata;
|
||||
const char *s;
|
||||
char *n;
|
||||
int r;
|
||||
|
||||
log_info("property set for %s called", property);
|
||||
|
||||
r = sd_bus_message_read(value, "s", &s);
|
||||
assert_se(r >= 0);
|
||||
|
||||
n = strdup(s);
|
||||
assert_se(n);
|
||||
|
||||
free(c->something);
|
||||
c->something = n;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int value_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, sd_bus_error *error, void *userdata) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
const char *x;
|
||||
int r;
|
||||
|
||||
assert_se(asprintf(&s, "object %p, path %s", userdata, path) >= 0);
|
||||
r = sd_bus_message_append(reply, "s", s);
|
||||
assert_se(r >= 0);
|
||||
|
||||
assert_se(x = startswith(path, "/value/"));
|
||||
|
||||
assert_se(PTR_TO_UINT(userdata) == 30);
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const sd_bus_vtable vtable[] = {
|
||||
SD_BUS_VTABLE_START(0),
|
||||
SD_BUS_METHOD("AlterSomething", "s", "s", 0, something_handler),
|
||||
SD_BUS_METHOD("Exit", "", "", 0, exit_handler),
|
||||
SD_BUS_WRITABLE_PROPERTY("Something", "s", get_handler, set_handler, 0, 0),
|
||||
SD_BUS_VTABLE_END
|
||||
};
|
||||
|
||||
static const sd_bus_vtable vtable2[] = {
|
||||
SD_BUS_VTABLE_START(0),
|
||||
SD_BUS_PROPERTY("Value", "s", value_handler, 10, 0),
|
||||
SD_BUS_VTABLE_END
|
||||
};
|
||||
|
||||
static int enumerator_callback(sd_bus *b, const char *path, char ***nodes, void *userdata) {
|
||||
|
||||
if (object_path_startswith("/value", path))
|
||||
assert_se(*nodes = strv_new("/value/a", "/value/b", "/value/c", NULL));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void *server(void *p) {
|
||||
struct context *c = p;
|
||||
sd_bus *bus = NULL;
|
||||
sd_id128_t id;
|
||||
int r;
|
||||
|
||||
c->quit = false;
|
||||
|
||||
assert_se(sd_id128_randomize(&id) >= 0);
|
||||
|
||||
assert_se(sd_bus_new(&bus) >= 0);
|
||||
assert_se(sd_bus_set_fd(bus, c->fds[0], c->fds[0]) >= 0);
|
||||
assert_se(sd_bus_set_server(bus, 1, id) >= 0);
|
||||
|
||||
assert_se(sd_bus_add_object_vtable(bus, "/foo", "org.freedesktop.systemd.test", vtable, c) >= 0);
|
||||
assert_se(sd_bus_add_object_vtable(bus, "/foo", "org.freedesktop.systemd.test2", vtable, c) >= 0);
|
||||
assert_se(sd_bus_add_fallback_vtable(bus, "/value", "org.freedesktop.systemd.ValueTest", vtable2, NULL, UINT_TO_PTR(20)) >= 0);
|
||||
assert_se(sd_bus_add_node_enumerator(bus, "/value", enumerator_callback, NULL) >= 0);
|
||||
|
||||
assert_se(sd_bus_start(bus) >= 0);
|
||||
|
||||
log_error("Entering event loop on server");
|
||||
|
||||
while (!c->quit) {
|
||||
log_error("Loop!");
|
||||
|
||||
r = sd_bus_process(bus, NULL);
|
||||
if (r < 0) {
|
||||
log_error("Failed to process requests: %s", strerror(-r));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (r == 0) {
|
||||
r = sd_bus_wait(bus, (uint64_t) -1);
|
||||
if (r < 0) {
|
||||
log_error("Failed to wait: %s", strerror(-r));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
r = 0;
|
||||
|
||||
fail:
|
||||
if (bus) {
|
||||
sd_bus_flush(bus);
|
||||
sd_bus_unref(bus);
|
||||
}
|
||||
|
||||
return INT_TO_PTR(r);
|
||||
}
|
||||
|
||||
static int client(struct context *c) {
|
||||
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
|
||||
_cleanup_bus_unref_ sd_bus *bus = NULL;
|
||||
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
const char *s;
|
||||
int r;
|
||||
|
||||
assert_se(sd_bus_new(&bus) >= 0);
|
||||
assert_se(sd_bus_set_fd(bus, c->fds[1], c->fds[1]) >= 0);
|
||||
assert_se(sd_bus_start(bus) >= 0);
|
||||
|
||||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "s", "hallo");
|
||||
assert_se(r >= 0);
|
||||
|
||||
r = sd_bus_message_read(reply, "s", &s);
|
||||
assert_se(r >= 0);
|
||||
assert_se(streq(s, "<<<hallo>>>"));
|
||||
|
||||
sd_bus_message_unref(reply);
|
||||
reply = NULL;
|
||||
|
||||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Doesntexist", &error, &reply, "");
|
||||
assert_se(r < 0);
|
||||
assert_se(sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.UnknownMethod"));
|
||||
|
||||
sd_bus_error_free(&error);
|
||||
|
||||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "as", 1, "hallo");
|
||||
assert_se(r < 0);
|
||||
assert_se(sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.InvalidArgs"));
|
||||
|
||||
sd_bus_error_free(&error);
|
||||
|
||||
r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s");
|
||||
assert_se(r >= 0);
|
||||
|
||||
r = sd_bus_message_read(reply, "s", &s);
|
||||
assert_se(r >= 0);
|
||||
assert_se(streq(s, "<<<hallo>>>"));
|
||||
|
||||
sd_bus_message_unref(reply);
|
||||
reply = NULL;
|
||||
|
||||
r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, "s", "test");
|
||||
assert_se(r >= 0);
|
||||
|
||||
r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s");
|
||||
assert_se(r >= 0);
|
||||
|
||||
r = sd_bus_message_read(reply, "s", &s);
|
||||
assert_se(r >= 0);
|
||||
assert_se(streq(s, "test"));
|
||||
|
||||
sd_bus_message_unref(reply);
|
||||
reply = NULL;
|
||||
|
||||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
|
||||
assert_se(r <= 0);
|
||||
|
||||
r = sd_bus_message_read(reply, "s", &s);
|
||||
assert_se(r >= 0);
|
||||
fputs(s, stdout);
|
||||
|
||||
sd_bus_message_unref(reply);
|
||||
reply = NULL;
|
||||
|
||||
r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/value/xuzz", "org.freedesktop.systemd.ValueTest", "Value", &error, &reply, "s");
|
||||
assert_se(r >= 0);
|
||||
|
||||
r = sd_bus_message_read(reply, "s", &s);
|
||||
assert_se(r >= 0);
|
||||
log_info("read %s", s);
|
||||
|
||||
sd_bus_message_unref(reply);
|
||||
reply = NULL;
|
||||
|
||||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
|
||||
assert_se(r <= 0);
|
||||
|
||||
r = sd_bus_message_read(reply, "s", &s);
|
||||
assert_se(r >= 0);
|
||||
fputs(s, stdout);
|
||||
|
||||
sd_bus_message_unref(reply);
|
||||
reply = NULL;
|
||||
|
||||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
|
||||
assert_se(r <= 0);
|
||||
|
||||
r = sd_bus_message_read(reply, "s", &s);
|
||||
assert_se(r >= 0);
|
||||
fputs(s, stdout);
|
||||
|
||||
sd_bus_message_unref(reply);
|
||||
reply = NULL;
|
||||
|
||||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
|
||||
assert_se(r <= 0);
|
||||
|
||||
r = sd_bus_message_read(reply, "s", &s);
|
||||
assert_se(r >= 0);
|
||||
fputs(s, stdout);
|
||||
|
||||
sd_bus_message_unref(reply);
|
||||
reply = NULL;
|
||||
|
||||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "");
|
||||
assert_se(r <= 0);
|
||||
|
||||
bus_message_dump(reply);
|
||||
|
||||
sd_bus_message_unref(reply);
|
||||
reply = NULL;
|
||||
|
||||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "org.freedesktop.systemd.ValueTest2");
|
||||
assert_se(r < 0);
|
||||
assert_se(sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.UnknownInterface"));
|
||||
sd_bus_error_free(&error);
|
||||
|
||||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Exit", &error, NULL, "");
|
||||
assert_se(r >= 0);
|
||||
|
||||
sd_bus_flush(bus);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
struct context c;
|
||||
pthread_t s;
|
||||
void *p;
|
||||
int r, q;
|
||||
|
||||
zero(c);
|
||||
|
||||
assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, c.fds) >= 0);
|
||||
|
||||
r = pthread_create(&s, NULL, server, &c);
|
||||
if (r != 0)
|
||||
return -r;
|
||||
|
||||
r = client(&c);
|
||||
|
||||
q = pthread_join(s, &p);
|
||||
if (q != 0)
|
||||
return -q;
|
||||
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (PTR_TO_INT(p) < 0)
|
||||
return PTR_TO_INT(p);
|
||||
|
||||
free(c.something);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
@ -28,29 +28,30 @@
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
assert_se(signature_is_single("y"));
|
||||
assert_se(signature_is_single("u"));
|
||||
assert_se(signature_is_single("v"));
|
||||
assert_se(signature_is_single("as"));
|
||||
assert_se(signature_is_single("(ss)"));
|
||||
assert_se(signature_is_single("()"));
|
||||
assert_se(signature_is_single("(()()()()())"));
|
||||
assert_se(signature_is_single("(((())))"));
|
||||
assert_se(signature_is_single("((((s))))"));
|
||||
assert_se(signature_is_single("{ss}"));
|
||||
assert_se(signature_is_single("a{ss}"));
|
||||
assert_se(!signature_is_single("uu"));
|
||||
assert_se(!signature_is_single(""));
|
||||
assert_se(!signature_is_single("("));
|
||||
assert_se(!signature_is_single(")"));
|
||||
assert_se(!signature_is_single("())"));
|
||||
assert_se(!signature_is_single("((())"));
|
||||
assert_se(!signature_is_single("{)"));
|
||||
assert_se(!signature_is_single("{}"));
|
||||
assert_se(!signature_is_single("{sss}"));
|
||||
assert_se(!signature_is_single("{s}"));
|
||||
assert_se(!signature_is_single("{ass}"));
|
||||
assert_se(!signature_is_single("a}"));
|
||||
assert_se(signature_is_single("y", false));
|
||||
assert_se(signature_is_single("u", false));
|
||||
assert_se(signature_is_single("v", false));
|
||||
assert_se(signature_is_single("as", false));
|
||||
assert_se(signature_is_single("(ss)", false));
|
||||
assert_se(signature_is_single("()", false));
|
||||
assert_se(signature_is_single("(()()()()())", false));
|
||||
assert_se(signature_is_single("(((())))", false));
|
||||
assert_se(signature_is_single("((((s))))", false));
|
||||
assert_se(signature_is_single("{ss}", true));
|
||||
assert_se(signature_is_single("a{ss}", false));
|
||||
assert_se(!signature_is_single("uu", false));
|
||||
assert_se(!signature_is_single("", false));
|
||||
assert_se(!signature_is_single("(", false));
|
||||
assert_se(!signature_is_single(")", false));
|
||||
assert_se(!signature_is_single("())", false));
|
||||
assert_se(!signature_is_single("((())", false));
|
||||
assert_se(!signature_is_single("{)", false));
|
||||
assert_se(!signature_is_single("{}", true));
|
||||
assert_se(!signature_is_single("{sss}", true));
|
||||
assert_se(!signature_is_single("{s}", true));
|
||||
assert_se(!signature_is_single("{ss}", false));
|
||||
assert_se(!signature_is_single("{ass}", true));
|
||||
assert_se(!signature_is_single("a}", true));
|
||||
|
||||
assert_se(signature_is_pair("yy"));
|
||||
assert_se(signature_is_pair("ss"));
|
||||
@ -112,5 +113,25 @@ int main(int argc, char *argv[]) {
|
||||
assert_se(!namespace_simple_pattern("", "foo"));
|
||||
assert_se(!namespace_simple_pattern("foo", ""));
|
||||
|
||||
assert_se(streq(object_path_startswith("/foo/bar", "/foo"), "bar"));
|
||||
assert_se(streq(object_path_startswith("/foo", "/foo"), ""));
|
||||
assert_se(streq(object_path_startswith("/foo", "/"), "foo"));
|
||||
assert_se(streq(object_path_startswith("/", "/"), ""));
|
||||
assert_se(!object_path_startswith("/foo", "/bar"));
|
||||
assert_se(!object_path_startswith("/", "/bar"));
|
||||
assert_se(!object_path_startswith("/foo", ""));
|
||||
|
||||
assert_se(object_path_is_valid("/foo/bar"));
|
||||
assert_se(object_path_is_valid("/foo"));
|
||||
assert_se(object_path_is_valid("/"));
|
||||
assert_se(object_path_is_valid("/foo5"));
|
||||
assert_se(object_path_is_valid("/foo_5"));
|
||||
assert_se(!object_path_is_valid(""));
|
||||
assert_se(!object_path_is_valid("/foo/"));
|
||||
assert_se(!object_path_is_valid("//"));
|
||||
assert_se(!object_path_is_valid("//foo"));
|
||||
assert_se(!object_path_is_valid("/foo//bar"));
|
||||
assert_se(!object_path_is_valid("/foo/aaaäöä"));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -108,6 +108,21 @@ enum {
|
||||
"<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n" \
|
||||
"\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
|
||||
|
||||
#define SD_BUS_INTROSPECT_INTERFACE_PEER \
|
||||
" <interface name=\"org.freedesktop.DBus.Peer\">\n" \
|
||||
" <method name=\"Ping\"/>\n" \
|
||||
" <method name=\"GetMachineId\">\n" \
|
||||
" <arg type=\"s\" name=\"machine_uuid\" direction=\"out\"/>\n" \
|
||||
" </method>\n" \
|
||||
" </interface>\n"
|
||||
|
||||
#define SD_BUS_INTROSPECT_INTERFACE_INTROSPECTABLE \
|
||||
" <interface name=\"org.freedesktop.DBus.Introspectable\">\n" \
|
||||
" <method name=\"Introspect\">\n" \
|
||||
" <arg name=\"data\" type=\"s\" direction=\"out\"/>\n" \
|
||||
" </method>\n" \
|
||||
" </interface>\n"
|
||||
|
||||
#define SD_BUS_INTROSPECT_INTERFACE_PROPERTIES \
|
||||
" <interface name=\"org.freedesktop.DBus.Properties\">\n" \
|
||||
" <method name=\"Get\">\n" \
|
||||
@ -131,21 +146,21 @@ enum {
|
||||
" </signal>\n" \
|
||||
" </interface>\n"
|
||||
|
||||
#define SD_BUS_INTROSPECT_INTERFACE_INTROSPECTABLE \
|
||||
" <interface name=\"org.freedesktop.DBus.Introspectable\">\n" \
|
||||
" <method name=\"Introspect\">\n" \
|
||||
" <arg name=\"data\" type=\"s\" direction=\"out\"/>\n" \
|
||||
#define SD_BUS_INTROSPECT_INTERFACE_OBJECT_MANAGER \
|
||||
" <interface name=\"org.freedesktop.DBus.ObjectManager\">\n" \
|
||||
" <method name=\"GetManagedObjects\">\n" \
|
||||
" <arg type=\"a{oa{sa{sv}}}\" name=\"object_paths_interfaces_and_properties\" direction=\"out\"/>\n" \
|
||||
" </method>\n" \
|
||||
" <signal name=\"InterfacesAdded\">\n" \
|
||||
" <arg type=\"o\" name=\"object_path\"/>\n" \
|
||||
" <arg type=\"a{sa{sv}}\" name=\"interfaces_and_properties\"/>\n" \
|
||||
" </signal>\n" \
|
||||
" <signal name=\"InterfacesRemoved\">\n" \
|
||||
" <arg type=\"o\" name=\"object_path\"/>\n" \
|
||||
" <arg type=\"as\" name=\"interfaces\"/>\n" \
|
||||
" </signal>\n" \
|
||||
" </interface>\n"
|
||||
|
||||
#define SD_BUS_INTROSPECT_INTERFACE_PEER \
|
||||
"<interface name=\"org.freedesktop.DBus.Peer\">\n" \
|
||||
" <method name=\"Ping\"/>\n" \
|
||||
" <method name=\"GetMachineId\">\n" \
|
||||
" <arg type=\"s\" name=\"machine_uuid\" direction=\"out\"/>\n" \
|
||||
" </method>\n" \
|
||||
"</interface>\n"
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
127
src/systemd/sd-bus-vtable.h
Normal file
127
src/systemd/sd-bus-vtable.h
Normal file
@ -0,0 +1,127 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#ifndef foosdbusvtablehfoo
|
||||
#define foosdbusvtablehfoo
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2013 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
typedef struct sd_bus_vtable sd_bus_vtable;
|
||||
|
||||
#include "sd-bus.h"
|
||||
|
||||
enum {
|
||||
_SD_BUS_VTABLE_START = '<',
|
||||
_SD_BUS_VTABLE_END = '>',
|
||||
_SD_BUS_VTABLE_METHOD = 'M',
|
||||
_SD_BUS_VTABLE_SIGNAL = 'S',
|
||||
_SD_BUS_VTABLE_PROPERTY = 'P',
|
||||
_SD_BUS_VTABLE_WRITABLE_PROPERTY = 'W',
|
||||
_SD_BUS_VTABLE_CHILDREN = 'C'
|
||||
};
|
||||
|
||||
enum {
|
||||
SD_BUS_VTABLE_DEPRECATED = 1,
|
||||
SD_BUS_VTABLE_METHOD_NO_REPLY = 2,
|
||||
SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE = 4,
|
||||
SD_BUS_VTABLE_PROPERTY_INVALIDATE_ONLY = 8,
|
||||
};
|
||||
|
||||
struct sd_bus_vtable {
|
||||
/* Please do not initialize this structure directly, use the
|
||||
* macros below instead */
|
||||
|
||||
int type;
|
||||
int flags;
|
||||
union {
|
||||
struct {
|
||||
size_t element_size;
|
||||
} start;
|
||||
struct {
|
||||
const char *member;
|
||||
const char *signature;
|
||||
const char *result;
|
||||
sd_bus_message_handler_t handler;
|
||||
} method;
|
||||
struct {
|
||||
const char *member;
|
||||
const char *signature;
|
||||
} signal;
|
||||
struct {
|
||||
const char *member;
|
||||
const char *signature;
|
||||
sd_bus_property_get_t get;
|
||||
sd_bus_property_set_t set;
|
||||
size_t offset;
|
||||
} property;
|
||||
};
|
||||
};
|
||||
|
||||
#define SD_BUS_VTABLE_START(_flags) \
|
||||
{ \
|
||||
.type = _SD_BUS_VTABLE_START, \
|
||||
.flags = _flags, \
|
||||
.start.element_size = sizeof(sd_bus_vtable), \
|
||||
}
|
||||
|
||||
#define SD_BUS_METHOD(_member, _signature, _result, _flags, _handler) \
|
||||
{ \
|
||||
.type = _SD_BUS_VTABLE_METHOD, \
|
||||
.flags = _flags, \
|
||||
.method.member = _member, \
|
||||
.method.signature = _signature, \
|
||||
.method.result = _result, \
|
||||
.method.handler = _handler, \
|
||||
}
|
||||
|
||||
#define SD_BUS_SIGNAL(_member, _signature, _flags) \
|
||||
{ \
|
||||
.type = _SD_BUS_VTABLE_SIGNAL, \
|
||||
.flags = _flags, \
|
||||
.signal.member = _member, \
|
||||
.signal.signature = _signature, \
|
||||
}
|
||||
|
||||
#define SD_BUS_PROPERTY(_member, _signature, _get, _offset, _flags) \
|
||||
{ \
|
||||
.type = _SD_BUS_VTABLE_PROPERTY, \
|
||||
.flags = _flags, \
|
||||
.property.member = _member, \
|
||||
.property.signature = _signature, \
|
||||
.property.get = _get, \
|
||||
.property.offset = _offset, \
|
||||
}
|
||||
|
||||
#define SD_BUS_WRITABLE_PROPERTY(_member, _signature, _get, _set, _offset, _flags) \
|
||||
{ \
|
||||
.type = _SD_BUS_VTABLE_WRITABLE_PROPERTY, \
|
||||
.flags = _flags, \
|
||||
.property.member = _member, \
|
||||
.property.signature = _signature, \
|
||||
.property.get = _get, \
|
||||
.property.set = _set, \
|
||||
.property.offset = _offset, \
|
||||
}
|
||||
|
||||
#define SD_BUS_VTABLE_END \
|
||||
{ \
|
||||
.type = _SD_BUS_VTABLE_END, \
|
||||
}
|
||||
|
||||
#endif
|
@ -26,8 +26,6 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <sd-id128.h>
|
||||
#include "sd-bus-protocol.h"
|
||||
#include "sd-memfd.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -41,6 +39,8 @@ extern "C" {
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Types */
|
||||
|
||||
typedef struct sd_bus sd_bus;
|
||||
typedef struct sd_bus_message sd_bus_message;
|
||||
|
||||
@ -50,8 +50,21 @@ typedef struct {
|
||||
int need_free;
|
||||
} sd_bus_error;
|
||||
|
||||
/* Callbacks */
|
||||
|
||||
typedef int (*sd_bus_message_handler_t)(sd_bus *bus, sd_bus_message *m, void *userdata);
|
||||
|
||||
typedef int (*sd_bus_property_get_t) (sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, sd_bus_error *error, void *userdata);
|
||||
typedef int (*sd_bus_property_set_t) (sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *value, sd_bus_error *error, void *userdata);
|
||||
|
||||
typedef int (*sd_bus_object_find_t) (sd_bus *bus, const char *path, const char *interface, void **found, void *userdata);
|
||||
|
||||
typedef int (*sd_bus_node_enumerator_t) (sd_bus *bus, const char *path, char ***nodes, void *userdata);
|
||||
|
||||
#include "sd-bus-protocol.h"
|
||||
#include "sd-bus-vtable.h"
|
||||
#include "sd-memfd.h"
|
||||
|
||||
/* Connections */
|
||||
|
||||
int sd_bus_open_system(sd_bus **ret);
|
||||
@ -98,21 +111,33 @@ int sd_bus_flush(sd_bus *bus);
|
||||
int sd_bus_add_filter(sd_bus *bus, sd_bus_message_handler_t callback, void *userdata);
|
||||
int sd_bus_remove_filter(sd_bus *bus, sd_bus_message_handler_t callback, void *userdata);
|
||||
|
||||
int sd_bus_add_match(sd_bus *bus, const char *match, sd_bus_message_handler_t callback, void *userdata);
|
||||
int sd_bus_remove_match(sd_bus *bus, const char *match, sd_bus_message_handler_t callback, void *userdata);
|
||||
|
||||
int sd_bus_add_object(sd_bus *bus, const char *path, sd_bus_message_handler_t callback, void *userdata);
|
||||
int sd_bus_remove_object(sd_bus *bus, const char *path, sd_bus_message_handler_t callback, void *userdata);
|
||||
|
||||
int sd_bus_add_fallback(sd_bus *bus, const char *prefix, sd_bus_message_handler_t callback, void *userdata);
|
||||
int sd_bus_remove_fallback(sd_bus *bus, const char *prefix, sd_bus_message_handler_t callback, void *userdata);
|
||||
|
||||
int sd_bus_add_match(sd_bus *bus, const char *match, sd_bus_message_handler_t callback, void *userdata);
|
||||
int sd_bus_remove_match(sd_bus *bus, const char *match, sd_bus_message_handler_t callback, void *userdata);
|
||||
int sd_bus_add_object_vtable(sd_bus *bus, const char *path, const char *interface, const sd_bus_vtable *vtable, void *userdata);
|
||||
int sd_bus_remove_object_vtable(sd_bus *bus, const char *path, const char *interface);
|
||||
|
||||
int sd_bus_add_fallback_vtable(sd_bus *bus, const char *path, const char *interface, const sd_bus_vtable *vtable, sd_bus_object_find_t find, void *userdata);
|
||||
int sd_bus_remove_fallback_vtable(sd_bus *bus, const char *path, const char *interface);
|
||||
|
||||
int sd_bus_add_node_enumerator(sd_bus *bus, const char *path, sd_bus_node_enumerator_t callback, void *userdata);
|
||||
int sd_bus_remove_node_enumerator(sd_bus *bus, const char *path, sd_bus_node_enumerator_t callback, void *userdata);
|
||||
|
||||
int sd_bus_add_object_manager(sd_bus *bus, const char *path);
|
||||
int sd_bus_remove_object_manager(sd_bus *bus, const char *path);
|
||||
|
||||
/* Message object */
|
||||
|
||||
int sd_bus_message_new_signal(sd_bus *bus, const char *path, const char *interface, const char *member, sd_bus_message **m);
|
||||
int sd_bus_message_new_method_call(sd_bus *bus, const char *destination, const char *path, const char *interface, const char *member, sd_bus_message **m);
|
||||
int sd_bus_message_new_method_return(sd_bus *bus, sd_bus_message *call, sd_bus_message **m);
|
||||
int sd_bus_message_new_method_error(sd_bus *bus, sd_bus_message *call, const sd_bus_error *e, sd_bus_message **m);
|
||||
int sd_bus_message_new_method_errorf(sd_bus *bus, sd_bus_message *call, sd_bus_message **m, const char *name, const char *format, ...);
|
||||
|
||||
sd_bus_message* sd_bus_message_ref(sd_bus_message *m);
|
||||
sd_bus_message* sd_bus_message_unref(sd_bus_message *m);
|
||||
@ -175,12 +200,26 @@ int sd_bus_message_exit_container(sd_bus_message *m);
|
||||
int sd_bus_message_peek_type(sd_bus_message *m, char *type, const char **contents);
|
||||
int sd_bus_message_rewind(sd_bus_message *m, int complete);
|
||||
|
||||
int sd_bus_message_get_signature(sd_bus_message *m, int complete, const char **signature);
|
||||
|
||||
/* Convenience calls */
|
||||
|
||||
int sd_bus_emit_signal(sd_bus *bus, const char *path, const char *interface, const char *member, const char *types, ...);
|
||||
int sd_bus_call_method(sd_bus *bus, const char *destination, const char *path, const char *interface, const char *member, sd_bus_error *error, sd_bus_message **reply, const char *types, ...);
|
||||
int sd_bus_get_property(sd_bus *bus, const char *destination, const char *path, const char *interface, const char *member, sd_bus_error *error, sd_bus_message **reply, const char *type);
|
||||
int sd_bus_set_property(sd_bus *bus, const char *destination, const char *path, const char *interface, const char *member, sd_bus_error *error, const char *type, ...);
|
||||
int sd_bus_reply_method_return(sd_bus *bus, sd_bus_message *call, const char *types, ...);
|
||||
int sd_bus_reply_method_error(sd_bus *bus, sd_bus_message *call, const sd_bus_error *e);
|
||||
int sd_bus_reply_method_errorf(sd_bus *bus, sd_bus_message *call, const char *name, const char *format, ...);
|
||||
|
||||
int sd_bus_emit_signal(sd_bus *bus, const char *path, const char *interface, const char *member, const char *types, ...);
|
||||
|
||||
int sd_bus_emit_properties_changed_strv(sd_bus *bus, const char *path, const char *interface, char **names);
|
||||
int sd_bus_emit_properties_changed(sd_bus *bus, const char *path, const char *interface, const char *name, ...);
|
||||
|
||||
int sd_bus_emit_interfaces_added_strv(sd_bus *bus, const char *path, char **interfaces); /* MISSING */
|
||||
int sd_bus_emit_interfaces_added(sd_bus *bus, const char *path, const char *interface, ...); /* MISSING */
|
||||
int sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path, char **interfaces); /* MISSING */
|
||||
int sd_bus_emit_interfaces_removed(sd_bus *bus, const char *path, const char *interface, ...); /* MISSING */
|
||||
|
||||
/* Bus management */
|
||||
|
||||
@ -199,7 +238,8 @@ int sd_bus_get_owner_machine_id(sd_bus *bus, const char *name, sd_id128_t *machi
|
||||
#define SD_BUS_ERROR_MAKE(name, message) ((sd_bus_error) {(name), (message), 0})
|
||||
|
||||
void sd_bus_error_free(sd_bus_error *e);
|
||||
int sd_bus_error_set(sd_bus_error *e, const char *name, const char *format, ...) _sd_printf_attr_(3, 0);
|
||||
int sd_bus_error_setf(sd_bus_error *e, const char *name, const char *format, ...) _sd_printf_attr_(3, 0);
|
||||
int sd_bus_error_set(sd_bus_error *e, const char *name, const char *message);
|
||||
void sd_bus_error_set_const(sd_bus_error *e, const char *name, const char *message);
|
||||
int sd_bus_error_copy(sd_bus_error *dest, const sd_bus_error *e);
|
||||
int sd_bus_error_is_set(const sd_bus_error *e);
|
||||
|
Loading…
x
Reference in New Issue
Block a user