dbus.c revision 417b1a62ed9ca700a180f27ed6ea8e972194b9ad
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering This file is part of systemd.
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering Copyright 2010 Lennart Poettering
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering systemd is free software; you can redistribute it and/or modify it
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering under the terms of the GNU Lesser General Public License as published by
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering (at your option) any later version.
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering systemd is distributed in the hope that it will be useful, but
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering Lesser General Public License for more details.
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering You should have received a copy of the GNU Lesser General Public License
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering/* Well-known address (http://dbus.freedesktop.org/doc/dbus-specification.html#message-bus-types) */
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering#define DBUS_SYSTEM_BUS_DEFAULT_ADDRESS "unix:path=/var/run/dbus/system_bus_socket"
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering/* Only used as a fallback */
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering#define DBUS_SESSION_BUS_DEFAULT_ADDRESS "autolaunch:"
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poetteringstatic const char bus_properties_interface[] = BUS_PROPERTIES_INTERFACE;
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poetteringstatic const char bus_introspectable_interface[] = BUS_INTROSPECTABLE_INTERFACE;
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poetteringconst char *const bus_interface_table[] = {
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering "org.freedesktop.DBus.Properties", bus_properties_interface,
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering "org.freedesktop.DBus.Introspectable", bus_introspectable_interface,
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering "org.freedesktop.systemd1.Manager", bus_manager_interface,
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering "org.freedesktop.systemd1.Job", bus_job_interface,
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering "org.freedesktop.systemd1.Unit", bus_unit_interface,
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering "org.freedesktop.systemd1.Service", bus_service_interface,
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering "org.freedesktop.systemd1.Socket", bus_socket_interface,
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering "org.freedesktop.systemd1.Target", bus_target_interface,
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering "org.freedesktop.systemd1.Device", bus_device_interface,
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering "org.freedesktop.systemd1.Mount", bus_mount_interface,
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering "org.freedesktop.systemd1.Automount", bus_automount_interface,
a71fe8b8aee1cb78c4d8c56eeb234743f64e4b4dLennart Poettering "org.freedesktop.systemd1.Snapshot", bus_snapshot_interface,
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering "org.freedesktop.systemd1.Swap", bus_swap_interface,
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering "org.freedesktop.systemd1.Timer", bus_timer_interface,
a71fe8b8aee1cb78c4d8c56eeb234743f64e4b4dLennart Poettering "org.freedesktop.systemd1.Path", bus_path_interface,
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poetteringstatic void shutdown_connection(Manager *m, DBusConnection *c);
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poetteringstatic void bus_dispatch_status(DBusConnection *bus, DBusDispatchStatus status, void *data) {
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering /* We maintain two sets, one for those connections where we
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering * requested a dispatch, and another where we didn't. And then,
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering * we move the connections between the two sets. */
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering set_move_one(m->bus_connections, m->bus_connections_for_dispatch, bus);
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering set_move_one(m->bus_connections_for_dispatch, m->bus_connections, bus);
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poetteringvoid bus_watch_event(Manager *m, Watch *w, int events) {
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering /* This is called by the event loop whenever there is
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering * something happening on D-Bus' file handles. */
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering if (!dbus_watch_get_enabled(w->data.bus_watch))
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering dbus_watch_handle(w->data.bus_watch, bus_events_to_flags(events));
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poetteringstatic dbus_bool_t bus_add_watch(DBusWatch *bus_watch, void *data) {
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering w->fd = dbus_watch_get_unix_fd(bus_watch);
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering ev.events = bus_flags_to_events(bus_watch);
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, w->fd, &ev) < 0) {
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering /* Hmm, bloody D-Bus creates multiple watches on the
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering * same fd. epoll() does not like that. As a dirty
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering * hack we simply dup() the fd and hence get a second
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering * one we can safely add to the epoll(). */
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, w->fd, &ev) < 0) {
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poetteringstatic void bus_remove_watch(DBusWatch *bus_watch, void *data) {
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering assert_se(epoll_ctl(m->epoll_fd, EPOLL_CTL_DEL, w->fd, NULL) >= 0);
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poetteringstatic void bus_toggle_watch(DBusWatch *bus_watch, void *data) {
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering ev.events = bus_flags_to_events(bus_watch);
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering assert_se(epoll_ctl(m->epoll_fd, EPOLL_CTL_MOD, w->fd, &ev) == 0);
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poetteringstatic int bus_timeout_arm(Manager *m, Watch *w) {
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering if (dbus_timeout_get_enabled(w->data.bus_timeout)) {
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering timespec_store(&its.it_value, dbus_timeout_get_interval(w->data.bus_timeout) * USEC_PER_MSEC);
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering if (timerfd_settime(w->fd, 0, &its, NULL) < 0)
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poetteringvoid bus_timeout_event(Manager *m, Watch *w, int events) {
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering /* This is called by the event loop whenever there is
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering * something happening on D-Bus' file handles. */
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering if (!(dbus_timeout_get_enabled(w->data.bus_timeout)))
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering dbus_timeout_handle(w->data.bus_timeout);
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poetteringstatic dbus_bool_t bus_add_timeout(DBusTimeout *timeout, void *data) {
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering if ((w->fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC)) < 0)
caa829849d6ac9f6e173f585f732054358311ae1Lennart Poettering if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, w->fd, &ev) < 0)
9cbfc66c621c42aa6e58e9e0da0adfb01efa7537Lennart Poetteringstatic void bus_remove_timeout(DBusTimeout *timeout, void *data) {
free(w);
Watch *w;
assert(m);
if ((r = bus_timeout_arm(m, w)) < 0)
static DBusHandlerResult api_bus_message_filter(DBusConnection *connection, DBusMessage *message, void *data) {
assert(m);
bus_done_api(m);
log_debug("Subscription client vanished: %s (left: %u)", name, set_size(BUS_CONNECTION_SUBSCRIBED(m, connection)));
if (old_owner[0] == 0)
if (new_owner[0] == 0)
} else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Activator", "ActivationRequest")) {
const char *name;
Unit *u;
r = -EADDRNOTAVAIL;
if (r >= 0 && u->refuse_manual_start)
r = -EPERM;
if (!(reply = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Activator", "ActivationFailure")))
goto oom;
goto oom;
if (reply) {
goto oom;
oom:
if (reply)
return DBUS_HANDLER_RESULT_NEED_MEMORY;
static DBusHandlerResult system_bus_message_filter(DBusConnection *connection, DBusMessage *message, void *data) {
assert(m);
bus_done_system(m);
const char *cgroup;
static DBusHandlerResult private_bus_message_filter(DBusConnection *connection, DBusMessage *message, void *data) {
assert(m);
const char *cgroup;
if (m->system_bus)
DBusConnection *c;
assert(m);
if (m->queued_message) {
if (m->queued_message_connection)
case DBUS_MESSAGE_TYPE_ERROR:
case DBUS_MESSAGE_TYPE_METHOD_RETURN: {
uint32_t r;
&error,
DBUS_TYPE_UINT32, &r,
goto oom;
if (!dbus_message_append_args(
goto oom;
goto oom;
goto oom;
oom:
if (pending) {
if (message)
return -ENOMEM;
assert(m);
case DBUS_MESSAGE_TYPE_ERROR:
case DBUS_MESSAGE_TYPE_METHOD_RETURN: {
STRV_FOREACH(t, l)
strv_free(l);
goto oom;
goto oom;
goto oom;
oom:
if (pending) {
if (message)
return -ENOMEM;
assert(m);
if (!dbus_connection_set_watch_functions(bus, bus_add_watch, bus_remove_watch, bus_toggle_watch, m, NULL) ||
!dbus_connection_set_timeout_functions(bus, bus_add_timeout, bus_remove_timeout, bus_toggle_timeout, m, NULL))
return log_oom();
return log_oom();
static dbus_bool_t allow_only_same_user(DBusConnection *connection, unsigned long uid, void *data) {
static void bus_new_connection(
void *data) {
assert(m);
if (!dbus_connection_register_object_path(new_connection, "/org/freedesktop/systemd1", &bus_manager_vtable, m) ||
!dbus_connection_register_fallback(new_connection, "/org/freedesktop/systemd1/unit", &bus_unit_vtable, m) ||
!dbus_connection_register_fallback(new_connection, "/org/freedesktop/systemd1/job", &bus_job_vtable, m) ||
log_oom();
char *id;
return log_oom();
"interface='org.freedesktop.systemd1.Agent',"
"path='/org/freedesktop/systemd1/agent'",
&error);
if (!dbus_connection_register_object_path(m->api_bus, "/org/freedesktop/systemd1", &bus_manager_vtable, m) ||
!dbus_connection_register_fallback(m->api_bus, "/org/freedesktop/systemd1/unit", &bus_unit_vtable, m) ||
!dbus_connection_register_fallback(m->api_bus, "/org/freedesktop/systemd1/job", &bus_job_vtable, m) ||
return log_oom();
NULL);
"interface='org.freedesktop.systemd1.Activator',"
NULL);
r = request_name(m);
r = query_name_list(m);
char *id;
const char *name;
case DBUS_MESSAGE_TYPE_ERROR:
r = init_registered_system_bus(m);
r = init_registered_api_bus(m);
r = init_registered_api_bus(m);
bus_done_system(m);
bus_done_api(m);
if (!message)
goto oom;
goto oom;
goto oom;
goto oom;
oom:
if (pending) {
if (message)
return -ENOMEM;
const char *address;
switch (type) {
case DBUS_BUS_SYSTEM:
case DBUS_BUS_SESSION:
if (!connection) {
goto fail;
return connection;
fail:
return NULL;
if (m->system_bus)
if (!m->system_bus) {
goto fail;
goto fail;
goto fail;
fail:
bus_done_system(m);
if (m->api_bus)
if (!m->api_bus) {
goto fail;
goto fail;
goto fail;
fail:
bus_done_api(m);
static const char *const external_only[] = {
assert(m);
if (m->private_bus)
char *escaped;
r = log_oom();
goto fail;
unlink(p);
free(p);
if (!escaped) {
r = log_oom();
goto fail;
r = log_oom();
goto fail;
free(p);
if (!m->private_bus) {
r = -EIO;
goto fail;
!dbus_server_set_watch_functions(m->private_bus, bus_add_watch, bus_remove_watch, bus_toggle_watch, m, NULL) ||
!dbus_server_set_timeout_functions(m->private_bus, bus_add_timeout, bus_remove_timeout, bus_toggle_timeout, m, NULL)) {
r = log_oom();
goto fail;
fail:
bus_done_private(m);
set_ensure_allocated(&m->bus_connections_for_dispatch, trivial_hash_func, trivial_compare_func) < 0)
goto oom;
if (m->name_data_slot < 0)
goto oom;
if (m->conn_data_slot < 0)
goto oom;
if (m->subscribed_data_slot < 0)
goto oom;
if (try_bus_connect) {
if ((r = bus_init_system(m)) < 0 ||
(r = bus_init_api(m)) < 0)
if ((r = bus_init_private(m)) < 0)
oom:
return log_oom();
Set *s;
Job *j;
Iterator i;
if ((s = BUS_CONNECTION_SUBSCRIBED(m, c))) {
while ((t = set_steal_first(s)))
free(t);
set_free(s);
if (m->queued_message_connection == c) {
if (m->queued_message) {
if (!m->api_bus)
if (m->queued_message) {
if (!m->system_bus)
bus_done_api(m);
if (!m->private_bus)
DBusConnection *c;
bus_done_api(m);
bus_done_system(m);
bus_done_private(m);
shutdown_connection(m, c);
shutdown_connection(m, c);
if (m->name_data_slot >= 0)
if (m->conn_data_slot >= 0)
if (m->subscribed_data_slot >= 0)
const char *name;
case DBUS_MESSAGE_TYPE_ERROR:
case DBUS_MESSAGE_TYPE_METHOD_RETURN: {
uint32_t r;
&error,
DBUS_TYPE_UINT32, &r,
char *n = NULL;
assert(m);
goto oom;
if (!(dbus_message_append_args(
goto oom;
goto oom;
goto oom;
goto oom;
n = NULL;
goto oom;
oom:
free(n);
if (pending) {
if (message)
return -ENOMEM;
bool oom = false;
Iterator i;
DBusConnection *c;
assert(m);
Iterator i;
DBusConnection *c;
assert(m);
if (bus_connection_has_subscriber(m, c))
if (bus_connection_has_subscriber(m, c))
assert(m);
assert(c);
Iterator i;
DBusConnection *c;
assert(m);
int fd;
if (fd < 0)
return fd;
int fd;
if (fd < 0)
return fd;
void bus_broadcast_finished(
Manager *m,
assert(m);
message = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartupFinished");
if (!message) {
log_oom();
log_oom();
goto finish;
log_oom();
goto finish;
if (message)