along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <dbus/dbus.h>
-
#include <sys/epoll.h>
#include <sys/timerfd.h>
#include <errno.h>
#include <unistd.h>
+#include <dbus/dbus.h>
#include "dbus.h"
#include "log.h"
#include "strv.h"
#include "cgroup.h"
+#include "dbus-unit.h"
+#include "dbus-job.h"
+#include "dbus-manager.h"
static void api_bus_dispatch_status(DBusConnection *bus, DBusDispatchStatus status, void *data) {
Manager *m = data;
assert(bus);
assert(m);
+
+ if (!m->api_bus)
+ return;
+
assert(m->api_bus == bus);
m->request_api_bus_dispatch = status != DBUS_DISPATCH_COMPLETE;
assert(bus);
assert(m);
+
+ if (!m->system_bus)
+ return;
+
assert(m->system_bus == bus);
m->request_system_bus_dispatch = status != DBUS_DISPATCH_COMPLETE;
/* dbus_message_get_path(message)); */
if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
- log_error("Warning! D-Bus connection terminated.");
+ log_error("Warning! API D-Bus connection terminated.");
bus_done_api(m);
} else if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) {
- const char *name, *old, *new;
+ const char *name, *old_owner, *new_owner;
if (!dbus_message_get_args(message, &error,
DBUS_TYPE_STRING, &name,
- DBUS_TYPE_STRING, &old,
- DBUS_TYPE_STRING, &new,
+ DBUS_TYPE_STRING, &old_owner,
+ DBUS_TYPE_STRING, &new_owner,
DBUS_TYPE_INVALID))
log_error("Failed to parse NameOwnerChanged message: %s", error.message);
else {
if (set_remove(m->subscribed, (char*) name))
log_debug("Subscription client vanished: %s (left: %u)", name, set_size(m->subscribed));
+
+ if (old_owner[0] == 0)
+ old_owner = NULL;
+
+ if (new_owner[0] == 0)
+ new_owner = NULL;
+
+ manager_dispatch_bus_name_owner_changed(m, name, old_owner, new_owner);
}
}
/* dbus_message_get_path(message)); */
if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
- log_error("Warning! D-Bus connection terminated.");
+ log_error("Warning! System D-Bus connection terminated.");
bus_done_system(m);
} if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
unsigned bus_dispatch(Manager *m) {
assert(m);
+ if (m->queued_message) {
+ /* If we cannot get rid of this message we won't
+ * dispatch any D-Bus messages, so that we won't end
+ * up wanting to queue another message. */
+
+ if (!dbus_connection_send(m->api_bus, m->queued_message, NULL))
+ return 0;
+
+ dbus_message_unref(m->queued_message);
+ m->queued_message = NULL;
+ }
+
if (m->request_api_bus_dispatch) {
if (dbus_connection_dispatch(m->api_bus) == DBUS_DISPATCH_COMPLETE)
m->request_api_bus_dispatch = false;
return 0;
}
-static void pending_cb(DBusPendingCall *pending, void *userdata) {
+static void request_name_pending_cb(DBusPendingCall *pending, void *userdata) {
DBusMessage *reply;
DBusError error;
}
static int request_name(Manager *m) {
- DBusMessage *message;
const char *name = "org.freedesktop.systemd1";
uint32_t flags = 0;
- DBusPendingCall *pending;
+ DBusMessage *message = NULL;
+ DBusPendingCall *pending = NULL;
if (!(message = dbus_message_new_method_call(
DBUS_SERVICE_DBUS,
DBUS_PATH_DBUS,
DBUS_INTERFACE_DBUS,
"RequestName")))
- return -ENOMEM;
+ goto oom;
if (!dbus_message_append_args(
message,
DBUS_TYPE_STRING, &name,
DBUS_TYPE_UINT32, &flags,
- DBUS_TYPE_INVALID)) {
- dbus_message_unref(message);
- return -ENOMEM;
- }
+ DBUS_TYPE_INVALID))
+ goto oom;
- if (!dbus_connection_send_with_reply(m->api_bus, message, &pending, -1)) {
- dbus_message_unref(message);
- return -ENOMEM;
- }
+ if (!dbus_connection_send_with_reply(m->api_bus, message, &pending, -1))
+ goto oom;
+ if (!dbus_pending_call_set_notify(pending, request_name_pending_cb, m, NULL))
+ goto oom;
dbus_message_unref(message);
-
- if (!dbus_pending_call_set_notify(pending, pending_cb, NULL, NULL)) {
- dbus_pending_call_cancel(pending);
- dbus_pending_call_unref(pending);
- return -ENOMEM;
- }
-
-
dbus_pending_call_unref(pending);
/* We simple ask for the name and don't wait for it. Sooner or
* later we'll have it. */
return 0;
+
+oom:
+ if (pending) {
+ dbus_pending_call_cancel(pending);
+ dbus_pending_call_unref(pending);
+ }
+
+ if (message)
+ dbus_message_unref(message);
+
+ return -ENOMEM;
}
static int bus_setup_loop(Manager *m, DBusConnection *bus) {
if (m->api_bus)
return 0;
+ if (m->name_data_slot < 0)
+ if (!dbus_pending_call_allocate_data_slot(&m->name_data_slot))
+ return -ENOMEM;
+
if (m->running_as != MANAGER_SESSION && m->system_bus)
m->api_bus = m->system_bus;
else {
if (m->system_bus == m->api_bus)
m->system_bus = NULL;
+ dbus_connection_set_dispatch_status_function(m->api_bus, NULL, NULL, NULL);
+ dbus_connection_flush(m->api_bus);
dbus_connection_close(m->api_bus);
dbus_connection_unref(m->api_bus);
m->api_bus = NULL;
-
}
if (m->subscribed) {
set_free(m->subscribed);
m->subscribed = NULL;
}
+
+ if (m->name_data_slot >= 0)
+ dbus_pending_call_free_data_slot(&m->name_data_slot);
+
+ if (m->queued_message) {
+ dbus_message_unref(m->queued_message);
+ m->queued_message = NULL;
+ }
}
void bus_done_system(Manager *m) {
bus_done_api(m);
if (m->system_bus) {
+ dbus_connection_set_dispatch_status_function(m->system_bus, NULL, NULL, NULL);
+ dbus_connection_flush(m->system_bus);
dbus_connection_close(m->system_bus);
dbus_connection_unref(m->system_bus);
m->system_bus = NULL;
}
}
+static void query_pid_pending_cb(DBusPendingCall *pending, void *userdata) {
+ Manager *m = userdata;
+ DBusMessage *reply;
+ DBusError error;
+ const char *name;
+
+ dbus_error_init(&error);
+
+ assert_se(name = dbus_pending_call_get_data(pending, m->name_data_slot));
+ assert_se(reply = dbus_pending_call_steal_reply(pending));
+
+ switch (dbus_message_get_type(reply)) {
+
+ case DBUS_MESSAGE_TYPE_ERROR:
+
+ assert_se(dbus_set_error_from_message(&error, reply));
+ log_warning("GetConnectionUnixProcessID() failed: %s", error.message);
+ break;
+
+ case DBUS_MESSAGE_TYPE_METHOD_RETURN: {
+ uint32_t r;
+
+ if (!dbus_message_get_args(reply,
+ &error,
+ DBUS_TYPE_UINT32, &r,
+ DBUS_TYPE_INVALID)) {
+ log_error("Failed to parse GetConnectionUnixProcessID() reply: %s", error.message);
+ break;
+ }
+
+ manager_dispatch_bus_query_pid_done(m, name, (pid_t) r);
+ break;
+ }
+
+ default:
+ assert_not_reached("Invalid reply message");
+ }
+
+ dbus_message_unref(reply);
+ dbus_error_free(&error);
+}
+
+int bus_query_pid(Manager *m, const char *name) {
+ DBusMessage *message = NULL;
+ DBusPendingCall *pending = NULL;
+ char *n = NULL;
+
+ assert(m);
+ assert(name);
+
+ if (!(message = dbus_message_new_method_call(
+ DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS,
+ "GetConnectionUnixProcessID")))
+ goto oom;
+
+ if (!(dbus_message_append_args(
+ message,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_INVALID)))
+ goto oom;
+
+ if (!dbus_connection_send_with_reply(m->api_bus, message, &pending, -1))
+ goto oom;
+
+ if (!(n = strdup(name)))
+ goto oom;
+
+ if (!dbus_pending_call_set_data(pending, m->name_data_slot, n, free))
+ goto oom;
+
+ n = NULL;
+
+ if (!dbus_pending_call_set_notify(pending, query_pid_pending_cb, m, NULL))
+ goto oom;
+
+ dbus_message_unref(message);
+ dbus_pending_call_unref(pending);
+
+ return 0;
+
+oom:
+ free(n);
+
+ if (pending) {
+ dbus_pending_call_cancel(pending);
+ dbus_pending_call_unref(pending);
+ }
+
+ if (message)
+ dbus_message_unref(message);
+
+ return -ENOMEM;
+}
+
DBusHandlerResult bus_default_message_handler(Manager *m, DBusMessage *message, const char*introspection, const BusProperty *properties) {
DBusError error;
DBusMessage *reply = NULL;
if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, p->signature, &sub))
goto oom;
- if ((r = p->append(m, &sub, property, p->data)) < 0) {
+ if ((r = p->append(m, &sub, property, (void*) p->data)) < 0) {
if (r == -ENOMEM)
goto oom;
!dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, p->signature, &sub3))
goto oom;
- if ((r = p->append(m, &sub3, p->property, p->data)) < 0) {
+ if ((r = p->append(m, &sub3, p->property, (void*) p->data)) < 0) {
if (r == -ENOMEM)
goto oom;
assert(property);
assert(data);
+ /* Let's ensure that pid_t is actually 64bit, and hence this
+ * function can be used for usec_t */
+ assert_cc(sizeof(uint64_t) == sizeof(usec_t));
+
if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, data))
return -ENOMEM;
assert(property);
assert(data);
+ /* Let's ensure that pid_t and mode_t is actually 32bit, and
+ * hence this function can be used for pid_t/mode_t */
+ assert_cc(sizeof(uint32_t) == sizeof(pid_t));
+ assert_cc(sizeof(uint32_t) == sizeof(mode_t));
+ assert_cc(sizeof(uint32_t) == sizeof(unsigned));
+
if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, data))
return -ENOMEM;
return 0;
}
+
+int bus_property_append_int32(Manager *m, DBusMessageIter *i, const char *property, void *data) {
+ assert(m);
+ assert(i);
+ assert(property);
+ assert(data);
+
+ assert_cc(sizeof(int32_t) == sizeof(int));
+
+ if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, data))
+ return -ENOMEM;
+
+ return 0;
+}