X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Flibelogind%2Fsd-bus%2Fsd-bus.c;h=a4f20ca1eabf4c02c384460872b60f720a9a785b;hp=8a5cd38f730974ec3497bb658fb3bf9b81a4e89c;hb=a97a730270418e53e9400de5dce7b07c7dacd19a;hpb=34a47924489b195799b36932f56db80f2d4e1ab6 diff --git a/src/libelogind/sd-bus/sd-bus.c b/src/libelogind/sd-bus/sd-bus.c index 8a5cd38f7..a4f20ca1e 100644 --- a/src/libelogind/sd-bus/sd-bus.c +++ b/src/libelogind/sd-bus/sd-bus.c @@ -109,6 +109,7 @@ static void bus_free(sd_bus *b) { assert(b); assert(!b->track_queue); + assert(!b->tracks); b->state = BUS_CLOSED; @@ -261,6 +262,7 @@ _public_ int sd_bus_set_exec(sd_bus *bus, const char *path, char *const argv[]) return 0; } +#endif // 0 _public_ int sd_bus_set_bus_client(sd_bus *bus, int b) { assert_return(bus, -EINVAL); @@ -271,6 +273,7 @@ _public_ int sd_bus_set_bus_client(sd_bus *bus, int b) { return 0; } +#if 0 /// UNNEEDED by elogind _public_ int sd_bus_set_monitor(sd_bus *bus, int b) { assert_return(bus, -EINVAL); assert_return(bus->state == BUS_UNSET, -EPERM); @@ -279,6 +282,7 @@ _public_ int sd_bus_set_monitor(sd_bus *bus, int b) { SET_FLAG(bus->hello_flags, KDBUS_HELLO_MONITOR, b); return 0; } +#endif // 0 _public_ int sd_bus_negotiate_fds(sd_bus *bus, int b) { assert_return(bus, -EINVAL); @@ -289,6 +293,7 @@ _public_ int sd_bus_negotiate_fds(sd_bus *bus, int b) { return 0; } +#if 0 /// UNNEEDED by elogind _public_ int sd_bus_negotiate_timestamp(sd_bus *bus, int b) { uint64_t new_flags; assert_return(bus, -EINVAL); @@ -332,6 +337,7 @@ _public_ int sd_bus_negotiate_creds(sd_bus *bus, int b, uint64_t mask) { return 0; } +#endif // 0 _public_ int sd_bus_set_server(sd_bus *bus, int b, sd_id128_t server_id) { assert_return(bus, -EINVAL); @@ -353,6 +359,7 @@ _public_ int sd_bus_set_anonymous(sd_bus *bus, int b) { return 0; } +#if 0 /// UNNEEDED by elogind _public_ int sd_bus_set_trusted(sd_bus *bus, int b) { assert_return(bus, -EINVAL); assert_return(bus->state == BUS_UNSET, -EPERM); @@ -1172,7 +1179,7 @@ _public_ int sd_bus_open(sd_bus **ret) { return sd_bus_open_user(ret); else #endif // 0 - return sd_bus_open_system(ret); + return sd_bus_open_system(ret); } r = sd_bus_new(&b); @@ -1354,7 +1361,7 @@ int bus_set_address_system_remote(sd_bus *b, const char *host) { return -ENOMEM; } - b->address = strjoin("unixexec:path=ssh,argv1=-xT,argv2=", e, ",argv3=systemd-stdio-bridge", c, NULL); + b->address = strjoin("unixexec:path=ssh,argv1=-xT,argv2=", e, ",argv3=systemd-stdio-bridge", c); if (!b->address) return -ENOMEM; @@ -1402,7 +1409,7 @@ int bus_set_address_system_machine(sd_bus *b, const char *machine) { if (!e) return -ENOMEM; - b->address = strjoin("x-machine-kernel:machine=", e, ";x-machine-unix:machine=", e, NULL); + b->address = strjoin("x-machine-kernel:machine=", e, ";x-machine-unix:machine=", e); if (!b->address) return -ENOMEM; @@ -2074,8 +2081,8 @@ _public_ int sd_bus_call( } else if (incoming->header->type == SD_BUS_MESSAGE_METHOD_ERROR) { r = sd_bus_error_copy(error, &incoming->error); - sd_bus_message_unref(incoming); - return r; + sd_bus_message_unref(incoming); + return r; } else { r = -EIO; goto fail; @@ -2664,62 +2671,101 @@ null_message: return r; } -static int process_closing(sd_bus *bus, sd_bus_message **ret) { +static int bus_exit_now(sd_bus *bus) { + assert(bus); + + /* Exit due to close, if this is requested. If this is bus object is attached to an event source, invokes + * sd_event_exit(), otherwise invokes libc exit(). */ + + if (bus->exited) /* did we already exit? */ + return 0; + if (!bus->exit_triggered) /* was the exit condition triggered? */ + return 0; + if (!bus->exit_on_disconnect) /* Shall we actually exit on disconnection? */ + return 0; + + bus->exited = true; /* never exit more than once */ + + log_debug("Bus connection disconnected, exiting."); + + if (bus->event) + return sd_event_exit(bus->event, EXIT_FAILURE); + else + exit(EXIT_FAILURE); + + assert_not_reached("exit() didn't exit?"); +} + +static int process_closing_reply_callback(sd_bus *bus, struct reply_callback *c) { + _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; - struct reply_callback *c; + sd_bus_slot *slot; int r; assert(bus); - assert(bus->state == BUS_CLOSING); + assert(c); - c = ordered_hashmap_first(bus->reply_callbacks); - if (c) { - _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL; - sd_bus_slot *slot; + r = bus_message_new_synthetic_error( + bus, + c->cookie, + &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_REPLY, "Connection terminated"), + &m); + if (r < 0) + return r; - /* First, fail all outstanding method calls */ - r = bus_message_new_synthetic_error( - bus, - c->cookie, - &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_REPLY, "Connection terminated"), - &m); - if (r < 0) - return r; + r = bus_seal_synthetic_message(bus, m); + if (r < 0) + return r; - r = bus_seal_synthetic_message(bus, m); - if (r < 0) - return r; + if (c->timeout != 0) { + prioq_remove(bus->reply_callbacks_prioq, c, &c->prioq_idx); + c->timeout = 0; + } - if (c->timeout != 0) { - prioq_remove(bus->reply_callbacks_prioq, c, &c->prioq_idx); - c->timeout = 0; - } + ordered_hashmap_remove(bus->reply_callbacks, &c->cookie); + c->cookie = 0; - ordered_hashmap_remove(bus->reply_callbacks, &c->cookie); - c->cookie = 0; + slot = container_of(c, sd_bus_slot, reply_callback); - slot = container_of(c, sd_bus_slot, reply_callback); + bus->iteration_counter++; - bus->iteration_counter++; + bus->current_message = m; + bus->current_slot = sd_bus_slot_ref(slot); + bus->current_handler = c->callback; + bus->current_userdata = slot->userdata; + r = c->callback(m, slot->userdata, &error_buffer); + bus->current_userdata = NULL; + bus->current_handler = NULL; + bus->current_slot = NULL; + bus->current_message = NULL; - bus->current_message = m; - bus->current_slot = sd_bus_slot_ref(slot); - bus->current_handler = c->callback; - bus->current_userdata = slot->userdata; - r = c->callback(m, slot->userdata, &error_buffer); - bus->current_userdata = NULL; - bus->current_handler = NULL; - bus->current_slot = NULL; - bus->current_message = NULL; + if (slot->floating) { + bus_slot_disconnect(slot); + sd_bus_slot_unref(slot); + } - if (slot->floating) { - bus_slot_disconnect(slot); - sd_bus_slot_unref(slot); - } + sd_bus_slot_unref(slot); - sd_bus_slot_unref(slot); + return bus_maybe_reply_error(m, r, &error_buffer); +} - return bus_maybe_reply_error(m, r, &error_buffer); +static int process_closing(sd_bus *bus, sd_bus_message **ret) { + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; + struct reply_callback *c; + int r; + + assert(bus); + assert(bus->state == BUS_CLOSING); + + /* First, fail all outstanding method calls */ + c = ordered_hashmap_first(bus->reply_callbacks); + if (c) + return process_closing_reply_callback(bus, c); + + /* Then, fake-drop all remaining bus tracking references */ + if (bus->tracks) { + bus_track_close(bus->tracks); + return 1; } /* Then, synthesize a Disconnected message */ @@ -2751,6 +2797,10 @@ static int process_closing(sd_bus *bus, sd_bus_message **ret) { if (r != 0) goto finish; + /* Nothing else to do, exit now, if the condition holds */ + bus->exit_triggered = true; + (void) bus_exit_now(bus); + if (ret) { *ret = m; m = NULL; @@ -3435,7 +3485,7 @@ _public_ int sd_bus_default(sd_bus **ret) { return sd_bus_default_user(ret); else #endif // 0 - return sd_bus_default_system(ret); + return sd_bus_default_system(ret); } #if 0 /// UNNEEDED by elogind @@ -3467,7 +3517,7 @@ _public_ int sd_bus_path_encode(const char *prefix, const char *external_id, cha if (!e) return -ENOMEM; - ret = strjoin(prefix, "/", e, NULL); + ret = strjoin(prefix, "/", e); if (!ret) return -ENOMEM; @@ -3833,3 +3883,23 @@ _public_ void sd_bus_default_flush_close(void) { flush_close(default_system_bus); } #endif // 0 + +_public_ int sd_bus_set_exit_on_disconnect(sd_bus *bus, int b) { + assert_return(bus, -EINVAL); + + /* Turns on exit-on-disconnect, and triggers it immediately if the bus connection was already + * disconnected. Note that this is triggered exclusively on disconnections triggered by the server side, never + * from the client side. */ + bus->exit_on_disconnect = b; + + /* If the exit condition was triggered already, exit immediately. */ + return bus_exit_now(bus); +} + +#if 0 /// UNNEEDED by elogind +_public_ int sd_bus_get_exit_on_disconnect(sd_bus *bus) { + assert_return(bus, -EINVAL); + + return bus->exit_on_disconnect; +} +#endif // 0