X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Flibelogind%2Fsd-bus%2Fsd-bus.c;h=fda12a38486e53b58442f630604d449068e4898d;hb=eb0e417895c37dbdb64f18ae95c6b1a7a99f871e;hp=6d304719e61f55d82467123aac2e5805d8b14693;hpb=1937e3ad6a7f701a09359841cd57e0549c3a3893;p=elogind.git diff --git a/src/libelogind/sd-bus/sd-bus.c b/src/libelogind/sd-bus/sd-bus.c index 6d304719e..fda12a384 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; @@ -233,7 +234,6 @@ _public_ int sd_bus_set_fd(sd_bus *bus, int input_fd, int output_fd) { return 0; } -#if 0 /// UNNEEDED by elogind _public_ int sd_bus_set_exec(sd_bus *bus, const char *path, char *const argv[]) { char *p, **a; @@ -369,7 +369,6 @@ _public_ int sd_bus_set_description(sd_bus *bus, const char *description) { return free_and_strdup(&bus->description, description); } -#endif // 0 _public_ int sd_bus_set_allow_interactive_authorization(sd_bus *bus, int b) { assert_return(bus, -EINVAL); @@ -379,14 +378,12 @@ _public_ int sd_bus_set_allow_interactive_authorization(sd_bus *bus, int b) { return 0; } -#if 0 /// UNNEEDED by elogind _public_ int sd_bus_get_allow_interactive_authorization(sd_bus *bus) { assert_return(bus, -EINVAL); assert_return(!bus_pid_changed(bus), -ECHILD); return bus->allow_interactive_authorization; } -#endif // 0 static int hello_callback(sd_bus_message *reply, void *userdata, sd_bus_error *error) { const char *s; @@ -593,6 +590,8 @@ static int parse_unix_address(sd_bus *b, const char **p, char **guid) { b->sockaddr_size = offsetof(struct sockaddr_un, sun_path) + 1 + l; } + b->is_local = true; + return 0; } @@ -660,6 +659,8 @@ static int parse_tcp_address(sd_bus *b, const char **p, char **guid) { freeaddrinfo(result); + b->is_local = false; + return 0; } @@ -742,6 +743,9 @@ static int parse_exec_address(sd_bus *b, const char **p, char **guid) { b->exec_path = path; b->exec_argv = argv; + + b->is_local = false; + return 0; fail: @@ -785,6 +789,8 @@ static int parse_kernel_address(sd_bus *b, const char **p, char **guid) { b->kernel = path; path = NULL; + b->is_local = true; + return 0; } @@ -842,7 +848,8 @@ static int parse_container_unix_address(sd_bus *b, const char **p, char **guid) b->sockaddr.un.sun_family = AF_UNIX; strncpy(b->sockaddr.un.sun_path, "/var/run/dbus/system_bus_socket", sizeof(b->sockaddr.un.sun_path)); - b->sockaddr_size = offsetof(struct sockaddr_un, sun_path) + strlen("/var/run/dbus/system_bus_socket"); + b->sockaddr_size = SOCKADDR_UN_LEN(b->sockaddr.un); + b->is_local = false; return 0; } @@ -903,6 +910,8 @@ static int parse_container_kernel_address(sd_bus *b, const char **p, char **guid if (r < 0) return r; + b->is_local = false; + return 0; } @@ -1172,7 +1181,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); @@ -1188,6 +1197,7 @@ _public_ int sd_bus_open(sd_bus **ret) { /* We don't know whether the bus is trusted or not, so better * be safe, and authenticate everything */ b->trusted = false; + b->is_local = false; b->attach_flags |= KDBUS_ATTACH_CAPS | KDBUS_ATTACH_CREDS; b->creds_mask |= SD_BUS_CREDS_UID | SD_BUS_CREDS_EUID | SD_BUS_CREDS_EFFECTIVE_CAPS; @@ -1236,6 +1246,7 @@ _public_ int sd_bus_open_system(sd_bus **ret) { b->trusted = false; b->attach_flags |= KDBUS_ATTACH_CAPS | KDBUS_ATTACH_CREDS; b->creds_mask |= SD_BUS_CREDS_UID | SD_BUS_CREDS_EUID | SD_BUS_CREDS_EFFECTIVE_CAPS; + b->is_local = true; r = sd_bus_start(b); if (r < 0) @@ -1305,6 +1316,7 @@ _public_ int sd_bus_open_user(sd_bus **ret) { /* We don't do any per-method access control on the user * bus. */ b->trusted = true; + b->is_local = true; r = sd_bus_start(b); if (r < 0) @@ -1354,7 +1366,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; @@ -1379,6 +1391,7 @@ _public_ int sd_bus_open_system_remote(sd_bus **ret, const char *host) { bus->bus_client = true; bus->trusted = false; bus->is_system = true; + bus->is_local = false; r = sd_bus_start(bus); if (r < 0) @@ -1402,7 +1415,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; @@ -1428,6 +1441,7 @@ _public_ int sd_bus_open_system_machine(sd_bus **ret, const char *machine) { bus->bus_client = true; bus->trusted = false; bus->is_system = true; + bus->is_local = false; r = sd_bus_start(bus); if (r < 0) @@ -1514,7 +1528,6 @@ _public_ sd_bus *sd_bus_unref(sd_bus *bus) { return NULL; } -#if 0 /// UNNEEDED by elogind _public_ int sd_bus_is_open(sd_bus *bus) { assert_return(bus, -EINVAL); @@ -1522,7 +1535,6 @@ _public_ int sd_bus_is_open(sd_bus *bus) { return BUS_IS_OPEN(bus->state); } -#endif // 0 _public_ int sd_bus_can_send(sd_bus *bus, char type) { int r; @@ -1548,7 +1560,6 @@ _public_ int sd_bus_can_send(sd_bus *bus, char type) { return bus_type_is_valid(type); } -#if 0 /// UNNEEDED by elogind _public_ int sd_bus_get_bus_id(sd_bus *bus, sd_id128_t *id) { int r; @@ -1563,7 +1574,6 @@ _public_ int sd_bus_get_bus_id(sd_bus *bus, sd_id128_t *id) { *id = bus->server_id; return 0; } -#endif // 0 static int bus_seal_message(sd_bus *b, sd_bus_message *m, usec_t timeout) { assert(b); @@ -1840,7 +1850,6 @@ _public_ int sd_bus_send(sd_bus *bus, sd_bus_message *m, uint64_t *cookie) { return bus_send_internal(bus, m, cookie, false); } -#if 0 /// UNNEEDED by elogind _public_ int sd_bus_send_to(sd_bus *bus, sd_bus_message *m, const char *destination, uint64_t *cookie) { int r; @@ -1866,7 +1875,6 @@ _public_ int sd_bus_send_to(sd_bus *bus, sd_bus_message *m, const char *destinat return sd_bus_send(bus, m, cookie); } -#endif // 0 static usec_t calc_elapse(uint64_t usec) { if (usec == (uint64_t) -1) @@ -2074,8 +2082,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; @@ -2151,7 +2159,6 @@ fail: return sd_bus_error_set_errno(error, r); } -#if 0 /// UNNEEDED by elogind _public_ int sd_bus_get_fd(sd_bus *bus) { assert_return(bus, -EINVAL); @@ -2160,7 +2167,6 @@ _public_ int sd_bus_get_fd(sd_bus *bus) { return bus->input_fd; } -#endif // 0 _public_ int sd_bus_get_events(sd_bus *bus) { int flags = 0; @@ -2664,62 +2670,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); +} + +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); - return bus_maybe_reply_error(m, r, &error_buffer); + /* 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 +2796,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; @@ -2836,11 +2885,9 @@ _public_ int sd_bus_process(sd_bus *bus, sd_bus_message **ret) { return bus_process_internal(bus, false, 0, ret); } -#if 0 /// UNNEEDED by elogind _public_ int sd_bus_process_priority(sd_bus *bus, int64_t priority, sd_bus_message **ret) { return bus_process_internal(bus, true, priority, ret); } -#endif // 0 static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec) { struct pollfd p[2] = {}; @@ -2957,7 +3004,6 @@ _public_ int sd_bus_flush(sd_bus *bus) { } } -#if 0 /// UNNEEDED by elogind _public_ int sd_bus_add_filter( sd_bus *bus, sd_bus_slot **slot, @@ -2984,7 +3030,6 @@ _public_ int sd_bus_add_filter( return 0; } -#endif // 0 _public_ int sd_bus_add_match( sd_bus *bus, @@ -3338,13 +3383,11 @@ _public_ sd_bus_message* sd_bus_get_current_message(sd_bus *bus) { return bus->current_message; } -#if 0 /// UNNEEDED by elogind _public_ sd_bus_slot* sd_bus_get_current_slot(sd_bus *bus) { assert_return(bus, NULL); return bus->current_slot; } -#endif // 0 _public_ sd_bus_message_handler_t sd_bus_get_current_handler(sd_bus *bus) { assert_return(bus, NULL); @@ -3435,10 +3478,9 @@ _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 _public_ int sd_bus_get_tid(sd_bus *b, pid_t *tid) { assert_return(b, -EINVAL); assert_return(tid, -EINVAL); @@ -3467,7 +3509,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; @@ -3697,7 +3739,6 @@ _public_ int sd_bus_get_description(sd_bus *bus, const char **description) { *description = bus->description; return 0; } -#endif // 0 int bus_get_root_path(sd_bus *bus) { int r; @@ -3717,7 +3758,6 @@ int bus_get_root_path(sd_bus *bus) { return r; } -#if 0 /// UNNEEDED by elogind _public_ int sd_bus_get_scope(sd_bus *bus, const char **scope) { int r; @@ -3829,7 +3869,26 @@ static void flush_close(sd_bus *bus) { _public_ void sd_bus_default_flush_close(void) { flush_close(default_starter_bus); +#if 0 /// There is no user bus with elogind flush_close(default_user_bus); +#endif // 0 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); +} + +_public_ int sd_bus_get_exit_on_disconnect(sd_bus *bus) { + assert_return(bus, -EINVAL); + + return bus->exit_on_disconnect; +}