X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Flibsystemd-bus%2Fsd-bus.c;h=665f1e6c8bae11c7035eed493f168389ac0bb0a9;hp=5d1fcd90a0b87d6e4c93689fc86cb7a13e9afe7b;hb=40ca29a1370379d43e44c0ed425eecc7218dcbca;hpb=7a37d62501c97eb3b48a418ef764d0308e0c3fb9 diff --git a/src/libsystemd-bus/sd-bus.c b/src/libsystemd-bus/sd-bus.c index 5d1fcd90a..665f1e6c8 100644 --- a/src/libsystemd-bus/sd-bus.c +++ b/src/libsystemd-bus/sd-bus.c @@ -45,6 +45,7 @@ #include "bus-introspect.h" #include "bus-signature.h" #include "bus-objects.h" +#include "bus-util.h" static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec); @@ -104,6 +105,8 @@ static void bus_free(sd_bus *b) { assert(b); + sd_bus_detach_event(b); + bus_close_fds(b); if (b->kdbus_buffer) @@ -350,9 +353,11 @@ static int hello_callback(sd_bus *bus, sd_bus_message *reply, void *userdata) { assert(bus->state == BUS_HELLO); assert(reply); - r = bus_message_to_errno(reply); + r = sd_bus_message_get_errno(reply); if (r < 0) return r; + if (r > 0) + return -r; r = sd_bus_message_read(reply, "s", &s); if (r < 0) @@ -1038,6 +1043,8 @@ void sd_bus_close(sd_bus *bus) { bus->state = BUS_CLOSED; + sd_bus_detach_event(bus); + if (!bus->is_kernel) bus_close_fds(bus); @@ -1318,7 +1325,7 @@ int sd_bus_send_with_reply( assert_return(bus, -EINVAL); assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); assert_return(m, -EINVAL); - assert_return(m->header->type == SD_BUS_MESSAGE_TYPE_METHOD_CALL, -EINVAL); + assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL); assert_return(!(m->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED), -EINVAL); assert_return(callback, -EINVAL); assert_return(!bus_pid_changed(bus), -ECHILD); @@ -1428,7 +1435,7 @@ int sd_bus_send_with_reply_and_block( assert_return(bus, -EINVAL); assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); assert_return(m, -EINVAL); - assert_return(m->header->type == SD_BUS_MESSAGE_TYPE_METHOD_CALL, -EINVAL); + assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL); assert_return(!(m->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED), -EINVAL); assert_return(!bus_error_is_dirty(error), -EINVAL); assert_return(!bus_pid_changed(bus), -ECHILD); @@ -1475,7 +1482,7 @@ int sd_bus_send_with_reply_and_block( if (incoming->reply_serial == serial) { /* Found a match! */ - if (incoming->header->type == SD_BUS_MESSAGE_TYPE_METHOD_RETURN) { + if (incoming->header->type == SD_BUS_MESSAGE_METHOD_RETURN) { if (reply) *reply = incoming; @@ -1485,7 +1492,7 @@ int sd_bus_send_with_reply_and_block( return 1; } - if (incoming->header->type == SD_BUS_MESSAGE_TYPE_METHOD_ERROR) { + if (incoming->header->type == SD_BUS_MESSAGE_METHOD_ERROR) { int k; r = sd_bus_error_copy(error, &incoming->error); @@ -1494,9 +1501,9 @@ int sd_bus_send_with_reply_and_block( return r; } - k = bus_error_to_errno(&incoming->error); + k = sd_bus_error_get_errno(&incoming->error); sd_bus_message_unref(incoming); - return k; + return -k; } sd_bus_message_unref(incoming); @@ -1623,7 +1630,7 @@ static int process_timeout(sd_bus *bus) { r = bus_message_new_synthetic_error( bus, c->serial, - &SD_BUS_ERROR_MAKE("org.freedesktop.DBus.Error.Timeout", "Timed out"), + &SD_BUS_ERROR_MAKE(SD_BUS_ERROR_NO_REPLY, "Method call timed out"), &m); if (r < 0) return r; @@ -1649,8 +1656,8 @@ static int process_hello(sd_bus *bus, sd_bus_message *m) { * here (we leave that to the usual handling), we just verify * we don't let any earlier msg through. */ - if (m->header->type != SD_BUS_MESSAGE_TYPE_METHOD_RETURN && - m->header->type != SD_BUS_MESSAGE_TYPE_METHOD_ERROR) + if (m->header->type != SD_BUS_MESSAGE_METHOD_RETURN && + m->header->type != SD_BUS_MESSAGE_METHOD_ERROR) return -EIO; if (m->reply_serial != bus->hello_serial) @@ -1666,8 +1673,8 @@ static int process_reply(sd_bus *bus, sd_bus_message *m) { assert(bus); assert(m); - if (m->header->type != SD_BUS_MESSAGE_TYPE_METHOD_RETURN && - m->header->type != SD_BUS_MESSAGE_TYPE_METHOD_ERROR) + if (m->header->type != SD_BUS_MESSAGE_METHOD_RETURN && + m->header->type != SD_BUS_MESSAGE_METHOD_ERROR) return 0; c = hashmap_remove(bus->reply_callbacks, &m->reply_serial); @@ -1748,7 +1755,7 @@ static int process_builtin(sd_bus *bus, sd_bus_message *m) { assert(bus); assert(m); - if (m->header->type != SD_BUS_MESSAGE_TYPE_METHOD_CALL) + if (m->header->type != SD_BUS_MESSAGE_METHOD_CALL) return 0; if (!streq_ptr(m->interface, "org.freedesktop.DBus.Peer")) @@ -1775,7 +1782,7 @@ static int process_builtin(sd_bus *bus, sd_bus_message *m) { } else { r = sd_bus_message_new_method_errorf( bus, m, &reply, - "org.freedesktop.DBus.Error.UnknownMethod", + SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method '%s' on interface '%s'.", m->member, m->interface); } @@ -1797,6 +1804,12 @@ static int process_message(sd_bus *bus, sd_bus_message *m) { bus->iteration_counter++; + log_debug("Got message sender=%s object=%s interface=%s member=%s", + strna(sd_bus_message_get_sender(m)), + strna(sd_bus_message_get_path(m)), + strna(sd_bus_message_get_interface(m)), + strna(sd_bus_message_get_member(m))); + r = process_hello(bus, m); if (r != 0) return r; @@ -1855,11 +1868,11 @@ static int process_running(sd_bus *bus, sd_bus_message **ret) { return 1; } - if (m->header->type == SD_BUS_MESSAGE_TYPE_METHOD_CALL) { + if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL) { r = sd_bus_reply_method_errorf( bus, m, - "org.freedesktop.DBus.Error.UnknownObject", + SD_BUS_ERROR_UNKNOWN_OBJECT, "Unknown object '%s'.", m->path); if (r < 0) return r; @@ -2123,3 +2136,143 @@ bool bus_pid_changed(sd_bus *bus) { return bus->original_pid != getpid(); } + +static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + void *bus = userdata; + int r; + + assert(bus); + + r = sd_bus_process(bus, NULL); + if (r < 0) + return r; + + return 1; +} + +static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) { + void *bus = userdata; + int r; + + assert(bus); + + r = sd_bus_process(bus, NULL); + if (r < 0) + return r; + + return 1; +} + +static int prepare_callback(sd_event_source *s, void *userdata) { + sd_bus *bus = userdata; + int r, e; + usec_t until; + + assert(s); + assert(bus); + + e = sd_bus_get_events(bus); + if (e < 0) + return e; + + if (bus->output_fd != bus->input_fd) { + + r = sd_event_source_set_io_events(bus->input_io_event_source, e & POLLIN); + if (r < 0) + return r; + + r = sd_event_source_set_io_events(bus->output_io_event_source, e & POLLOUT); + if (r < 0) + return r; + } else { + r = sd_event_source_set_io_events(bus->input_io_event_source, e); + if (r < 0) + return r; + } + + r = sd_bus_get_timeout(bus, &until); + if (r < 0) + return r; + if (r > 0) { + int j; + + j = sd_event_source_set_time(bus->time_event_source, until); + if (j < 0) + return j; + } + + r = sd_event_source_set_enabled(bus->time_event_source, r > 0); + if (r < 0) + return r; + + return 1; +} + +int sd_bus_attach_event(sd_bus *bus, sd_event *event, int priority) { + int r; + + assert_return(bus, -EINVAL); + assert_return(event, -EINVAL); + assert_return(!bus->event, -EBUSY); + + assert(!bus->input_io_event_source); + assert(!bus->output_io_event_source); + assert(!bus->time_event_source); + + bus->event = sd_event_ref(event); + + r = sd_event_add_io(event, bus->input_fd, 0, io_callback, bus, &bus->input_io_event_source); + if (r < 0) + goto fail; + + r = sd_event_source_set_priority(bus->input_io_event_source, priority); + if (r < 0) + goto fail; + + if (bus->output_fd != bus->input_fd) { + r = sd_event_add_io(event, bus->output_fd, 0, io_callback, bus, &bus->output_io_event_source); + if (r < 0) + goto fail; + + r = sd_event_source_set_priority(bus->output_io_event_source, priority); + if (r < 0) + goto fail; + } + + r = sd_event_source_set_prepare(bus->input_io_event_source, prepare_callback); + if (r < 0) + goto fail; + + r = sd_event_add_monotonic(event, 0, 0, time_callback, bus, &bus->time_event_source); + if (r < 0) + goto fail; + + r = sd_event_source_set_priority(bus->time_event_source, priority); + if (r < 0) + goto fail; + + return 0; + +fail: + sd_bus_detach_event(bus); + return r; +} + +int sd_bus_detach_event(sd_bus *bus) { + assert_return(bus, -EINVAL); + assert_return(bus->event, -ENXIO); + + if (bus->input_io_event_source) + bus->input_io_event_source = sd_event_source_unref(bus->input_io_event_source); + + if (bus->output_io_event_source) + bus->output_io_event_source = sd_event_source_unref(bus->output_io_event_source); + + if (bus->time_event_source) + bus->time_event_source = sd_event_source_unref(bus->time_event_source); + + if (bus->event) + bus->event = sd_event_unref(bus->event); + + return 0; +}