mirror of
https://github.com/Dasharo/systemd.git
synced 2026-03-06 15:02:31 -08:00
bus: parse matches locally and allow registration of callbacks for them
This includes code to parse and split up match strings which will also be useful to calculate bloom filter masks when the time comes.
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -81,9 +81,10 @@
|
||||
/systemd-user-sessions
|
||||
/systemd-vconsole-setup
|
||||
/tags
|
||||
/test-bus-marshal
|
||||
/test-bus-signature
|
||||
/test-bus-chat
|
||||
/test-bus-marshal
|
||||
/test-bus-match
|
||||
/test-bus-signature
|
||||
/test-bus-server
|
||||
/test-calendarspec
|
||||
/test-catalog
|
||||
|
||||
19
Makefile.am
19
Makefile.am
@@ -1670,6 +1670,7 @@ libsystemd_bus_la_SOURCES = \
|
||||
src/libsystemd-bus/sd-bus.h \
|
||||
src/libsystemd-bus/sd-bus-protocol.h \
|
||||
src/libsystemd-bus/bus-control.c \
|
||||
src/libsystemd-bus/bus-control.h \
|
||||
src/libsystemd-bus/bus-error.c \
|
||||
src/libsystemd-bus/bus-error.h \
|
||||
src/libsystemd-bus/bus-internal.c \
|
||||
@@ -1681,7 +1682,9 @@ libsystemd_bus_la_SOURCES = \
|
||||
src/libsystemd-bus/bus-signature.c \
|
||||
src/libsystemd-bus/bus-signature.h \
|
||||
src/libsystemd-bus/bus-type.c \
|
||||
src/libsystemd-bus/bus-type.h
|
||||
src/libsystemd-bus/bus-type.h \
|
||||
src/libsystemd-bus/bus-match.c \
|
||||
src/libsystemd-bus/bus-match.h
|
||||
|
||||
libsystemd_bus_la_LIBADD = \
|
||||
libsystemd-id128-internal.la \
|
||||
@@ -1694,7 +1697,8 @@ noinst_tests += \
|
||||
test-bus-marshal \
|
||||
test-bus-signature \
|
||||
test-bus-chat \
|
||||
test-bus-server
|
||||
test-bus-server \
|
||||
test-bus-match
|
||||
|
||||
noinst_PROGRAMS += \
|
||||
busctl
|
||||
@@ -1744,6 +1748,17 @@ test_bus_server_LDADD = \
|
||||
libsystemd-bus.la \
|
||||
libsystemd-id128-internal.la
|
||||
|
||||
test_bus_match_SOURCES = \
|
||||
src/libsystemd-bus/test-bus-match.c
|
||||
|
||||
test_bus_match_CFLAGS = \
|
||||
$(AM_CFLAGS)
|
||||
|
||||
test_bus_match_LDADD = \
|
||||
libsystemd-shared.la \
|
||||
libsystemd-bus.la \
|
||||
libsystemd-id128-internal.la
|
||||
|
||||
busctl_SOURCES = \
|
||||
src/libsystemd-bus/busctl.c
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "sd-bus.h"
|
||||
#include "bus-internal.h"
|
||||
#include "bus-message.h"
|
||||
#include "bus-control.h"
|
||||
|
||||
int sd_bus_get_unique_name(sd_bus *bus, const char **unique) {
|
||||
int r;
|
||||
@@ -292,14 +293,12 @@ int sd_bus_get_owner_pid(sd_bus *bus, const char *name, pid_t *pid) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_bus_add_match(sd_bus *bus, const char *match) {
|
||||
int bus_add_match_internal(sd_bus *bus, const char *match) {
|
||||
_cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
|
||||
int r;
|
||||
|
||||
if (!bus)
|
||||
return -EINVAL;
|
||||
if (!match)
|
||||
return -EINVAL;
|
||||
assert(bus);
|
||||
assert(match);
|
||||
|
||||
r = sd_bus_message_new_method_call(
|
||||
bus,
|
||||
@@ -318,14 +317,12 @@ int sd_bus_add_match(sd_bus *bus, const char *match) {
|
||||
return sd_bus_send_with_reply_and_block(bus, m, 0, NULL, &reply);
|
||||
}
|
||||
|
||||
int sd_bus_remove_match(sd_bus *bus, const char *match) {
|
||||
int bus_remove_match_internal(sd_bus *bus, const char *match) {
|
||||
_cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
|
||||
int r;
|
||||
|
||||
if (!bus)
|
||||
return -EINVAL;
|
||||
if (!match)
|
||||
return -EINVAL;
|
||||
assert(bus);
|
||||
assert(match);
|
||||
|
||||
r = sd_bus_message_new_method_call(
|
||||
bus,
|
||||
|
||||
27
src/libsystemd-bus/bus-control.h
Normal file
27
src/libsystemd-bus/bus-control.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/*-*- 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 "sd-bus.h"
|
||||
|
||||
int bus_add_match_internal(sd_bus *bus, const char *match);
|
||||
int bus_remove_match_internal(sd_bus *bus, const char *match);
|
||||
@@ -168,3 +168,64 @@ bool member_name_is_valid(const char *p) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool complex_pattern_check(char c, const char *a, const char *b) {
|
||||
bool separator = false;
|
||||
|
||||
for (;;) {
|
||||
if (*a != *b)
|
||||
return (separator && (*a == 0 || *b == 0)) ||
|
||||
(*a == 0 && *b == c && b[1] == 0) ||
|
||||
(*b == 0 && *a == c && a[1] == 0);
|
||||
|
||||
if (*a == 0)
|
||||
return true;
|
||||
|
||||
separator = *a == c;
|
||||
|
||||
a++, b++;
|
||||
}
|
||||
}
|
||||
|
||||
bool namespace_complex_pattern(const char *pattern, const char *value) {
|
||||
return complex_pattern_check('.', pattern, value);
|
||||
}
|
||||
|
||||
bool path_complex_pattern(const char *pattern, const char *value) {
|
||||
return complex_pattern_check('/', pattern, value);
|
||||
}
|
||||
|
||||
static bool simple_pattern_check(char c, const char *a, const char *b) {
|
||||
for (;;) {
|
||||
if (*a != *b)
|
||||
return *a == 0 && *b == c;
|
||||
|
||||
if (*a == 0)
|
||||
return true;
|
||||
|
||||
a++, b++;
|
||||
}
|
||||
}
|
||||
|
||||
bool namespace_simple_pattern(const char *pattern, const char *value) {
|
||||
return simple_pattern_check('.', pattern, value);
|
||||
}
|
||||
|
||||
bool path_simple_pattern(const char *pattern, const char *value) {
|
||||
return simple_pattern_check('/', pattern, value);
|
||||
}
|
||||
|
||||
int bus_message_type_from_string(const char *s, uint8_t *u) {
|
||||
if (streq(s, "signal"))
|
||||
*u = SD_BUS_MESSAGE_TYPE_SIGNAL;
|
||||
else if (streq(s, "method_call"))
|
||||
*u = SD_BUS_MESSAGE_TYPE_METHOD_CALL;
|
||||
else if (streq(s, "error"))
|
||||
*u = SD_BUS_MESSAGE_TYPE_METHOD_ERROR;
|
||||
else if (streq(s, "method_return"))
|
||||
*u = SD_BUS_MESSAGE_TYPE_METHOD_RETURN;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
|
||||
#include "sd-bus.h"
|
||||
#include "bus-error.h"
|
||||
#include "bus-match.h"
|
||||
|
||||
struct reply_callback {
|
||||
sd_message_handler_t callback;
|
||||
@@ -97,6 +98,7 @@ struct sd_bus {
|
||||
|
||||
char *unique_name;
|
||||
|
||||
struct bus_match_node match_callbacks;
|
||||
Prioq *reply_callbacks_prioq;
|
||||
Hashmap *reply_callbacks;
|
||||
LIST_HEAD(struct filter_callback, filter_callbacks);
|
||||
@@ -166,6 +168,14 @@ 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 namespace_complex_pattern(const char *pattern, const char *value);
|
||||
bool path_complex_pattern(const char *pattern, const char *value);
|
||||
|
||||
bool namespace_simple_pattern(const char *pattern, const char *value);
|
||||
bool path_simple_pattern(const char *pattern, const char *value);
|
||||
|
||||
int bus_message_type_from_string(const char *s, uint8_t *u);
|
||||
|
||||
#define error_name_is_valid interface_name_is_valid
|
||||
|
||||
int bus_ensure_running(sd_bus *bus);
|
||||
|
||||
978
src/libsystemd-bus/bus-match.c
Normal file
978
src/libsystemd-bus/bus-match.c
Normal file
File diff suppressed because it is too large
Load Diff
81
src/libsystemd-bus/bus-match.h
Normal file
81
src/libsystemd-bus/bus-match.h
Normal file
@@ -0,0 +1,81 @@
|
||||
/*-*- 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 "hashmap.h"
|
||||
|
||||
#include "sd-bus.h"
|
||||
|
||||
enum bus_match_node_type {
|
||||
BUS_MATCH_ROOT,
|
||||
BUS_MATCH_VALUE,
|
||||
BUS_MATCH_LEAF,
|
||||
|
||||
/* The following are all different kinds of compare nodes */
|
||||
BUS_MATCH_MESSAGE_TYPE,
|
||||
BUS_MATCH_SENDER,
|
||||
BUS_MATCH_DESTINATION,
|
||||
BUS_MATCH_INTERFACE,
|
||||
BUS_MATCH_MEMBER,
|
||||
BUS_MATCH_PATH,
|
||||
BUS_MATCH_PATH_NAMESPACE,
|
||||
BUS_MATCH_ARG,
|
||||
BUS_MATCH_ARG_LAST = BUS_MATCH_ARG + 63,
|
||||
BUS_MATCH_ARG_PATH,
|
||||
BUS_MATCH_ARG_PATH_LAST = BUS_MATCH_ARG_PATH + 63,
|
||||
BUS_MATCH_ARG_NAMESPACE,
|
||||
BUS_MATCH_ARG_NAMESPACE_LAST = BUS_MATCH_ARG_NAMESPACE + 63,
|
||||
_BUS_MATCH_NODE_TYPE_MAX,
|
||||
_BUS_MATCH_NODE_TYPE_INVALID = -1
|
||||
};
|
||||
|
||||
struct bus_match_node {
|
||||
enum bus_match_node_type type;
|
||||
struct bus_match_node *parent, *next, *prev, *child;
|
||||
|
||||
union {
|
||||
struct {
|
||||
uint8_t u8;
|
||||
char *str;
|
||||
} value;
|
||||
struct {
|
||||
sd_message_handler_t callback;
|
||||
void *userdata;
|
||||
} leaf;
|
||||
struct {
|
||||
/* If this is set, then the child is NULL */
|
||||
Hashmap *children;
|
||||
} compare;
|
||||
};
|
||||
};
|
||||
|
||||
int bus_match_run(sd_bus *bus, struct bus_match_node *root, int ret, sd_bus_message *m);
|
||||
|
||||
int bus_match_add(struct bus_match_node *root, const char *match, sd_message_handler_t callback, void *userdata, struct bus_match_node **ret);
|
||||
int bus_match_remove(struct bus_match_node *root, const char *match, sd_message_handler_t callback, void *userdata);
|
||||
|
||||
void bus_match_free(struct bus_match_node *node);
|
||||
|
||||
void bus_match_dump(struct bus_match_node *node, unsigned level);
|
||||
|
||||
const char* bus_match_node_type_to_string(enum bus_match_node_type t, char buf[], size_t l);
|
||||
enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n);
|
||||
@@ -3002,3 +3002,38 @@ int bus_message_read_strv_extend(sd_bus_message *m, char ***l) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* bus_message_get_arg(sd_bus_message *m, unsigned i) {
|
||||
int r;
|
||||
const char *t;
|
||||
char type;
|
||||
|
||||
assert(m);
|
||||
|
||||
r = sd_bus_message_rewind(m, true);
|
||||
if (r < 0)
|
||||
return NULL;
|
||||
|
||||
while (i > 0) {
|
||||
r = sd_bus_message_peek_type(m, &type, NULL);
|
||||
if (r < 0)
|
||||
return NULL;
|
||||
|
||||
if (type != SD_BUS_TYPE_STRING &&
|
||||
type != SD_BUS_TYPE_OBJECT_PATH &&
|
||||
type != SD_BUS_TYPE_SIGNATURE)
|
||||
return NULL;
|
||||
|
||||
r = sd_bus_message_read_basic(m, type, &t);
|
||||
if (r < 0)
|
||||
return NULL;
|
||||
|
||||
i--;
|
||||
}
|
||||
|
||||
r = sd_bus_message_rewind(m, true);
|
||||
if (r < 0)
|
||||
return NULL;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
@@ -142,3 +142,5 @@ int bus_message_from_malloc(
|
||||
const struct ucred *ucred,
|
||||
const char *label,
|
||||
sd_bus_message **ret);
|
||||
|
||||
const char* bus_message_get_arg(sd_bus_message *m, unsigned i);
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "bus-message.h"
|
||||
#include "bus-type.h"
|
||||
#include "bus-socket.h"
|
||||
#include "bus-control.h"
|
||||
|
||||
static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec);
|
||||
|
||||
@@ -84,6 +85,8 @@ static void bus_free(sd_bus *b) {
|
||||
|
||||
hashmap_free(b->object_callbacks);
|
||||
|
||||
bus_match_free(&b->match_callbacks);
|
||||
|
||||
free(b);
|
||||
}
|
||||
|
||||
@@ -1493,6 +1496,9 @@ static int process_filter(sd_bus *bus, sd_bus_message *m) {
|
||||
struct filter_callback *l;
|
||||
int r;
|
||||
|
||||
assert(bus);
|
||||
assert(m);
|
||||
|
||||
LIST_FOREACH(callbacks, l, bus->filter_callbacks) {
|
||||
r = l->callback(bus, 0, m, l->userdata);
|
||||
if (r != 0)
|
||||
@@ -1502,6 +1508,13 @@ static int process_filter(sd_bus *bus, sd_bus_message *m) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int process_match(sd_bus *bus, sd_bus_message *m) {
|
||||
assert(bus);
|
||||
assert(m);
|
||||
|
||||
return bus_match_run(bus, &bus->match_callbacks, 0, m);
|
||||
}
|
||||
|
||||
static int process_builtin(sd_bus *bus, sd_bus_message *m) {
|
||||
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
|
||||
int r;
|
||||
@@ -1731,6 +1744,10 @@ static int process_message(sd_bus *bus, sd_bus_message *m) {
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
r = process_match(bus, m);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
r = process_builtin(bus, m);
|
||||
if (r != 0)
|
||||
return r;
|
||||
@@ -2057,3 +2074,48 @@ int sd_bus_add_fallback(sd_bus *bus, const char *prefix, sd_message_handler_t ca
|
||||
int sd_bus_remove_fallback(sd_bus *bus, const char *prefix, sd_message_handler_t callback, void *userdata) {
|
||||
return bus_remove_object(bus, true, prefix, callback, userdata);
|
||||
}
|
||||
|
||||
int sd_bus_add_match(sd_bus *bus, const char *match, sd_message_handler_t callback, void *userdata) {
|
||||
int r = 0;
|
||||
|
||||
if (!bus)
|
||||
return -EINVAL;
|
||||
if (!match)
|
||||
return -EINVAL;
|
||||
|
||||
if (bus->bus_client) {
|
||||
r = bus_add_match_internal(bus, match);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
r = bus_match_add(&bus->match_callbacks, match, callback, userdata, NULL);
|
||||
if (r < 0) {
|
||||
|
||||
if (bus->bus_client)
|
||||
bus_remove_match_internal(bus, match);
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int sd_bus_remove_match(sd_bus *bus, const char *match, sd_message_handler_t callback, void *userdata) {
|
||||
int r = 0, q = 0;
|
||||
|
||||
if (!bus)
|
||||
return -EINVAL;
|
||||
if (!match)
|
||||
return -EINVAL;
|
||||
|
||||
if (bus->bus_client)
|
||||
r = bus_remove_match_internal(bus, match);
|
||||
|
||||
if (callback)
|
||||
q = bus_match_remove(&bus->match_callbacks, match, callback, userdata);
|
||||
|
||||
if (r < 0)
|
||||
return r;
|
||||
return q;
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
/* TODO:
|
||||
* - allow installing match callbacks
|
||||
* - sd_message_handler_t needs to be renamed to sd_bus_message_handler_t
|
||||
*
|
||||
* Later:
|
||||
* - add page donation logic
|
||||
@@ -98,6 +98,9 @@ int sd_bus_remove_object(sd_bus *bus, const char *path, sd_message_handler_t cal
|
||||
int sd_bus_add_fallback(sd_bus *bus, const char *prefix, sd_message_handler_t callback, void *userdata);
|
||||
int sd_bus_remove_fallback(sd_bus *bus, const char *prefix, sd_message_handler_t callback, void *userdata);
|
||||
|
||||
int sd_bus_add_match(sd_bus *bus, const char *match, sd_message_handler_t callback, void *userdata);
|
||||
int sd_bus_remove_match(sd_bus *bus, const char *match, sd_message_handler_t callback, void *userdata);
|
||||
|
||||
/* Message object */
|
||||
|
||||
int sd_bus_message_new_signal(sd_bus *bus, const char *path, const char *interface, const char *member, sd_bus_message **m);
|
||||
@@ -154,8 +157,6 @@ int sd_bus_list_names(sd_bus *bus, char ***l);
|
||||
int sd_bus_get_owner(sd_bus *bus, const char *name, char **owner);
|
||||
int sd_bus_get_owner_uid(sd_bus *bus, const char *name, uid_t *uid);
|
||||
int sd_bus_get_owner_pid(sd_bus *bus, const char *name, pid_t *pid);
|
||||
int sd_bus_add_match(sd_bus *bus, const char *match);
|
||||
int sd_bus_remove_match(sd_bus *bus, const char *match);
|
||||
|
||||
/* Error structures */
|
||||
|
||||
|
||||
@@ -32,6 +32,13 @@
|
||||
#include "sd-bus.h"
|
||||
#include "bus-message.h"
|
||||
#include "bus-error.h"
|
||||
#include "bus-match.h"
|
||||
#include "bus-internal.h"
|
||||
|
||||
static int match_callback(sd_bus *bus, int error, sd_bus_message *m, void *userdata) {
|
||||
log_info("Match triggered! interface=%s member=%s", strna(sd_bus_message_get_interface(m)), strna(sd_bus_message_get_member(m)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int object_callback(sd_bus *bus, int error, sd_bus_message *m, void *userdata) {
|
||||
int r;
|
||||
@@ -106,6 +113,20 @@ static int server_init(sd_bus **_bus) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = sd_bus_add_match(bus, "type='signal',interface='foo.bar',member='Notify'", match_callback, NULL);
|
||||
if (r < 0) {
|
||||
log_error("Failed to add match: %s", strerror(-r));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = sd_bus_add_match(bus, "type='signal',interface='org.freedesktop.DBus',member='NameOwnerChanged'", match_callback, NULL);
|
||||
if (r < 0) {
|
||||
log_error("Failed to add match: %s", strerror(-r));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
bus_match_dump(&bus->match_callbacks, 0);
|
||||
|
||||
*_bus = bus;
|
||||
return 0;
|
||||
|
||||
@@ -424,6 +445,26 @@ static void* client2(void*p) {
|
||||
sd_bus_message_unref(m);
|
||||
m = NULL;
|
||||
|
||||
r = sd_bus_message_new_signal(
|
||||
bus,
|
||||
"/foobar",
|
||||
"foo.bar",
|
||||
"Notify",
|
||||
&m);
|
||||
if (r < 0) {
|
||||
log_error("Failed to allocate signal: %s", strerror(-r));
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = sd_bus_send(bus, m, NULL);
|
||||
if (r < 0) {
|
||||
log_error("Failed to issue signal: %s", bus_error_message(&error, -r));
|
||||
goto finish;
|
||||
}
|
||||
|
||||
sd_bus_message_unref(m);
|
||||
m = NULL;
|
||||
|
||||
r = sd_bus_message_new_method_call(
|
||||
bus,
|
||||
"org.freedesktop.systemd.test",
|
||||
|
||||
114
src/libsystemd-bus/test-bus-match.c
Normal file
114
src/libsystemd-bus/test-bus-match.c
Normal file
@@ -0,0 +1,114 @@
|
||||
/*-*- 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 "log.h"
|
||||
#include "util.h"
|
||||
#include "macro.h"
|
||||
|
||||
#include "bus-match.h"
|
||||
#include "bus-message.h"
|
||||
|
||||
static bool mask[32];
|
||||
|
||||
static int filter(sd_bus *b, int ret, sd_bus_message *m, void *userdata) {
|
||||
log_info("Ran %i", PTR_TO_INT(userdata));
|
||||
mask[PTR_TO_INT(userdata)] = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool mask_contains(unsigned a[], unsigned n) {
|
||||
unsigned i, j;
|
||||
|
||||
for (i = 0; i < ELEMENTSOF(mask); i++) {
|
||||
bool found = false;
|
||||
|
||||
for (j = 0; j < n; j++)
|
||||
if (a[j] == i) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (found != mask[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
struct bus_match_node root;
|
||||
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
|
||||
enum bus_match_node_type i;
|
||||
|
||||
zero(root);
|
||||
root.type = BUS_MATCH_ROOT;
|
||||
|
||||
assert_se(bus_match_add(&root, "arg3='wal\\'do',sender='foo',type='signal',interface='bar',", filter, INT_TO_PTR(1), NULL) >= 0);
|
||||
assert_se(bus_match_add(&root, "arg3='wal\\'do2',sender='foo',type='signal',interface='bar',", filter, INT_TO_PTR(2), NULL) >= 0);
|
||||
assert_se(bus_match_add(&root, "arg4='test',sender='foo',type='signal',interface='bar',", filter, INT_TO_PTR(3), NULL) >= 0);
|
||||
assert_se(bus_match_add(&root, "arg4='test',sender='foo',type='method_call',interface='bar',", filter, INT_TO_PTR(4), NULL) >= 0);
|
||||
assert_se(bus_match_add(&root, "", filter, INT_TO_PTR(5), NULL) >= 0);
|
||||
assert_se(bus_match_add(&root, "interface='quux'", filter, INT_TO_PTR(6), NULL) >= 0);
|
||||
assert_se(bus_match_add(&root, "interface='bar'", filter, INT_TO_PTR(7), NULL) >= 0);
|
||||
assert_se(bus_match_add(&root, "member='waldo',path='/foo/bar'", filter, INT_TO_PTR(8), NULL) >= 0);
|
||||
assert_se(bus_match_add(&root, "path='/foo/bar'", filter, INT_TO_PTR(9), NULL) >= 0);
|
||||
assert_se(bus_match_add(&root, "path_namespace='/foo'", filter, INT_TO_PTR(10), NULL) >= 0);
|
||||
assert_se(bus_match_add(&root, "path_namespace='/foo/quux'", filter, INT_TO_PTR(11), NULL) >= 0);
|
||||
assert_se(bus_match_add(&root, "arg2='two'", filter, INT_TO_PTR(12), NULL) >= 0);
|
||||
assert_se(bus_match_add(&root, "member='waldo',arg3path='/prefix/'", filter, INT_TO_PTR(13), NULL) >= 0);
|
||||
assert_se(bus_match_add(&root, "member='waldo',path='/foo/bar',arg4namespace='prefix'", filter, INT_TO_PTR(14), NULL) >= 0);
|
||||
|
||||
bus_match_dump(&root, 0);
|
||||
|
||||
assert_se(sd_bus_message_new_signal(NULL, "/foo/bar", "bar", "waldo", &m) >= 0);
|
||||
assert_se(sd_bus_message_append(m, "ssss", "one", "two", "/prefix/three", "prefix.four") >= 0);
|
||||
assert_se(bus_message_seal(m, 1) >= 0);
|
||||
|
||||
zero(mask);
|
||||
assert_se(bus_match_run(NULL, &root, 0, m) == 0);
|
||||
assert_se(mask_contains((unsigned[]) { 9, 8, 7, 5, 10, 12, 13, 14 }, 8));
|
||||
|
||||
assert_se(bus_match_remove(&root, "member='waldo',path='/foo/bar'", filter, INT_TO_PTR(8)) > 0);
|
||||
assert_se(bus_match_remove(&root, "arg3path='/prefix/',member='waldo'", filter, INT_TO_PTR(13)) > 0);
|
||||
assert_se(bus_match_remove(&root, "interface='barxx'", filter, INT_TO_PTR(7)) == 0);
|
||||
|
||||
bus_match_dump(&root, 0);
|
||||
|
||||
zero(mask);
|
||||
assert_se(bus_match_run(NULL, &root, 0, m) == 0);
|
||||
assert_se(mask_contains((unsigned[]) { 9, 5, 10, 12, 14, 7 }, 6));
|
||||
|
||||
for (i = 0; i < _BUS_MATCH_NODE_TYPE_MAX; i++) {
|
||||
char buf[32];
|
||||
const char *x;
|
||||
|
||||
assert_se(x = bus_match_node_type_to_string(i, buf, sizeof(buf)));
|
||||
|
||||
if (i >= BUS_MATCH_MESSAGE_TYPE)
|
||||
assert_se(bus_match_node_type_from_string(x, strlen(x)) == i);
|
||||
}
|
||||
|
||||
bus_match_free(&root);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#include "log.h"
|
||||
#include "bus-signature.h"
|
||||
#include "bus-internal.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
@@ -81,5 +82,35 @@ int main(int argc, char *argv[]) {
|
||||
assert_se(signature_is_valid("(((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))", false));
|
||||
assert_se(!signature_is_valid("((((((((((((((((((((((((((((((((()))))))))))))))))))))))))))))))))", false));
|
||||
|
||||
assert_se(namespace_complex_pattern("", ""));
|
||||
assert_se(namespace_complex_pattern("foobar", "foobar"));
|
||||
assert_se(namespace_complex_pattern("foobar.waldo", "foobar.waldo"));
|
||||
assert_se(namespace_complex_pattern("foobar.", "foobar.waldo"));
|
||||
assert_se(namespace_complex_pattern("foobar.waldo", "foobar."));
|
||||
assert_se(!namespace_complex_pattern("foobar.waldo", "foobar"));
|
||||
assert_se(!namespace_complex_pattern("foobar", "foobar.waldo"));
|
||||
assert_se(!namespace_complex_pattern("", "foo"));
|
||||
assert_se(!namespace_complex_pattern("foo", ""));
|
||||
assert_se(!namespace_complex_pattern("foo.", ""));
|
||||
|
||||
assert_se(path_complex_pattern("", ""));
|
||||
assert_se(path_complex_pattern("", "/"));
|
||||
assert_se(path_complex_pattern("/", ""));
|
||||
assert_se(path_complex_pattern("/", "/"));
|
||||
assert_se(path_complex_pattern("/foobar/", "/"));
|
||||
assert_se(path_complex_pattern("/foobar/", "/foobar"));
|
||||
assert_se(path_complex_pattern("/foobar", "/foobar"));
|
||||
assert_se(path_complex_pattern("/foobar", "/foobar/"));
|
||||
assert_se(!path_complex_pattern("/foobar", "/foobar/waldo"));
|
||||
assert_se(path_complex_pattern("/foobar/", "/foobar/waldo"));
|
||||
|
||||
assert_se(namespace_simple_pattern("", ""));
|
||||
assert_se(namespace_simple_pattern("foobar", "foobar"));
|
||||
assert_se(namespace_simple_pattern("foobar.waldo", "foobar.waldo"));
|
||||
assert_se(namespace_simple_pattern("foobar", "foobar.waldo"));
|
||||
assert_se(!namespace_simple_pattern("foobar.waldo", "foobar"));
|
||||
assert_se(!namespace_simple_pattern("", "foo"));
|
||||
assert_se(!namespace_simple_pattern("foo", ""));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -5855,3 +5855,20 @@ char *strrep(const char *s, unsigned n) {
|
||||
*p = 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
void* greedy_realloc(void **p, size_t *allocated, size_t need) {
|
||||
size_t a;
|
||||
void *q;
|
||||
|
||||
if (*allocated >= need)
|
||||
return *p;
|
||||
|
||||
a = MAX(64, need * 2);
|
||||
q = realloc(*p, a);
|
||||
if (!q)
|
||||
return NULL;
|
||||
|
||||
*p = q;
|
||||
*allocated = a;
|
||||
return q;
|
||||
}
|
||||
|
||||
@@ -613,3 +613,5 @@ void *unhexmem(const char *p, size_t l);
|
||||
|
||||
char *strextend(char **x, ...);
|
||||
char *strrep(const char *s, unsigned n);
|
||||
|
||||
void* greedy_realloc(void **p, size_t *allocated, size_t need);
|
||||
|
||||
Reference in New Issue
Block a user