X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Flibsystemd%2Fsd-bus%2Fsd-bus.c;h=e677a88bac2919b6e93f029b6e7187a3b010c172;hp=ea80e9d19b5e1ad5d8c5807e0224b2c39d56da7e;hb=affcf189153714f0de4d0986d18e2bc1b35c1b20;hpb=19befb2d5fc087f96e40ddc432b2cc9385666209 diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c index ea80e9d19..e677a88ba 100644 --- a/src/libsystemd/sd-bus/sd-bus.c +++ b/src/libsystemd/sd-bus/sd-bus.c @@ -75,12 +75,6 @@ static void bus_close_fds(sd_bus *b) { static void bus_reset_queues(sd_bus *b) { assert(b); - /* NOTE: We _must_ decrement b->Xqueue_size before calling - * sd_bus_message_unref() for _each_ message. Otherwise the - * self-reference checks in sd_bus_unref() will fire for each message. - * We would thus recurse into sd_bus_message_unref() and trigger the - * assert(m->n_ref > 0) */ - while (b->rqueue_size > 0) sd_bus_message_unref(b->rqueue[--b->rqueue_size]); @@ -148,6 +142,7 @@ static void bus_free(sd_bus *b) { hashmap_free_free(b->reply_callbacks); prioq_free(b->reply_callbacks_prioq); + assert(b->match_callbacks.type == BUS_MATCH_ROOT); bus_match_free(&b->match_callbacks); hashmap_free_free(b->vtable_methods); @@ -355,8 +350,6 @@ static int hello_callback(sd_bus *bus, sd_bus_message *reply, void *userdata, sd assert(reply); r = sd_bus_message_get_errno(reply); - if (r < 0) - return r; if (r > 0) return -r; @@ -774,7 +767,7 @@ static int parse_container_unix_address(sd_bus *b, const char **p, char **guid) if (!machine) return -EINVAL; - if (!filename_is_safe(machine)) + if (!machine_name_is_valid(machine)) return -EINVAL; free(b->machine); @@ -816,7 +809,7 @@ static int parse_container_kernel_address(sd_bus *b, const char **p, char **guid if (!machine) return -EINVAL; - if (!filename_is_safe(machine)) + if (!machine_name_is_valid(machine)) return -EINVAL; free(b->machine); @@ -1039,8 +1032,10 @@ _public_ int sd_bus_start(sd_bus *bus) { else return -EINVAL; - if (r < 0) + if (r < 0) { + sd_bus_close(bus); return r; + } return bus_send_hello(bus); } @@ -1162,13 +1157,17 @@ int bus_set_address_user(sd_bus *b) { return -ENOMEM; #ifdef ENABLE_KDBUS - asprintf(&b->address, KERNEL_USER_BUS_FMT ";" UNIX_USER_BUS_FMT, (unsigned long) getuid(), ee); + asprintf(&b->address, KERNEL_USER_BUS_FMT ";" UNIX_USER_BUS_FMT, getuid(), ee); #else asprintf(&b->address, UNIX_USER_BUS_FMT, ee); #endif } else { #ifdef ENABLE_KDBUS - asprintf(&b->address, KERNEL_USER_BUS_FMT, (unsigned long) getuid()); + int r; + + r = asprintf(&b->address, KERNEL_USER_BUS_FMT, getuid()); + if (r < 0) + return -ENOMEM; #else return -ECONNREFUSED; #endif @@ -1215,15 +1214,38 @@ fail: int bus_set_address_system_remote(sd_bus *b, const char *host) { _cleanup_free_ char *e = NULL; + char *m = NULL, *c = NULL; assert(b); assert(host); - e = bus_address_escape(host); - if (!e) - return -ENOMEM; + /* Let's see if we shall enter some container */ + m = strchr(host, ':'); + if (m) { + m++; + + /* Let's make sure this is not a port of some kind, + * and is a valid machine name. */ + if (!in_charset(m, "0123456789") && machine_name_is_valid(m)) { + char *t; - b->address = strjoin("unixexec:path=ssh,argv1=-xT,argv2=", e, ",argv3=systemd-stdio-bridge", NULL); + /* Cut out the host part */ + t = strndupa(host, m - host - 1); + e = bus_address_escape(t); + if (!e) + return -ENOMEM; + + c = strappenda(",argv4=--machine=", m); + } + } + + if (!e) { + e = bus_address_escape(host); + if (!e) + return -ENOMEM; + } + + b->address = strjoin("unixexec:path=ssh,argv1=-xT,argv2=", e, ",argv3=systemd-stdio-bridge", c, NULL); if (!b->address) return -ENOMEM; @@ -1287,7 +1309,7 @@ _public_ int sd_bus_open_system_container(sd_bus **ret, const char *machine) { assert_return(machine, -EINVAL); assert_return(ret, -EINVAL); - assert_return(filename_is_safe(machine), -EINVAL); + assert_return(machine_name_is_valid(machine), -EINVAL); r = sd_bus_new(&bus); if (r < 0) @@ -1364,53 +1386,6 @@ _public_ sd_bus *sd_bus_unref(sd_bus *bus) { if (!bus) return NULL; - /* TODO/FIXME: It's naive to think REFCNT_GET() is thread-safe in any - * way but exclusive REFCNT_DEC(). The current logic _must_ lock around - * REFCNT_GET() until REFCNT_DEC() or two threads might end up in - * parallel in bus_reset_queues(). But locking would totally break the - * recursion we introduce by bus_reset_queues()... - * (Imagine one thread in sd_bus_message_unref() setting n_ref to 0 and - * thus calling into sd_bus_unref(). If at the same time the real - * thread calls sd_bus_unref(), both end up with "q == true" and will - * call into bus_reset_queues(). - * If we require the main bus to be alive until all dispatch threads - * are done, there is no need to do ref-counts at all. So in both ways, - * the REFCNT thing is humbug.) - * - * On a second note: messages are *not* required to have ->bus set nor - * does it have to be _this_ bus that they're assigned to. This whole - * ref-cnt checking breaks apart if a message is not assigned to us. - * (which is _very_ easy to trigger with the current API). */ - - if (REFCNT_GET(bus->n_ref) == bus->rqueue_size + bus->wqueue_size + 1) { - bool q = true; - - for (i = 0; i < bus->rqueue_size; i++) - if (bus->rqueue[i]->n_ref > 1) { - q = false; - break; - } - - if (q) { - for (i = 0; i < bus->wqueue_size; i++) - if (bus->wqueue[i]->n_ref > 1) { - q = false; - break; - } - } - - /* We are the only holders on the messages, and the - * messages are the only holders on us, so let's drop - * the messages and thus implicitly also kill our own - * last references. - * bus_reset_queues() decrements the queue-size before - * calling into sd_bus_message_unref(). Thus, it - * protects us from recursion. */ - - if (q) - bus_reset_queues(bus); - } - i = REFCNT_DEC(bus->n_ref); if (i > 0) return NULL; @@ -1784,7 +1759,7 @@ _public_ int sd_bus_call_async( if (!BUS_IS_OPEN(bus->state)) return -ENOTCONN; - r = hashmap_ensure_allocated(&bus->reply_callbacks, uint64_hash_func, uint64_compare_func); + r = hashmap_ensure_allocated(&bus->reply_callbacks, &uint64_hash_ops); if (r < 0) return r; @@ -2090,6 +2065,7 @@ static int process_timeout(sd_bus *bus) { _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL; _cleanup_bus_message_unref_ sd_bus_message* m = NULL; struct reply_callback *c; + sd_bus_slot *slot; usec_t n; int r; @@ -2123,18 +2099,28 @@ static int process_timeout(sd_bus *bus) { hashmap_remove(bus->reply_callbacks, &c->cookie); c->cookie = 0; - bus->current_message = m; - bus->current_slot = container_of(c, sd_bus_slot, reply_callback); + slot = container_of(c, sd_bus_slot, reply_callback); bus->iteration_counter ++; - r = c->callback(bus, m, bus->current_slot->userdata, &error_buffer); - r = bus_maybe_reply_error(m, r, &error_buffer); - - 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(bus, m, slot->userdata, &error_buffer); + bus->current_userdata = NULL; + bus->current_handler = NULL; bus->current_slot = NULL; + bus->current_message = NULL; - return r; + if (slot->floating) { + bus_slot_disconnect(slot); + sd_bus_slot_unref(slot); + } + + sd_bus_slot_unref(slot); + + return bus_maybe_reply_error(m, r, &error_buffer); } static int process_hello(sd_bus *bus, sd_bus_message *m) { @@ -2162,8 +2148,8 @@ static int process_hello(sd_bus *bus, sd_bus_message *m) { static int process_reply(sd_bus *bus, sd_bus_message *m) { _cleanup_bus_message_unref_ sd_bus_message *synthetic_reply = NULL; _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL; - sd_bus_slot *slot; struct reply_callback *c; + sd_bus_slot *slot; int r; assert(bus); @@ -2184,12 +2170,8 @@ static int process_reply(sd_bus *bus, sd_bus_message *m) { return 0; c->cookie = 0; - slot = container_of(c, sd_bus_slot, reply_callback); - if (c->timeout != 0) { - prioq_remove(bus->reply_callbacks_prioq, c, &c->prioq_idx); - c->timeout = 0; - } + slot = container_of(c, sd_bus_slot, reply_callback); if (m->n_fds > 0 && !(bus->hello_flags & KDBUS_HELLO_ACCEPT_FD)) { @@ -2202,32 +2184,40 @@ static int process_reply(sd_bus *bus, sd_bus_message *m) { &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INCONSISTENT_MESSAGE, "Reply message contained file descriptor"), &synthetic_reply); if (r < 0) - goto finish; + return r; r = bus_seal_synthetic_message(bus, synthetic_reply); if (r < 0) - goto finish; + return r; m = synthetic_reply; } else { r = sd_bus_message_rewind(m, true); if (r < 0) - goto finish; + return r; } - bus->current_slot = slot; - r = c->callback(bus, m, bus->current_slot->userdata, &error_buffer); - bus->current_slot = NULL; + if (c->timeout != 0) { + prioq_remove(bus->reply_callbacks_prioq, c, &c->prioq_idx); + c->timeout = 0; + } - r = bus_maybe_reply_error(m, r, &error_buffer); + bus->current_slot = sd_bus_slot_ref(slot); + bus->current_handler = c->callback; + bus->current_userdata = slot->userdata; + r = c->callback(bus, m, slot->userdata, &error_buffer); + bus->current_userdata = NULL; + bus->current_handler = NULL; + bus->current_slot = NULL; -finish: if (slot->floating) { bus_slot_disconnect(slot); sd_bus_slot_unref(slot); } - return r; + sd_bus_slot_unref(slot); + + return bus_maybe_reply_error(m, r, &error_buffer); } static int process_filter(sd_bus *bus, sd_bus_message *m) { @@ -2242,6 +2232,7 @@ static int process_filter(sd_bus *bus, sd_bus_message *m) { bus->filter_callbacks_modified = false; LIST_FOREACH(callbacks, l, bus->filter_callbacks) { + sd_bus_slot *slot; if (bus->filter_callbacks_modified) break; @@ -2256,9 +2247,15 @@ static int process_filter(sd_bus *bus, sd_bus_message *m) { if (r < 0) return r; - bus->current_slot = container_of(l, sd_bus_slot, filter_callback); - r = l->callback(bus, m, bus->current_slot->userdata, &error_buffer); - bus->current_slot = NULL; + slot = container_of(l, sd_bus_slot, filter_callback); + + bus->current_slot = sd_bus_slot_ref(slot); + bus->current_handler = l->callback; + bus->current_userdata = slot->userdata; + r = l->callback(bus, m, slot->userdata, &error_buffer); + bus->current_userdata = NULL; + bus->current_handler = NULL; + bus->current_slot = sd_bus_slot_unref(slot); r = bus_maybe_reply_error(m, r, &error_buffer); if (r != 0) @@ -2505,6 +2502,7 @@ static int process_closing(sd_bus *bus, sd_bus_message **ret) { c = hashmap_first(bus->reply_callbacks); if (c) { _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL; + sd_bus_slot *slot; /* First, fail all outstanding method calls */ r = bus_message_new_synthetic_error( @@ -2527,17 +2525,28 @@ static int process_closing(sd_bus *bus, sd_bus_message **ret) { hashmap_remove(bus->reply_callbacks, &c->cookie); c->cookie = 0; - bus->current_message = m; - bus->current_slot = container_of(c, sd_bus_slot, reply_callback); + slot = container_of(c, sd_bus_slot, reply_callback); bus->iteration_counter++; - r = c->callback(bus, m, bus->current_slot->userdata, &error_buffer); - r = bus_maybe_reply_error(m, r, &error_buffer); - + 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(bus, m, slot->userdata, &error_buffer); + bus->current_userdata = NULL; + bus->current_handler = NULL; bus->current_slot = NULL; + bus->current_message = NULL; - goto finish; + if (slot->floating) { + bus_slot_disconnect(slot); + sd_bus_slot_unref(slot); + } + + sd_bus_slot_unref(slot); + + return bus_maybe_reply_error(m, r, &error_buffer); } /* Then, synthesize a Disconnected message */ @@ -2662,7 +2671,7 @@ static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec) { struct pollfd p[2] = {}; int r, e, n; struct timespec ts; - usec_t m = (usec_t) -1; + usec_t m = USEC_INFINITY; assert(bus); @@ -2809,7 +2818,7 @@ _public_ int sd_bus_add_match( struct bus_match_component *components = NULL; unsigned n_components = 0; - sd_bus_slot *s; + sd_bus_slot *s = NULL; int r = 0; assert_return(bus, -EINVAL); @@ -2981,6 +2990,7 @@ static int quit_callback(sd_event_source *event, void *userdata) { assert(event); sd_bus_flush(bus); + sd_bus_close(bus); return 1; } @@ -3006,6 +3016,10 @@ static int attach_io_events(sd_bus *bus) { return r; r = sd_event_source_set_priority(bus->input_io_event_source, bus->event_priority); + if (r < 0) + return r; + + r = sd_event_source_set_name(bus->input_io_event_source, "bus-input"); } else r = sd_event_source_set_io_fd(bus->input_io_event_source, bus->input_fd); @@ -3021,6 +3035,10 @@ static int attach_io_events(sd_bus *bus) { return r; r = sd_event_source_set_priority(bus->output_io_event_source, bus->event_priority); + if (r < 0) + return r; + + r = sd_event_source_set_name(bus->input_io_event_source, "bus-output"); } else r = sd_event_source_set_io_fd(bus->output_io_event_source, bus->output_fd); @@ -3073,10 +3091,18 @@ _public_ int sd_bus_attach_event(sd_bus *bus, sd_event *event, int priority) { if (r < 0) goto fail; + r = sd_event_source_set_name(bus->time_event_source, "bus-time"); + if (r < 0) + goto fail; + r = sd_event_add_exit(bus->event, &bus->quit_event_source, quit_callback, bus); if (r < 0) goto fail; + r = sd_event_source_set_name(bus->quit_event_source, "bus-exit"); + if (r < 0) + goto fail; + r = attach_io_events(bus); if (r < 0) goto fail; @@ -3128,6 +3154,18 @@ _public_ sd_bus_slot* sd_bus_get_current_slot(sd_bus *bus) { return bus->current_slot; } +_public_ sd_bus_message_handler_t sd_bus_get_current_handler(sd_bus *bus) { + assert_return(bus, NULL); + + return bus->current_handler; +} + +_public_ void* sd_bus_get_current_userdata(sd_bus *bus) { + assert_return(bus, NULL); + + return bus->current_userdata; +} + static int bus_default(int (*bus_open)(sd_bus **), sd_bus **default_bus, sd_bus **ret) { sd_bus *b = NULL; int r; @@ -3262,55 +3300,6 @@ _public_ int sd_bus_path_decode(const char *path, const char *prefix, char **ext return 1; } -_public_ int sd_bus_get_peer_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) { - sd_bus_creds *c; - pid_t pid = 0; - int r; - - assert_return(bus, -EINVAL); - assert_return(mask <= _SD_BUS_CREDS_ALL, -ENOTSUP); - assert_return(ret, -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); - - if (bus->is_kernel) - return -ENOTSUP; - - if (!BUS_IS_OPEN(bus->state)) - return -ENOTCONN; - - if (!bus->ucred_valid && !isempty(bus->label)) - return -ENODATA; - - c = bus_creds_new(); - if (!c) - return -ENOMEM; - - if (bus->ucred_valid) { - pid = c->pid = bus->ucred.pid; - c->uid = bus->ucred.uid; - c->gid = bus->ucred.gid; - - c->mask |= (SD_BUS_CREDS_UID | SD_BUS_CREDS_PID | SD_BUS_CREDS_GID) & mask; - } - - if (!isempty(bus->label) && (mask & SD_BUS_CREDS_SELINUX_CONTEXT)) { - c->label = strdup(bus->label); - if (!c->label) { - sd_bus_creds_unref(c); - return -ENOMEM; - } - - c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT; - } - - r = bus_creds_add_more(c, mask, pid, 0); - if (r < 0) - return r; - - *ret = c; - return 0; -} - _public_ int sd_bus_try_close(sd_bus *bus) { int r; @@ -3345,3 +3334,21 @@ _public_ int sd_bus_get_name(sd_bus *bus, const char **name) { *name = bus->connection_name; return 0; } + +int bus_get_root_path(sd_bus *bus) { + int r; + + if (bus->cgroup_root) + return 0; + + r = cg_get_root_path(&bus->cgroup_root); + if (r == -ENOENT) { + bus->cgroup_root = strdup("/"); + if (!bus->cgroup_root) + return -ENOMEM; + + r = 0; + } + + return r; +}