mirror of
https://github.com/systemd/systemd-stable.git
synced 2024-12-22 13:33:56 +03:00
bus: add basic implementation of a native bus client library
This commit is contained in:
parent
76f0199f2c
commit
de1c301ed1
2
.gitignore
vendored
2
.gitignore
vendored
@ -80,6 +80,8 @@
|
||||
/systemd-user-sessions
|
||||
/systemd-vconsole-setup
|
||||
/tags
|
||||
/test-bus-marshal
|
||||
/test-bus-signature
|
||||
/test-calendarspec
|
||||
/test-catalog
|
||||
/test-cgroup
|
||||
|
44
Makefile.am
44
Makefile.am
@ -1638,6 +1638,50 @@ EXTRA_DIST += \
|
||||
src/libsystemd-daemon/libsystemd-daemon.pc.in \
|
||||
src/libsystemd-daemon/libsystemd-daemon.sym
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
libsystemd_bus_la_SOURCES = \
|
||||
src/libsystemd-bus/sd-bus.c \
|
||||
src/libsystemd-bus/sd-bus.h \
|
||||
src/libsystemd-bus/sd-bus-protocol.h \
|
||||
src/libsystemd-bus/bus-control.c \
|
||||
src/libsystemd-bus/bus-error.c \
|
||||
src/libsystemd-bus/bus-error.h \
|
||||
src/libsystemd-bus/bus-internal.c \
|
||||
src/libsystemd-bus/bus-internal.h \
|
||||
src/libsystemd-bus/bus-message.c \
|
||||
src/libsystemd-bus/bus-message.h \
|
||||
src/libsystemd-bus/bus-signature.c \
|
||||
src/libsystemd-bus/bus-type.c \
|
||||
src/libsystemd-bus/bus-type.h
|
||||
|
||||
noinst_LTLIBRARIES += \
|
||||
libsystemd-bus.la
|
||||
|
||||
noinst_tests += \
|
||||
test-bus-marshal \
|
||||
test-bus-signature
|
||||
|
||||
test_bus_marshal_SOURCES = \
|
||||
src/libsystemd-bus/test-bus-marshal.c
|
||||
|
||||
test_bus_marshal_LDADD = \
|
||||
libsystemd-shared.la \
|
||||
libsystemd-bus.la \
|
||||
$(GLIB_LIBS) \
|
||||
$(DBUS_LIBS)
|
||||
|
||||
test_bus_marshal_CFLAGS = \
|
||||
$(AM_CFLAGS) \
|
||||
$(GLIB_CFLAGS) \
|
||||
$(DBUS_CFLAGS)
|
||||
|
||||
test_bus_signature_SOURCES = \
|
||||
src/libsystemd-bus/test-bus-signature.c
|
||||
|
||||
test_bus_signature_LDADD = \
|
||||
libsystemd-shared.la \
|
||||
libsystemd-bus.la
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
if ENABLE_GTK_DOC
|
||||
SUBDIRS += \
|
||||
|
@ -724,9 +724,11 @@ AM_CONDITIONAL(ENABLE_FIRMWARE, [test "x${FIRMWARE_PATH}" != "x"])
|
||||
AC_ARG_ENABLE([gudev],
|
||||
AS_HELP_STRING([--disable-gudev], [disable Gobject libudev support @<:@default=enabled@:>@]),
|
||||
[], [enable_gudev=yes])
|
||||
AS_IF([test "x$enable_gudev" = "xyes"], [ PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.22.0 gobject-2.0 >= 2.22.0]) ])
|
||||
AS_IF([test "x$enable_gudev" = "xyes"], [ PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.22.0 gobject-2.0 >= 2.22.0 gio-2.0]) ])
|
||||
AM_CONDITIONAL([ENABLE_GUDEV], [test "x$enable_gudev" = "xyes"])
|
||||
|
||||
AS_IF([test "x$enable_gudev" = "xyes"], [ AC_DEFINE(HAVE_GLIB, 1, [Define if glib is available]) ])
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
AC_ARG_ENABLE([keymap],
|
||||
AS_HELP_STRING([--disable-keymap], [disable keymap fixup support @<:@default=enabled@:>@]),
|
||||
|
1
src/libsystemd-bus/Makefile
Symbolic link
1
src/libsystemd-bus/Makefile
Symbolic link
@ -0,0 +1 @@
|
||||
../Makefile
|
322
src/libsystemd-bus/bus-control.c
Normal file
322
src/libsystemd-bus/bus-control.c
Normal file
@ -0,0 +1,322 @@
|
||||
/*-*- 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 <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "strv.h"
|
||||
|
||||
#include "sd-bus.h"
|
||||
#include "bus-internal.h"
|
||||
#include "bus-message.h"
|
||||
|
||||
const char *sd_bus_get_unique_name(sd_bus *bus) {
|
||||
if (!bus)
|
||||
return NULL;
|
||||
|
||||
return bus->unique_name;
|
||||
}
|
||||
|
||||
int sd_bus_request_name(sd_bus *bus, const char *name, int flags) {
|
||||
_cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
|
||||
uint32_t ret;
|
||||
int r;
|
||||
|
||||
if (!bus)
|
||||
return -EINVAL;
|
||||
if (!name)
|
||||
return -EINVAL;
|
||||
|
||||
r = sd_bus_message_new_method_call(
|
||||
bus,
|
||||
"org.freedesktop.DBus",
|
||||
"/",
|
||||
"org.freedesktop.DBus",
|
||||
"RequestName",
|
||||
&m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_append(m, "su", name, flags);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_send_with_reply_and_block(bus, m, (uint64_t) -1, NULL, &reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_read(reply, "u", &ret);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sd_bus_release_name(sd_bus *bus, const char *name) {
|
||||
_cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
|
||||
uint32_t ret;
|
||||
int r;
|
||||
|
||||
if (!bus)
|
||||
return -EINVAL;
|
||||
if (!name)
|
||||
return -EINVAL;
|
||||
|
||||
r = sd_bus_message_new_method_call(
|
||||
bus,
|
||||
"org.freedesktop.DBus",
|
||||
"/",
|
||||
"org.freedesktop.DBus",
|
||||
"ReleaseName",
|
||||
&m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_append(m, "s", name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_send_with_reply_and_block(bus, m, (uint64_t) -1, NULL, &reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_read(reply, "u", &ret);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sd_bus_list_names(sd_bus *bus, char ***l) {
|
||||
_cleanup_bus_message_unref_ sd_bus_message *m1 = NULL, *reply1 = NULL, *m2 = NULL, *reply2 = NULL;
|
||||
_cleanup_strv_free_ char **a = NULL, **b = NULL;
|
||||
char **x = NULL;
|
||||
int r;
|
||||
|
||||
if (!bus)
|
||||
return -EINVAL;
|
||||
if (!l)
|
||||
return -EINVAL;
|
||||
|
||||
r = sd_bus_message_new_method_call(
|
||||
bus,
|
||||
"org.freedesktop.DBus",
|
||||
"/",
|
||||
"org.freedesktop.DBus",
|
||||
"ListNames",
|
||||
&m1);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_new_method_call(
|
||||
bus,
|
||||
"org.freedesktop.DBus",
|
||||
"/",
|
||||
"org.freedesktop.DBus",
|
||||
"ListActivatableNames",
|
||||
&m2);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_send_with_reply_and_block(bus, m1, (uint64_t) -1, NULL, &reply1);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_send_with_reply_and_block(bus, m2, (uint64_t) -1, NULL, &reply2);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_read(reply1, "as", &a);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_read(reply2, "as", &b);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
x = strv_merge(a, b);
|
||||
if (!x)
|
||||
return -ENOMEM;
|
||||
|
||||
*l = strv_uniq(x);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_bus_get_owner(sd_bus *bus, const char *name, char **owner) {
|
||||
_cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
|
||||
int r;
|
||||
|
||||
if (!bus)
|
||||
return -EINVAL;
|
||||
if (!name)
|
||||
return -EINVAL;
|
||||
|
||||
r = sd_bus_message_new_method_call(
|
||||
bus,
|
||||
"org.freedesktop.DBus",
|
||||
"/",
|
||||
"org.freedesktop.DBus",
|
||||
"GetNameOwner",
|
||||
&m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_append(m, "s", name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_send_with_reply_and_block(bus, m, (uint64_t) -1, NULL, &reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_bus_message_read(reply, "s", owner);
|
||||
}
|
||||
|
||||
int sd_bus_get_owner_uid(sd_bus *bus, const char *name, uid_t *uid) {
|
||||
_cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
|
||||
uint32_t u;
|
||||
int r;
|
||||
|
||||
if (!bus)
|
||||
return -EINVAL;
|
||||
if (!name)
|
||||
return -EINVAL;
|
||||
if (!uid)
|
||||
return -EINVAL;
|
||||
|
||||
r = sd_bus_message_new_method_call(
|
||||
bus,
|
||||
"org.freedesktop.DBus",
|
||||
"/",
|
||||
"org.freedesktop.DBus",
|
||||
"GetConnectionUnixUser",
|
||||
&m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_append(m, "s", name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_send_with_reply_and_block(bus, m, (uint64_t) -1, NULL, &reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_read(reply, "u", &u);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*uid = (uid_t) u;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_bus_get_owner_pid(sd_bus *bus, const char *name, pid_t *pid) {
|
||||
_cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
|
||||
uint32_t u;
|
||||
int r;
|
||||
|
||||
if (!bus)
|
||||
return -EINVAL;
|
||||
if (!name)
|
||||
return -EINVAL;
|
||||
if (!pid)
|
||||
return -EINVAL;
|
||||
|
||||
r = sd_bus_message_new_method_call(
|
||||
bus,
|
||||
"org.freedesktop.DBus",
|
||||
"/",
|
||||
"org.freedesktop.DBus",
|
||||
"GetConnectionUnixUser",
|
||||
&m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_append(m, "s", name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_send_with_reply_and_block(bus, m, (uint64_t) -1, NULL, &reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_read(reply, "u", &u);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (u == 0)
|
||||
return -EIO;
|
||||
|
||||
*pid = (uid_t) u;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_bus_add_match(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;
|
||||
|
||||
r = sd_bus_message_new_method_call(
|
||||
bus,
|
||||
"org.freedesktop.DBus",
|
||||
"/",
|
||||
"org.freedesktop.DBus",
|
||||
"AddMatch",
|
||||
&m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_append(m, "s", match);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_bus_send_with_reply_and_block(bus, m, (uint64_t) -1, NULL, &reply);
|
||||
}
|
||||
|
||||
int sd_bus_remove_match(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;
|
||||
|
||||
r = sd_bus_message_new_method_call(
|
||||
bus,
|
||||
"org.freedesktop.DBus",
|
||||
"/",
|
||||
"org.freedesktop.DBus",
|
||||
"RemoveMatch",
|
||||
&m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_append(m, "s", match);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_bus_send_with_reply_and_block(bus, m, (uint64_t) -1, NULL, &reply);
|
||||
}
|
166
src/libsystemd-bus/bus-error.c
Normal file
166
src/libsystemd-bus/bus-error.c
Normal file
@ -0,0 +1,166 @@
|
||||
/*-*- 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 <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#include "sd-bus.h"
|
||||
#include "bus-error.h"
|
||||
|
||||
void sd_bus_error_free(sd_bus_error *e) {
|
||||
if (!e)
|
||||
return;
|
||||
|
||||
if (e->need_free) {
|
||||
free((void*) e->name);
|
||||
free((void*) e->message);
|
||||
}
|
||||
|
||||
e->name = e->message = NULL;
|
||||
e->need_free = false;
|
||||
}
|
||||
|
||||
int sd_bus_error_set(sd_bus_error *e, const char *name, const char *format, ...) {
|
||||
char *n, *m = NULL;
|
||||
va_list ap;
|
||||
int r;
|
||||
|
||||
if (!e)
|
||||
return 0;
|
||||
if (sd_bus_error_is_set(e))
|
||||
return -EINVAL;
|
||||
if (!name)
|
||||
return -EINVAL;
|
||||
|
||||
n = strdup(name);
|
||||
if (!n)
|
||||
return -ENOMEM;
|
||||
|
||||
if (format) {
|
||||
va_start(ap, format);
|
||||
r = vasprintf(&m, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (r < 0) {
|
||||
free(n);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
e->name = n;
|
||||
e->message = m;
|
||||
e->need_free = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_bus_error_copy(sd_bus_error *dest, const sd_bus_error *e) {
|
||||
if (!dest)
|
||||
return 0;
|
||||
if (sd_bus_error_is_set(dest))
|
||||
return -EINVAL;
|
||||
if (!sd_bus_error_is_set(e))
|
||||
return 0;
|
||||
|
||||
if (e->need_free) {
|
||||
char *x, *y = NULL;
|
||||
|
||||
x = strdup(e->name);
|
||||
if (!x)
|
||||
return -ENOMEM;
|
||||
|
||||
if (e->message) {
|
||||
y = strdup(e->message);
|
||||
if (!y) {
|
||||
free(x);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
dest->name = x;
|
||||
dest->message = y;
|
||||
dest->need_free = true;
|
||||
} else
|
||||
*dest = *e;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sd_bus_error_set_const(sd_bus_error *e, const char *name, const char *message) {
|
||||
if (!e)
|
||||
return;
|
||||
if (sd_bus_error_is_set(e))
|
||||
return;
|
||||
|
||||
e->name = name;
|
||||
e->message = message;
|
||||
}
|
||||
|
||||
int sd_bus_error_is_set(const sd_bus_error *e) {
|
||||
if (!e)
|
||||
return 0;
|
||||
|
||||
return e->name || e->message || e->need_free;
|
||||
}
|
||||
|
||||
int sd_bus_error_has_name(const sd_bus_error *e, const char *name) {
|
||||
if (!e)
|
||||
return 0;
|
||||
|
||||
return streq_ptr(e->name, name);
|
||||
}
|
||||
|
||||
int bus_error_to_errno(const sd_bus_error* e) {
|
||||
|
||||
/* Better replce this with a gperf table */
|
||||
|
||||
if (!e->name)
|
||||
return -EIO;
|
||||
|
||||
if (streq(e->name, "org.freedesktop.DBus.Error.NoMemory"))
|
||||
return -ENOMEM;
|
||||
|
||||
if (streq(e->name, "org.freedesktop.DBus.Error.AuthFailed") ||
|
||||
streq(e->name, "org.freedesktop.DBus.Error.AccessDenied"))
|
||||
return -EPERM;
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
int bus_error_from_errno(sd_bus_error *e, int error) {
|
||||
if (!e)
|
||||
return error;
|
||||
|
||||
if (error == -ENOMEM)
|
||||
sd_bus_error_set_const(e, "org.freedesktop.DBus.Error.NoMemory", strerror(-error));
|
||||
else if (error == -EPERM || error == EACCES)
|
||||
sd_bus_error_set_const(e, "org.freedesktop.DBus.Error.AccessDenied", strerror(-error));
|
||||
else
|
||||
sd_bus_error_set_const(e, "org.freedesktop.DBus.Error.Failed", "Operation failed");
|
||||
|
||||
return error;
|
||||
}
|
27
src/libsystemd-bus/bus-error.h
Normal file
27
src/libsystemd-bus/bus-error.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_error_to_errno(const sd_bus_error *e);
|
||||
int bus_error_from_errno(sd_bus_error *e, int error);
|
22
src/libsystemd-bus/bus-internal.c
Normal file
22
src/libsystemd-bus/bus-internal.c
Normal file
@ -0,0 +1,22 @@
|
||||
/*-*- 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 "bus-internal.h"
|
101
src/libsystemd-bus/bus-internal.h
Normal file
101
src/libsystemd-bus/bus-internal.h
Normal file
@ -0,0 +1,101 @@
|
||||
/*-*- 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/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "hashmap.h"
|
||||
#include "list.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "sd-bus.h"
|
||||
#include "bus-error.h"
|
||||
|
||||
struct reply_callback {
|
||||
sd_message_handler_t callback;
|
||||
void *userdata;
|
||||
usec_t timeout;
|
||||
uint64_t serial;
|
||||
};
|
||||
|
||||
struct filter_callback {
|
||||
sd_message_handler_t callback;
|
||||
void *userdata;
|
||||
|
||||
LIST_FIELDS(struct filter_callback, callbacks);
|
||||
};
|
||||
|
||||
enum bus_state {
|
||||
BUS_OPENING,
|
||||
BUS_AUTHENTICATING,
|
||||
BUS_HELLO,
|
||||
BUS_RUNNING,
|
||||
BUS_CLOSED
|
||||
};
|
||||
|
||||
struct sd_bus {
|
||||
unsigned n_ref;
|
||||
enum bus_state state;
|
||||
int fd;
|
||||
int message_version;
|
||||
bool can_fds:1;
|
||||
bool send_hello:1;
|
||||
|
||||
void *rbuffer;
|
||||
size_t rbuffer_size;
|
||||
|
||||
sd_bus_message **rqueue;
|
||||
unsigned rqueue_size;
|
||||
|
||||
sd_bus_message **wqueue;
|
||||
unsigned wqueue_size;
|
||||
size_t windex;
|
||||
|
||||
uint64_t serial;
|
||||
|
||||
char *unique_name;
|
||||
|
||||
Hashmap *reply_callbacks;
|
||||
LIST_HEAD(struct filter_callback, filter_callbacks);
|
||||
|
||||
union {
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_un un;
|
||||
struct sockaddr_in in;
|
||||
struct sockaddr_in6 in6;
|
||||
} sockaddr;
|
||||
socklen_t sockaddr_size;
|
||||
|
||||
sd_id128_t peer;
|
||||
|
||||
char *address;
|
||||
unsigned address_index;
|
||||
|
||||
int last_connect_error;
|
||||
|
||||
struct iovec auth_iovec[3];
|
||||
unsigned auth_index;
|
||||
size_t auth_size;
|
||||
char *auth_uid;
|
||||
};
|
1413
src/libsystemd-bus/bus-message.c
Normal file
1413
src/libsystemd-bus/bus-message.c
Normal file
File diff suppressed because it is too large
Load Diff
120
src/libsystemd-bus/bus-message.h
Normal file
120
src/libsystemd-bus/bus-message.h
Normal file
@ -0,0 +1,120 @@
|
||||
/*-*- 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 <stdbool.h>
|
||||
#include <byteswap.h>
|
||||
|
||||
#include "macro.h"
|
||||
#include "sd-bus.h"
|
||||
|
||||
struct bus_container {
|
||||
char enclosing;
|
||||
|
||||
char *signature;
|
||||
unsigned index;
|
||||
|
||||
uint32_t *array_size;
|
||||
};
|
||||
|
||||
_packed_ struct bus_header {
|
||||
uint8_t endian;
|
||||
uint8_t type;
|
||||
uint8_t flags;
|
||||
uint8_t version;
|
||||
uint32_t body_size;
|
||||
uint32_t serial;
|
||||
uint32_t fields_size;
|
||||
};
|
||||
|
||||
struct sd_bus_message {
|
||||
unsigned n_ref;
|
||||
|
||||
uint32_t reply_serial;
|
||||
|
||||
const char *path;
|
||||
const char *interface;
|
||||
const char *member;
|
||||
const char *destination;
|
||||
const char *sender;
|
||||
const char *signature;
|
||||
|
||||
sd_bus_error error;
|
||||
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
pid_t pid;
|
||||
pid_t tid;
|
||||
|
||||
bool sealed:1;
|
||||
bool uid_valid:1;
|
||||
bool gid_valid:1;
|
||||
bool free_header:1;
|
||||
bool free_fields:1;
|
||||
bool free_body:1;
|
||||
|
||||
struct bus_header *header;
|
||||
void *fields;
|
||||
void *body;
|
||||
|
||||
uint32_t n_fds;
|
||||
int *fds;
|
||||
|
||||
struct bus_container root_container, *sub_containers;
|
||||
unsigned n_containers;
|
||||
|
||||
struct iovec iovec[4];
|
||||
unsigned n_iovec;
|
||||
};
|
||||
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
#define BUS_MESSAGE_NEED_BSWAP(m) ((m)->header->endian != SD_BUS_BIG_ENDIAN)
|
||||
#else
|
||||
#define BUS_MESSAGE_NEED_BSWAP(m) ((m)->header->endian != SD_BUS_LITTLE_ENDIAN)
|
||||
#endif
|
||||
|
||||
static inline uint32_t BUS_MESSAGE_BSWAP(sd_bus_message *m, uint32_t u) {
|
||||
return BUS_MESSAGE_NEED_BSWAP(m) ? bswap_32(u) : u;
|
||||
}
|
||||
|
||||
static inline uint32_t BUS_MESSAGE_SERIAL(sd_bus_message *m) {
|
||||
return BUS_MESSAGE_BSWAP(m, m->header->serial);
|
||||
}
|
||||
|
||||
static inline uint32_t BUS_MESSAGE_BODY_SIZE(sd_bus_message *m) {
|
||||
return BUS_MESSAGE_BSWAP(m, m->header->body_size);
|
||||
}
|
||||
|
||||
static inline uint32_t BUS_MESSAGE_FIELDS_SIZE(sd_bus_message *m) {
|
||||
return BUS_MESSAGE_BSWAP(m, m->header->fields_size);
|
||||
}
|
||||
|
||||
static inline void bus_message_unrefp(sd_bus_message **m) {
|
||||
sd_bus_message_unref(*m);
|
||||
}
|
||||
|
||||
#define _cleanup_bus_message_unref_ __attribute__((cleanup(bus_message_unrefp)))
|
||||
|
||||
int message_parse(sd_bus_message *m);
|
||||
int message_seal(sd_bus_message *m, uint64_t serial);
|
||||
void message_dump(sd_bus_message *m);
|
||||
int bus_message_get_blob(sd_bus_message *m, void **buffer, size_t *sz);
|
141
src/libsystemd-bus/bus-signature.c
Normal file
141
src/libsystemd-bus/bus-signature.c
Normal file
@ -0,0 +1,141 @@
|
||||
/*-*- 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 "bus-signature.h"
|
||||
#include "bus-type.h"
|
||||
|
||||
static int signature_element_length_internal(
|
||||
const char *s,
|
||||
bool allow_dict_entry,
|
||||
size_t *l) {
|
||||
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
|
||||
if (bus_type_is_basic(*s) || *s == SD_BUS_TYPE_VARIANT) {
|
||||
*l = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*s == SD_BUS_TYPE_ARRAY) {
|
||||
size_t t;
|
||||
|
||||
r = signature_element_length_internal(s + 1, true, &t);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*l = t + 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*s == SD_BUS_TYPE_STRUCT_BEGIN) {
|
||||
const char *p = s + 1;
|
||||
|
||||
while (*p != SD_BUS_TYPE_STRUCT_END) {
|
||||
size_t t;
|
||||
|
||||
r = signature_element_length_internal(p, false, &t);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
p += t;
|
||||
}
|
||||
|
||||
*l = p - s + 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*s == SD_BUS_TYPE_DICT_ENTRY_BEGIN && allow_dict_entry) {
|
||||
const char *p = s + 1;
|
||||
unsigned n = 0;
|
||||
|
||||
while (*p != SD_BUS_TYPE_DICT_ENTRY_END) {
|
||||
size_t t;
|
||||
|
||||
if (n == 0 && !bus_type_is_basic(*p))
|
||||
return -EINVAL;
|
||||
|
||||
r = signature_element_length_internal(p, false, &t);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
p += t;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (n != 2)
|
||||
return -EINVAL;
|
||||
|
||||
*l = p - s + 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bool signature_is_single(const char *s) {
|
||||
int r;
|
||||
size_t t;
|
||||
|
||||
assert(s);
|
||||
|
||||
r = signature_element_length(s, &t);
|
||||
if (r < 0)
|
||||
return false;
|
||||
|
||||
return s[t] == 0;
|
||||
}
|
||||
|
||||
bool signature_is_pair(const char *s) {
|
||||
assert(s);
|
||||
|
||||
if (!bus_type_is_basic(*s))
|
||||
return false;
|
||||
|
||||
return signature_is_single(s + 1);
|
||||
}
|
||||
|
||||
bool signature_is_valid(const char *s, bool allow_dict_entry) {
|
||||
const char *p;
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
|
||||
p = s;
|
||||
while (*p) {
|
||||
size_t t;
|
||||
|
||||
r = signature_element_length_internal(p, allow_dict_entry, &t);
|
||||
if (r < 0)
|
||||
return false;
|
||||
|
||||
p += t;
|
||||
}
|
||||
|
||||
return p - s <= 255;
|
||||
}
|
||||
|
||||
int signature_element_length(const char *s, size_t *l) {
|
||||
return signature_element_length_internal(s, true, l);
|
||||
}
|
31
src/libsystemd-bus/bus-signature.h
Normal file
31
src/libsystemd-bus/bus-signature.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*-*- 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 <stdbool.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
bool signature_is_single(const char *s);
|
||||
bool signature_is_pair(const char *s);
|
||||
bool signature_is_valid(const char *s, bool allow_dict_entry);
|
||||
|
||||
int signature_element_length(const char *s, size_t *l);
|
163
src/libsystemd-bus/bus-type.c
Normal file
163
src/libsystemd-bus/bus-type.c
Normal file
@ -0,0 +1,163 @@
|
||||
/*-*- 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 "bus-type.h"
|
||||
|
||||
bool bus_type_is_valid(char c) {
|
||||
static const char valid[] = {
|
||||
SD_BUS_TYPE_BYTE,
|
||||
SD_BUS_TYPE_BOOLEAN,
|
||||
SD_BUS_TYPE_INT16,
|
||||
SD_BUS_TYPE_UINT16,
|
||||
SD_BUS_TYPE_INT32,
|
||||
SD_BUS_TYPE_UINT32,
|
||||
SD_BUS_TYPE_INT64,
|
||||
SD_BUS_TYPE_UINT64,
|
||||
SD_BUS_TYPE_DOUBLE,
|
||||
SD_BUS_TYPE_STRING,
|
||||
SD_BUS_TYPE_OBJECT_PATH,
|
||||
SD_BUS_TYPE_SIGNATURE,
|
||||
SD_BUS_TYPE_ARRAY,
|
||||
SD_BUS_TYPE_VARIANT,
|
||||
SD_BUS_TYPE_STRUCT,
|
||||
SD_BUS_TYPE_DICT_ENTRY,
|
||||
SD_BUS_TYPE_UNIX_FD
|
||||
};
|
||||
|
||||
return !!memchr(valid, c, sizeof(valid));
|
||||
}
|
||||
|
||||
bool bus_type_is_valid_in_signature(char c) {
|
||||
static const char valid[] = {
|
||||
SD_BUS_TYPE_BYTE,
|
||||
SD_BUS_TYPE_BOOLEAN,
|
||||
SD_BUS_TYPE_INT16,
|
||||
SD_BUS_TYPE_UINT16,
|
||||
SD_BUS_TYPE_INT32,
|
||||
SD_BUS_TYPE_UINT32,
|
||||
SD_BUS_TYPE_INT64,
|
||||
SD_BUS_TYPE_UINT64,
|
||||
SD_BUS_TYPE_DOUBLE,
|
||||
SD_BUS_TYPE_STRING,
|
||||
SD_BUS_TYPE_OBJECT_PATH,
|
||||
SD_BUS_TYPE_SIGNATURE,
|
||||
SD_BUS_TYPE_ARRAY,
|
||||
SD_BUS_TYPE_VARIANT,
|
||||
SD_BUS_TYPE_STRUCT_BEGIN,
|
||||
SD_BUS_TYPE_STRUCT_END,
|
||||
SD_BUS_TYPE_DICT_ENTRY_BEGIN,
|
||||
SD_BUS_TYPE_DICT_ENTRY_END,
|
||||
SD_BUS_TYPE_UNIX_FD
|
||||
};
|
||||
|
||||
return !!memchr(valid, c, sizeof(valid));
|
||||
}
|
||||
|
||||
bool bus_type_is_basic(char c) {
|
||||
static const char valid[] = {
|
||||
SD_BUS_TYPE_BYTE,
|
||||
SD_BUS_TYPE_BOOLEAN,
|
||||
SD_BUS_TYPE_INT16,
|
||||
SD_BUS_TYPE_UINT16,
|
||||
SD_BUS_TYPE_INT32,
|
||||
SD_BUS_TYPE_UINT32,
|
||||
SD_BUS_TYPE_INT64,
|
||||
SD_BUS_TYPE_UINT64,
|
||||
SD_BUS_TYPE_DOUBLE,
|
||||
SD_BUS_TYPE_STRING,
|
||||
SD_BUS_TYPE_OBJECT_PATH,
|
||||
SD_BUS_TYPE_SIGNATURE,
|
||||
SD_BUS_TYPE_UNIX_FD
|
||||
};
|
||||
|
||||
return !!memchr(valid, c, sizeof(valid));
|
||||
}
|
||||
|
||||
bool bus_type_is_container(char c) {
|
||||
static const char valid[] = {
|
||||
SD_BUS_TYPE_ARRAY,
|
||||
SD_BUS_TYPE_VARIANT,
|
||||
SD_BUS_TYPE_STRUCT,
|
||||
SD_BUS_TYPE_DICT_ENTRY
|
||||
};
|
||||
|
||||
return !!memchr(valid, c, sizeof(valid));
|
||||
}
|
||||
|
||||
int bus_type_get_alignment(char c) {
|
||||
|
||||
switch (c) {
|
||||
case SD_BUS_TYPE_BYTE:
|
||||
case SD_BUS_TYPE_SIGNATURE:
|
||||
case SD_BUS_TYPE_VARIANT:
|
||||
return 1;
|
||||
|
||||
case SD_BUS_TYPE_INT16:
|
||||
case SD_BUS_TYPE_UINT16:
|
||||
return 2;
|
||||
|
||||
case SD_BUS_TYPE_BOOLEAN:
|
||||
case SD_BUS_TYPE_INT32:
|
||||
case SD_BUS_TYPE_UINT32:
|
||||
case SD_BUS_TYPE_STRING:
|
||||
case SD_BUS_TYPE_OBJECT_PATH:
|
||||
case SD_BUS_TYPE_ARRAY:
|
||||
case SD_BUS_TYPE_UNIX_FD:
|
||||
return 4;
|
||||
|
||||
case SD_BUS_TYPE_INT64:
|
||||
case SD_BUS_TYPE_UINT64:
|
||||
case SD_BUS_TYPE_DOUBLE:
|
||||
case SD_BUS_TYPE_STRUCT:
|
||||
case SD_BUS_TYPE_STRUCT_BEGIN:
|
||||
case SD_BUS_TYPE_DICT_ENTRY:
|
||||
case SD_BUS_TYPE_DICT_ENTRY_BEGIN:
|
||||
return 8;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int bus_type_get_size(char c) {
|
||||
|
||||
switch (c) {
|
||||
case SD_BUS_TYPE_BYTE:
|
||||
return 1;
|
||||
|
||||
case SD_BUS_TYPE_INT16:
|
||||
case SD_BUS_TYPE_UINT16:
|
||||
return 2;
|
||||
|
||||
case SD_BUS_TYPE_BOOLEAN:
|
||||
case SD_BUS_TYPE_INT32:
|
||||
case SD_BUS_TYPE_UINT32:
|
||||
case SD_BUS_TYPE_UNIX_FD:
|
||||
return 4;
|
||||
|
||||
case SD_BUS_TYPE_INT64:
|
||||
case SD_BUS_TYPE_UINT64:
|
||||
case SD_BUS_TYPE_DOUBLE:
|
||||
return 8;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
34
src/libsystemd-bus/bus-type.h
Normal file
34
src/libsystemd-bus/bus-type.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*-*- 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 <stdbool.h>
|
||||
|
||||
#include "sd-bus.h"
|
||||
#include "sd-bus-protocol.h"
|
||||
|
||||
bool bus_type_is_valid(char c);
|
||||
bool bus_type_is_valid_in_signature(char c);
|
||||
bool bus_type_is_basic(char c);
|
||||
bool bus_type_is_container(char c);
|
||||
int bus_type_get_alignment(char c);
|
||||
int bus_type_get_size(char c);
|
68
src/libsystemd-bus/busctl.c
Normal file
68
src/libsystemd-bus/busctl.c
Normal file
@ -0,0 +1,68 @@
|
||||
/*-*- 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 "sd-bus.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
_cleanup_bus_unref_ sd_bus *bus = NULL;
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
char **i;
|
||||
int r;
|
||||
|
||||
r = bus_open_system(&bus);
|
||||
if (r < 0) {
|
||||
log_error("Failed to connect to bus: %s", strerror(-r));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = sd_bus_list_names(bus, &l);
|
||||
if (r < 0) {
|
||||
log_error("Failed to list names: %s", strerror(-r));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
STRV_FOREACH(i, l) {
|
||||
_cleanup_free_ char *owner = NULL;
|
||||
pid_t pid = 0;
|
||||
uid_t uid;
|
||||
bool uid_valid;
|
||||
|
||||
r = sd_bus_get_owner(bus, *i, &owner);
|
||||
if (r == -ENXIO)
|
||||
continue;
|
||||
|
||||
r = sd_get_owner_pid(bus, *i, &pid);
|
||||
if (r == -ENXIO)
|
||||
continue;
|
||||
|
||||
r = sd_get_owner_uid(bus, *i, &pid);
|
||||
if (r == -ENXIO)
|
||||
continue;
|
||||
uid_valid = r >= 0;
|
||||
|
||||
printf("%s (%s) %llu %llu\n", *i, owner, (unsigned long long) pid, (unsigned long long) uid);
|
||||
}
|
||||
|
||||
r = 0;
|
||||
|
||||
fail:
|
||||
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
96
src/libsystemd-bus/sd-bus-protocol.h
Normal file
96
src/libsystemd-bus/sd-bus-protocol.h
Normal file
@ -0,0 +1,96 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#ifndef foosdbusprotocolhfoo
|
||||
#define foosdbusprotocolhfoo
|
||||
|
||||
/***
|
||||
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/>.
|
||||
***/
|
||||
|
||||
/* Types of message */
|
||||
|
||||
#define SD_BUS_DEFAULT_TIMEOUT ((usec_t) (25 * USEC_PER_SEC))
|
||||
|
||||
enum {
|
||||
_SD_BUS_MESSAGE_TYPE_INVALID = 0,
|
||||
SD_BUS_MESSAGE_TYPE_METHOD_CALL,
|
||||
SD_BUS_MESSAGE_TYPE_METHOD_RETURN,
|
||||
SD_BUS_MESSAGE_TYPE_METHOD_ERROR,
|
||||
SD_BUS_MESSAGE_TYPE_SIGNAL,
|
||||
_SD_BUS_MESSAGE_TYPE_MAX
|
||||
};
|
||||
|
||||
/* Primitive types */
|
||||
|
||||
enum {
|
||||
_SD_BUS_TYPE_INVALID = 0,
|
||||
SD_BUS_TYPE_BYTE = 'y',
|
||||
SD_BUS_TYPE_BOOLEAN = 'b',
|
||||
SD_BUS_TYPE_INT16 = 'n',
|
||||
SD_BUS_TYPE_UINT16 = 'q',
|
||||
SD_BUS_TYPE_INT32 = 'i',
|
||||
SD_BUS_TYPE_UINT32 = 'u',
|
||||
SD_BUS_TYPE_INT64 = 'x',
|
||||
SD_BUS_TYPE_UINT64 = 't',
|
||||
SD_BUS_TYPE_DOUBLE = 'd',
|
||||
SD_BUS_TYPE_STRING = 's',
|
||||
SD_BUS_TYPE_OBJECT_PATH = 'o',
|
||||
SD_BUS_TYPE_SIGNATURE = 'g',
|
||||
SD_BUS_TYPE_UNIX_FD = 'h',
|
||||
SD_BUS_TYPE_ARRAY = 'a',
|
||||
SD_BUS_TYPE_VARIANT = 'v',
|
||||
SD_BUS_TYPE_STRUCT = 'r', /* not actually used in signatures */
|
||||
SD_BUS_TYPE_STRUCT_BEGIN = '(',
|
||||
SD_BUS_TYPE_STRUCT_END = ')',
|
||||
SD_BUS_TYPE_DICT_ENTRY = 'e', /* not actually used in signatures */
|
||||
SD_BUS_TYPE_DICT_ENTRY_BEGIN = '{',
|
||||
SD_BUS_TYPE_DICT_ENTRY_END = '}',
|
||||
};
|
||||
|
||||
/* Endianess */
|
||||
|
||||
enum {
|
||||
_SD_BUS_INVALID_ENDIAN = 0,
|
||||
SD_BUS_LITTLE_ENDIAN = 'l',
|
||||
SD_BUS_BIG_ENDIAN = 'B'
|
||||
};
|
||||
|
||||
/* Flags */
|
||||
|
||||
enum {
|
||||
SD_BUS_MESSAGE_NO_REPLY_EXPECTED = 1,
|
||||
SD_BUS_MESSAGE_NO_AUTO_START = 2
|
||||
};
|
||||
|
||||
/* Header fields */
|
||||
|
||||
enum {
|
||||
_SD_BUS_MESSAGE_HEADER_INVALID = 0,
|
||||
SD_BUS_MESSAGE_HEADER_PATH,
|
||||
SD_BUS_MESSAGE_HEADER_INTERFACE,
|
||||
SD_BUS_MESSAGE_HEADER_MEMBER,
|
||||
SD_BUS_MESSAGE_HEADER_ERROR_NAME,
|
||||
SD_BUS_MESSAGE_HEADER_REPLY_SERIAL,
|
||||
SD_BUS_MESSAGE_HEADER_DESTINATION,
|
||||
SD_BUS_MESSAGE_HEADER_SENDER,
|
||||
SD_BUS_MESSAGE_HEADER_SIGNATURE,
|
||||
SD_BUS_MESSAGE_HEADER_UNIX_FDS,
|
||||
_SD_BUS_MESSAGE_HEADER_MAX
|
||||
};
|
||||
|
||||
#endif
|
1437
src/libsystemd-bus/sd-bus.c
Normal file
1437
src/libsystemd-bus/sd-bus.c
Normal file
File diff suppressed because it is too large
Load Diff
135
src/libsystemd-bus/sd-bus.h
Normal file
135
src/libsystemd-bus/sd-bus.h
Normal file
@ -0,0 +1,135 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#ifndef foosdbushfoo
|
||||
#define foosdbushfoo
|
||||
|
||||
/***
|
||||
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 <inttypes.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "sd-bus-protocol.h"
|
||||
|
||||
typedef struct sd_bus sd_bus;
|
||||
typedef struct sd_bus_message sd_bus_message;
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
const char *message;
|
||||
int need_free;
|
||||
} sd_bus_error;
|
||||
|
||||
typedef int (*sd_message_handler_t)(sd_bus *bus, sd_bus_message *m, void *userdata);
|
||||
|
||||
/* Connections */
|
||||
|
||||
int sd_bus_open_system(sd_bus **ret);
|
||||
int sd_bus_open_user(sd_bus **ret);
|
||||
int sd_bus_open_address(const char *address, sd_bus **ret);
|
||||
int sd_bus_open_fd(int fd, sd_bus **ret);
|
||||
void sd_bus_close(sd_bus *bus);
|
||||
|
||||
sd_bus *sd_bus_ref(sd_bus *bus);
|
||||
sd_bus *sd_bus_unref(sd_bus *bus);
|
||||
|
||||
int sd_bus_is_running(sd_bus *bus);
|
||||
int sd_bus_can_send(sd_bus *bus, char type);
|
||||
|
||||
int sd_bus_send(sd_bus *bus, sd_bus_message *m, uint64_t *serial);
|
||||
int sd_bus_send_with_reply(sd_bus *bus, sd_bus_message *m, sd_message_handler_t callback, void *userdata, uint64_t usec, uint64_t *serial);
|
||||
int sd_bus_send_with_reply_cancel(sd_bus *bus, uint64_t serial);
|
||||
int sd_bus_send_with_reply_and_block(sd_bus *bus, sd_bus_message *m, uint64_t usec, sd_bus_error *error, sd_bus_message **r);
|
||||
|
||||
int sd_bus_get_fd(sd_bus *bus);
|
||||
int sd_bus_get_events(sd_bus *bus);
|
||||
int sd_bus_process(sd_bus *bus, sd_bus_message **r);
|
||||
int sd_bus_wait(sd_bus *bus, uint64_t timeout_usec);
|
||||
int sd_bus_flush(sd_bus *bus);
|
||||
|
||||
int sd_bus_add_filter(sd_bus *bus, sd_message_handler_t callback, void *userdata);
|
||||
int sd_bus_remove_filter(sd_bus *bus, 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);
|
||||
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);
|
||||
|
||||
sd_bus_message* sd_bus_message_ref(sd_bus_message *m);
|
||||
sd_bus_message* sd_bus_message_unref(sd_bus_message *m);
|
||||
|
||||
int sd_bus_message_get_type(sd_bus_message *m, uint8_t *type);
|
||||
int sd_bus_message_get_serial(sd_bus_message *m, uint64_t *serial);
|
||||
int sd_bus_message_get_reply_serial(sd_bus_message *m, uint64_t *serial);
|
||||
int sd_bus_message_get_no_reply(sd_bus_message *m);
|
||||
|
||||
const char *sd_bus_message_get_path(sd_bus_message *m);
|
||||
const char *sd_bus_message_get_interface(sd_bus_message *m);
|
||||
const char *sd_bus_message_get_member(sd_bus_message *m);
|
||||
const char *sd_bus_message_get_destination(sd_bus_message *m);
|
||||
const char *sd_bus_message_get_sender(sd_bus_message *m);
|
||||
const sd_bus_error *sd_bus_message_get_error(sd_bus_message *m);
|
||||
|
||||
int sd_bus_message_get_uid(sd_bus_message *m, uid_t *uid);
|
||||
int sd_bus_message_get_gid(sd_bus_message *m, gid_t *gid);
|
||||
int sd_bus_message_get_pid(sd_bus_message *m, pid_t *pid);
|
||||
int sd_bus_message_get_tid(sd_bus_message *m, pid_t *tid);
|
||||
|
||||
int sd_bus_message_is_signal(sd_bus_message *m, const char *interface, const char *member);
|
||||
int sd_bus_message_is_method_call(sd_bus_message *m, const char *interface, const char *member);
|
||||
int sd_bus_message_is_method_error(sd_bus_message *m, const char *name);
|
||||
|
||||
int sd_bus_message_set_no_reply(sd_bus_message *m, int b);
|
||||
int sd_bus_message_set_destination(sd_bus_message *m, const char *destination);
|
||||
|
||||
int sd_bus_message_append(sd_bus_message *m, const char *types, ...);
|
||||
int sd_bus_message_append_basic(sd_bus_message *m, char type, const void *p);
|
||||
int sd_bus_message_open_container(sd_bus_message *m, char type, const char *contents);
|
||||
int sd_bus_message_close_container(sd_bus_message *m);
|
||||
|
||||
int sd_bus_message_read_type(sd_bus_message *m, char *type, char *element, size_t *length);
|
||||
int sd_bus_message_read_basic(sd_bus_message *m, char type, char element, const void **p, size_t *length);
|
||||
int sd_bus_message_read(sd_bus_message *m, const char *types, ...);
|
||||
|
||||
/* Bus management */
|
||||
|
||||
const char *sd_bus_get_unique_name(sd_bus *bus);
|
||||
int sd_bus_request_name(sd_bus *bus, const char *name, int flags);
|
||||
int sd_bus_release_name(sd_bus *bus, const char *name);
|
||||
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 objects */
|
||||
|
||||
#define SD_BUS_ERROR_INIT (NULL, NULL, false)
|
||||
|
||||
void sd_bus_error_free(sd_bus_error *e);
|
||||
int sd_bus_error_set(sd_bus_error *e, const char *name, const char *format, ...);
|
||||
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);
|
||||
int sd_bus_error_has_name(const sd_bus_error *e, const char *name);
|
||||
|
||||
#endif
|
129
src/libsystemd-bus/test-bus-marshal.c
Normal file
129
src/libsystemd-bus/test-bus-marshal.c
Normal file
@ -0,0 +1,129 @@
|
||||
/*-*- 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 <byteswap.h>
|
||||
|
||||
#ifdef HAVE_GLIB
|
||||
#include <gio/gio.h>
|
||||
#endif
|
||||
|
||||
#include <dbus.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "sd-bus.h"
|
||||
#include "bus-message.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
|
||||
int r;
|
||||
const char *x, *y, *z, *a, *b, *c;
|
||||
uint8_t u, v;
|
||||
void *buffer = NULL;
|
||||
size_t sz;
|
||||
char *h;
|
||||
|
||||
r = sd_bus_message_new_method_call(NULL, "foobar.waldo", "/", "foobar.waldo", "Piep", &m);
|
||||
assert_se(r >= 0);
|
||||
|
||||
r = sd_bus_message_append(m, "s", "a string");
|
||||
assert_se(r >= 0);
|
||||
|
||||
r = sd_bus_message_append(m, "as", 2, "string #1", "string #2");
|
||||
assert_se(r >= 0);
|
||||
|
||||
r = sd_bus_message_append(m, "sass", "foobar", 5, "foo", "bar", "waldo", "piep", "pap", "after");
|
||||
assert_se(r >= 0);
|
||||
|
||||
r = sd_bus_message_append(m, "a{yv}", 2, 3, "s", "foo", 5, "s", "waldo");
|
||||
assert_se(r >= 0);
|
||||
|
||||
r = sd_bus_message_append(m, "ba(ss)", 255, 3, "aaa", "1", "bbb", "2", "ccc", "3");
|
||||
assert_se(r >= 0);
|
||||
|
||||
r = sd_bus_message_open_container(m, 'a', "s");
|
||||
assert_se(r >= 0);
|
||||
|
||||
r = sd_bus_message_append_basic(m, 's', "foobar");
|
||||
assert_se(r >= 0);
|
||||
|
||||
r = sd_bus_message_append_basic(m, 's', "waldo");
|
||||
assert_se(r >= 0);
|
||||
|
||||
r = sd_bus_message_close_container(m);
|
||||
assert_se(r >= 0);
|
||||
|
||||
r = message_seal(m, 4711);
|
||||
assert_se(r >= 0);
|
||||
|
||||
message_dump(m);
|
||||
|
||||
r = bus_message_get_blob(m, &buffer, &sz);
|
||||
assert_se(r >= 0);
|
||||
|
||||
h = hexmem(buffer, sz);
|
||||
assert_se(h);
|
||||
|
||||
log_info("message size = %lu, contents =\n%s", (unsigned long) sz, h);
|
||||
free(h);
|
||||
|
||||
#ifdef HAVE_GLIB
|
||||
{
|
||||
GDBusMessage *g;
|
||||
char *p;
|
||||
|
||||
g_type_init();
|
||||
|
||||
g = g_dbus_message_new_from_blob(buffer, sz, 0, NULL);
|
||||
p = g_dbus_message_print(g, 0);
|
||||
log_info("%s", p);
|
||||
g_free(p);
|
||||
g_object_unref(g);
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
DBusMessage *w;
|
||||
DBusError error;
|
||||
|
||||
dbus_error_init(&error);
|
||||
|
||||
w = dbus_message_demarshal(buffer, sz, &error);
|
||||
if (!w) {
|
||||
log_error("%s", error.message);
|
||||
} else
|
||||
dbus_message_unref(w);
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
|
||||
/* r = sd_bus_message_read(m, "sas", &x, 5, &y, &z, &a, &b, &c); */
|
||||
/* assert_se(r >= 0); */
|
||||
|
||||
/* r = sd_bus_message_read(m, "a{yv}", 2, */
|
||||
/* &u, "s", &x, */
|
||||
/* &v, "s", &y); */
|
||||
|
||||
return 0;
|
||||
}
|
74
src/libsystemd-bus/test-bus-signature.c
Normal file
74
src/libsystemd-bus/test-bus-signature.c
Normal file
@ -0,0 +1,74 @@
|
||||
/*-*- 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 "log.h"
|
||||
#include "bus-signature.h"
|
||||
|
||||
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_pair("yy"));
|
||||
assert_se(signature_is_pair("ss"));
|
||||
assert_se(signature_is_pair("sas"));
|
||||
assert_se(signature_is_pair("sv"));
|
||||
assert_se(signature_is_pair("sa(vs)"));
|
||||
assert_se(!signature_is_pair(""));
|
||||
assert_se(!signature_is_pair("va"));
|
||||
assert_se(!signature_is_pair("sss"));
|
||||
assert_se(!signature_is_pair("{s}ss"));
|
||||
|
||||
assert_se(signature_is_valid("ssa{ss}sssub", true));
|
||||
assert_se(signature_is_valid("ssa{ss}sssub", false));
|
||||
assert_se(signature_is_valid("{ss}", true));
|
||||
assert_se(!signature_is_valid("{ss}", false));
|
||||
assert_se(signature_is_valid("", true));
|
||||
assert_se(signature_is_valid("", false));
|
||||
|
||||
assert_se(signature_is_valid("sssusa(uuubbba(uu)uuuu)a{u(uuuvas)}", false));
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user