diff options
Diffstat (limited to 'src/libsystemd')
48 files changed, 1801 insertions, 1017 deletions
diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym index 7bf1d66dde..843a1e9880 100644 --- a/src/libsystemd/libsystemd.sym +++ b/src/libsystemd/libsystemd.sym @@ -467,3 +467,16 @@ global: sd_bus_emit_object_removed; sd_bus_flush_close_unref; } LIBSYSTEMD_221; + +LIBSYSTEMD_226 { +global: + sd_pid_get_cgroup; + sd_peer_get_cgroup; +} LIBSYSTEMD_222; + +LIBSYSTEMD_227 { +global: + sd_bus_default_flush_close; + sd_bus_path_decode_many; + sd_bus_path_encode_many; +} LIBSYSTEMD_226; diff --git a/src/libsystemd/sd-bus/bus-common-errors.h b/src/libsystemd/sd-bus/bus-common-errors.h index 0dbfbddcf6..f2092795f4 100644 --- a/src/libsystemd/sd-bus/bus-common-errors.h +++ b/src/libsystemd/sd-bus/bus-common-errors.h @@ -46,6 +46,8 @@ #define BUS_ERROR_NO_MACHINE_FOR_PID "org.freedesktop.machine1.NoMachineForPID" #define BUS_ERROR_MACHINE_EXISTS "org.freedesktop.machine1.MachineExists" #define BUS_ERROR_NO_PRIVATE_NETWORKING "org.freedesktop.machine1.NoPrivateNetworking" +#define BUS_ERROR_NO_SUCH_USER_MAPPING "org.freedesktop.machine1.NoSuchUserMapping" +#define BUS_ERROR_NO_SUCH_GROUP_MAPPING "org.freedesktop.machine1.NoSuchGroupMapping" #define BUS_ERROR_NO_SUCH_SESSION "org.freedesktop.login1.NoSuchSession" #define BUS_ERROR_NO_SESSION_FOR_PID "org.freedesktop.login1.NoSessionForPID" diff --git a/src/libsystemd/sd-bus/bus-container.c b/src/libsystemd/sd-bus/bus-container.c index fa7a207448..435ec92d6f 100644 --- a/src/libsystemd/sd-bus/bus-container.c +++ b/src/libsystemd/sd-bus/bus-container.c @@ -29,10 +29,12 @@ #include "bus-container.h" int bus_container_connect_socket(sd_bus *b) { - _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1; + _cleanup_close_pair_ int pair[2] = { -1, -1 }; + _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1; pid_t child; siginfo_t si; - int r; + int r, error_buf = 0; + ssize_t n; assert(b); assert(b->input_fd < 0); @@ -45,7 +47,7 @@ int bus_container_connect_socket(sd_bus *b) { return r; } - r = namespace_open(b->nspid, &pidnsfd, &mntnsfd, NULL, &rootfd); + r = namespace_open(b->nspid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd); if (r < 0) return r; @@ -57,6 +59,9 @@ int bus_container_connect_socket(sd_bus *b) { bus_socket_setup(b); + if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0) + return -errno; + child = fork(); if (child < 0) return -errno; @@ -64,9 +69,11 @@ int bus_container_connect_socket(sd_bus *b) { if (child == 0) { pid_t grandchild; - r = namespace_enter(pidnsfd, mntnsfd, -1, rootfd); + pair[0] = safe_close(pair[0]); + + r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd); if (r < 0) - _exit(255); + _exit(EXIT_FAILURE); /* We just changed PID namespace, however it will only * take effect on the children we now fork. Hence, @@ -77,16 +84,16 @@ int bus_container_connect_socket(sd_bus *b) { grandchild = fork(); if (grandchild < 0) - _exit(255); + _exit(EXIT_FAILURE); if (grandchild == 0) { r = connect(b->input_fd, &b->sockaddr.sa, b->sockaddr_size); if (r < 0) { - if (errno == EINPROGRESS) - _exit(1); - - _exit(255); + /* Try to send error up */ + error_buf = errno; + (void) write(pair[1], &error_buf, sizeof(error_buf)); + _exit(EXIT_FAILURE); } _exit(EXIT_SUCCESS); @@ -94,24 +101,41 @@ int bus_container_connect_socket(sd_bus *b) { r = wait_for_terminate(grandchild, &si); if (r < 0) - _exit(255); + _exit(EXIT_FAILURE); if (si.si_code != CLD_EXITED) - _exit(255); + _exit(EXIT_FAILURE); _exit(si.si_status); } + pair[1] = safe_close(pair[1]); + r = wait_for_terminate(child, &si); if (r < 0) return r; + n = read(pair[0], &error_buf, sizeof(error_buf)); + if (n < 0) + return -errno; + + if (n > 0) { + if (n != sizeof(error_buf)) + return -EIO; + + if (error_buf < 0) + return -EIO; + + if (error_buf == EINPROGRESS) + return 1; + + if (error_buf > 0) + return -error_buf; + } + if (si.si_code != CLD_EXITED) return -EIO; - if (si.si_status == 1) - return 1; - if (si.si_status != EXIT_SUCCESS) return -EIO; @@ -120,20 +144,27 @@ int bus_container_connect_socket(sd_bus *b) { int bus_container_connect_kernel(sd_bus *b) { _cleanup_close_pair_ int pair[2] = { -1, -1 }; - _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1; + _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1; union { struct cmsghdr cmsghdr; uint8_t buf[CMSG_SPACE(sizeof(int))]; } control = {}; + int error_buf = 0; + struct iovec iov = { + .iov_base = &error_buf, + .iov_len = sizeof(error_buf), + }; struct msghdr mh = { .msg_control = &control, .msg_controllen = sizeof(control), + .msg_iov = &iov, + .msg_iovlen = 1, }; struct cmsghdr *cmsg; pid_t child; siginfo_t si; - int r; - _cleanup_close_ int fd = -1; + int r, fd = -1; + ssize_t n; assert(b); assert(b->input_fd < 0); @@ -146,11 +177,11 @@ int bus_container_connect_kernel(sd_bus *b) { return r; } - r = namespace_open(b->nspid, &pidnsfd, &mntnsfd, NULL, &rootfd); + r = namespace_open(b->nspid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd); if (r < 0) return r; - if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0) + if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0) return -errno; child = fork(); @@ -162,7 +193,7 @@ int bus_container_connect_kernel(sd_bus *b) { pair[0] = safe_close(pair[0]); - r = namespace_enter(pidnsfd, mntnsfd, -1, rootfd); + r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd); if (r < 0) _exit(EXIT_FAILURE); @@ -178,20 +209,16 @@ int bus_container_connect_kernel(sd_bus *b) { _exit(EXIT_FAILURE); if (grandchild == 0) { - fd = open(b->kernel, O_RDWR|O_NOCTTY|O_CLOEXEC); - if (fd < 0) + if (fd < 0) { + /* Try to send error up */ + error_buf = errno; + (void) write(pair[1], &error_buf, sizeof(error_buf)); _exit(EXIT_FAILURE); + } - cmsg = CMSG_FIRSTHDR(&mh); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - cmsg->cmsg_len = CMSG_LEN(sizeof(int)); - memcpy(CMSG_DATA(cmsg), &fd, sizeof(int)); - - mh.msg_controllen = cmsg->cmsg_len; - - if (sendmsg(pair[1], &mh, MSG_NOSIGNAL) < 0) + r = send_one_fd(pair[1], fd, 0); + if (r < 0) _exit(EXIT_FAILURE); _exit(EXIT_SUCCESS); @@ -213,20 +240,17 @@ int bus_container_connect_kernel(sd_bus *b) { if (r < 0) return r; - if (si.si_code != CLD_EXITED) - return -EIO; - - if (si.si_status != EXIT_SUCCESS) - return -EIO; - - if (recvmsg(pair[0], &mh, MSG_NOSIGNAL|MSG_CMSG_CLOEXEC) < 0) + n = recvmsg(pair[0], &mh, MSG_NOSIGNAL|MSG_CMSG_CLOEXEC); + if (n < 0) return -errno; - CMSG_FOREACH(cmsg, &mh) + CMSG_FOREACH(cmsg, &mh) { if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { int *fds; unsigned n_fds; + assert(fd < 0); + fds = (int*) CMSG_DATA(cmsg); n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); @@ -237,9 +261,18 @@ int bus_container_connect_kernel(sd_bus *b) { fd = fds[0]; } + } + + /* If there's an fd passed, we are good. */ + if (fd >= 0) { + b->input_fd = b->output_fd = fd; + return bus_kernel_take_fd(b); + } - b->input_fd = b->output_fd = fd; - fd = -1; + /* If there's an error passed, use it */ + if (n == sizeof(error_buf) && error_buf > 0) + return -error_buf; - return bus_kernel_take_fd(b); + /* Otherwise, we have no clue */ + return -EIO; } diff --git a/src/libsystemd/sd-bus/bus-control.c b/src/libsystemd/sd-bus/bus-control.c index a38c5c50fc..aeb48bedd1 100644 --- a/src/libsystemd/sd-bus/bus-control.c +++ b/src/libsystemd/sd-bus/bus-control.c @@ -256,11 +256,9 @@ static int kernel_get_list(sd_bus *bus, uint64_t flags, char ***x) { name_list = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd.offset); KDBUS_FOREACH(name, name_list, cmd.list_size) { - struct kdbus_item *item; - const char *entry_name = NULL; - if ((flags & KDBUS_LIST_UNIQUE) && name->id != previous_id) { + if ((flags & KDBUS_LIST_UNIQUE) && name->id != previous_id && !(name->flags & KDBUS_HELLO_ACTIVATOR)) { char *n; if (asprintf(&n, ":1.%llu", (unsigned long long) name->id) < 0) { @@ -275,15 +273,15 @@ static int kernel_get_list(sd_bus *bus, uint64_t flags, char ***x) { previous_id = name->id; } - KDBUS_ITEM_FOREACH(item, name, items) - if (item->type == KDBUS_ITEM_OWNED_NAME) - entry_name = item->name.name; - - if (entry_name && service_name_is_valid(entry_name)) { - r = strv_extend(x, entry_name); - if (r < 0) { - r = -ENOMEM; - goto fail; + KDBUS_ITEM_FOREACH(item, name, items) { + if (item->type == KDBUS_ITEM_OWNED_NAME) { + if (service_name_is_valid(item->name.name)) { + r = strv_extend(x, item->name.name); + if (r < 0) { + r = -ENOMEM; + goto fail; + } + } } } } @@ -1131,7 +1129,7 @@ static int add_name_change_match(sd_bus *bus, /* If the old name is unset or empty, then * this can match against added names */ - if (!old_owner || old_owner[0] == 0) { + if (isempty(old_owner)) { item->type = KDBUS_ITEM_NAME_ADD; r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m); @@ -1141,7 +1139,7 @@ static int add_name_change_match(sd_bus *bus, /* If the new name is unset or empty, then * this can match against removed names */ - if (!new_owner || new_owner[0] == 0) { + if (isempty(new_owner)) { item->type = KDBUS_ITEM_NAME_REMOVE; r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m); @@ -1185,8 +1183,10 @@ static int add_name_change_match(sd_bus *bus, /* If the old name is unset or empty, then this can * match against added ids */ - if (!old_owner || old_owner[0] == 0) { + if (isempty(old_owner)) { item->type = KDBUS_ITEM_ID_ADD; + if (!isempty(new_owner)) + item->id_change.id = new_owner_id; r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m); if (r < 0) @@ -1195,8 +1195,10 @@ static int add_name_change_match(sd_bus *bus, /* If thew new name is unset or empty, then this can * match against removed ids */ - if (!new_owner || new_owner[0] == 0) { + if (isempty(new_owner)) { item->type = KDBUS_ITEM_ID_REMOVE; + if (!isempty(old_owner)) + item->id_change.id = old_owner_id; r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m); if (r < 0) @@ -1307,7 +1309,16 @@ int bus_add_match_internal_kernel( break; } - case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST: { + case BUS_MATCH_ARG_HAS...BUS_MATCH_ARG_HAS_LAST: { + char buf[sizeof("arg")-1 + 2 + sizeof("-has")]; + + xsprintf(buf, "arg%i-has", c->type - BUS_MATCH_ARG_HAS); + bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str); + using_bloom = true; + break; + } + + case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST: /* * XXX: DBus spec defines arg[0..63]path= matching to be * a two-way glob. That is, if either string is a prefix @@ -1321,7 +1332,6 @@ int bus_add_match_internal_kernel( * to properly support multiple-matches here. */ break; - } case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: { char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")]; @@ -1332,7 +1342,7 @@ int bus_add_match_internal_kernel( break; } - case BUS_MATCH_DESTINATION: { + case BUS_MATCH_DESTINATION: /* * Kernel only supports matching on destination IDs, but * not on destination names. So just skip the @@ -1345,8 +1355,11 @@ int bus_add_match_internal_kernel( else if (r > 0) sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t)); + /* if not a broadcast, it cannot be a name-change */ + if (r <= 0 || dst_id != KDBUS_DST_ID_BROADCAST) + matches_name_change = false; + break; - } case BUS_MATCH_ROOT: case BUS_MATCH_VALUE: diff --git a/src/libsystemd/sd-bus/bus-convenience.c b/src/libsystemd/sd-bus/bus-convenience.c index dfd82e746d..af5f7da11c 100644 --- a/src/libsystemd/sd-bus/bus-convenience.c +++ b/src/libsystemd/sd-bus/bus-convenience.c @@ -108,15 +108,17 @@ _public_ int sd_bus_call_method( _cleanup_bus_message_unref_ sd_bus_message *m = NULL; int r; - assert_return(bus, -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + bus_assert_return(bus, -EINVAL, error); + bus_assert_return(!bus_pid_changed(bus), -ECHILD, error); - if (!BUS_IS_OPEN(bus->state)) - return -ENOTCONN; + if (!BUS_IS_OPEN(bus->state)) { + r = -ENOTCONN; + goto fail; + } r = sd_bus_message_new_method_call(bus, &m, destination, path, interface, member); if (r < 0) - return r; + goto fail; if (!isempty(types)) { va_list ap; @@ -125,10 +127,13 @@ _public_ int sd_bus_call_method( r = bus_message_append_ap(m, types, ap); va_end(ap); if (r < 0) - return r; + goto fail; } return sd_bus_call(bus, m, 0, error, reply); + +fail: + return sd_bus_error_set_errno(error, r); } _public_ int sd_bus_reply_method_return( @@ -290,15 +295,17 @@ _public_ int sd_bus_get_property( sd_bus_message *rep = NULL; int r; - assert_return(bus, -EINVAL); - assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL); - assert_return(member_name_is_valid(member), -EINVAL); - assert_return(reply, -EINVAL); - assert_return(signature_is_single(type, false), -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + bus_assert_return(bus, -EINVAL, error); + bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error); + bus_assert_return(member_name_is_valid(member), -EINVAL, error); + bus_assert_return(reply, -EINVAL, error); + bus_assert_return(signature_is_single(type, false), -EINVAL, error); + bus_assert_return(!bus_pid_changed(bus), -ECHILD, error); - if (!BUS_IS_OPEN(bus->state)) - return -ENOTCONN; + if (!BUS_IS_OPEN(bus->state)) { + r = -ENOTCONN; + goto fail; + } r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &rep, "ss", strempty(interface), member); if (r < 0) @@ -307,11 +314,14 @@ _public_ int sd_bus_get_property( r = sd_bus_message_enter_container(rep, 'v', type); if (r < 0) { sd_bus_message_unref(rep); - return r; + goto fail; } *reply = rep; return 0; + +fail: + return sd_bus_error_set_errno(error, r); } _public_ int sd_bus_get_property_trivial( @@ -326,15 +336,17 @@ _public_ int sd_bus_get_property_trivial( _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; int r; - assert_return(bus, -EINVAL); - assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL); - assert_return(member_name_is_valid(member), -EINVAL); - assert_return(bus_type_is_trivial(type), -EINVAL); - assert_return(ptr, -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + bus_assert_return(bus, -EINVAL, error); + bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error); + bus_assert_return(member_name_is_valid(member), -EINVAL, error); + bus_assert_return(bus_type_is_trivial(type), -EINVAL, error); + bus_assert_return(ptr, -EINVAL, error); + bus_assert_return(!bus_pid_changed(bus), -ECHILD, error); - if (!BUS_IS_OPEN(bus->state)) - return -ENOTCONN; + if (!BUS_IS_OPEN(bus->state)) { + r = -ENOTCONN; + goto fail; + } r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member); if (r < 0) @@ -342,13 +354,16 @@ _public_ int sd_bus_get_property_trivial( r = sd_bus_message_enter_container(reply, 'v', CHAR_TO_STR(type)); if (r < 0) - return r; + goto fail; r = sd_bus_message_read_basic(reply, type, ptr); if (r < 0) - return r; + goto fail; return 0; + +fail: + return sd_bus_error_set_errno(error, r); } _public_ int sd_bus_get_property_string( @@ -365,14 +380,16 @@ _public_ int sd_bus_get_property_string( char *n; int r; - assert_return(bus, -EINVAL); - assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL); - assert_return(member_name_is_valid(member), -EINVAL); - assert_return(ret, -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + bus_assert_return(bus, -EINVAL, error); + bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error); + bus_assert_return(member_name_is_valid(member), -EINVAL, error); + bus_assert_return(ret, -EINVAL, error); + bus_assert_return(!bus_pid_changed(bus), -ECHILD, error); - if (!BUS_IS_OPEN(bus->state)) - return -ENOTCONN; + if (!BUS_IS_OPEN(bus->state)) { + r = -ENOTCONN; + goto fail; + } r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member); if (r < 0) @@ -380,18 +397,23 @@ _public_ int sd_bus_get_property_string( r = sd_bus_message_enter_container(reply, 'v', "s"); if (r < 0) - return r; + goto fail; r = sd_bus_message_read_basic(reply, 's', &s); if (r < 0) - return r; + goto fail; n = strdup(s); - if (!n) - return -ENOMEM; + if (!n) { + r = -ENOMEM; + goto fail; + } *ret = n; return 0; + +fail: + return sd_bus_error_set_errno(error, r); } _public_ int sd_bus_get_property_strv( @@ -406,14 +428,16 @@ _public_ int sd_bus_get_property_strv( _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; int r; - assert_return(bus, -EINVAL); - assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL); - assert_return(member_name_is_valid(member), -EINVAL); - assert_return(ret, -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + bus_assert_return(bus, -EINVAL, error); + bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error); + bus_assert_return(member_name_is_valid(member), -EINVAL, error); + bus_assert_return(ret, -EINVAL, error); + bus_assert_return(!bus_pid_changed(bus), -ECHILD, error); - if (!BUS_IS_OPEN(bus->state)) - return -ENOTCONN; + if (!BUS_IS_OPEN(bus->state)) { + r = -ENOTCONN; + goto fail; + } r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member); if (r < 0) @@ -421,13 +445,16 @@ _public_ int sd_bus_get_property_strv( r = sd_bus_message_enter_container(reply, 'v', NULL); if (r < 0) - return r; + goto fail; r = sd_bus_message_read_strv(reply, ret); if (r < 0) - return r; + goto fail; return 0; + +fail: + return sd_bus_error_set_errno(error, r); } _public_ int sd_bus_set_property( @@ -443,38 +470,43 @@ _public_ int sd_bus_set_property( va_list ap; int r; - assert_return(bus, -EINVAL); - assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL); - assert_return(member_name_is_valid(member), -EINVAL); - assert_return(signature_is_single(type, false), -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + bus_assert_return(bus, -EINVAL, error); + bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error); + bus_assert_return(member_name_is_valid(member), -EINVAL, error); + bus_assert_return(signature_is_single(type, false), -EINVAL, error); + bus_assert_return(!bus_pid_changed(bus), -ECHILD, error); - if (!BUS_IS_OPEN(bus->state)) - return -ENOTCONN; + if (!BUS_IS_OPEN(bus->state)) { + r = -ENOTCONN; + goto fail; + } r = sd_bus_message_new_method_call(bus, &m, destination, path, "org.freedesktop.DBus.Properties", "Set"); if (r < 0) - return r; + goto fail; r = sd_bus_message_append(m, "ss", strempty(interface), member); if (r < 0) - return r; + goto fail; r = sd_bus_message_open_container(m, 'v', type); if (r < 0) - return r; + goto fail; va_start(ap, type); r = bus_message_append_ap(m, type, ap); va_end(ap); if (r < 0) - return r; + goto fail; r = sd_bus_message_close_container(m); if (r < 0) - return r; + goto fail; return sd_bus_call(bus, m, 0, error, NULL); + +fail: + return sd_bus_error_set_errno(error, r); } _public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_bus_creds **creds) { diff --git a/src/libsystemd/sd-bus/bus-creds.c b/src/libsystemd/sd-bus/bus-creds.c index 1c365b7fcd..3e8cb0b7d0 100644 --- a/src/libsystemd/sd-bus/bus-creds.c +++ b/src/libsystemd/sd-bus/bus-creds.c @@ -107,11 +107,9 @@ _public_ sd_bus_creds *sd_bus_creds_unref(sd_bus_creds *c) { free(c->cgroup_root); free(c->description); - free(c->supplementary_gids); - c->supplementary_gids = NULL; + c->supplementary_gids = mfree(c->supplementary_gids); - strv_free(c->well_known_names); - c->well_known_names = NULL; + c->well_known_names = strv_free(c->well_known_names); bus_creds_done(c); @@ -1015,10 +1013,8 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) { if (r != -EPERM && r != -EACCES) return r; } else { - if (c->cmdline_size == 0) { - free(c->cmdline); - c->cmdline = NULL; - } + if (c->cmdline_size == 0) + c->cmdline = mfree(c->cmdline); c->mask |= SD_BUS_CREDS_CMDLINE; } @@ -1062,8 +1058,8 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) { if (missing & SD_BUS_CREDS_AUDIT_SESSION_ID) { r = audit_session_from_pid(pid, &c->audit_session_id); - if (r == -ENXIO) { - /* ENXIO means: no audit session id assigned */ + if (r == -ENODATA) { + /* ENODATA means: no audit session id assigned */ c->audit_session_id = AUDIT_SESSION_INVALID; c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID; } else if (r < 0) { @@ -1075,8 +1071,8 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) { if (missing & SD_BUS_CREDS_AUDIT_LOGIN_UID) { r = audit_loginuid_from_pid(pid, &c->audit_login_uid); - if (r == -ENXIO) { - /* ENXIO means: no audit login uid assigned */ + if (r == -ENODATA) { + /* ENODATA means: no audit login uid assigned */ c->audit_login_uid = UID_INVALID; c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID; } else if (r < 0) { diff --git a/src/libsystemd/sd-bus/bus-dump.c b/src/libsystemd/sd-bus/bus-dump.c index 9db86adb7f..8833b9c677 100644 --- a/src/libsystemd/sd-bus/bus-dump.c +++ b/src/libsystemd/sd-bus/bus-dump.c @@ -73,8 +73,8 @@ int bus_message_dump(sd_bus_message *m, FILE *f, unsigned flags) { "%s%s%s Type=%s%s%s Endian=%c Flags=%u Version=%u Priority=%"PRIi64, m->header->type == SD_BUS_MESSAGE_METHOD_ERROR ? ansi_highlight_red() : m->header->type == SD_BUS_MESSAGE_METHOD_RETURN ? ansi_highlight_green() : - m->header->type != SD_BUS_MESSAGE_SIGNAL ? ansi_highlight() : "", draw_special_char(DRAW_TRIANGULAR_BULLET), ansi_highlight_off(), - ansi_highlight(), bus_message_type_to_string(m->header->type), ansi_highlight_off(), + m->header->type != SD_BUS_MESSAGE_SIGNAL ? ansi_highlight() : "", draw_special_char(DRAW_TRIANGULAR_BULLET), ansi_normal(), + ansi_highlight(), bus_message_type_to_string(m->header->type), ansi_normal(), m->header->endian, m->header->flags, m->header->version, @@ -93,15 +93,15 @@ int bus_message_dump(sd_bus_message *m, FILE *f, unsigned flags) { fputs("\n", f); if (m->sender) - fprintf(f, " Sender=%s%s%s", ansi_highlight(), m->sender, ansi_highlight_off()); + fprintf(f, " Sender=%s%s%s", ansi_highlight(), m->sender, ansi_normal()); if (m->destination) - fprintf(f, " Destination=%s%s%s", ansi_highlight(), m->destination, ansi_highlight_off()); + fprintf(f, " Destination=%s%s%s", ansi_highlight(), m->destination, ansi_normal()); if (m->path) - fprintf(f, " Path=%s%s%s", ansi_highlight(), m->path, ansi_highlight_off()); + fprintf(f, " Path=%s%s%s", ansi_highlight(), m->path, ansi_normal()); if (m->interface) - fprintf(f, " Interface=%s%s%s", ansi_highlight(), m->interface, ansi_highlight_off()); + fprintf(f, " Interface=%s%s%s", ansi_highlight(), m->interface, ansi_normal()); if (m->member) - fprintf(f, " Member=%s%s%s", ansi_highlight(), m->member, ansi_highlight_off()); + fprintf(f, " Member=%s%s%s", ansi_highlight(), m->member, ansi_normal()); if (m->sender || m->destination || m->path || m->interface || m->member) fputs("\n", f); @@ -110,8 +110,8 @@ int bus_message_dump(sd_bus_message *m, FILE *f, unsigned flags) { fprintf(f, " ErrorName=%s%s%s" " ErrorMessage=%s\"%s\"%s\n", - ansi_highlight_red(), strna(m->error.name), ansi_highlight_off(), - ansi_highlight_red(), strna(m->error.message), ansi_highlight_off()); + ansi_highlight_red(), strna(m->error.name), ansi_normal(), + ansi_highlight_red(), strna(m->error.message), ansi_normal()); if (m->monotonic != 0) fprintf(f, " Monotonic="USEC_FMT, m->monotonic); @@ -211,55 +211,55 @@ int bus_message_dump(sd_bus_message *m, FILE *f, unsigned flags) { switch (type) { case SD_BUS_TYPE_BYTE: - fprintf(f, "%sBYTE %s%u%s;\n", prefix, ansi_highlight(), basic.u8, ansi_highlight_off()); + fprintf(f, "%sBYTE %s%u%s;\n", prefix, ansi_highlight(), basic.u8, ansi_normal()); break; case SD_BUS_TYPE_BOOLEAN: - fprintf(f, "%sBOOLEAN %s%s%s;\n", prefix, ansi_highlight(), true_false(basic.i), ansi_highlight_off()); + fprintf(f, "%sBOOLEAN %s%s%s;\n", prefix, ansi_highlight(), true_false(basic.i), ansi_normal()); break; case SD_BUS_TYPE_INT16: - fprintf(f, "%sINT16 %s%i%s;\n", prefix, ansi_highlight(), basic.s16, ansi_highlight_off()); + fprintf(f, "%sINT16 %s%i%s;\n", prefix, ansi_highlight(), basic.s16, ansi_normal()); break; case SD_BUS_TYPE_UINT16: - fprintf(f, "%sUINT16 %s%u%s;\n", prefix, ansi_highlight(), basic.u16, ansi_highlight_off()); + fprintf(f, "%sUINT16 %s%u%s;\n", prefix, ansi_highlight(), basic.u16, ansi_normal()); break; case SD_BUS_TYPE_INT32: - fprintf(f, "%sINT32 %s%i%s;\n", prefix, ansi_highlight(), basic.s32, ansi_highlight_off()); + fprintf(f, "%sINT32 %s%i%s;\n", prefix, ansi_highlight(), basic.s32, ansi_normal()); break; case SD_BUS_TYPE_UINT32: - fprintf(f, "%sUINT32 %s%u%s;\n", prefix, ansi_highlight(), basic.u32, ansi_highlight_off()); + fprintf(f, "%sUINT32 %s%u%s;\n", prefix, ansi_highlight(), basic.u32, ansi_normal()); break; case SD_BUS_TYPE_INT64: - fprintf(f, "%sINT64 %s%"PRIi64"%s;\n", prefix, ansi_highlight(), basic.s64, ansi_highlight_off()); + fprintf(f, "%sINT64 %s%"PRIi64"%s;\n", prefix, ansi_highlight(), basic.s64, ansi_normal()); break; case SD_BUS_TYPE_UINT64: - fprintf(f, "%sUINT64 %s%"PRIu64"%s;\n", prefix, ansi_highlight(), basic.u64, ansi_highlight_off()); + fprintf(f, "%sUINT64 %s%"PRIu64"%s;\n", prefix, ansi_highlight(), basic.u64, ansi_normal()); break; case SD_BUS_TYPE_DOUBLE: - fprintf(f, "%sDOUBLE %s%g%s;\n", prefix, ansi_highlight(), basic.d64, ansi_highlight_off()); + fprintf(f, "%sDOUBLE %s%g%s;\n", prefix, ansi_highlight(), basic.d64, ansi_normal()); break; case SD_BUS_TYPE_STRING: - fprintf(f, "%sSTRING \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_highlight_off()); + fprintf(f, "%sSTRING \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_normal()); break; case SD_BUS_TYPE_OBJECT_PATH: - fprintf(f, "%sOBJECT_PATH \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_highlight_off()); + fprintf(f, "%sOBJECT_PATH \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_normal()); break; case SD_BUS_TYPE_SIGNATURE: - fprintf(f, "%sSIGNATURE \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_highlight_off()); + fprintf(f, "%sSIGNATURE \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_normal()); break; case SD_BUS_TYPE_UNIX_FD: - fprintf(f, "%sUNIX_FD %s%i%s;\n", prefix, ansi_highlight(), basic.i, ansi_highlight_off()); + fprintf(f, "%sUNIX_FD %s%i%s;\n", prefix, ansi_highlight(), basic.i, ansi_normal()); break; default: @@ -327,7 +327,7 @@ static void dump_capabilities( fputs("\n", f); if (!terse) - fputs(ansi_highlight_off(), f); + fputs(ansi_normal(), f); } int bus_creds_dump(sd_bus_creds *c, FILE *f, bool terse) { @@ -352,7 +352,7 @@ int bus_creds_dump(sd_bus_creds *c, FILE *f, bool terse) { prefix = ""; color = ansi_highlight(); - off = ansi_highlight_off(); + off = ansi_normal(); suffix = strjoina(off, "\n"); } @@ -551,9 +551,8 @@ int bus_pcap_header(size_t snaplen, FILE *f) { hdr.snaplen = (uint32_t) snaplen; fwrite(&hdr, 1, sizeof(hdr), f); - fflush(f); - return 0; + return fflush_and_check(f); } int bus_message_pcap_frame(sd_bus_message *m, size_t snaplen, FILE *f) { @@ -598,7 +597,5 @@ int bus_message_pcap_frame(sd_bus_message *m, size_t snaplen, FILE *f) { snaplen -= w; } - fflush(f); - - return 0; + return fflush_and_check(f); } diff --git a/src/libsystemd/sd-bus/bus-gvariant.c b/src/libsystemd/sd-bus/bus-gvariant.c index 2d18a4e6c1..402d43d66d 100644 --- a/src/libsystemd/sd-bus/bus-gvariant.c +++ b/src/libsystemd/sd-bus/bus-gvariant.c @@ -75,14 +75,19 @@ int bus_gvariant_get_size(const char *signature) { case SD_BUS_TYPE_STRUCT_BEGIN: case SD_BUS_TYPE_DICT_ENTRY_BEGIN: { - char t[n-1]; - - memcpy(t, p + 1, n - 2); - t[n - 2] = 0; - - r = bus_gvariant_get_size(t); - if (r < 0) - return r; + if (n == 2) { + /* unary type () has fixed size of 1 */ + r = 1; + } else { + char t[n-1]; + + memcpy(t, p + 1, n - 2); + t[n - 2] = 0; + + r = bus_gvariant_get_size(t); + if (r < 0) + return r; + } sum += r; break; diff --git a/src/libsystemd/sd-bus/bus-internal.h b/src/libsystemd/sd-bus/bus-internal.h index c3e20ee1bf..e399701beb 100644 --- a/src/libsystemd/sd-bus/bus-internal.h +++ b/src/libsystemd/sd-bus/bus-internal.h @@ -393,3 +393,9 @@ int bus_remove_match_by_string(sd_bus *bus, const char *match, sd_bus_message_ha int bus_get_root_path(sd_bus *bus); int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error); + +#define bus_assert_return(expr, r, error) \ + do { \ + if (!assert_log(expr, #expr)) \ + return sd_bus_error_set_errno(error, r); \ + } while (false) diff --git a/src/libsystemd/sd-bus/bus-introspect.c b/src/libsystemd/sd-bus/bus-introspect.c index e2f4550c7e..3149a56397 100644 --- a/src/libsystemd/sd-bus/bus-introspect.c +++ b/src/libsystemd/sd-bus/bus-introspect.c @@ -81,6 +81,9 @@ static void introspect_write_flags(struct introspect *i, int type, int flags) { fputs(" <annotation name=\"org.freedesktop.DBus.Method.NoReply\" value=\"true\"/>\n", i->f); if (type == _SD_BUS_VTABLE_PROPERTY || type == _SD_BUS_VTABLE_WRITABLE_PROPERTY) { + if (flags & SD_BUS_VTABLE_PROPERTY_EXPLICIT) + fputs(" <annotation name=\"org.freedesktop.systemd1.Explicit\" value=\"true\"/>\n", i->f); + if (flags & SD_BUS_VTABLE_PROPERTY_CONST) fputs(" <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"const\"/>\n", i->f); else if (flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) @@ -179,10 +182,10 @@ int introspect_finish(struct introspect *i, sd_bus *bus, sd_bus_message *m, sd_b assert(reply); fputs("</node>\n", i->f); - fflush(i->f); - if (ferror(i->f)) - return -ENOMEM; + r = fflush_and_check(i->f); + if (r < 0) + return r; r = sd_bus_message_new_method_return(m, &q); if (r < 0) @@ -201,11 +204,8 @@ int introspect_finish(struct introspect *i, sd_bus *bus, sd_bus_message *m, sd_b void introspect_free(struct introspect *i) { assert(i); - if (i->f) - fclose(i->f); - - if (i->introspection) - free(i->introspection); + safe_fclose(i->f); + free(i->introspection); zero(*i); } diff --git a/src/libsystemd/sd-bus/bus-kernel.c b/src/libsystemd/sd-bus/bus-kernel.c index e3fac01f92..577a8b44c3 100644 --- a/src/libsystemd/sd-bus/bus-kernel.c +++ b/src/libsystemd/sd-bus/bus-kernel.c @@ -168,6 +168,27 @@ static void add_bloom_arg(void *data, size_t size, unsigned n_hash, unsigned i, bloom_add_prefixes(data, size, n_hash, buf, t, '/'); } +static void add_bloom_arg_has(void *data, size_t size, unsigned n_hash, unsigned i, const char *t) { + char buf[sizeof("arg")-1 + 2 + sizeof("-has")]; + char *e; + + assert(data); + assert(size > 0); + assert(i < 64); + assert(t); + + e = stpcpy(buf, "arg"); + if (i < 10) + *(e++) = '0' + (char) i; + else { + *(e++) = '0' + (char) (i / 10); + *(e++) = '0' + (char) (i % 10); + } + + strcpy(e, "-has"); + bloom_add_pair(data, size, n_hash, buf, t); +} + static int bus_message_setup_bloom(sd_bus_message *m, struct kdbus_bloom_filter *bloom) { void *data; unsigned i; @@ -212,7 +233,9 @@ static int bus_message_setup_bloom(sd_bus_message *m, struct kdbus_bloom_filter return r; add_bloom_arg(data, m->bus->bloom_size, m->bus->bloom_n_hash, i, t); - } if (type == SD_BUS_TYPE_ARRAY && STR_IN_SET(contents, "s", "o", "g")) { + } + + if (type == SD_BUS_TYPE_ARRAY && STR_IN_SET(contents, "s", "o", "g")) { /* As well as array of simple strings of any kinds */ r = sd_bus_message_enter_container(m, type, contents); @@ -220,7 +243,7 @@ static int bus_message_setup_bloom(sd_bus_message *m, struct kdbus_bloom_filter return r; while ((r = sd_bus_message_read_basic(m, contents[0], &t)) > 0) - add_bloom_arg(data, m->bus->bloom_size, m->bus->bloom_n_hash, i, t); + add_bloom_arg_has(data, m->bus->bloom_size, m->bus->bloom_n_hash, i, t); if (r < 0) return r; @@ -774,6 +797,7 @@ static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) { case KDBUS_ITEM_FDS: case KDBUS_ITEM_SECLABEL: + case KDBUS_ITEM_BLOOM_FILTER: break; default: @@ -1332,8 +1356,7 @@ static int bus_kernel_translate_message(sd_bus *bus, struct kdbus_msg *k) { KDBUS_ITEM_FOREACH(d, k, items) { if (d->type == KDBUS_ITEM_TIMESTAMP) ts = &d->timestamp; - - if (d->type >= _KDBUS_ITEM_KERNEL_BASE && d->type < _KDBUS_ITEM_KERNEL_BASE + ELEMENTSOF(translate)) { + else if (d->type >= _KDBUS_ITEM_KERNEL_BASE && d->type < _KDBUS_ITEM_KERNEL_BASE + ELEMENTSOF(translate)) { if (found) return -EBADMSG; found = d; diff --git a/src/libsystemd/sd-bus/bus-match.c b/src/libsystemd/sd-bus/bus-match.c index 132b37526e..7234e7926a 100644 --- a/src/libsystemd/sd-bus/bus-match.c +++ b/src/libsystemd/sd-bus/bus-match.c @@ -62,12 +62,13 @@ */ static inline bool BUS_MATCH_IS_COMPARE(enum bus_match_node_type t) { - return t >= BUS_MATCH_SENDER && t <= BUS_MATCH_ARG_NAMESPACE_LAST; + return t >= BUS_MATCH_SENDER && t <= BUS_MATCH_ARG_HAS_LAST; } static inline bool BUS_MATCH_CAN_HASH(enum bus_match_node_type t) { return (t >= BUS_MATCH_MESSAGE_TYPE && t <= BUS_MATCH_PATH) || - (t >= BUS_MATCH_ARG && t <= BUS_MATCH_ARG_LAST); + (t >= BUS_MATCH_ARG && t <= BUS_MATCH_ARG_LAST) || + (t >= BUS_MATCH_ARG_HAS && t <= BUS_MATCH_ARG_HAS_LAST); } static void bus_match_node_free(struct bus_match_node *node) { @@ -179,12 +180,16 @@ static bool value_node_test( case BUS_MATCH_INTERFACE: case BUS_MATCH_MEMBER: case BUS_MATCH_PATH: - case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST: { - char **i; + case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST: if (value_str) return streq_ptr(node->value.str, value_str); + return false; + + case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST: { + char **i; + STRV_FOREACH(i, value_strv) if (streq_ptr(node->value.str, *i)) return true; @@ -192,33 +197,20 @@ static bool value_node_test( return false; } - case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST: { - char **i; - + case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST: if (value_str) return namespace_simple_pattern(node->value.str, value_str); - STRV_FOREACH(i, value_strv) - if (namespace_simple_pattern(node->value.str, *i)) - return true; return false; - } case BUS_MATCH_PATH_NAMESPACE: return path_simple_pattern(node->value.str, value_str); - case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST: { - char **i; - + case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST: if (value_str) return path_complex_pattern(node->value.str, value_str); - STRV_FOREACH(i, value_strv) - if (path_complex_pattern(node->value.str, *i)) - return true; - return false; - } default: assert_not_reached("Invalid node type"); @@ -249,6 +241,7 @@ static bool value_node_same( case BUS_MATCH_MEMBER: case BUS_MATCH_PATH: case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST: + case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST: case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST: case BUS_MATCH_PATH_NAMESPACE: case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST: @@ -372,15 +365,19 @@ int bus_match_run( break; case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST: - (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG, &test_str, &test_strv); + (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG, &test_str); break; case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST: - (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG_PATH, &test_str, &test_strv); + (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG_PATH, &test_str); break; case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST: - (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG_NAMESPACE, &test_str, &test_strv); + (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG_NAMESPACE, &test_str); + break; + + case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST: + (void) bus_message_get_arg_strv(m, node->type - BUS_MATCH_ARG_HAS, &test_strv); break; default: @@ -743,6 +740,32 @@ enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n return t; } + if (n == 7 && startswith(k, "arg") && startswith(k + 4, "has")) { + int j; + + j = undecchar(k[3]); + if (j < 0) + return -EINVAL; + + return BUS_MATCH_ARG_HAS + j; + } + + if (n == 8 && startswith(k, "arg") && startswith(k + 5, "has")) { + enum bus_match_node_type t; + int a, b; + + a = undecchar(k[3]); + b = undecchar(k[4]); + if (a <= 0 || b < 0) + return -EINVAL; + + t = BUS_MATCH_ARG_HAS + a * 10 + b; + if (t > BUS_MATCH_ARG_HAS_LAST) + return -EINVAL; + + return t; + } + return -EINVAL; } @@ -861,8 +884,7 @@ int bus_match_parse( if (r < 0) goto fail; - free(value); - value = NULL; + value = mfree(value); } else u = 0; @@ -910,10 +932,11 @@ fail: } char *bus_match_to_string(struct bus_match_component *components, unsigned n_components) { - _cleanup_free_ FILE *f = NULL; + _cleanup_fclose_ FILE *f = NULL; char *buffer = NULL; size_t size = 0; unsigned i; + int r; if (n_components <= 0) return strdup(""); @@ -942,8 +965,8 @@ char *bus_match_to_string(struct bus_match_component *components, unsigned n_com fputc('\'', f); } - fflush(f); - if (ferror(f)) + r = fflush_and_check(f); + if (r < 0) return NULL; return buffer; @@ -1111,6 +1134,10 @@ const char* bus_match_node_type_to_string(enum bus_match_node_type t, char buf[] snprintf(buf, l, "arg%inamespace", t - BUS_MATCH_ARG_NAMESPACE); return buf; + case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST: + snprintf(buf, l, "arg%ihas", t - BUS_MATCH_ARG_HAS); + return buf; + default: return NULL; } diff --git a/src/libsystemd/sd-bus/bus-match.h b/src/libsystemd/sd-bus/bus-match.h index 56516be9fa..53ee0463ca 100644 --- a/src/libsystemd/sd-bus/bus-match.h +++ b/src/libsystemd/sd-bus/bus-match.h @@ -44,6 +44,8 @@ enum bus_match_node_type { BUS_MATCH_ARG_PATH_LAST = BUS_MATCH_ARG_PATH + 63, BUS_MATCH_ARG_NAMESPACE, BUS_MATCH_ARG_NAMESPACE_LAST = BUS_MATCH_ARG_NAMESPACE + 63, + BUS_MATCH_ARG_HAS, + BUS_MATCH_ARG_HAS_LAST = BUS_MATCH_ARG_HAS + 63, _BUS_MATCH_NODE_TYPE_MAX, _BUS_MATCH_NODE_TYPE_INVALID = -1 }; diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c index 983e2f62cd..72e2b9f785 100644 --- a/src/libsystemd/sd-bus/bus-message.c +++ b/src/libsystemd/sd-bus/bus-message.c @@ -113,8 +113,7 @@ static void message_reset_containers(sd_bus_message *m) { free(m->containers[i].offsets); } - free(m->containers); - m->containers = NULL; + m->containers = mfree(m->containers); m->n_containers = m->containers_allocated = 0; m->root_container.index = 0; @@ -144,11 +143,7 @@ static void message_free(sd_bus_message *m) { if (m->iovec != m->iovec_fixed) free(m->iovec); - if (m->destination_ptr) { - free(m->destination_ptr); - m->destination_ptr = NULL; - } - + m->destination_ptr = mfree(m->destination_ptr); message_reset_containers(m); free(m->root_container.signature); free(m->root_container.offsets); @@ -608,8 +603,8 @@ static sd_bus_message *message_new(sd_bus *bus, uint8_t type) { m->header = (struct bus_header*) ((uint8_t*) m + ALIGN(sizeof(struct sd_bus_message))); m->header->endian = BUS_NATIVE_ENDIAN; m->header->type = type; - m->header->version = bus ? bus->message_version : 1; - m->allow_fds = !bus || bus->can_fds || (bus->state != BUS_HELLO && bus->state != BUS_RUNNING); + m->header->version = bus->message_version; + m->allow_fds = bus->can_fds || (bus->state != BUS_HELLO && bus->state != BUS_RUNNING); m->root_container.need_offsets = BUS_MESSAGE_IS_GVARIANT(m); m->bus = sd_bus_ref(bus); @@ -1028,7 +1023,9 @@ _public_ const char *sd_bus_message_get_sender(sd_bus_message *m) { _public_ const sd_bus_error *sd_bus_message_get_error(sd_bus_message *m) { assert_return(m, NULL); - assert_return(sd_bus_error_is_set(&m->error), NULL); + + if (!sd_bus_error_is_set(&m->error)) + return NULL; return &m->error; } @@ -2161,6 +2158,7 @@ static int bus_message_close_variant(sd_bus_message *m, struct bus_container *c) } static int bus_message_close_struct(sd_bus_message *m, struct bus_container *c, bool add_offset) { + bool fixed_size = true; size_t n_variable = 0; unsigned i = 0; const char *p; @@ -2196,6 +2194,8 @@ static int bus_message_close_struct(sd_bus_message *m, struct bus_container *c, /* We need to add an offset for each item that has a * variable size and that is not the last one in the * list */ + if (r == 0) + fixed_size = false; if (r == 0 && p[n] != 0) n_variable++; @@ -2206,8 +2206,27 @@ static int bus_message_close_struct(sd_bus_message *m, struct bus_container *c, assert(!c->need_offsets || i == c->n_offsets); assert(c->need_offsets || n_variable == 0); - if (n_variable <= 0) { - a = message_extend_body(m, 1, 0, add_offset, false); + if (isempty(c->signature)) { + /* The unary type is encoded as fixed 1 byte padding */ + a = message_extend_body(m, 1, 1, add_offset, false); + if (!a) + return -ENOMEM; + + *a = 0; + } else if (n_variable <= 0) { + int alignment = 1; + + /* Structures with fixed-size members only have to be + * fixed-size themselves. But gvariant requires all fixed-size + * elements to be sized a multiple of their alignment. Hence, + * we must *always* add final padding after the last member so + * the overall size of the structure is properly aligned. */ + if (fixed_size) + alignment = bus_gvariant_get_alignment(strempty(c->signature)); + + assert(alignment > 0); + + a = message_extend_body(m, alignment, 0, add_offset, false); if (!a) return -ENOMEM; } else { @@ -2665,7 +2684,7 @@ _public_ int sd_bus_message_append_array_memfd( int r; assert_return(m, -EINVAL); - assert_return(memfd >= 0, -EINVAL); + assert_return(memfd >= 0, -EBADF); assert_return(bus_type_is_trivial(type), -EINVAL); assert_return(size > 0, -EINVAL); assert_return(!m->sealed, -EPERM); @@ -2741,7 +2760,7 @@ _public_ int sd_bus_message_append_string_memfd( int r; assert_return(m, -EINVAL); - assert_return(memfd >= 0, -EINVAL); + assert_return(memfd >= 0, -EBADF); assert_return(size > 0, -EINVAL); assert_return(!m->sealed, -EPERM); assert_return(!m->poisoned, -ESTALE); @@ -2884,18 +2903,20 @@ static int bus_message_close_header(sd_bus_message *m) { signature = strempty(m->root_container.signature); l = strlen(signature); - sz = bus_gvariant_determine_word_size(sizeof(struct bus_header) + ALIGN8(m->fields_size) + m->body_size + 1 + l, 1); - d = message_extend_body(m, 1, 1 + l + sz, false, true); + sz = bus_gvariant_determine_word_size(sizeof(struct bus_header) + ALIGN8(m->fields_size) + m->body_size + 1 + l + 2, 1); + d = message_extend_body(m, 1, 1 + l + 2 + sz, false, true); if (!d) return -ENOMEM; *(uint8_t*) d = 0; - memcpy((uint8_t*) d + 1, signature, l); + *((uint8_t*) d + 1) = SD_BUS_TYPE_STRUCT_BEGIN; + memcpy((uint8_t*) d + 2, signature, l); + *((uint8_t*) d + 1 + l + 1) = SD_BUS_TYPE_STRUCT_END; - bus_gvariant_write_word_le((uint8_t*) d + 1 + l, sz, sizeof(struct bus_header) + m->fields_size); + bus_gvariant_write_word_le((uint8_t*) d + 1 + l + 2, sz, sizeof(struct bus_header) + m->fields_size); m->footer = d; - m->footer_accessible = 1 + l + sz; + m->footer_accessible = 1 + l + 2 + sz; } else { m->header->dbus1.fields_size = m->fields_size; m->header->dbus1.body_size = m->body_size; @@ -3799,6 +3820,14 @@ static int build_struct_offsets( assert(n_offsets); if (isempty(signature)) { + /* Unary type is encoded as *fixed* 1 byte padding */ + r = message_peek_body(m, &m->rindex, 1, 1, &q); + if (r < 0) + return r; + + if (*(uint8_t *) q != 0) + return -EBADMSG; + *item_size = 0; *offsets = NULL; *n_offsets = 0; @@ -3939,12 +3968,6 @@ static int enter_struct_or_dict_entry( if (r < 0) return r; - } else if (c->item_size <= 0) { - - /* gvariant empty struct */ - *item_size = 0; - *offsets = NULL; - *n_offsets = 0; } else /* gvariant with contents */ return build_struct_offsets(m, contents, c->item_size, item_size, offsets, n_offsets); @@ -4131,7 +4154,14 @@ _public_ int sd_bus_message_enter_container(sd_bus_message *m, w->before = before; w->begin = m->rindex; - w->end = m->rindex + c->item_size; + + /* Unary type has fixed size of 1, but virtual size of 0 */ + if (BUS_MESSAGE_IS_GVARIANT(m) && + type == SD_BUS_TYPE_STRUCT && + isempty(signature)) + w->end = m->rindex + 0; + else + w->end = m->rindex + c->item_size; w->array_size = array_size; w->item_size = item_size; @@ -4741,7 +4771,6 @@ _public_ int sd_bus_message_skip(sd_bus_message *m, const char *types) { r = sd_bus_message_skip(m, s); if (r < 0) return r; - assert(r != 0); r = sd_bus_message_exit_container(m); if (r < 0) @@ -5149,11 +5178,21 @@ int bus_message_parse_fields(sd_bus_message *m) { return -EBADMSG; if (*p == 0) { + size_t l; char *c; - /* We found the beginning of the signature string, yay! */ + /* We found the beginning of the signature + * string, yay! We require the body to be a + * structure, so verify it and then strip the + * opening/closing brackets. */ + + l = ((char*) m->footer + m->footer_accessible) - p - (1 + sz); + if (l < 2 || + p[1] != SD_BUS_TYPE_STRUCT_BEGIN || + p[1 + l - 1] != SD_BUS_TYPE_STRUCT_END) + return -EBADMSG; - c = strndup(p + 1, ((char*) m->footer + m->footer_accessible) - p - (1 + sz)); + c = strndup(p + 1 + 1, l - 2); if (!c) return -ENOMEM; @@ -5574,21 +5613,23 @@ _public_ int sd_bus_message_read_strv(sd_bus_message *m, char ***l) { return 1; } -int bus_message_get_arg(sd_bus_message *m, unsigned i, const char **str, char ***strv) { - const char *contents; +static int bus_message_get_arg_skip( + sd_bus_message *m, + unsigned i, + char *_type, + const char **_contents) { + unsigned j; - char type; int r; - assert(m); - assert(str); - assert(strv); - r = sd_bus_message_rewind(m, true); if (r < 0) return r; for (j = 0;; j++) { + const char *contents; + char type; + r = sd_bus_message_peek_type(m, &type, &contents); if (r < 0) return r; @@ -5600,31 +5641,56 @@ int bus_message_get_arg(sd_bus_message *m, unsigned i, const char **str, char ** !(type == SD_BUS_TYPE_ARRAY && STR_IN_SET(contents, "s", "o", "g"))) return -ENXIO; - if (j >= i) - break; + if (j >= i) { + if (_contents) + *_contents = contents; + if (_type) + *_type = type; + return 0; + } r = sd_bus_message_skip(m, NULL); if (r < 0) return r; } - if (type == SD_BUS_TYPE_ARRAY) { +} - r = sd_bus_message_read_strv(m, strv); - if (r < 0) - return r; +int bus_message_get_arg(sd_bus_message *m, unsigned i, const char **str) { + char type; + int r; - *str = NULL; + assert(m); + assert(str); - } else { - r = sd_bus_message_read_basic(m, type, str); - if (r < 0) - return r; + r = bus_message_get_arg_skip(m, i, &type, NULL); + if (r < 0) + return r; - *strv = NULL; - } + if (!IN_SET(type, SD_BUS_TYPE_STRING, SD_BUS_TYPE_OBJECT_PATH, SD_BUS_TYPE_SIGNATURE)) + return -ENXIO; - return 0; + return sd_bus_message_read_basic(m, type, str); +} + +int bus_message_get_arg_strv(sd_bus_message *m, unsigned i, char ***strv) { + const char *contents; + char type; + int r; + + assert(m); + assert(strv); + + r = bus_message_get_arg_skip(m, i, &type, &contents); + if (r < 0) + return r; + + if (type != SD_BUS_TYPE_ARRAY) + return -ENXIO; + if (!STR_IN_SET(contents, "s", "o", "g")) + return -ENXIO; + + return sd_bus_message_read_strv(m, strv); } _public_ int sd_bus_message_get_errno(sd_bus_message *m) { diff --git a/src/libsystemd/sd-bus/bus-message.h b/src/libsystemd/sd-bus/bus-message.h index 088d5b1109..ff25003461 100644 --- a/src/libsystemd/sd-bus/bus-message.h +++ b/src/libsystemd/sd-bus/bus-message.h @@ -218,7 +218,8 @@ int bus_message_from_malloc( const char *label, sd_bus_message **ret); -int bus_message_get_arg(sd_bus_message *m, unsigned i, const char **str, char ***strv); +int bus_message_get_arg(sd_bus_message *m, unsigned i, const char **str); +int bus_message_get_arg_strv(sd_bus_message *m, unsigned i, char ***strv); int bus_message_append_ap(sd_bus_message *m, const char *types, va_list ap); diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c index cbdf6552f9..1d061cb9cf 100644 --- a/src/libsystemd/sd-bus/bus-objects.c +++ b/src/libsystemd/sd-bus/bus-objects.c @@ -68,6 +68,12 @@ static int node_vtable_get_userdata( return 1; } +static void *vtable_method_convert_userdata(const sd_bus_vtable *p, void *u) { + assert(p); + + return (uint8_t*) u + p->x.method.offset; +} + static void *vtable_property_convert_userdata(const sd_bus_vtable *p, void *u) { assert(p); @@ -163,10 +169,18 @@ static int add_enumerated_to_set( return 0; } +enum { + /* if set, add_subtree() works recursively */ + CHILDREN_RECURSIVE = (1U << 1), + /* if set, add_subtree() scans object-manager hierarchies recursively */ + CHILDREN_SUBHIERARCHIES = (1U << 0), +}; + static int add_subtree_to_set( sd_bus *bus, const char *prefix, struct node *n, + unsigned int flags, Set *s, sd_bus_error *error) { @@ -198,11 +212,14 @@ static int add_subtree_to_set( if (r < 0 && r != -EEXIST) return r; - r = add_subtree_to_set(bus, prefix, i, s, error); - if (r < 0) - return r; - if (bus->nodes_modified) - return 0; + if ((flags & CHILDREN_RECURSIVE) && + ((flags & CHILDREN_SUBHIERARCHIES) || !i->object_managers)) { + r = add_subtree_to_set(bus, prefix, i, flags, s, error); + if (r < 0) + return r; + if (bus->nodes_modified) + return 0; + } } return 0; @@ -212,6 +229,7 @@ static int get_child_nodes( sd_bus *bus, const char *prefix, struct node *n, + unsigned int flags, Set **_s, sd_bus_error *error) { @@ -227,7 +245,7 @@ static int get_child_nodes( if (!s) return -ENOMEM; - r = add_subtree_to_set(bus, prefix, n, s, error); + r = add_subtree_to_set(bus, prefix, n, flags, s, error); if (r < 0) { set_free_free(s); return r; @@ -360,6 +378,8 @@ static int method_callbacks_run( if (bus->nodes_modified) return 0; + u = vtable_method_convert_userdata(c->vtable, u); + *found_object = true; if (c->last_iteration == bus->iteration_counter) @@ -738,6 +758,9 @@ static int vtable_append_all_properties( if (v->flags & SD_BUS_VTABLE_HIDDEN) continue; + if (v->flags & SD_BUS_VTABLE_PROPERTY_EXPLICIT) + continue; + r = vtable_append_one_property(bus, reply, path, c, v, userdata, error); if (r < 0) return r; @@ -892,7 +915,7 @@ static int process_introspect( assert(n); assert(found_object); - r = get_child_nodes(bus, m->path, n, &s, &error); + r = get_child_nodes(bus, m->path, n, 0, &s, &error); if (r < 0) return bus_maybe_reply_error(m, r, &error); if (bus->nodes_modified) @@ -1158,16 +1181,12 @@ static int process_get_managed_objects( if (require_fallback || !n->object_managers) return 0; - r = get_child_nodes(bus, m->path, n, &s, &error); + r = get_child_nodes(bus, m->path, n, CHILDREN_RECURSIVE, &s, &error); if (r < 0) return r; if (bus->nodes_modified) return 0; - r = set_put_strdup(s, m->path); - if (r < 0) - return r; - r = sd_bus_message_new_method_return(m, &reply); if (r < 0) return r; @@ -1467,6 +1486,32 @@ void bus_node_gc(sd_bus *b, struct node *n) { free(n); } +static int bus_find_parent_object_manager(sd_bus *bus, struct node **out, const char *path) { + struct node *n; + + assert(bus); + assert(path); + + n = hashmap_get(bus->nodes, path); + if (!n) { + char *prefix; + + prefix = alloca(strlen(path) + 1); + OBJECT_PATH_FOREACH_PREFIX(prefix, path) { + n = hashmap_get(bus->nodes, prefix); + if (n) + break; + } + } + + while (n && !n->object_managers) + n = n->parent; + + if (out) + *out = n; + return !!n; +} + static int bus_add_object( sd_bus *bus, sd_bus_slot **slot, @@ -1707,8 +1752,9 @@ static int add_object_vtable_internal( if (!member_name_is_valid(v->x.property.member) || !signature_is_single(v->x.property.signature, false) || !(v->x.property.get || bus_type_is_basic(v->x.property.signature[0]) || streq(v->x.property.signature, "as")) || - v->flags & SD_BUS_VTABLE_METHOD_NO_REPLY || + (v->flags & SD_BUS_VTABLE_METHOD_NO_REPLY) || (!!(v->flags & SD_BUS_VTABLE_PROPERTY_CONST) + !!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) + !!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION)) > 1 || + ((v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) && (v->flags & SD_BUS_VTABLE_PROPERTY_EXPLICIT)) || (v->flags & SD_BUS_VTABLE_UNPRIVILEGED && v->type == _SD_BUS_VTABLE_PROPERTY)) { r = -EINVAL; goto fail; @@ -2269,6 +2315,7 @@ _public_ int sd_bus_emit_object_added(sd_bus *bus, const char *path) { BUS_DONT_DESTROY(bus); _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + struct node *object_manager; int r; /* @@ -2289,11 +2336,17 @@ _public_ int sd_bus_emit_object_added(sd_bus *bus, const char *path) { if (!BUS_IS_OPEN(bus->state)) return -ENOTCONN; + r = bus_find_parent_object_manager(bus, &object_manager, path); + if (r < 0) + return r; + if (r == 0) + return -ESRCH; + do { bus->nodes_modified = false; m = sd_bus_message_unref(m); - r = sd_bus_message_new_signal(bus, &m, path, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"); + r = sd_bus_message_new_signal(bus, &m, object_manager->path, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"); if (r < 0) return r; @@ -2432,6 +2485,7 @@ _public_ int sd_bus_emit_object_removed(sd_bus *bus, const char *path) { BUS_DONT_DESTROY(bus); _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + struct node *object_manager; int r; /* @@ -2452,11 +2506,17 @@ _public_ int sd_bus_emit_object_removed(sd_bus *bus, const char *path) { if (!BUS_IS_OPEN(bus->state)) return -ENOTCONN; + r = bus_find_parent_object_manager(bus, &object_manager, path); + if (r < 0) + return r; + if (r == 0) + return -ESRCH; + do { bus->nodes_modified = false; m = sd_bus_message_unref(m); - r = sd_bus_message_new_signal(bus, &m, path, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"); + r = sd_bus_message_new_signal(bus, &m, object_manager->path, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"); if (r < 0) return r; @@ -2588,6 +2648,7 @@ _public_ int sd_bus_emit_interfaces_added_strv(sd_bus *bus, const char *path, ch BUS_DONT_DESTROY(bus); _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + struct node *object_manager; char **i; int r; @@ -2601,11 +2662,17 @@ _public_ int sd_bus_emit_interfaces_added_strv(sd_bus *bus, const char *path, ch if (strv_isempty(interfaces)) return 0; + r = bus_find_parent_object_manager(bus, &object_manager, path); + if (r < 0) + return r; + if (r == 0) + return -ESRCH; + do { bus->nodes_modified = false; m = sd_bus_message_unref(m); - r = sd_bus_message_new_signal(bus, &m, path, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"); + r = sd_bus_message_new_signal(bus, &m, object_manager->path, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"); if (r < 0) return r; @@ -2665,6 +2732,7 @@ _public_ int sd_bus_emit_interfaces_added(sd_bus *bus, const char *path, const c _public_ int sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path, char **interfaces) { _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + struct node *object_manager; int r; assert_return(bus, -EINVAL); @@ -2677,7 +2745,13 @@ _public_ int sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path, if (strv_isempty(interfaces)) return 0; - r = sd_bus_message_new_signal(bus, &m, path, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"); + r = bus_find_parent_object_manager(bus, &object_manager, path); + if (r < 0) + return r; + if (r == 0) + return -ESRCH; + + r = sd_bus_message_new_signal(bus, &m, object_manager->path, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"); if (r < 0) return r; diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c index 735a775cb4..d0b1e3d7dc 100644 --- a/src/libsystemd/sd-bus/bus-socket.c +++ b/src/libsystemd/sd-bus/bus-socket.c @@ -985,7 +985,7 @@ int bus_socket_read_message(sd_bus *bus) { return -EIO; } - f = realloc(bus->fds, sizeof(int) + (bus->n_fds + n)); + f = realloc(bus->fds, sizeof(int) * (bus->n_fds + n)); if (!f) { close_many((int*) CMSG_DATA(cmsg), n); return -ENOMEM; diff --git a/src/libsystemd/sd-bus/busctl-introspect.c b/src/libsystemd/sd-bus/busctl-introspect.c index 15c10da7e9..abe482fc46 100644 --- a/src/libsystemd/sd-bus/busctl-introspect.c +++ b/src/libsystemd/sd-bus/busctl-introspect.c @@ -55,8 +55,7 @@ static void context_reset_member(Context *c) { } static void context_reset_interface(Context *c) { - free(c->interface_name); - c->interface_name = NULL; + c->interface_name = mfree(c->interface_name); c->interface_flags = 0; context_reset_member(c); @@ -462,9 +461,8 @@ static int parse_xml_node(Context *context, const char *prefix, unsigned n_depth } } - free(argument_type); - free(argument_direction); - argument_type = argument_direction = NULL; + argument_type = mfree(argument_type); + argument_direction = mfree(argument_direction); } state = STATE_METHOD; @@ -604,8 +602,7 @@ static int parse_xml_node(Context *context, const char *prefix, unsigned n_depth if (!strextend(&context->member_signature, argument_type, NULL)) return log_oom(); - free(argument_type); - argument_type = NULL; + argument_type = mfree(argument_type); } state = STATE_SIGNAL; diff --git a/src/libsystemd/sd-bus/busctl.c b/src/libsystemd/sd-bus/busctl.c index 6aaaf0e5ec..ab8816942c 100644 --- a/src/libsystemd/sd-bus/busctl.c +++ b/src/libsystemd/sd-bus/busctl.c @@ -21,22 +21,21 @@ #include <getopt.h> -#include "strv.h" -#include "util.h" -#include "log.h" -#include "build.h" -#include "pager.h" -#include "path-util.h" -#include "set.h" - #include "sd-bus.h" -#include "bus-internal.h" -#include "bus-util.h" + #include "bus-dump.h" +#include "bus-internal.h" #include "bus-signature.h" #include "bus-type.h" +#include "bus-util.h" #include "busctl-introspect.h" +#include "log.h" +#include "pager.h" +#include "path-util.h" +#include "set.h" +#include "strv.h" #include "terminal-util.h" +#include "util.h" static bool arg_no_pager = false; static bool arg_legend = true; @@ -449,7 +448,7 @@ static int tree(sd_bus *bus, char **argv) { if (not_first) printf("\n"); - printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_highlight_off()); + printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_normal()); q = tree_one(bus, *i, NULL, true); if (q < 0 && r >= 0) @@ -466,7 +465,7 @@ static int tree(sd_bus *bus, char **argv) { if (argv[2]) { pager_open_if_enabled(); - printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_highlight_off()); + printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_normal()); } q = tree_one(bus, *i, NULL, !!argv[2]); @@ -656,28 +655,15 @@ static int member_compare_func(const void *a, const void *b) { assert(x->type); assert(y->type); - if (!x->interface && y->interface) - return -1; - if (x->interface && !y->interface) - return 1; - if (x->interface && y->interface) { - d = strcmp(x->interface, y->interface); - if (d != 0) - return d; - } + d = strcmp_ptr(x->interface, y->interface); + if (d != 0) + return d; d = strcmp(x->type, y->type); if (d != 0) return d; - if (!x->name && y->name) - return -1; - if (x->name && !y->name) - return 1; - if (x->name && y->name) - return strcmp(x->name, y->name); - - return 0; + return strcmp_ptr(x->name, y->name); } static int member_compare_funcp(const void *a, const void *b) { @@ -1065,7 +1051,7 @@ static int introspect(sd_bus *bus, char **argv) { is_interface ? ansi_highlight() : "", is_interface ? "" : ".", - !is_interface + (int) name_width, strdash(streq_ptr(m->type, "interface") ? m->interface : m->name), - is_interface ? ansi_highlight_off() : "", + is_interface ? ansi_normal() : "", (int) type_width, strdash(m->type), (int) signature_width, strdash(m->signature), (int) result_width, rv, @@ -1109,6 +1095,15 @@ static int monitor(sd_bus *bus, char *argv[], int (*dump)(sd_bus_message *m, FIL if (r < 0) return log_error_errno(r, "Failed to add match: %m"); + free(m); + m = strjoin("destination='", *i, "'", NULL); + if (!m) + return log_oom(); + + r = sd_bus_add_match(bus, NULL, m, NULL, NULL); + if (r < 0) + return log_error_errno(r, "Failed to add match: %m"); + added_something = true; } @@ -1209,15 +1204,15 @@ static int status(sd_bus *bus, char *argv[]) { r = sd_bus_get_address(bus, &address); if (r >= 0) - printf("BusAddress=%s%s%s\n", ansi_highlight(), address, ansi_highlight_off()); + printf("BusAddress=%s%s%s\n", ansi_highlight(), address, ansi_normal()); r = sd_bus_get_scope(bus, &scope); if (r >= 0) - printf("BusScope=%s%s%s\n", ansi_highlight(), scope, ansi_highlight_off()); + printf("BusScope=%s%s%s\n", ansi_highlight(), scope, ansi_normal()); r = sd_bus_get_bus_id(bus, &bus_id); if (r >= 0) - printf("BusID=%s" SD_ID128_FORMAT_STR "%s\n", ansi_highlight(), SD_ID128_FORMAT_VAL(bus_id), ansi_highlight_off()); + printf("BusID=%s" SD_ID128_FORMAT_STR "%s\n", ansi_highlight(), SD_ID128_FORMAT_VAL(bus_id), ansi_normal()); r = sd_bus_get_owner_creds( bus, @@ -1697,6 +1692,7 @@ static int help(void) { " --acquired Only show acquired names\n" " --activatable Only show activatable names\n" " --match=MATCH Only show matching messages\n" + " --size=SIZE Maximum length of captured packet\n" " --list Don't show tree, but simple object path list\n" " --quiet Don't show method call reply\n" " --verbose Show result values in long format\n" @@ -1789,9 +1785,7 @@ static int parse_argv(int argc, char *argv[]) { return help(); case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case ARG_NO_PAGER: arg_no_pager = true; @@ -1835,20 +1829,20 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_SIZE: { - off_t o; + uint64_t sz; - r = parse_size(optarg, 0, &o); + r = parse_size(optarg, 1024, &sz); if (r < 0) { log_error("Failed to parse size: %s", optarg); return r; } - if ((off_t) (size_t) o != o) { + if ((uint64_t) (size_t) sz != sz) { log_error("Size out of range."); return -E2BIG; } - arg_snaplen = (size_t) o; + arg_snaplen = (size_t) sz; break; } @@ -2018,15 +2012,15 @@ int main(int argc, char *argv[]) { } } + r = sd_bus_set_bus_client(bus, true); + if (r < 0) { + log_error_errno(r, "Failed to set bus client: %m"); + goto finish; + } + if (arg_address) r = sd_bus_set_address(bus, arg_address); else { - r = sd_bus_set_bus_client(bus, true); - if (r < 0) { - log_error_errno(r, "Failed to set bus client: %m"); - goto finish; - } - switch (arg_transport) { case BUS_TRANSPORT_LOCAL: diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c index 0ca225c617..a23f7257fa 100644 --- a/src/libsystemd/sd-bus/sd-bus.c +++ b/src/libsystemd/sd-bus/sd-bus.c @@ -33,6 +33,7 @@ #include "missing.h" #include "def.h" #include "cgroup-util.h" +#include "hostname-util.h" #include "bus-label.h" #include "sd-bus.h" @@ -68,18 +69,18 @@ static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec); static int attach_io_events(sd_bus *b); static void detach_io_events(sd_bus *b); +static thread_local sd_bus *default_system_bus = NULL; +static thread_local sd_bus *default_user_bus = NULL; +static thread_local sd_bus *default_starter_bus = NULL; + static void bus_close_fds(sd_bus *b) { assert(b); detach_io_events(b); - if (b->input_fd >= 0) - safe_close(b->input_fd); - - if (b->output_fd >= 0 && b->output_fd != b->input_fd) + if (b->input_fd != b->output_fd) safe_close(b->output_fd); - - b->input_fd = b->output_fd = -1; + b->output_fd = b->input_fd = safe_close(b->input_fd); } static void bus_reset_queues(sd_bus *b) { @@ -88,15 +89,13 @@ static void bus_reset_queues(sd_bus *b) { while (b->rqueue_size > 0) sd_bus_message_unref(b->rqueue[--b->rqueue_size]); - free(b->rqueue); - b->rqueue = NULL; + b->rqueue = mfree(b->rqueue); b->rqueue_allocated = 0; while (b->wqueue_size > 0) sd_bus_message_unref(b->wqueue[--b->wqueue_size]); - free(b->wqueue); - b->wqueue = NULL; + b->wqueue = mfree(b->wqueue); b->wqueue_allocated = 0; } @@ -220,8 +219,8 @@ _public_ int sd_bus_set_address(sd_bus *bus, const char *address) { _public_ int sd_bus_set_fd(sd_bus *bus, int input_fd, int output_fd) { assert_return(bus, -EINVAL); assert_return(bus->state == BUS_UNSET, -EPERM); - assert_return(input_fd >= 0, -EINVAL); - assert_return(output_fd >= 0, -EINVAL); + assert_return(input_fd >= 0, -EBADF); + assert_return(output_fd >= 0, -EBADF); assert_return(!bus_pid_changed(bus), -ECHILD); bus->input_fd = input_fd; @@ -825,8 +824,7 @@ static int parse_container_unix_address(sd_bus *b, const char **p, char **guid) b->machine = machine; machine = NULL; } else { - free(b->machine); - b->machine = NULL; + b->machine = mfree(b->machine); } if (pid) { @@ -885,8 +883,7 @@ static int parse_container_kernel_address(sd_bus *b, const char **p, char **guid b->machine = machine; machine = NULL; } else { - free(b->machine); - b->machine = NULL; + b->machine = mfree(b->machine); } if (pid) { @@ -896,10 +893,9 @@ static int parse_container_kernel_address(sd_bus *b, const char **p, char **guid } else b->nspid = 0; - free(b->kernel); - b->kernel = strdup("/sys/fs/kdbus/0-system/bus"); - if (!b->kernel) - return -ENOMEM; + r = free_and_strdup(&b->kernel, "/sys/fs/kdbus/0-system/bus"); + if (r < 0) + return r; return 0; } @@ -909,15 +905,11 @@ static void bus_reset_parsed_address(sd_bus *b) { zero(b->sockaddr); b->sockaddr_size = 0; - strv_free(b->exec_argv); - free(b->exec_path); - b->exec_path = NULL; - b->exec_argv = NULL; + b->exec_argv = strv_free(b->exec_argv); + b->exec_path = mfree(b->exec_path); b->server_id = SD_ID128_NULL; - free(b->kernel); - b->kernel = NULL; - free(b->machine); - b->machine = NULL; + b->kernel = mfree(b->kernel); + b->machine = mfree(b->machine); b->nspid = 0; } @@ -1012,6 +1004,8 @@ static int bus_parse_next_address(sd_bus *b) { } static int bus_start_address(sd_bus *b) { + bool container_kdbus_available = false; + bool kdbus_available = false; int r; assert(b); @@ -1021,17 +1015,40 @@ static int bus_start_address(sd_bus *b) { bus_close_fds(b); + /* + * Usually, if you provide multiple different bus-addresses, we + * try all of them in order. We use the first one that + * succeeds. However, if you mix kernel and unix addresses, we + * never try unix-addresses if a previous kernel address was + * tried and kdbus was available. This is required to prevent + * clients to fallback to the bus-proxy if kdbus is available + * but failed (eg., too many connections). + */ + if (b->exec_path) r = bus_socket_exec(b); - else if ((b->nspid > 0 || b->machine) && b->kernel) + else if ((b->nspid > 0 || b->machine) && b->kernel) { r = bus_container_connect_kernel(b); - else if ((b->nspid > 0 || b->machine) && b->sockaddr.sa.sa_family != AF_UNSPEC) - r = bus_container_connect_socket(b); - else if (b->kernel) + if (r < 0 && !IN_SET(r, -ENOENT, -ESOCKTNOSUPPORT)) + container_kdbus_available = true; + + } else if ((b->nspid > 0 || b->machine) && b->sockaddr.sa.sa_family != AF_UNSPEC) { + if (!container_kdbus_available) + r = bus_container_connect_socket(b); + else + skipped = true; + + } else if (b->kernel) { r = bus_kernel_connect(b); - else if (b->sockaddr.sa.sa_family != AF_UNSPEC) - r = bus_socket_connect(b); - else + if (r < 0 && !IN_SET(r, -ENOENT, -ESOCKTNOSUPPORT)) + kdbus_available = true; + + } else if (b->sockaddr.sa.sa_family != AF_UNSPEC) { + if (!kdbus_available) + r = bus_socket_connect(b); + else + skipped = true; + } else skipped = true; if (!skipped) { @@ -1224,6 +1241,8 @@ fail: int bus_set_address_user(sd_bus *b) { const char *e; + uid_t uid; + int r; assert(b); @@ -1231,6 +1250,10 @@ int bus_set_address_user(sd_bus *b) { if (e) return sd_bus_set_address(b, e); + r = cg_pid_get_owner_uid(0, &uid); + if (r < 0) + uid = getuid(); + e = secure_getenv("XDG_RUNTIME_DIR"); if (e) { _cleanup_free_ char *ee = NULL; @@ -1239,9 +1262,9 @@ int bus_set_address_user(sd_bus *b) { if (!ee) return -ENOMEM; - (void) asprintf(&b->address, KERNEL_USER_BUS_ADDRESS_FMT ";" UNIX_USER_BUS_ADDRESS_FMT, getuid(), ee); + (void) asprintf(&b->address, KERNEL_USER_BUS_ADDRESS_FMT ";" UNIX_USER_BUS_ADDRESS_FMT, uid, ee); } else - (void) asprintf(&b->address, KERNEL_USER_BUS_ADDRESS_FMT, getuid()); + (void) asprintf(&b->address, KERNEL_USER_BUS_ADDRESS_FMT, uid); if (!b->address) return -ENOMEM; @@ -1959,37 +1982,39 @@ _public_ int sd_bus_call( unsigned i; int r; - assert_return(m, -EINVAL); - assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL); - assert_return(!(m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED), -EINVAL); - assert_return(!bus_error_is_dirty(error), -EINVAL); + bus_assert_return(m, -EINVAL, error); + bus_assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL, error); + bus_assert_return(!(m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED), -EINVAL, error); + bus_assert_return(!bus_error_is_dirty(error), -EINVAL, error); if (!bus) bus = m->bus; - assert_return(!bus_pid_changed(bus), -ECHILD); - assert_return(!bus->is_kernel || !(bus->hello_flags & KDBUS_HELLO_MONITOR), -EROFS); + bus_assert_return(!bus_pid_changed(bus), -ECHILD, error); + bus_assert_return(!bus->is_kernel || !(bus->hello_flags & KDBUS_HELLO_MONITOR), -EROFS, error); - if (!BUS_IS_OPEN(bus->state)) - return -ENOTCONN; + if (!BUS_IS_OPEN(bus->state)) { + r = -ENOTCONN; + goto fail; + } r = bus_ensure_running(bus); if (r < 0) - return r; + goto fail; i = bus->rqueue_size; r = bus_seal_message(bus, m, usec); if (r < 0) - return r; + goto fail; r = bus_remarshal_message(bus, &m); if (r < 0) - return r; + goto fail; r = bus_send_internal(bus, m, &cookie, true); if (r < 0) - return r; + goto fail; timeout = calc_elapse(m->timeout); @@ -2020,14 +2045,17 @@ _public_ int sd_bus_call( } r = sd_bus_error_setf(error, SD_BUS_ERROR_INCONSISTENT_MESSAGE, "Reply message contained file descriptors which I couldn't accept. Sorry."); + sd_bus_message_unref(incoming); + return r; - } else if (incoming->header->type == SD_BUS_MESSAGE_METHOD_ERROR) + } else if (incoming->header->type == SD_BUS_MESSAGE_METHOD_ERROR) { r = sd_bus_error_copy(error, &incoming->error); - else + sd_bus_message_unref(incoming); + return r; + } else { r = -EIO; - - sd_bus_message_unref(incoming); - return r; + goto fail; + } } else if (BUS_MESSAGE_COOKIE(incoming) == cookie && bus->unique_name && @@ -2043,7 +2071,8 @@ _public_ int sd_bus_call( * immediately. */ sd_bus_message_unref(incoming); - return -ELOOP; + r = -ELOOP; + goto fail; } /* Try to read more, right-away */ @@ -2054,10 +2083,10 @@ _public_ int sd_bus_call( if (r < 0) { if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) { bus_enter_closing(bus); - return -ECONNRESET; + r = -ECONNRESET; } - return r; + goto fail; } if (r > 0) continue; @@ -2066,8 +2095,10 @@ _public_ int sd_bus_call( usec_t n; n = now(CLOCK_MONOTONIC); - if (n >= timeout) - return -ETIMEDOUT; + if (n >= timeout) { + r = -ETIMEDOUT; + goto fail; + } left = timeout - n; } else @@ -2075,20 +2106,25 @@ _public_ int sd_bus_call( r = bus_poll(bus, true, left); if (r < 0) - return r; - if (r == 0) - return -ETIMEDOUT; + goto fail; + if (r == 0) { + r = -ETIMEDOUT; + goto fail; + } r = dispatch_wqueue(bus); if (r < 0) { if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) { bus_enter_closing(bus); - return -ECONNRESET; + r = -ECONNRESET; } - return r; + goto fail; } } + +fail: + return sd_bus_error_set_errno(error, r); } _public_ int sd_bus_get_fd(sd_bus *bus) { @@ -3316,14 +3352,11 @@ static int bus_default(int (*bus_open)(sd_bus **), sd_bus **default_bus, sd_bus } _public_ int sd_bus_default_system(sd_bus **ret) { - static thread_local sd_bus *default_system_bus = NULL; - return bus_default(sd_bus_open_system, &default_system_bus, ret); } -_public_ int sd_bus_default_user(sd_bus **ret) { - static thread_local sd_bus *default_user_bus = NULL; +_public_ int sd_bus_default_user(sd_bus **ret) { return bus_default(sd_bus_open_user, &default_user_bus, ret); } @@ -3350,7 +3383,6 @@ _public_ int sd_bus_default(sd_bus **ret) { e = secure_getenv("DBUS_STARTER_ADDRESS"); if (e) { - static thread_local sd_bus *default_starter_bus = NULL; return bus_default(sd_bus_open, &default_starter_bus, ret); } @@ -3422,6 +3454,171 @@ _public_ int sd_bus_path_decode(const char *path, const char *prefix, char **ext return 1; } +_public_ int sd_bus_path_encode_many(char **out, const char *path_template, ...) { + _cleanup_strv_free_ char **labels = NULL; + char *path, *path_pos, **label_pos; + const char *sep, *template_pos; + size_t path_length; + va_list list; + int r; + + assert_return(out, -EINVAL); + assert_return(path_template, -EINVAL); + + path_length = strlen(path_template); + + va_start(list, path_template); + for (sep = strchr(path_template, '%'); sep; sep = strchr(sep + 1, '%')) { + const char *arg; + char *label; + + arg = va_arg(list, const char *); + if (!arg) { + va_end(list); + return -EINVAL; + } + + label = bus_label_escape(arg); + if (!label) { + va_end(list); + return -ENOMEM; + } + + r = strv_consume(&labels, label); + if (r < 0) { + va_end(list); + return r; + } + + /* add label length, but account for the format character */ + path_length += strlen(label) - 1; + } + va_end(list); + + path = malloc(path_length + 1); + if (!path) + return -ENOMEM; + + path_pos = path; + label_pos = labels; + + for (template_pos = path_template; *template_pos; ) { + sep = strchrnul(template_pos, '%'); + path_pos = mempcpy(path_pos, template_pos, sep - template_pos); + if (!*sep) + break; + + path_pos = stpcpy(path_pos, *label_pos++); + template_pos = sep + 1; + } + + *path_pos = 0; + *out = path; + return 0; +} + +_public_ int sd_bus_path_decode_many(const char *path, const char *path_template, ...) { + _cleanup_strv_free_ char **labels = NULL; + const char *template_pos, *path_pos; + char **label_pos; + va_list list; + int r; + + /* + * This decodes an object-path based on a template argument. The + * template consists of a verbatim path, optionally including special + * directives: + * + * - Each occurrence of '%' in the template matches an arbitrary + * substring of a label in the given path. At most one such + * directive is allowed per label. For each such directive, the + * caller must provide an output parameter (char **) via va_arg. If + * NULL is passed, the given label is verified, but not returned. + * For each matched label, the *decoded* label is stored in the + * passed output argument, and the caller is responsible to free + * it. Note that the output arguments are only modified if the + * actualy path matched the template. Otherwise, they're left + * untouched. + * + * This function returns <0 on error, 0 if the path does not match the + * template, 1 if it matched. + */ + + assert_return(path, -EINVAL); + assert_return(path_template, -EINVAL); + + path_pos = path; + + for (template_pos = path_template; *template_pos; ) { + const char *sep; + size_t length; + char *label; + + /* verify everything until the next '%' matches verbatim */ + sep = strchrnul(template_pos, '%'); + length = sep - template_pos; + if (strncmp(path_pos, template_pos, length)) + return 0; + + path_pos += length; + template_pos += length; + + if (!*template_pos) + break; + + /* We found the next '%' character. Everything up until here + * matched. We now skip ahead to the end of this label and make + * sure it matches the tail of the label in the path. Then we + * decode the string in-between and save it for later use. */ + + ++template_pos; /* skip over '%' */ + + sep = strchrnul(template_pos, '/'); + length = sep - template_pos; /* length of suffix to match verbatim */ + + /* verify the suffixes match */ + sep = strchrnul(path_pos, '/'); + if (sep - path_pos < (ssize_t)length || + strncmp(sep - length, template_pos, length)) + return 0; + + template_pos += length; /* skip over matched label */ + length = sep - path_pos - length; /* length of sub-label to decode */ + + /* store unescaped label for later use */ + label = bus_label_unescape_n(path_pos, length); + if (!label) + return -ENOMEM; + + r = strv_consume(&labels, label); + if (r < 0) + return r; + + path_pos = sep; /* skip decoded label and suffix */ + } + + /* end of template must match end of path */ + if (*path_pos) + return 0; + + /* copy the labels over to the caller */ + va_start(list, path_template); + for (label_pos = labels; label_pos && *label_pos; ++label_pos) { + char **arg; + + arg = va_arg(list, char **); + if (arg) + *arg = *label_pos; + else + free(*label_pos); + } + va_end(list); + + free(labels); + labels = NULL; + return 1; +} + _public_ int sd_bus_try_close(sd_bus *bus) { int r; @@ -3573,3 +3770,20 @@ _public_ int sd_bus_is_monitor(sd_bus *bus) { return !!(bus->hello_flags & KDBUS_HELLO_MONITOR); } + +static void flush_close(sd_bus *bus) { + if (!bus) + return; + + /* Flushes and closes the specified bus. We take a ref before, + * to ensure the flushing does not cause the bus to be + * unreferenced. */ + + sd_bus_flush_close_unref(sd_bus_ref(bus)); +} + +_public_ void sd_bus_default_flush_close(void) { + flush_close(default_starter_bus); + flush_close(default_user_bus); + flush_close(default_system_bus); +} diff --git a/src/libsystemd/sd-bus/test-bus-chat.c b/src/libsystemd/sd-bus/test-bus-chat.c index 754335b5e7..20f1b532b7 100644 --- a/src/libsystemd/sd-bus/test-bus-chat.c +++ b/src/libsystemd/sd-bus/test-bus-chat.c @@ -119,9 +119,7 @@ static int server_init(sd_bus **_bus) { return 0; fail: - if (bus) - sd_bus_unref(bus); - + sd_bus_unref(bus); return r; } diff --git a/src/libsystemd/sd-bus/test-bus-creds.c b/src/libsystemd/sd-bus/test-bus-creds.c index edd5033db2..580117165a 100644 --- a/src/libsystemd/sd-bus/test-bus-creds.c +++ b/src/libsystemd/sd-bus/test-bus-creds.c @@ -22,11 +22,17 @@ #include "sd-bus.h" #include "bus-dump.h" #include "bus-util.h" +#include "cgroup-util.h" int main(int argc, char *argv[]) { _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; int r; + if (cg_unified() == -ENOEXEC) { + puts("Skipping test: /sys/fs/cgroup/ not available"); + return EXIT_TEST_SKIP; + } + r = sd_bus_creds_new_from_pid(&creds, 0, _SD_BUS_CREDS_ALL); assert_se(r >= 0); diff --git a/src/libsystemd/sd-bus/test-bus-gvariant.c b/src/libsystemd/sd-bus/test-bus-gvariant.c index 9b7dd2e499..b078bdc5f6 100644 --- a/src/libsystemd/sd-bus/test-bus-gvariant.c +++ b/src/libsystemd/sd-bus/test-bus-gvariant.c @@ -59,7 +59,7 @@ static void test_bus_gvariant_is_fixed_size(void) { static void test_bus_gvariant_get_size(void) { assert_se(bus_gvariant_get_size("") == 0); - assert_se(bus_gvariant_get_size("()") == 0); + assert_se(bus_gvariant_get_size("()") == 1); assert_se(bus_gvariant_get_size("y") == 1); assert_se(bus_gvariant_get_size("u") == 4); assert_se(bus_gvariant_get_size("b") == 1); diff --git a/src/libsystemd/sd-bus/test-bus-introspect.c b/src/libsystemd/sd-bus/test-bus-introspect.c index b2caa02870..f39dedeb24 100644 --- a/src/libsystemd/sd-bus/test-bus-introspect.c +++ b/src/libsystemd/sd-bus/test-bus-introspect.c @@ -41,7 +41,7 @@ static const sd_bus_vtable vtable[] = { SD_BUS_PROPERTY("AReadOnlyDeprecatedProperty", "(ut)", prop_get, 0, SD_BUS_VTABLE_DEPRECATED), SD_BUS_PROPERTY("ChangingProperty", "t", prop_get, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("Invalidating", "t", prop_get, 0, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), - SD_BUS_PROPERTY("Constant", "t", prop_get, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Constant", "t", prop_get, 0, SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_PROPERTY_EXPLICIT), SD_BUS_VTABLE_END }; diff --git a/src/libsystemd/sd-bus/test-bus-kernel-bloom.c b/src/libsystemd/sd-bus/test-bus-kernel-bloom.c index 90eb1f2a33..f3d1099dd2 100644 --- a/src/libsystemd/sd-bus/test-bus-kernel-bloom.c +++ b/src/libsystemd/sd-bus/test-bus-kernel-bloom.c @@ -108,8 +108,10 @@ int main(int argc, char *argv[]) { test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "member='Pi_ep'", false); test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "arg0='foobar'", true); test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "arg0='foo_bar'", false); - test_one("/foo/bar/waldo", "waldo.com", "Piep", true, "foobar", "arg0='foobar'", true); + test_one("/foo/bar/waldo", "waldo.com", "Piep", true, "foobar", "arg0='foobar'", false); test_one("/foo/bar/waldo", "waldo.com", "Piep", true, "foobar", "arg0='foo_bar'", false); + test_one("/foo/bar/waldo", "waldo.com", "Piep", true, "foobar", "arg0has='foobar'", true); + test_one("/foo/bar/waldo", "waldo.com", "Piep", true, "foobar", "arg0has='foo_bar'", false); test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path='/foo/bar/waldo',interface='waldo.com',member='Piep',arg0='foobar'", true); test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path='/foo/bar/waldo',interface='waldo.com',member='Piep',arg0='foobar2'", false); diff --git a/src/libsystemd/sd-bus/test-bus-marshal.c b/src/libsystemd/sd-bus/test-bus-marshal.c index a866a56179..ff6bba5988 100644 --- a/src/libsystemd/sd-bus/test-bus-marshal.c +++ b/src/libsystemd/sd-bus/test-bus-marshal.c @@ -66,6 +66,36 @@ static void test_bus_path_encode(void) { assert_se(sd_bus_path_decode(e, "/foo/bar", &f) > 0 && streq(f, "foo.bar")); } +static void test_bus_path_encode_many(void) { + _cleanup_free_ char *a = NULL, *b = NULL, *c = NULL, *d = NULL, *e = NULL, *f = NULL; + + assert_se(sd_bus_path_decode_many("/foo/bar", "/prefix/%", NULL) == 0); + assert_se(sd_bus_path_decode_many("/prefix/bar", "/prefix/%bar", NULL) == 1); + assert_se(sd_bus_path_decode_many("/foo/bar", "/prefix/%/suffix", NULL) == 0); + assert_se(sd_bus_path_decode_many("/prefix/foobar/suffix", "/prefix/%/suffix", &a) == 1 && streq_ptr(a, "foobar")); + assert_se(sd_bus_path_decode_many("/prefix/one_foo_two/mid/three_bar_four/suffix", "/prefix/one_%_two/mid/three_%_four/suffix", &b, &c) == 1 && streq_ptr(b, "foo") && streq_ptr(c, "bar")); + assert_se(sd_bus_path_decode_many("/prefix/one_foo_two/mid/three_bar_four/suffix", "/prefix/one_%_two/mid/three_%_four/suffix", NULL, &d) == 1 && streq_ptr(d, "bar")); + + assert_se(sd_bus_path_decode_many("/foo/bar", "/foo/bar/%", NULL) == 0); + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/bar%", NULL) == 0); + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/%/bar", NULL) == 0); + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/%bar", NULL) == 0); + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/bar/suffix") == 1); + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/%%/suffix", NULL, NULL) == 0); /* multiple '%' are treated verbatim */ + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/%/suffi", NULL) == 0); + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/%/suffix", &e) == 1 && streq_ptr(e, "bar")); + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/%/%", NULL, NULL) == 1); + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/%/%/%", NULL, NULL, NULL) == 1); + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "%/%/%", NULL, NULL, NULL) == 0); + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/%/%", NULL, NULL) == 0); + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/%/%/", NULL, NULL) == 0); + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/%/", NULL) == 0); + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/%", NULL) == 0); + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "%", NULL) == 0); + + assert_se(sd_bus_path_encode_many(&f, "/prefix/one_%_two/mid/three_%_four/suffix", "foo", "bar") >= 0 && streq_ptr(f, "/prefix/one_foo_two/mid/three_bar_four/suffix")); +} + static void test_bus_label_escape_one(const char *a, const char *b) { _cleanup_free_ char *t = NULL, *x = NULL, *y = NULL; @@ -131,6 +161,12 @@ int main(int argc, char *argv[]) { r = sd_bus_message_append(m, "a{yv}", 2, 3, "s", "foo", 5, "s", "waldo"); assert_se(r >= 0); + r = sd_bus_message_append(m, "y(ty)y(yt)y", 8, 777ULL, 7, 9, 77, 7777ULL, 10); + assert_se(r >= 0); + + r = sd_bus_message_append(m, "()"); + assert_se(r >= 0); + r = sd_bus_message_append(m, "ba(ss)", 255, 3, "aaa", "1", "bbb", "2", "ccc", "3"); assert_se(r >= 0); @@ -252,6 +288,25 @@ int main(int argc, char *argv[]) { assert_se(v == 5); assert_se(streq(y, "waldo")); + r = sd_bus_message_read(m, "y(ty)", &v, &u64, &u); + assert_se(r > 0); + assert_se(v == 8); + assert_se(u64 == 777); + assert_se(u == 7); + + r = sd_bus_message_read(m, "y(yt)", &v, &u, &u64); + assert_se(r > 0); + assert_se(v == 9); + assert_se(u == 77); + assert_se(u64 == 7777); + + r = sd_bus_message_read(m, "y", &v); + assert_se(r > 0); + assert_se(v == 10); + + r = sd_bus_message_read(m, "()"); + assert_se(r > 0); + r = sd_bus_message_read(m, "ba(ss)", &boolean, 3, &x, &y, &a, &b, &c, &d); assert_se(r > 0); assert_se(boolean); @@ -331,7 +386,7 @@ int main(int argc, char *argv[]) { assert_se(sd_bus_message_verify_type(m, 'a', "{yv}") > 0); - r = sd_bus_message_skip(m, "a{yv}"); + r = sd_bus_message_skip(m, "a{yv}y(ty)y(yt)y()"); assert_se(r >= 0); assert_se(sd_bus_message_verify_type(m, 'b', NULL) > 0); @@ -368,6 +423,7 @@ int main(int argc, char *argv[]) { test_bus_label_escape(); test_bus_path_encode(); test_bus_path_encode_unique(); + test_bus_path_encode_many(); return 0; } diff --git a/src/libsystemd/sd-bus/test-bus-match.c b/src/libsystemd/sd-bus/test-bus-match.c index 83cb5c62c2..75ea28371b 100644 --- a/src/libsystemd/sd-bus/test-bus-match.c +++ b/src/libsystemd/sd-bus/test-bus-match.c @@ -115,10 +115,10 @@ int main(int argc, char *argv[]) { assert_se(match_add(slots, &root, "arg1='two'", 12) >= 0); assert_se(match_add(slots, &root, "member='waldo',arg2path='/prefix/'", 13) >= 0); assert_se(match_add(slots, &root, "member=waldo,path='/foo/bar',arg3namespace='prefix'", 14) >= 0); - assert_se(match_add(slots, &root, "arg4='pi'", 15) >= 0); - assert_se(match_add(slots, &root, "arg4='pa'", 16) >= 0); - assert_se(match_add(slots, &root, "arg4='po'", 17) >= 0); - assert_se(match_add(slots, &root, "arg4='pu'", 18) >= 0); + assert_se(match_add(slots, &root, "arg4has='pi'", 15) >= 0); + assert_se(match_add(slots, &root, "arg4has='pa'", 16) >= 0); + assert_se(match_add(slots, &root, "arg4has='po'", 17) >= 0); + assert_se(match_add(slots, &root, "arg4='pi'", 18) >= 0); bus_match_dump(&root, 0); diff --git a/src/libsystemd/sd-bus/test-bus-objects.c b/src/libsystemd/sd-bus/test-bus-objects.c index 1db67ecfac..0a35b750b3 100644 --- a/src/libsystemd/sd-bus/test-bus-objects.c +++ b/src/libsystemd/sd-bus/test-bus-objects.c @@ -115,13 +115,14 @@ static int set_handler(sd_bus *bus, const char *path, const char *interface, con static int value_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error) { _cleanup_free_ char *s = NULL; + const char *x; int r; assert_se(asprintf(&s, "object %p, path %s", userdata, path) >= 0); r = sd_bus_message_append(reply, "s", s); assert_se(r >= 0); - assert_se(startswith(path, "/value/") != NULL || strcmp(path, "/value") == 0); + assert_se(x = startswith(path, "/value/")); assert_se(PTR_TO_UINT(userdata) == 30); @@ -153,7 +154,7 @@ static int notify_test2(sd_bus_message *m, void *userdata, sd_bus_error *error) static int emit_interfaces_added(sd_bus_message *m, void *userdata, sd_bus_error *error) { int r; - assert_se(sd_bus_emit_interfaces_added(sd_bus_message_get_bus(m), m->path, "org.freedesktop.systemd.test", NULL) >= 0); + assert_se(sd_bus_emit_interfaces_added(sd_bus_message_get_bus(m), "/value/a/x", "org.freedesktop.systemd.ValueTest", NULL) >= 0); r = sd_bus_reply_method_return(m, NULL); assert_se(r >= 0); @@ -164,7 +165,7 @@ static int emit_interfaces_added(sd_bus_message *m, void *userdata, sd_bus_error static int emit_interfaces_removed(sd_bus_message *m, void *userdata, sd_bus_error *error) { int r; - assert_se(sd_bus_emit_interfaces_removed(sd_bus_message_get_bus(m), m->path, "org.freedesktop.systemd.test", NULL) >= 0); + assert_se(sd_bus_emit_interfaces_removed(sd_bus_message_get_bus(m), "/value/a/x", "org.freedesktop.systemd.ValueTest", NULL) >= 0); r = sd_bus_reply_method_return(m, NULL); assert_se(r >= 0); @@ -175,7 +176,7 @@ static int emit_interfaces_removed(sd_bus_message *m, void *userdata, sd_bus_err static int emit_object_added(sd_bus_message *m, void *userdata, sd_bus_error *error) { int r; - assert_se(sd_bus_emit_object_added(sd_bus_message_get_bus(m), m->path) >= 0); + assert_se(sd_bus_emit_object_added(sd_bus_message_get_bus(m), "/value/a/x") >= 0); r = sd_bus_reply_method_return(m, NULL); assert_se(r >= 0); @@ -186,7 +187,7 @@ static int emit_object_added(sd_bus_message *m, void *userdata, sd_bus_error *er static int emit_object_removed(sd_bus_message *m, void *userdata, sd_bus_error *error) { int r; - assert_se(sd_bus_emit_object_removed(sd_bus_message_get_bus(m), m->path) >= 0); + assert_se(sd_bus_emit_object_removed(sd_bus_message_get_bus(m), "/value/a/x") >= 0); r = sd_bus_reply_method_return(m, NULL); assert_se(r >= 0); @@ -217,6 +218,7 @@ static const sd_bus_vtable vtable2[] = { SD_BUS_PROPERTY("Value2", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), SD_BUS_PROPERTY("Value3", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Value4", "s", value_handler, 10, 0), + SD_BUS_PROPERTY("AnExplicitProperty", "s", NULL, offsetof(struct context, something), SD_BUS_VTABLE_PROPERTY_EXPLICIT|SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), SD_BUS_VTABLE_END }; @@ -228,6 +230,14 @@ static int enumerator_callback(sd_bus *bus, const char *path, void *userdata, ch return 1; } +static int enumerator2_callback(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) { + + if (object_path_startswith("/value/a", path)) + assert_se(*nodes = strv_new("/value/a/x", "/value/a/y", "/value/a/z", NULL)); + + return 1; +} + static void *server(void *p) { struct context *c = p; sd_bus *bus = NULL; @@ -246,7 +256,9 @@ static void *server(void *p) { assert_se(sd_bus_add_object_vtable(bus, NULL, "/foo", "org.freedesktop.systemd.test2", vtable, c) >= 0); assert_se(sd_bus_add_fallback_vtable(bus, NULL, "/value", "org.freedesktop.systemd.ValueTest", vtable2, NULL, UINT_TO_PTR(20)) >= 0); assert_se(sd_bus_add_node_enumerator(bus, NULL, "/value", enumerator_callback, NULL) >= 0); + assert_se(sd_bus_add_node_enumerator(bus, NULL, "/value/a", enumerator2_callback, NULL) >= 0); assert_se(sd_bus_add_object_manager(bus, NULL, "/value") >= 0); + assert_se(sd_bus_add_object_manager(bus, NULL, "/value/a") >= 0); assert_se(sd_bus_start(bus) >= 0); diff --git a/src/libsystemd/sd-bus/test-bus-proxy.c b/src/libsystemd/sd-bus/test-bus-proxy.c new file mode 100644 index 0000000000..aef768dc18 --- /dev/null +++ b/src/libsystemd/sd-bus/test-bus-proxy.c @@ -0,0 +1,118 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2015 David Herrmann <dh.herrmann@gmail.com> + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <errno.h> +#include <fcntl.h> +#include <stdlib.h> + +#include "util.h" +#include "log.h" + +#include "sd-bus.h" +#include "bus-kernel.h" +#include "bus-util.h" +#include "bus-dump.h" + +typedef struct { + const char *sender; + int matched_acquired; +} TestProxyMatch; + +static int test_proxy_acquired(sd_bus_message *m, void *userdata, sd_bus_error *error) { + TestProxyMatch *match = userdata; + const char *name; + int r; + + r = sd_bus_message_read(m, "s", &name); + assert_se(r >= 0); + + if (!streq_ptr(match->sender, name)) + return 0; + + ++match->matched_acquired; + return 1; +} + +static void test_proxy_matched(void) { + _cleanup_bus_flush_close_unref_ sd_bus *a = NULL; + _cleanup_free_ char *matchstr = NULL; + TestProxyMatch match = {}; + const char *me; + int r; + + /* open bus 'a' */ + + r = sd_bus_new(&a); + assert_se(r >= 0); + + r = sd_bus_set_address(a, "unix:path=/var/run/dbus/system_bus_socket"); + assert_se(r >= 0); + + r = sd_bus_set_bus_client(a, true); + assert_se(r >= 0); + + r = sd_bus_start(a); + assert_se(r >= 0); + + r = sd_bus_get_unique_name(a, &me); + assert_se(r >= 0); + + matchstr = strjoin("type='signal'," + "member='NameAcquired'," + "destination='", + me, + "'", + NULL); + assert_se(matchstr); + r = sd_bus_add_match(a, NULL, matchstr, test_proxy_acquired, &match); + assert_se(r >= 0); + + r = sd_bus_get_unique_name(a, &match.sender); + assert_se(r >= 0); + + /* barrier to guarantee proxy/dbus-daemon handled the previous data */ + r = sd_bus_call_method(a, + "org.freedesktop.DBus", + "/org/freedesktop/DBus", + "org.freedesktop.DBus", + "GetId", + NULL, NULL, NULL); + assert_se(r >= 0); + + /* now we can be sure the Name* signals were sent */ + do { + r = sd_bus_process(a, NULL); + } while (r > 0); + assert_se(r == 0); + + assert_se(match.matched_acquired == 1); +} + +int main(int argc, char **argv) { + if (access("/var/run/dbus/system_bus_socket", F_OK) < 0) + return EXIT_TEST_SKIP; + + log_parse_environment(); + + test_proxy_matched(); + + return EXIT_SUCCESS; +} diff --git a/src/libsystemd/sd-daemon/sd-daemon.c b/src/libsystemd/sd-daemon/sd-daemon.c index 82ac72c72a..5fb0b73d02 100644 --- a/src/libsystemd/sd-daemon/sd-daemon.c +++ b/src/libsystemd/sd-daemon/sd-daemon.c @@ -90,7 +90,7 @@ finish: _public_ int sd_is_fifo(int fd, const char *path) { struct stat st_fd; - assert_return(fd >= 0, -EINVAL); + assert_return(fd >= 0, -EBADF); if (fstat(fd, &st_fd) < 0) return -errno; @@ -120,7 +120,7 @@ _public_ int sd_is_fifo(int fd, const char *path) { _public_ int sd_is_special(int fd, const char *path) { struct stat st_fd; - assert_return(fd >= 0, -EINVAL); + assert_return(fd >= 0, -EBADF); if (fstat(fd, &st_fd) < 0) return -errno; @@ -155,7 +155,7 @@ _public_ int sd_is_special(int fd, const char *path) { static int sd_is_socket_internal(int fd, int type, int listening) { struct stat st_fd; - assert_return(fd >= 0, -EINVAL); + assert_return(fd >= 0, -EBADF); assert_return(type >= 0, -EINVAL); if (fstat(fd, &st_fd) < 0) @@ -198,7 +198,7 @@ static int sd_is_socket_internal(int fd, int type, int listening) { _public_ int sd_is_socket(int fd, int family, int type, int listening) { int r; - assert_return(fd >= 0, -EINVAL); + assert_return(fd >= 0, -EBADF); assert_return(family >= 0, -EINVAL); r = sd_is_socket_internal(fd, type, listening); @@ -226,7 +226,7 @@ _public_ int sd_is_socket_inet(int fd, int family, int type, int listening, uint socklen_t l = sizeof(sockaddr); int r; - assert_return(fd >= 0, -EINVAL); + assert_return(fd >= 0, -EBADF); assert_return(IN_SET(family, 0, AF_INET, AF_INET6), -EINVAL); r = sd_is_socket_internal(fd, type, listening); @@ -269,7 +269,7 @@ _public_ int sd_is_socket_unix(int fd, int type, int listening, const char *path socklen_t l = sizeof(sockaddr); int r; - assert_return(fd >= 0, -EINVAL); + assert_return(fd >= 0, -EBADF); r = sd_is_socket_internal(fd, type, listening); if (r <= 0) @@ -310,10 +310,15 @@ _public_ int sd_is_socket_unix(int fd, int type, int listening, const char *path _public_ int sd_is_mq(int fd, const char *path) { struct mq_attr attr; - assert_return(fd >= 0, -EINVAL); + /* Check that the fd is valid */ + assert_return(fcntl(fd, F_GETFD) >= 0, -errno); - if (mq_getattr(fd, &attr) < 0) + if (mq_getattr(fd, &attr) < 0) { + if (errno == EBADF) + /* A non-mq fd (or an invalid one, but we ruled that out above) */ + return 0; return -errno; + } if (path) { char fpath[PATH_MAX]; @@ -395,8 +400,9 @@ _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char have_pid = pid != 0 && pid != getpid(); if (n_fds > 0 || have_pid) { - msghdr.msg_controllen = CMSG_SPACE(sizeof(int) * n_fds) + - CMSG_SPACE(sizeof(struct ucred) * have_pid); + /* CMSG_SPACE(0) may return value different then zero, which results in miscalculated controllen. */ + msghdr.msg_controllen = (n_fds ? CMSG_SPACE(sizeof(int) * n_fds) : 0) + + CMSG_SPACE(sizeof(struct ucred)) * have_pid; msghdr.msg_control = alloca(msghdr.msg_controllen); cmsg = CMSG_FIRSTHDR(&msghdr); @@ -497,16 +503,11 @@ _public_ int sd_notifyf(int unset_environment, const char *format, ...) { } _public_ int sd_booted(void) { - struct stat st; - /* We test whether the runtime unit file directory has been * created. This takes place in mount-setup.c, so is * guaranteed to happen very early during boot. */ - if (lstat("/run/systemd/system/", &st) < 0) - return 0; - - return !!S_ISDIR(st.st_mode); + return laccess("/run/systemd/system/", F_OK) >= 0; } _public_ int sd_watchdog_enabled(int unset_environment, uint64_t *usec) { diff --git a/src/libsystemd/sd-device/device-enumerator.c b/src/libsystemd/sd-device/device-enumerator.c index 7fd77e9480..45a4d12eb7 100644 --- a/src/libsystemd/sd-device/device-enumerator.c +++ b/src/libsystemd/sd-device/device-enumerator.c @@ -719,6 +719,8 @@ static int parent_add_child(sd_device_enumerator *enumerator, const char *path) return r; r = sd_device_get_subsystem(device, &subsystem); + if (r == -ENOENT) + return 0; if (r < 0) return r; @@ -810,10 +812,8 @@ static int enumerator_scan_devices_all(sd_device_enumerator *enumerator) { if (access("/sys/subsystem", F_OK) >= 0) { /* we have /subsystem/, forget all the old stuff */ r = enumerator_scan_dir(enumerator, "subsystem", "devices", NULL); - if (r < 0) { - log_debug("device-enumerator: failed to scan /sys/subsystem: %s", strerror(-r)); - return r; - } + if (r < 0) + return log_debug_errno(r, "device-enumerator: failed to scan /sys/subsystem: %m"); } else { int k; diff --git a/src/libsystemd/sd-device/device-private.c b/src/libsystemd/sd-device/device-private.c index 2e60433246..b5215cb9b5 100644 --- a/src/libsystemd/sd-device/device-private.c +++ b/src/libsystemd/sd-device/device-private.c @@ -200,10 +200,8 @@ static int device_read_db(sd_device *device) { if (r < 0) { if (r == -ENOENT) return 0; - else { - log_debug("sd-device: failed to read db '%s': %s", path, strerror(-r)); - return r; - } + else + return log_debug_errno(r, "sd-device: failed to read db '%s': %m", path); } /* devices with a database entry are initialized */ @@ -247,7 +245,7 @@ static int device_read_db(sd_device *device) { db[i] = '\0'; r = handle_db_line(device, key, value); if (r < 0) - log_debug("sd-device: failed to handle db entry '%c:%s': %s", key, value, strerror(-r)); + log_debug_errno(r, "sd-device: failed to handle db entry '%c:%s': %m", key, value); state = PRE_KEY; } @@ -1082,12 +1080,10 @@ int device_update_db(sd_device *device) { return 0; fail: - log_error_errno(r, "failed to create %s file '%s' for '%s'", has_info ? "db" : "empty", - path, device->devpath); - unlink(path); - unlink(path_tmp); + (void) unlink(path); + (void) unlink(path_tmp); - return r; + return log_error_errno(r, "failed to create %s file '%s' for '%s'", has_info ? "db" : "empty", path, device->devpath); } int device_delete_db(sd_device *device) { diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c index 7cea5a0746..c528a157c1 100644 --- a/src/libsystemd/sd-device/sd-device.c +++ b/src/libsystemd/sd-device/sd-device.c @@ -169,11 +169,10 @@ int device_set_syspath(sd_device *device, const char *_syspath, bool verify) { /* the device does not exist (any more?) */ return -ENODEV; - log_debug("sd-device: could not canonicalize '%s': %m", _syspath); - return -errno; + return log_debug_errno(errno, "sd-device: could not canonicalize '%s': %m", _syspath); } } else if (r < 0) { - log_debug("sd-device: could not get target of '%s': %s", _syspath, strerror(-r)); + log_debug_errno(r, "sd-device: could not get target of '%s': %m", _syspath); return r; } @@ -516,7 +515,7 @@ int device_read_uevent_file(sd_device *device) { /* some devices may not have uevent files, see set_syspath() */ return 0; else if (r < 0) { - log_debug("sd-device: failed to read uevent file '%s': %s", path, strerror(-r)); + log_debug_errno(r, "sd-device: failed to read uevent file '%s': %m", path); return r; } @@ -555,7 +554,7 @@ int device_read_uevent_file(sd_device *device) { r = handle_uevent_line(device, key, value, &major, &minor); if (r < 0) - log_debug("sd-device: failed to handle uevent entry '%s=%s': %s", key, value, strerror(-r)); + log_debug_errno(r, "sd-device: failed to handle uevent entry '%s=%s': %m", key, value); state = PRE_KEY; } @@ -569,7 +568,7 @@ int device_read_uevent_file(sd_device *device) { if (major) { r = device_set_devnum(device, major, minor); if (r < 0) - log_debug("sd-device: could not set 'MAJOR=%s' or 'MINOR=%s' from '%s': %s", major, minor, path, strerror(-r)); + log_debug_errno(r, "sd-device: could not set 'MAJOR=%s' or 'MINOR=%s' from '%s': %m", major, minor, path); } return 0; @@ -1271,10 +1270,8 @@ int device_read_db_aux(sd_device *device, bool force) { if (r < 0) { if (r == -ENOENT) return 0; - else { - log_debug("sd-device: failed to read db '%s': %s", path, strerror(-r)); - return r; - } + else + return log_debug_errno(r, "sd-device: failed to read db '%s': %m", path); } /* devices with a database entry are initialized */ @@ -1318,7 +1315,7 @@ int device_read_db_aux(sd_device *device, bool force) { db[i] = '\0'; r = handle_db_line(device, key, value); if (r < 0) - log_debug("sd-device: failed to handle db entry '%c:%s': %s", key, value, strerror(-r)); + log_debug_errno(r, "sd-device: failed to handle db entry '%c:%s': %m", key, value); state = PRE_KEY; } diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c index 76964aa0cc..1a82c4c940 100644 --- a/src/libsystemd/sd-event/sd-event.c +++ b/src/libsystemd/sd-event/sd-event.c @@ -56,9 +56,22 @@ typedef enum EventSourceType { _SOURCE_EVENT_SOURCE_TYPE_INVALID = -1 } EventSourceType; +/* All objects we use in epoll events start with this value, so that + * we know how to dispatch it */ +typedef enum WakeupType { + WAKEUP_NONE, + WAKEUP_EVENT_SOURCE, + WAKEUP_CLOCK_DATA, + WAKEUP_SIGNAL_DATA, + _WAKEUP_TYPE_MAX, + _WAKEUP_TYPE_INVALID = -1, +} WakeupType; + #define EVENT_SOURCE_IS_TIME(t) IN_SET((t), SOURCE_TIME_REALTIME, SOURCE_TIME_BOOTTIME, SOURCE_TIME_MONOTONIC, SOURCE_TIME_REALTIME_ALARM, SOURCE_TIME_BOOTTIME_ALARM) struct sd_event_source { + WakeupType wakeup; + unsigned n_ref; sd_event *event; @@ -120,6 +133,7 @@ struct sd_event_source { }; struct clock_data { + WakeupType wakeup; int fd; /* For all clocks we maintain two priority queues each, one @@ -136,11 +150,23 @@ struct clock_data { bool needs_rearm:1; }; +struct signal_data { + WakeupType wakeup; + + /* For each priority we maintain one signal fd, so that we + * only have to dequeue a single event per priority at a + * time. */ + + int fd; + int64_t priority; + sigset_t sigset; + sd_event_source *current; +}; + struct sd_event { unsigned n_ref; int epoll_fd; - int signal_fd; int watchdog_fd; Prioq *pending; @@ -157,8 +183,8 @@ struct sd_event { usec_t perturb; - sigset_t sigset; - sd_event_source **signal_sources; + sd_event_source **signal_sources; /* indexed by signal number */ + Hashmap *signal_data; /* indexed by priority */ Hashmap *child_sources; unsigned n_enabled_child_sources; @@ -216,12 +242,6 @@ static int pending_prioq_compare(const void *a, const void *b) { if (x->pending_iteration > y->pending_iteration) return 1; - /* Stability for the rest */ - if (x < y) - return -1; - if (x > y) - return 1; - return 0; } @@ -231,6 +251,12 @@ static int prepare_prioq_compare(const void *a, const void *b) { assert(x->prepare); assert(y->prepare); + /* Enabled ones first */ + if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF) + return -1; + if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF) + return 1; + /* Move most recently prepared ones last, so that we can stop * preparing as soon as we hit one that has already been * prepared in the current iteration */ @@ -239,24 +265,12 @@ static int prepare_prioq_compare(const void *a, const void *b) { if (x->prepare_iteration > y->prepare_iteration) return 1; - /* Enabled ones first */ - if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF) - return -1; - if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF) - return 1; - /* Lower priority values first */ if (x->priority < y->priority) return -1; if (x->priority > y->priority) return 1; - /* Stability for the rest */ - if (x < y) - return -1; - if (x > y) - return 1; - return 0; } @@ -284,12 +298,6 @@ static int earliest_time_prioq_compare(const void *a, const void *b) { if (x->time.next > y->time.next) return 1; - /* Stability for the rest */ - if (x < y) - return -1; - if (x > y) - return 1; - return 0; } @@ -317,12 +325,6 @@ static int latest_time_prioq_compare(const void *a, const void *b) { if (x->time.next + x->time.accuracy > y->time.next + y->time.accuracy) return 1; - /* Stability for the rest */ - if (x < y) - return -1; - if (x > y) - return 1; - return 0; } @@ -344,17 +346,12 @@ static int exit_prioq_compare(const void *a, const void *b) { if (x->priority > y->priority) return 1; - /* Stability for the rest */ - if (x < y) - return -1; - if (x > y) - return 1; - return 0; } static void free_clock_data(struct clock_data *d) { assert(d); + assert(d->wakeup == WAKEUP_CLOCK_DATA); safe_close(d->fd); prioq_free(d->earliest); @@ -378,7 +375,6 @@ static void event_free(sd_event *e) { *(e->default_event_ptr) = NULL; safe_close(e->epoll_fd); - safe_close(e->signal_fd); safe_close(e->watchdog_fd); free_clock_data(&e->realtime); @@ -392,6 +388,7 @@ static void event_free(sd_event *e) { prioq_free(e->exit); free(e->signal_sources); + hashmap_free(e->signal_data); hashmap_free(e->child_sources); set_free(e->post_sources); @@ -409,13 +406,12 @@ _public_ int sd_event_new(sd_event** ret) { return -ENOMEM; e->n_ref = 1; - e->signal_fd = e->watchdog_fd = e->epoll_fd = e->realtime.fd = e->boottime.fd = e->monotonic.fd = e->realtime_alarm.fd = e->boottime_alarm.fd = -1; + e->watchdog_fd = e->epoll_fd = e->realtime.fd = e->boottime.fd = e->monotonic.fd = e->realtime_alarm.fd = e->boottime_alarm.fd = -1; e->realtime.next = e->boottime.next = e->monotonic.next = e->realtime_alarm.next = e->boottime_alarm.next = USEC_INFINITY; + e->realtime.wakeup = e->boottime.wakeup = e->monotonic.wakeup = e->realtime_alarm.wakeup = e->boottime_alarm.wakeup = WAKEUP_CLOCK_DATA; e->original_pid = getpid(); e->perturb = USEC_INFINITY; - assert_se(sigemptyset(&e->sigset) == 0); - e->pending = prioq_new(pending_prioq_compare); if (!e->pending) { r = -ENOMEM; @@ -481,7 +477,8 @@ static void source_io_unregister(sd_event_source *s) { return; r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->io.fd, NULL); - assert_log(r >= 0); + if (r < 0) + log_debug_errno(errno, "Failed to remove source %s from epoll: %m", strna(s->description)); s->io.registered = false; } @@ -508,7 +505,6 @@ static int source_io_register( r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_MOD, s->io.fd, &ev); else r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_ADD, s->io.fd, &ev); - if (r < 0) return -errno; @@ -590,45 +586,171 @@ static struct clock_data* event_get_clock_data(sd_event *e, EventSourceType t) { } } -static bool need_signal(sd_event *e, int signal) { - return (e->signal_sources && e->signal_sources[signal] && - e->signal_sources[signal]->enabled != SD_EVENT_OFF) - || - (signal == SIGCHLD && - e->n_enabled_child_sources > 0); -} +static int event_make_signal_data( + sd_event *e, + int sig, + struct signal_data **ret) { -static int event_update_signal_fd(sd_event *e) { struct epoll_event ev = {}; - bool add_to_epoll; + struct signal_data *d; + bool added = false; + sigset_t ss_copy; + int64_t priority; int r; assert(e); if (event_pid_changed(e)) - return 0; + return -ECHILD; - add_to_epoll = e->signal_fd < 0; + if (e->signal_sources && e->signal_sources[sig]) + priority = e->signal_sources[sig]->priority; + else + priority = 0; - r = signalfd(e->signal_fd, &e->sigset, SFD_NONBLOCK|SFD_CLOEXEC); - if (r < 0) - return -errno; + d = hashmap_get(e->signal_data, &priority); + if (d) { + if (sigismember(&d->sigset, sig) > 0) { + if (ret) + *ret = d; + return 0; + } + } else { + r = hashmap_ensure_allocated(&e->signal_data, &uint64_hash_ops); + if (r < 0) + return r; + + d = new0(struct signal_data, 1); + if (!d) + return -ENOMEM; + + d->wakeup = WAKEUP_SIGNAL_DATA; + d->fd = -1; + d->priority = priority; + + r = hashmap_put(e->signal_data, &d->priority, d); + if (r < 0) + return r; + + added = true; + } + + ss_copy = d->sigset; + assert_se(sigaddset(&ss_copy, sig) >= 0); + + r = signalfd(d->fd, &ss_copy, SFD_NONBLOCK|SFD_CLOEXEC); + if (r < 0) { + r = -errno; + goto fail; + } - e->signal_fd = r; + d->sigset = ss_copy; - if (!add_to_epoll) + if (d->fd >= 0) { + if (ret) + *ret = d; return 0; + } + + d->fd = r; ev.events = EPOLLIN; - ev.data.ptr = INT_TO_PTR(SOURCE_SIGNAL); + ev.data.ptr = d; - r = epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, e->signal_fd, &ev); - if (r < 0) { - e->signal_fd = safe_close(e->signal_fd); - return -errno; + r = epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, d->fd, &ev); + if (r < 0) { + r = -errno; + goto fail; } + if (ret) + *ret = d; + return 0; + +fail: + if (added) { + d->fd = safe_close(d->fd); + hashmap_remove(e->signal_data, &d->priority); + free(d); + } + + return r; +} + +static void event_unmask_signal_data(sd_event *e, struct signal_data *d, int sig) { + assert(e); + assert(d); + + /* Turns off the specified signal in the signal data + * object. If the signal mask of the object becomes empty that + * way removes it. */ + + if (sigismember(&d->sigset, sig) == 0) + return; + + assert_se(sigdelset(&d->sigset, sig) >= 0); + + if (sigisemptyset(&d->sigset)) { + + /* If all the mask is all-zero we can get rid of the structure */ + hashmap_remove(e->signal_data, &d->priority); + assert(!d->current); + safe_close(d->fd); + free(d); + return; + } + + assert(d->fd >= 0); + + if (signalfd(d->fd, &d->sigset, SFD_NONBLOCK|SFD_CLOEXEC) < 0) + log_debug_errno(errno, "Failed to unset signal bit, ignoring: %m"); +} + +static void event_gc_signal_data(sd_event *e, const int64_t *priority, int sig) { + struct signal_data *d; + static const int64_t zero_priority = 0; + + assert(e); + + /* Rechecks if the specified signal is still something we are + * interested in. If not, we'll unmask it, and possibly drop + * the signalfd for it. */ + + if (sig == SIGCHLD && + e->n_enabled_child_sources > 0) + return; + + if (e->signal_sources && + e->signal_sources[sig] && + e->signal_sources[sig]->enabled != SD_EVENT_OFF) + return; + + /* + * The specified signal might be enabled in three different queues: + * + * 1) the one that belongs to the priority passed (if it is non-NULL) + * 2) the one that belongs to the priority of the event source of the signal (if there is one) + * 3) the 0 priority (to cover the SIGCHLD case) + * + * Hence, let's remove it from all three here. + */ + + if (priority) { + d = hashmap_get(e->signal_data, priority); + if (d) + event_unmask_signal_data(e, d, sig); + } + + if (e->signal_sources && e->signal_sources[sig]) { + d = hashmap_get(e->signal_data, &e->signal_sources[sig]->priority); + if (d) + event_unmask_signal_data(e, d, sig); + } + + d = hashmap_get(e->signal_data, &zero_priority); + if (d) + event_unmask_signal_data(e, d, sig); } static void source_disconnect(sd_event_source *s) { @@ -667,17 +789,11 @@ static void source_disconnect(sd_event_source *s) { case SOURCE_SIGNAL: if (s->signal.sig > 0) { + if (s->event->signal_sources) s->event->signal_sources[s->signal.sig] = NULL; - /* If the signal was on and now it is off... */ - if (s->enabled != SD_EVENT_OFF && !need_signal(s->event, s->signal.sig)) { - assert_se(sigdelset(&s->event->sigset, s->signal.sig) == 0); - - (void) event_update_signal_fd(s->event); - /* If disabling failed, we might get a spurious event, - * but otherwise nothing bad should happen. */ - } + event_gc_signal_data(s->event, &s->priority, s->signal.sig); } break; @@ -687,18 +803,10 @@ static void source_disconnect(sd_event_source *s) { if (s->enabled != SD_EVENT_OFF) { assert(s->event->n_enabled_child_sources > 0); s->event->n_enabled_child_sources--; - - /* We know the signal was on, if it is off now... */ - if (!need_signal(s->event, SIGCHLD)) { - assert_se(sigdelset(&s->event->sigset, SIGCHLD) == 0); - - (void) event_update_signal_fd(s->event); - /* If disabling failed, we might get a spurious event, - * but otherwise nothing bad should happen. */ - } } - hashmap_remove(s->event->child_sources, INT_TO_PTR(s->child.pid)); + (void) hashmap_remove(s->event->child_sources, INT_TO_PTR(s->child.pid)); + event_gc_signal_data(s->event, &s->priority, SIGCHLD); } break; @@ -777,6 +885,14 @@ static int source_set_pending(sd_event_source *s, bool b) { d->needs_rearm = true; } + if (s->type == SOURCE_SIGNAL && !b) { + struct signal_data *d; + + d = hashmap_get(s->event->signal_data, &s->priority); + if (d && d->current == s) + d->current = NULL; + } + return 0; } @@ -816,7 +932,7 @@ _public_ int sd_event_add_io( int r; assert_return(e, -EINVAL); - assert_return(fd >= 0, -EINVAL); + assert_return(fd >= 0, -EBADF); assert_return(!(events & ~(EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLPRI|EPOLLERR|EPOLLHUP|EPOLLET)), -EINVAL); assert_return(callback, -EINVAL); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); @@ -826,6 +942,7 @@ _public_ int sd_event_add_io( if (!s) return -ENOMEM; + s->wakeup = WAKEUP_EVENT_SOURCE; s->io.fd = fd; s->io.events = events; s->io.callback = callback; @@ -882,7 +999,7 @@ static int event_setup_timer_fd( return -errno; ev.events = EPOLLIN; - ev.data.ptr = INT_TO_PTR(clock_to_event_source_type(clock)); + ev.data.ptr = d; r = epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, fd, &ev); if (r < 0) { @@ -992,9 +1109,9 @@ _public_ int sd_event_add_signal( void *userdata) { sd_event_source *s; + struct signal_data *d; sigset_t ss; int r; - bool previous; assert_return(e, -EINVAL); assert_return(sig > 0, -EINVAL); @@ -1019,8 +1136,6 @@ _public_ int sd_event_add_signal( } else if (e->signal_sources[sig]) return -EBUSY; - previous = need_signal(e, sig); - s = source_new(e, !ret, SOURCE_SIGNAL); if (!s) return -ENOMEM; @@ -1032,14 +1147,10 @@ _public_ int sd_event_add_signal( e->signal_sources[sig] = s; - if (!previous) { - assert_se(sigaddset(&e->sigset, sig) == 0); - - r = event_update_signal_fd(e); - if (r < 0) { - source_free(s); - return r; - } + r = event_make_signal_data(e, sig, &d); + if (r < 0) { + source_free(s); + return r; } /* Use the signal name as description for the event source by default */ @@ -1061,7 +1172,6 @@ _public_ int sd_event_add_child( sd_event_source *s; int r; - bool previous; assert_return(e, -EINVAL); assert_return(pid > 1, -EINVAL); @@ -1078,8 +1188,6 @@ _public_ int sd_event_add_child( if (hashmap_contains(e->child_sources, INT_TO_PTR(pid))) return -EBUSY; - previous = need_signal(e, SIGCHLD); - s = source_new(e, !ret, SOURCE_CHILD); if (!s) return -ENOMEM; @@ -1098,14 +1206,11 @@ _public_ int sd_event_add_child( e->n_enabled_child_sources ++; - if (!previous) { - assert_se(sigaddset(&e->sigset, SIGCHLD) == 0); - - r = event_update_signal_fd(e); - if (r < 0) { - source_free(s); - return r; - } + r = event_make_signal_data(e, SIGCHLD, NULL); + if (r < 0) { + e->n_enabled_child_sources--; + source_free(s); + return r; } e->need_process_child = true; @@ -1311,7 +1416,7 @@ _public_ int sd_event_source_set_io_fd(sd_event_source *s, int fd) { int r; assert_return(s, -EINVAL); - assert_return(fd >= 0, -EINVAL); + assert_return(fd >= 0, -EBADF); assert_return(s->type == SOURCE_IO, -EDOM); assert_return(!event_pid_changed(s->event), -ECHILD); @@ -1405,6 +1510,8 @@ _public_ int sd_event_source_get_priority(sd_event_source *s, int64_t *priority) } _public_ int sd_event_source_set_priority(sd_event_source *s, int64_t priority) { + int r; + assert_return(s, -EINVAL); assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE); assert_return(!event_pid_changed(s->event), -ECHILD); @@ -1412,7 +1519,25 @@ _public_ int sd_event_source_set_priority(sd_event_source *s, int64_t priority) if (s->priority == priority) return 0; - s->priority = priority; + if (s->type == SOURCE_SIGNAL && s->enabled != SD_EVENT_OFF) { + struct signal_data *old, *d; + + /* Move us from the signalfd belonging to the old + * priority to the signalfd of the new priority */ + + assert_se(old = hashmap_get(s->event->signal_data, &s->priority)); + + s->priority = priority; + + r = event_make_signal_data(s->event, s->signal.sig, &d); + if (r < 0) { + s->priority = old->priority; + return r; + } + + event_unmask_signal_data(s->event, old, s->signal.sig); + } else + s->priority = priority; if (s->pending) prioq_reshuffle(s->event->pending, s, &s->pending_index); @@ -1477,34 +1602,18 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { } case SOURCE_SIGNAL: - assert(need_signal(s->event, s->signal.sig)); - s->enabled = m; - if (!need_signal(s->event, s->signal.sig)) { - assert_se(sigdelset(&s->event->sigset, s->signal.sig) == 0); - - (void) event_update_signal_fd(s->event); - /* If disabling failed, we might get a spurious event, - * but otherwise nothing bad should happen. */ - } - + event_gc_signal_data(s->event, &s->priority, s->signal.sig); break; case SOURCE_CHILD: - assert(need_signal(s->event, SIGCHLD)); - s->enabled = m; assert(s->event->n_enabled_child_sources > 0); s->event->n_enabled_child_sources--; - if (!need_signal(s->event, SIGCHLD)) { - assert_se(sigdelset(&s->event->sigset, SIGCHLD) == 0); - - (void) event_update_signal_fd(s->event); - } - + event_gc_signal_data(s->event, &s->priority, SIGCHLD); break; case SOURCE_EXIT: @@ -1550,37 +1659,33 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { } case SOURCE_SIGNAL: - /* Check status before enabling. */ - if (!need_signal(s->event, s->signal.sig)) { - assert_se(sigaddset(&s->event->sigset, s->signal.sig) == 0); - - r = event_update_signal_fd(s->event); - if (r < 0) { - s->enabled = SD_EVENT_OFF; - return r; - } - } s->enabled = m; + + r = event_make_signal_data(s->event, s->signal.sig, NULL); + if (r < 0) { + s->enabled = SD_EVENT_OFF; + event_gc_signal_data(s->event, &s->priority, s->signal.sig); + return r; + } + break; case SOURCE_CHILD: - /* Check status before enabling. */ - if (s->enabled == SD_EVENT_OFF) { - if (!need_signal(s->event, SIGCHLD)) { - assert_se(sigaddset(&s->event->sigset, s->signal.sig) == 0); - - r = event_update_signal_fd(s->event); - if (r < 0) { - s->enabled = SD_EVENT_OFF; - return r; - } - } + if (s->enabled == SD_EVENT_OFF) s->event->n_enabled_child_sources++; - } s->enabled = m; + + r = event_make_signal_data(s->event, SIGCHLD, NULL); + if (r < 0) { + s->enabled = SD_EVENT_OFF; + s->event->n_enabled_child_sources--; + event_gc_signal_data(s->event, &s->priority, SIGCHLD); + return r; + } + break; case SOURCE_EXIT: @@ -2024,20 +2129,35 @@ static int process_child(sd_event *e) { return 0; } -static int process_signal(sd_event *e, uint32_t events) { +static int process_signal(sd_event *e, struct signal_data *d, uint32_t events) { bool read_one = false; int r; assert(e); - assert_return(events == EPOLLIN, -EIO); + /* If there's a signal queued on this priority and SIGCHLD is + on this priority too, then make sure to recheck the + children we watch. This is because we only ever dequeue + the first signal per priority, and if we dequeue one, and + SIGCHLD might be enqueued later we wouldn't know, but we + might have higher priority children we care about hence we + need to check that explicitly. */ + + if (sigismember(&d->sigset, SIGCHLD)) + e->need_process_child = true; + + /* If there's already an event source pending for this + * priority we don't read another */ + if (d->current) + return 0; + for (;;) { struct signalfd_siginfo si; ssize_t n; sd_event_source *s = NULL; - n = read(e->signal_fd, &si, sizeof(si)); + n = read(d->fd, &si, sizeof(si)); if (n < 0) { if (errno == EAGAIN || errno == EINTR) return read_one; @@ -2052,24 +2172,21 @@ static int process_signal(sd_event *e, uint32_t events) { read_one = true; - if (si.ssi_signo == SIGCHLD) { - r = process_child(e); - if (r < 0) - return r; - if (r > 0) - continue; - } - if (e->signal_sources) s = e->signal_sources[si.ssi_signo]; - if (!s) continue; + if (s->pending) + continue; s->signal.siginfo = si; + d->current = s; + r = source_set_pending(s, true); if (r < 0) return r; + + return 1; } } @@ -2387,23 +2504,31 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) { for (i = 0; i < m; i++) { - if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_TIME_REALTIME)) - r = flush_timer(e, e->realtime.fd, ev_queue[i].events, &e->realtime.next); - else if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_TIME_BOOTTIME)) - r = flush_timer(e, e->boottime.fd, ev_queue[i].events, &e->boottime.next); - else if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_TIME_MONOTONIC)) - r = flush_timer(e, e->monotonic.fd, ev_queue[i].events, &e->monotonic.next); - else if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_TIME_REALTIME_ALARM)) - r = flush_timer(e, e->realtime_alarm.fd, ev_queue[i].events, &e->realtime_alarm.next); - else if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_TIME_BOOTTIME_ALARM)) - r = flush_timer(e, e->boottime_alarm.fd, ev_queue[i].events, &e->boottime_alarm.next); - else if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_SIGNAL)) - r = process_signal(e, ev_queue[i].events); - else if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_WATCHDOG)) + if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_WATCHDOG)) r = flush_timer(e, e->watchdog_fd, ev_queue[i].events, NULL); - else - r = process_io(e, ev_queue[i].data.ptr, ev_queue[i].events); + else { + WakeupType *t = ev_queue[i].data.ptr; + + switch (*t) { + + case WAKEUP_EVENT_SOURCE: + r = process_io(e, ev_queue[i].data.ptr, ev_queue[i].events); + break; + + case WAKEUP_CLOCK_DATA: { + struct clock_data *d = ev_queue[i].data.ptr; + r = flush_timer(e, d->fd, ev_queue[i].events, &d->next); + break; + } + case WAKEUP_SIGNAL_DATA: + r = process_signal(e, ev_queue[i].data.ptr, ev_queue[i].events); + break; + + default: + assert_not_reached("Invalid wake-up pointer"); + } + } if (r < 0) goto finish; } @@ -2572,9 +2697,12 @@ _public_ int sd_event_now(sd_event *e, clockid_t clock, uint64_t *usec) { assert_return(usec, -EINVAL); assert_return(!event_pid_changed(e), -ECHILD); - /* If we haven't run yet, just get the actual time */ - if (!dual_timestamp_is_set(&e->timestamp)) - return -ENODATA; + if (!dual_timestamp_is_set(&e->timestamp)) { + /* Implicitly fall back to now() if we never ran + * before and thus have no cached time. */ + *usec = now(clock); + return 1; + } switch (clock) { diff --git a/src/libsystemd/sd-event/test-event.c b/src/libsystemd/sd-event/test-event.c index 408e1679a2..c092e56b7a 100644 --- a/src/libsystemd/sd-event/test-event.c +++ b/src/libsystemd/sd-event/test-event.c @@ -156,7 +156,7 @@ static int exit_handler(sd_event_source *s, void *userdata) { return 3; } -int main(int argc, char *argv[]) { +static void test_basic(void) { sd_event *e = NULL; sd_event_source *w = NULL, *x = NULL, *y = NULL, *z = NULL, *q = NULL, *t = NULL; static const char ch = 'x'; @@ -244,6 +244,70 @@ int main(int argc, char *argv[]) { safe_close_pair(b); safe_close_pair(d); safe_close_pair(k); +} + +static int last_rtqueue_sigval = 0; +static int n_rtqueue = 0; + +static int rtqueue_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { + last_rtqueue_sigval = si->ssi_int; + n_rtqueue ++; + return 0; +} + +static void test_rtqueue(void) { + sd_event_source *u = NULL, *v = NULL, *s = NULL; + sd_event *e = NULL; + + assert_se(sd_event_default(&e) >= 0); + + assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGRTMIN+2, SIGRTMIN+3, SIGUSR2, -1) >= 0); + assert_se(sd_event_add_signal(e, &u, SIGRTMIN+2, rtqueue_handler, NULL) >= 0); + assert_se(sd_event_add_signal(e, &v, SIGRTMIN+3, rtqueue_handler, NULL) >= 0); + assert_se(sd_event_add_signal(e, &s, SIGUSR2, rtqueue_handler, NULL) >= 0); + + assert_se(sd_event_source_set_priority(v, -10) >= 0); + + assert(sigqueue(getpid(), SIGRTMIN+2, (union sigval) { .sival_int = 1 }) >= 0); + assert(sigqueue(getpid(), SIGRTMIN+3, (union sigval) { .sival_int = 2 }) >= 0); + assert(sigqueue(getpid(), SIGUSR2, (union sigval) { .sival_int = 3 }) >= 0); + assert(sigqueue(getpid(), SIGRTMIN+3, (union sigval) { .sival_int = 4 }) >= 0); + assert(sigqueue(getpid(), SIGUSR2, (union sigval) { .sival_int = 5 }) >= 0); + + assert_se(n_rtqueue == 0); + assert_se(last_rtqueue_sigval == 0); + + assert_se(sd_event_run(e, (uint64_t) -1) >= 1); + assert_se(n_rtqueue == 1); + assert_se(last_rtqueue_sigval == 2); /* first SIGRTMIN+3 */ + + assert_se(sd_event_run(e, (uint64_t) -1) >= 1); + assert_se(n_rtqueue == 2); + assert_se(last_rtqueue_sigval == 4); /* second SIGRTMIN+3 */ + + assert_se(sd_event_run(e, (uint64_t) -1) >= 1); + assert_se(n_rtqueue == 3); + assert_se(last_rtqueue_sigval == 3); /* first SIGUSR2 */ + + assert_se(sd_event_run(e, (uint64_t) -1) >= 1); + assert_se(n_rtqueue == 4); + assert_se(last_rtqueue_sigval == 1); /* SIGRTMIN+2 */ + + assert_se(sd_event_run(e, 0) == 0); /* the other SIGUSR2 is dropped, because the first one was still queued */ + assert_se(n_rtqueue == 4); + assert_se(last_rtqueue_sigval == 1); + + sd_event_source_unref(u); + sd_event_source_unref(v); + sd_event_source_unref(s); + + sd_event_unref(e); +} + +int main(int argc, char *argv[]) { + + test_basic(); + test_rtqueue(); return 0; } diff --git a/src/libsystemd/sd-hwdb/hwdb-internal.h b/src/libsystemd/sd-hwdb/hwdb-internal.h index fedccdec72..13fddfc8ad 100644 --- a/src/libsystemd/sd-hwdb/hwdb-internal.h +++ b/src/libsystemd/sd-hwdb/hwdb-internal.h @@ -19,6 +19,7 @@ #pragma once #include "sparse-endian.h" +#include "util.h" #define HWDB_SIG { 'K', 'S', 'L', 'P', 'H', 'H', 'R', 'H' } diff --git a/src/libsystemd/sd-hwdb/sd-hwdb.c b/src/libsystemd/sd-hwdb/sd-hwdb.c index 40aa77ee5c..f0316be659 100644 --- a/src/libsystemd/sd-hwdb/sd-hwdb.c +++ b/src/libsystemd/sd-hwdb/sd-hwdb.c @@ -79,8 +79,7 @@ static bool linebuf_add(struct linebuf *buf, const char *s, size_t len) { return true; } -static bool linebuf_add_char(struct linebuf *buf, char c) -{ +static bool linebuf_add_char(struct linebuf *buf, char c) { if (buf->len + 1 >= sizeof(buf->bytes)) return false; buf->bytes[buf->len++] = c; @@ -269,13 +268,13 @@ static int trie_search_f(sd_hwdb *hwdb, const char *search) { } static const char hwdb_bin_paths[] = - "/etc/systemd/hwdb/hwdb.bin\0" - "/etc/udev/hwdb.bin\0" - "/usr/lib/systemd/hwdb/hwdb.bin\0" + "/etc/systemd/hwdb/hwdb.bin\0" + "/etc/udev/hwdb.bin\0" + "/usr/lib/systemd/hwdb/hwdb.bin\0" #ifdef HAVE_SPLIT_USR - "/lib/systemd/hwdb/hwdb.bin\0" + "/lib/systemd/hwdb/hwdb.bin\0" #endif - UDEVLIBEXECDIR "/hwdb.bin\0"; + UDEVLIBEXECDIR "/hwdb.bin\0"; _public_ int sd_hwdb_new(sd_hwdb **ret) { _cleanup_hwdb_unref_ sd_hwdb *hwdb = NULL; @@ -345,8 +344,7 @@ _public_ sd_hwdb *sd_hwdb_unref(sd_hwdb *hwdb) { if (hwdb && REFCNT_DEC(hwdb->n_ref) == 0) { if (hwdb->map) munmap((void *)hwdb->map, hwdb->st.st_size); - if (hwdb->f) - fclose(hwdb->f); + safe_fclose(hwdb->f); free(hwdb->modalias); ordered_hashmap_free(hwdb->properties); free(hwdb); diff --git a/src/libsystemd/sd-id128/sd-id128.c b/src/libsystemd/sd-id128/sd-id128.c index 46f2181ea8..eb539ad318 100644 --- a/src/libsystemd/sd-id128/sd-id128.c +++ b/src/libsystemd/sd-id128/sd-id128.c @@ -28,7 +28,7 @@ #include "sd-id128.h" #include "random-util.h" -_public_ char *sd_id128_to_string(sd_id128_t id, char s[33]) { +_public_ char *sd_id128_to_string(sd_id128_t id, char s[SD_ID128_STRING_MAX]) { unsigned n; assert_return(s, NULL); diff --git a/src/libsystemd/sd-login/sd-login.c b/src/libsystemd/sd-login/sd-login.c index e3885ecba6..265c7c7db2 100644 --- a/src/libsystemd/sd-login/sd-login.c +++ b/src/libsystemd/sd-login/sd-login.c @@ -32,8 +32,19 @@ #include "fileio.h" #include "login-util.h" #include "formats-util.h" +#include "hostname-util.h" #include "sd-login.h" +/* Error codes: + * + * invalid input parameters → -EINVAL + * invalid fd → -EBADF + * process does not exist → -ESRCH + * cgroup does not exist → -ENOENT + * machine, session does not exist → -ENXIO + * requested metadata on object is missing → -ENODATA + */ + _public_ int sd_pid_get_session(pid_t pid, char **session) { assert_return(pid >= 0, -EINVAL); @@ -90,11 +101,37 @@ _public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) { return cg_pid_get_owner_uid(pid, uid); } +_public_ int sd_pid_get_cgroup(pid_t pid, char **cgroup) { + char *c; + int r; + + assert_return(pid >= 0, -EINVAL); + assert_return(cgroup, -EINVAL); + + r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &c); + if (r < 0) + return r; + + /* The internal APIs return the empty string for the root + * cgroup, let's return the "/" in the public APIs instead, as + * that's easier and less ambigious for people to grok. */ + if (isempty(c)) { + free(c); + c = strdup("/"); + if (!c) + return -ENOMEM; + + } + + *cgroup = c; + return 0; +} + _public_ int sd_peer_get_session(int fd, char **session) { struct ucred ucred = {}; int r; - assert_return(fd >= 0, -EINVAL); + assert_return(fd >= 0, -EBADF); assert_return(session, -EINVAL); r = getpeercred(fd, &ucred); @@ -108,7 +145,7 @@ _public_ int sd_peer_get_owner_uid(int fd, uid_t *uid) { struct ucred ucred; int r; - assert_return(fd >= 0, -EINVAL); + assert_return(fd >= 0, -EBADF); assert_return(uid, -EINVAL); r = getpeercred(fd, &ucred); @@ -122,7 +159,7 @@ _public_ int sd_peer_get_unit(int fd, char **unit) { struct ucred ucred; int r; - assert_return(fd >= 0, -EINVAL); + assert_return(fd >= 0, -EBADF); assert_return(unit, -EINVAL); r = getpeercred(fd, &ucred); @@ -136,7 +173,7 @@ _public_ int sd_peer_get_user_unit(int fd, char **unit) { struct ucred ucred; int r; - assert_return(fd >= 0, -EINVAL); + assert_return(fd >= 0, -EBADF); assert_return(unit, -EINVAL); r = getpeercred(fd, &ucred); @@ -150,7 +187,7 @@ _public_ int sd_peer_get_machine_name(int fd, char **machine) { struct ucred ucred; int r; - assert_return(fd >= 0, -EINVAL); + assert_return(fd >= 0, -EBADF); assert_return(machine, -EINVAL); r = getpeercred(fd, &ucred); @@ -164,7 +201,7 @@ _public_ int sd_peer_get_slice(int fd, char **slice) { struct ucred ucred; int r; - assert_return(fd >= 0, -EINVAL); + assert_return(fd >= 0, -EBADF); assert_return(slice, -EINVAL); r = getpeercred(fd, &ucred); @@ -178,7 +215,7 @@ _public_ int sd_peer_get_user_slice(int fd, char **slice) { struct ucred ucred; int r; - assert_return(fd >= 0, -EINVAL); + assert_return(fd >= 0, -EBADF); assert_return(slice, -EINVAL); r = getpeercred(fd, &ucred); @@ -188,7 +225,23 @@ _public_ int sd_peer_get_user_slice(int fd, char **slice) { return cg_pid_get_user_slice(ucred.pid, slice); } +_public_ int sd_peer_get_cgroup(int fd, char **cgroup) { + struct ucred ucred; + int r; + + assert_return(fd >= 0, -EBADF); + assert_return(cgroup, -EINVAL); + + r = getpeercred(fd, &ucred); + if (r < 0) + return r; + + return sd_pid_get_cgroup(ucred.pid, cgroup); +} + static int file_of_uid(uid_t uid, char **p) { + + assert_return(uid_is_valid(uid), -EINVAL); assert(p); if (asprintf(p, "/run/systemd/users/" UID_FMT, uid) < 0) @@ -215,11 +268,15 @@ _public_ int sd_uid_get_state(uid_t uid, char**state) { if (!s) return -ENOMEM; - } else if (r < 0) { + } + if (r < 0) { free(s); return r; - } else if (!s) + } + if (isempty(s)) { + free(s); return -EIO; + } *state = s; return 0; @@ -236,11 +293,12 @@ _public_ int sd_uid_get_display(uid_t uid, char **session) { return r; r = parse_env_file(p, NEWLINE, "DISPLAY", &s, NULL); + if (r == -ENOENT) + return -ENODATA; if (r < 0) return r; - if (isempty(s)) - return -ENOENT; + return -ENODATA; *session = s; s = NULL; @@ -248,35 +306,63 @@ _public_ int sd_uid_get_display(uid_t uid, char **session) { return 0; } +static int file_of_seat(const char *seat, char **_p) { + char *p; + int r; + + assert(_p); + + if (seat) { + if (!filename_is_valid(seat)) + return -EINVAL; + + p = strappend("/run/systemd/seats/", seat); + } else { + _cleanup_free_ char *buf = NULL; + + r = sd_session_get_seat(NULL, &buf); + if (r < 0) + return r; + + p = strappend("/run/systemd/seats/", buf); + } + + if (!p) + return -ENOMEM; + + *_p = p; + p = NULL; + return 0; +} + _public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) { _cleanup_free_ char *t = NULL, *s = NULL, *p = NULL; size_t l; int r; const char *word, *variable, *state; - assert_return(seat, -EINVAL); + assert_return(uid_is_valid(uid), -EINVAL); - variable = require_active ? "ACTIVE_UID" : "UIDS"; + r = file_of_seat(seat, &p); + if (r < 0) + return r; - p = strappend("/run/systemd/seats/", seat); - if (!p) - return -ENOMEM; + variable = require_active ? "ACTIVE_UID" : "UIDS"; r = parse_env_file(p, NEWLINE, variable, &s, NULL); - + if (r == -ENOENT) + return 0; if (r < 0) return r; - - if (!s) - return -EIO; + if (isempty(s)) + return 0; if (asprintf(&t, UID_FMT, uid) < 0) return -ENOMEM; - FOREACH_WORD(word, l, s, state) { + FOREACH_WORD(word, l, s, state) if (strneq(t, word, l)) return 1; - } return 0; } @@ -286,31 +372,22 @@ static int uid_get_array(uid_t uid, const char *variable, char ***array) { char **a; int r; + assert(variable); + r = file_of_uid(uid, &p); if (r < 0) return r; - r = parse_env_file(p, NEWLINE, - variable, &s, - NULL); - if (r < 0) { - if (r == -ENOENT) { - if (array) - *array = NULL; - return 0; - } - - return r; - } - - if (!s) { + r = parse_env_file(p, NEWLINE, variable, &s, NULL); + if (r == -ENOENT || (r >= 0 && isempty(s))) { if (array) *array = NULL; return 0; } + if (r < 0) + return r; a = strv_split(s, " "); - if (!a) return -ENOMEM; @@ -372,37 +449,39 @@ static int file_of_session(const char *session, char **_p) { } _public_ int sd_session_is_active(const char *session) { - int r; _cleanup_free_ char *p = NULL, *s = NULL; + int r; r = file_of_session(session, &p); if (r < 0) return r; r = parse_env_file(p, NEWLINE, "ACTIVE", &s, NULL); + if (r == -ENOENT) + return -ENXIO; if (r < 0) return r; - - if (!s) + if (isempty(s)) return -EIO; return parse_boolean(s); } _public_ int sd_session_is_remote(const char *session) { - int r; _cleanup_free_ char *p = NULL, *s = NULL; + int r; r = file_of_session(session, &p); if (r < 0) return r; r = parse_env_file(p, NEWLINE, "REMOTE", &s, NULL); + if (r == -ENOENT) + return -ENXIO; if (r < 0) return r; - - if (!s) - return -EIO; + if (isempty(s)) + return -ENODATA; return parse_boolean(s); } @@ -418,9 +497,11 @@ _public_ int sd_session_get_state(const char *session, char **state) { return r; r = parse_env_file(p, NEWLINE, "STATE", &s, NULL); + if (r == -ENOENT) + return -ENXIO; if (r < 0) return r; - else if (!s) + if (isempty(s)) return -EIO; *state = s; @@ -440,10 +521,11 @@ _public_ int sd_session_get_uid(const char *session, uid_t *uid) { return r; r = parse_env_file(p, NEWLINE, "UID", &s, NULL); + if (r == -ENOENT) + return -ENXIO; if (r < 0) return r; - - if (!s) + if (isempty(s)) return -EIO; return parse_uid(s, uid); @@ -454,17 +536,19 @@ static int session_get_string(const char *session, const char *field, char **val int r; assert_return(value, -EINVAL); + assert(field); r = file_of_session(session, &p); if (r < 0) return r; r = parse_env_file(p, NEWLINE, field, &s, NULL); + if (r == -ENOENT) + return -ENXIO; if (r < 0) return r; - if (isempty(s)) - return -ENOENT; + return -ENODATA; *value = s; s = NULL; @@ -484,6 +568,8 @@ _public_ int sd_session_get_vt(const char *session, unsigned *vtnr) { unsigned u; int r; + assert_return(vtnr, -EINVAL); + r = session_get_string(session, "VTNR", &vtnr_string); if (r < 0) return r; @@ -539,32 +625,6 @@ _public_ int sd_session_get_remote_host(const char *session, char **remote_host) return session_get_string(session, "REMOTE_HOST", remote_host); } -static int file_of_seat(const char *seat, char **_p) { - char *p; - int r; - - assert(_p); - - if (seat) - p = strappend("/run/systemd/seats/", seat); - else { - _cleanup_free_ char *buf = NULL; - - r = sd_session_get_seat(NULL, &buf); - if (r < 0) - return r; - - p = strappend("/run/systemd/seats/", buf); - } - - if (!p) - return -ENOMEM; - - *_p = p; - p = NULL; - return 0; -} - _public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) { _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL; int r; @@ -579,14 +639,16 @@ _public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) { "ACTIVE", &s, "ACTIVE_UID", &t, NULL); + if (r == -ENOENT) + return -ENXIO; if (r < 0) return r; if (session && !s) - return -ENOENT; + return -ENODATA; if (uid && !t) - return -ENOENT; + return -ENODATA; if (uid && t) { r = parse_uid(t, uid); @@ -617,7 +679,8 @@ _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **ui "SESSIONS", &s, "ACTIVE_SESSIONS", &t, NULL); - + if (r == -ENOENT) + return -ENXIO; if (r < 0) return r; @@ -649,7 +712,6 @@ _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **ui return -ENOMEM; r = parse_uid(k, b + i); - if (r < 0) continue; @@ -680,7 +742,7 @@ static int seat_get_can(const char *seat, const char *variable) { _cleanup_free_ char *p = NULL, *s = NULL; int r; - assert_return(variable, -EINVAL); + assert(variable); r = file_of_seat(seat, &p); if (r < 0) @@ -689,10 +751,12 @@ static int seat_get_can(const char *seat, const char *variable) { r = parse_env_file(p, NEWLINE, variable, &s, NULL); + if (r == -ENOENT) + return -ENXIO; if (r < 0) return r; - if (!s) - return 0; + if (isempty(s)) + return -ENODATA; return parse_boolean(s); } @@ -790,7 +854,7 @@ _public_ int sd_get_machine_names(char ***machines) { /* Filter out the unit: symlinks */ for (a = l, b = l; *a; a++) { - if (startswith(*a, "unit:")) + if (startswith(*a, "unit:") || !machine_name_is_valid(*a)) free(*a); else { *b = *a; @@ -816,6 +880,8 @@ _public_ int sd_machine_get_class(const char *machine, char **class) { p = strjoina("/run/systemd/machines/", machine); r = parse_env_file(p, NEWLINE, "CLASS", &c, NULL); + if (r == -ENOENT) + return -ENXIO; if (r < 0) return r; if (!c) @@ -839,6 +905,8 @@ _public_ int sd_machine_get_ifindices(const char *machine, int **ifindices) { p = strjoina("/run/systemd/machines/", machine); r = parse_env_file(p, NEWLINE, "NETIF", &netif, NULL); + if (r == -ENOENT) + return -ENXIO; if (r < 0) return r; if (!netif) { diff --git a/src/libsystemd/sd-login/test-login.c b/src/libsystemd/sd-login/test-login.c index 05affa442d..f734ce9eee 100644 --- a/src/libsystemd/sd-login/test-login.c +++ b/src/libsystemd/sd-login/test-login.c @@ -33,7 +33,7 @@ static void test_login(void) { _cleanup_free_ char *pp = NULL, *qq = NULL; int r, k; uid_t u, u2; - char *seat, *type, *class, *display, *remote_user, *remote_host; + char *seat, *type, *class, *display, *remote_user, *remote_host, *display_session, *cgroup; char *session; char *state; char *session2; @@ -50,6 +50,16 @@ static void test_login(void) { assert_se(sd_pid_get_owner_uid(0, &u2) == 0); printf("user = "UID_FMT"\n", u2); + assert_se(sd_pid_get_cgroup(0, &cgroup) == 0); + printf("cgroup = %s\n", cgroup); + free(cgroup); + + display_session = NULL; + r = sd_uid_get_display(u2, &display_session); + assert_se(r >= 0 || r == -ENODATA); + printf("user's display session = %s\n", strna(display_session)); + free(display_session); + assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == 0); sd_peer_get_session(pair[0], &pp); sd_peer_get_session(pair[1], &qq); @@ -100,16 +110,22 @@ static void test_login(void) { printf("class = %s\n", class); free(class); - assert_se(sd_session_get_display(session, &display) >= 0); - printf("display = %s\n", display); + display = NULL; + r = sd_session_get_display(session, &display); + assert_se(r >= 0 || r == -ENODATA); + printf("display = %s\n", strna(display)); free(display); - assert_se(sd_session_get_remote_user(session, &remote_user) >= 0); - printf("remote_user = %s\n", remote_user); + remote_user = NULL; + r = sd_session_get_remote_user(session, &remote_user); + assert_se(r >= 0 || r == -ENODATA); + printf("remote_user = %s\n", strna(remote_user)); free(remote_user); - assert_se(sd_session_get_remote_host(session, &remote_host) >= 0); - printf("remote_host = %s\n", remote_host); + remote_host = NULL; + r = sd_session_get_remote_host(session, &remote_host); + assert_se(r >= 0 || r == -ENODATA); + printf("remote_host = %s\n", strna(remote_host)); free(remote_host); assert_se(sd_session_get_seat(session, &seat) >= 0); diff --git a/src/libsystemd/sd-netlink/netlink-message.c b/src/libsystemd/sd-netlink/netlink-message.c index b0ed2f2882..0d8e37b856 100644 --- a/src/libsystemd/sd-netlink/netlink-message.c +++ b/src/libsystemd/sd-netlink/netlink-message.c @@ -262,6 +262,24 @@ int sd_netlink_message_append_string(sd_netlink_message *m, unsigned short type, return 0; } +int sd_netlink_message_append_flag(sd_netlink_message *m, unsigned short type) { + size_t size; + int r; + + assert_return(m, -EINVAL); + assert_return(!m->sealed, -EPERM); + + r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_FLAG); + if (r < 0) + return r; + + r = add_rtattr(m, type, NULL, 0); + if (r < 0) + return r; + + return 0; +} + int sd_netlink_message_append_u8(sd_netlink_message *m, unsigned short type, uint8_t data) { int r; @@ -483,7 +501,7 @@ static int netlink_message_read_internal(sd_netlink_message *m, unsigned short t assert_return(m, -EINVAL); assert_return(m->sealed, -EPERM); assert_return(data, -EINVAL); - assert(m->n_containers <= RTNL_CONTAINER_DEPTH); + assert(m->n_containers < RTNL_CONTAINER_DEPTH); assert(m->containers[m->n_containers].attributes); assert(type < m->containers[m->n_containers].n_attributes); @@ -825,8 +843,7 @@ int sd_netlink_message_exit_container(sd_netlink_message *m) { assert_return(m->sealed, -EINVAL); assert_return(m->n_containers > 0, -EINVAL); - free(m->containers[m->n_containers].attributes); - m->containers[m->n_containers].attributes = NULL; + m->containers[m->n_containers].attributes = mfree(m->containers[m->n_containers].attributes); m->containers[m->n_containers].type_system = NULL; m->n_containers --; @@ -875,17 +892,14 @@ int sd_netlink_message_rewind(sd_netlink_message *m) { if (!m->sealed) rtnl_message_seal(m); - for (i = 1; i <= m->n_containers; i++) { - free(m->containers[i].attributes); - m->containers[i].attributes = NULL; - } + for (i = 1; i <= m->n_containers; i++) + m->containers[i].attributes = mfree(m->containers[i].attributes); m->n_containers = 0; - if (m->containers[0].attributes) { + if (m->containers[0].attributes) /* top-level attributes have already been parsed */ return 0; - } assert(m->hdr); diff --git a/src/libsystemd/sd-netlink/netlink-types.c b/src/libsystemd/sd-netlink/netlink-types.c index 74ac2ab344..2128329191 100644 --- a/src/libsystemd/sd-netlink/netlink-types.c +++ b/src/libsystemd/sd-netlink/netlink-types.c @@ -117,20 +117,30 @@ static const NLType rtnl_link_info_data_vlan_types[IFLA_VLAN_MAX + 1] = { }; static const NLType rtnl_link_info_data_vxlan_types[IFLA_VXLAN_MAX+1] = { - [IFLA_VXLAN_ID] = { .type = NETLINK_TYPE_U32 }, - [IFLA_VXLAN_GROUP] = { .type = NETLINK_TYPE_IN_ADDR }, - [IFLA_VXLAN_LINK] = { .type = NETLINK_TYPE_U32 }, - [IFLA_VXLAN_LOCAL] = { .type = NETLINK_TYPE_U32}, - [IFLA_VXLAN_TTL] = { .type = NETLINK_TYPE_U8 }, - [IFLA_VXLAN_TOS] = { .type = NETLINK_TYPE_U8 }, - [IFLA_VXLAN_LEARNING] = { .type = NETLINK_TYPE_U8 }, - [IFLA_VXLAN_AGEING] = { .type = NETLINK_TYPE_U32 }, - [IFLA_VXLAN_LIMIT] = { .type = NETLINK_TYPE_U32 }, - [IFLA_VXLAN_PORT_RANGE] = { .type = NETLINK_TYPE_U32}, - [IFLA_VXLAN_PROXY] = { .type = NETLINK_TYPE_U8 }, - [IFLA_VXLAN_RSC] = { .type = NETLINK_TYPE_U8 }, - [IFLA_VXLAN_L2MISS] = { .type = NETLINK_TYPE_U8 }, - [IFLA_VXLAN_L3MISS] = { .type = NETLINK_TYPE_U8 }, + [IFLA_VXLAN_ID] = { .type = NETLINK_TYPE_U32 }, + [IFLA_VXLAN_GROUP] = { .type = NETLINK_TYPE_IN_ADDR }, + [IFLA_VXLAN_LINK] = { .type = NETLINK_TYPE_U32 }, + [IFLA_VXLAN_LOCAL] = { .type = NETLINK_TYPE_U32}, + [IFLA_VXLAN_TTL] = { .type = NETLINK_TYPE_U8 }, + [IFLA_VXLAN_TOS] = { .type = NETLINK_TYPE_U8 }, + [IFLA_VXLAN_LEARNING] = { .type = NETLINK_TYPE_U8 }, + [IFLA_VXLAN_AGEING] = { .type = NETLINK_TYPE_U32 }, + [IFLA_VXLAN_LIMIT] = { .type = NETLINK_TYPE_U32 }, + [IFLA_VXLAN_PORT_RANGE] = { .type = NETLINK_TYPE_U32}, + [IFLA_VXLAN_PROXY] = { .type = NETLINK_TYPE_U8 }, + [IFLA_VXLAN_RSC] = { .type = NETLINK_TYPE_U8 }, + [IFLA_VXLAN_L2MISS] = { .type = NETLINK_TYPE_U8 }, + [IFLA_VXLAN_L3MISS] = { .type = NETLINK_TYPE_U8 }, + [IFLA_VXLAN_PORT] = { .type = NETLINK_TYPE_U16 }, + [IFLA_VXLAN_GROUP6] = { .type = NETLINK_TYPE_IN_ADDR }, + [IFLA_VXLAN_LOCAL6] = { .type = NETLINK_TYPE_IN_ADDR }, + [IFLA_VXLAN_UDP_CSUM] = { .type = NETLINK_TYPE_U8 }, + [IFLA_VXLAN_UDP_ZERO_CSUM6_TX] = { .type = NETLINK_TYPE_U8 }, + [IFLA_VXLAN_UDP_ZERO_CSUM6_RX] = { .type = NETLINK_TYPE_U8 }, + [IFLA_VXLAN_REMCSUM_TX] = { .type = NETLINK_TYPE_U8 }, + [IFLA_VXLAN_REMCSUM_RX] = { .type = NETLINK_TYPE_U8 }, + [IFLA_VXLAN_GBP] = { .type = NETLINK_TYPE_FLAG }, + [IFLA_VXLAN_REMCSUM_NOPARTIAL] = { .type = NETLINK_TYPE_FLAG }, }; static const NLType rtnl_bond_arp_target_types[BOND_ARP_TARGETS_MAX + 1] = { @@ -196,27 +206,37 @@ static const NLType rtnl_link_info_data_iptun_types[IFLA_IPTUN_MAX + 1] = { [IFLA_IPTUN_6RD_RELAY_PREFIX] = { .type = NETLINK_TYPE_U32 }, [IFLA_IPTUN_6RD_PREFIXLEN] = { .type = NETLINK_TYPE_U16 }, [IFLA_IPTUN_6RD_RELAY_PREFIXLEN] = { .type = NETLINK_TYPE_U16 }, + [IFLA_IPTUN_ENCAP_TYPE] = { .type = NETLINK_TYPE_U16 }, + [IFLA_IPTUN_ENCAP_FLAGS] = { .type = NETLINK_TYPE_U16 }, + [IFLA_IPTUN_ENCAP_SPORT] = { .type = NETLINK_TYPE_U16 }, + [IFLA_IPTUN_ENCAP_DPORT] = { .type = NETLINK_TYPE_U16 }, }; static const NLType rtnl_link_info_data_ipgre_types[IFLA_GRE_MAX + 1] = { - [IFLA_GRE_LINK] = { .type = NETLINK_TYPE_U32 }, - [IFLA_GRE_IFLAGS] = { .type = NETLINK_TYPE_U16 }, - [IFLA_GRE_OFLAGS] = { .type = NETLINK_TYPE_U16 }, - [IFLA_GRE_IKEY] = { .type = NETLINK_TYPE_U32 }, - [IFLA_GRE_OKEY] = { .type = NETLINK_TYPE_U32 }, - [IFLA_GRE_LOCAL] = { .type = NETLINK_TYPE_IN_ADDR }, - [IFLA_GRE_REMOTE] = { .type = NETLINK_TYPE_IN_ADDR }, - [IFLA_GRE_TTL] = { .type = NETLINK_TYPE_U8 }, - [IFLA_GRE_TOS] = { .type = NETLINK_TYPE_U8 }, - [IFLA_GRE_PMTUDISC] = { .type = NETLINK_TYPE_U8 }, + [IFLA_GRE_LINK] = { .type = NETLINK_TYPE_U32 }, + [IFLA_GRE_IFLAGS] = { .type = NETLINK_TYPE_U16 }, + [IFLA_GRE_OFLAGS] = { .type = NETLINK_TYPE_U16 }, + [IFLA_GRE_IKEY] = { .type = NETLINK_TYPE_U32 }, + [IFLA_GRE_OKEY] = { .type = NETLINK_TYPE_U32 }, + [IFLA_GRE_LOCAL] = { .type = NETLINK_TYPE_IN_ADDR }, + [IFLA_GRE_REMOTE] = { .type = NETLINK_TYPE_IN_ADDR }, + [IFLA_GRE_TTL] = { .type = NETLINK_TYPE_U8 }, + [IFLA_GRE_TOS] = { .type = NETLINK_TYPE_U8 }, + [IFLA_GRE_PMTUDISC] = { .type = NETLINK_TYPE_U8 }, + [IFLA_GRE_FLOWINFO] = { .type = NETLINK_TYPE_U32 }, + [IFLA_GRE_FLAGS] = { .type = NETLINK_TYPE_U32 }, + [IFLA_GRE_ENCAP_TYPE] = { .type = NETLINK_TYPE_U16 }, + [IFLA_GRE_ENCAP_FLAGS] = { .type = NETLINK_TYPE_U16 }, + [IFLA_GRE_ENCAP_SPORT] = { .type = NETLINK_TYPE_U16 }, + [IFLA_GRE_ENCAP_DPORT] = { .type = NETLINK_TYPE_U16 }, }; static const NLType rtnl_link_info_data_ipvti_types[IFLA_VTI_MAX + 1] = { [IFLA_VTI_LINK] = { .type = NETLINK_TYPE_U32 }, [IFLA_VTI_IKEY] = { .type = NETLINK_TYPE_U32 }, [IFLA_VTI_OKEY] = { .type = NETLINK_TYPE_U32 }, - [IFLA_VTI_LOCAL] = { .type = NETLINK_TYPE_IN_ADDR }, - [IFLA_VTI_REMOTE] = { .type = NETLINK_TYPE_IN_ADDR }, + [IFLA_VTI_LOCAL] = { .type = NETLINK_TYPE_IN_ADDR }, + [IFLA_VTI_REMOTE] = { .type = NETLINK_TYPE_IN_ADDR }, }; static const NLType rtnl_link_info_data_ip6tnl_types[IFLA_IPTUN_MAX + 1] = { @@ -227,7 +247,7 @@ static const NLType rtnl_link_info_data_ip6tnl_types[IFLA_IPTUN_MAX + 1] = { [IFLA_IPTUN_FLAGS] = { .type = NETLINK_TYPE_U32 }, [IFLA_IPTUN_PROTO] = { .type = NETLINK_TYPE_U8 }, [IFLA_IPTUN_ENCAP_LIMIT] = { .type = NETLINK_TYPE_U8 }, - [IFLA_IPTUN_FLOWINFO] = { .type = NETLINK_TYPE_U32}, + [IFLA_IPTUN_FLOWINFO] = { .type = NETLINK_TYPE_U32 }, }; /* these strings must match the .kind entries in the kernel */ @@ -238,6 +258,7 @@ static const char* const nl_union_link_info_data_table[_NL_UNION_LINK_INFO_DATA_ [NL_UNION_LINK_INFO_DATA_VETH] = "veth", [NL_UNION_LINK_INFO_DATA_DUMMY] = "dummy", [NL_UNION_LINK_INFO_DATA_MACVLAN] = "macvlan", + [NL_UNION_LINK_INFO_DATA_MACVTAP] = "macvtap", [NL_UNION_LINK_INFO_DATA_IPVLAN] = "ipvlan", [NL_UNION_LINK_INFO_DATA_VXLAN] = "vxlan", [NL_UNION_LINK_INFO_DATA_IPIP_TUNNEL] = "ipip", @@ -264,6 +285,8 @@ static const NLTypeSystem rtnl_link_info_data_type_systems[_NL_UNION_LINK_INFO_D .types = rtnl_link_info_data_veth_types }, [NL_UNION_LINK_INFO_DATA_MACVLAN] = { .count = ELEMENTSOF(rtnl_link_info_data_macvlan_types), .types = rtnl_link_info_data_macvlan_types }, + [NL_UNION_LINK_INFO_DATA_MACVTAP] = { .count = ELEMENTSOF(rtnl_link_info_data_macvlan_types), + .types = rtnl_link_info_data_macvlan_types }, [NL_UNION_LINK_INFO_DATA_IPVLAN] = { .count = ELEMENTSOF(rtnl_link_info_data_ipvlan_types), .types = rtnl_link_info_data_ipvlan_types }, [NL_UNION_LINK_INFO_DATA_VXLAN] = { .count = ELEMENTSOF(rtnl_link_info_data_vxlan_types), @@ -319,8 +342,11 @@ static const struct NLType rtnl_prot_info_bridge_port_types[IFLA_BRPORT_MAX + 1] [IFLA_BRPORT_MODE] = { .type = NETLINK_TYPE_U8 }, [IFLA_BRPORT_GUARD] = { .type = NETLINK_TYPE_U8 }, [IFLA_BRPORT_PROTECT] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BRPORT_FAST_LEAVE] = { .type = NETLINK_TYPE_U8 }, [IFLA_BRPORT_LEARNING] = { .type = NETLINK_TYPE_U8 }, [IFLA_BRPORT_UNICAST_FLOOD] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BRPORT_PROXYARP] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BRPORT_LEARNING_SYNC] = { .type = NETLINK_TYPE_U8 }, }; static const NLTypeSystem rtnl_prot_info_type_systems[AF_MAX] = { @@ -362,9 +388,9 @@ static const NLTypeSystem rtnl_af_spec_type_system = { }; static const NLType rtnl_link_types[IFLA_MAX + 1 ] = { - [IFLA_ADDRESS] = { .type = NETLINK_TYPE_ETHER_ADDR, }, - [IFLA_BROADCAST] = { .type = NETLINK_TYPE_ETHER_ADDR, }, - [IFLA_IFNAME] = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ - 1, }, + [IFLA_ADDRESS] = { .type = NETLINK_TYPE_ETHER_ADDR }, + [IFLA_BROADCAST] = { .type = NETLINK_TYPE_ETHER_ADDR }, + [IFLA_IFNAME] = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ - 1 }, [IFLA_MTU] = { .type = NETLINK_TYPE_U32 }, [IFLA_LINK] = { .type = NETLINK_TYPE_U32 }, /* diff --git a/src/libsystemd/sd-netlink/netlink-types.h b/src/libsystemd/sd-netlink/netlink-types.h index a210163241..bf7c641541 100644 --- a/src/libsystemd/sd-netlink/netlink-types.h +++ b/src/libsystemd/sd-netlink/netlink-types.h @@ -28,6 +28,7 @@ enum { NETLINK_TYPE_U32, /* NLA_U32 */ NETLINK_TYPE_U64, /* NLA_U64 */ NETLINK_TYPE_STRING, /* NLA_STRING */ + NETLINK_TYPE_FLAG, /* NLA_FLAG */ NETLINK_TYPE_IN_ADDR, NETLINK_TYPE_ETHER_ADDR, NETLINK_TYPE_CACHE_INFO, @@ -73,6 +74,7 @@ typedef enum NLUnionLinkInfoData { NL_UNION_LINK_INFO_DATA_VETH, NL_UNION_LINK_INFO_DATA_DUMMY, NL_UNION_LINK_INFO_DATA_MACVLAN, + NL_UNION_LINK_INFO_DATA_MACVTAP, NL_UNION_LINK_INFO_DATA_IPVLAN, NL_UNION_LINK_INFO_DATA_VXLAN, NL_UNION_LINK_INFO_DATA_IPIP_TUNNEL, diff --git a/src/libsystemd/sd-netlink/sd-netlink.c b/src/libsystemd/sd-netlink/sd-netlink.c index c413b1c266..d248869c8d 100644 --- a/src/libsystemd/sd-netlink/sd-netlink.c +++ b/src/libsystemd/sd-netlink/sd-netlink.c @@ -106,7 +106,7 @@ int sd_netlink_open_fd(sd_netlink **ret, int fd) { int r; assert_return(ret, -EINVAL); - assert_return(fd >= 0, -EINVAL); + assert_return(fd >= 0, -EBADF); r = sd_netlink_new(&rtnl); if (r < 0) diff --git a/src/libsystemd/sd-netlink/test-local-addresses.c b/src/libsystemd/sd-netlink/test-local-addresses.c index 38cbcfbccb..9867eec065 100644 --- a/src/libsystemd/sd-netlink/test-local-addresses.c +++ b/src/libsystemd/sd-netlink/test-local-addresses.c @@ -44,9 +44,8 @@ int main(int argc, char *argv[]) { printf("Local Addresses:\n"); print_local_addresses(a, (unsigned) n); - free(a); + a = mfree(a); - a = NULL; n = local_gateways(NULL, 0, AF_UNSPEC, &a); assert_se(n >= 0); diff --git a/src/libsystemd/sd-network/sd-network.c b/src/libsystemd/sd-network/sd-network.c index b63fdf8fcb..87d87359b8 100644 --- a/src/libsystemd/sd-network/sd-network.c +++ b/src/libsystemd/sd-network/sd-network.c @@ -214,6 +214,28 @@ _public_ int sd_network_link_get_lldp(int ifindex, char **lldp) { return 0; } +int sd_network_link_get_timezone(int ifindex, char **ret) { + _cleanup_free_ char *s = NULL, *p = NULL; + int r; + + assert_return(ifindex > 0, -EINVAL); + assert_return(ret, -EINVAL); + + if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0) + return -ENOMEM; + + r = parse_env_file(p, NEWLINE, "TIMEZONE", &s, NULL); + if (r == -ENOENT) + return -ENODATA; + if (r < 0) + return r; + if (isempty(s)) + return -ENODATA; + + *ret = s; + s = NULL; + return 0; +} static int network_get_link_strv(const char *key, int ifindex, char ***ret) { _cleanup_free_ char *p = NULL, *s = NULL; diff --git a/src/libsystemd/sd-resolve/sd-resolve.c b/src/libsystemd/sd-resolve/sd-resolve.c index b0dc822591..888b372c99 100644 --- a/src/libsystemd/sd-resolve/sd-resolve.c +++ b/src/libsystemd/sd-resolve/sd-resolve.c @@ -48,9 +48,6 @@ typedef enum { RESPONSE_ADDRINFO, REQUEST_NAMEINFO, RESPONSE_NAMEINFO, - REQUEST_RES_QUERY, - REQUEST_RES_SEARCH, - RESPONSE_RES, REQUEST_TERMINATE, RESPONSE_DIED } QueryType; @@ -104,12 +101,10 @@ struct sd_resolve_query { int _h_errno; struct addrinfo *addrinfo; char *serv, *host; - unsigned char *answer; union { sd_resolve_getaddrinfo_handler_t getaddrinfo_handler; sd_resolve_getnameinfo_handler_t getnameinfo_handler; - sd_resolve_res_handler_t res_handler; }; void *userdata; @@ -166,33 +161,16 @@ typedef struct NameInfoResponse { int _h_errno; } NameInfoResponse; -typedef struct ResRequest { - struct RHeader header; - int class; - int type; - size_t dname_len; -} ResRequest; - -typedef struct ResResponse { - struct RHeader header; - int ret; - int _errno; - int _h_errno; -} ResResponse; - typedef union Packet { RHeader rheader; AddrInfoRequest addrinfo_request; AddrInfoResponse addrinfo_response; NameInfoRequest nameinfo_request; NameInfoResponse nameinfo_response; - ResRequest res_request; - ResResponse res_response; } Packet; static int getaddrinfo_done(sd_resolve_query* q); static int getnameinfo_done(sd_resolve_query *q); -static int res_query_done(sd_resolve_query* q); static void resolve_query_disconnect(sd_resolve_query *q); @@ -343,38 +321,6 @@ static int send_nameinfo_reply( return 0; } -static int send_res_reply(int out_fd, unsigned id, const unsigned char *answer, int ret, int _errno, int _h_errno) { - - ResResponse resp = { - .header.type = RESPONSE_RES, - .header.id = id, - .ret = ret, - ._errno = _errno, - ._h_errno = _h_errno, - }; - - struct msghdr mh = {}; - struct iovec iov[2]; - size_t l; - - assert(out_fd >= 0); - - l = ret > 0 ? (size_t) ret : 0; - - resp.header.length = sizeof(ResResponse) + l; - - iov[0] = (struct iovec) { .iov_base = &resp, .iov_len = sizeof(ResResponse) }; - iov[1] = (struct iovec) { .iov_base = (void*) answer, .iov_len = l }; - - mh.msg_iov = iov; - mh.msg_iovlen = ELEMENTSOF(iov); - - if (sendmsg(out_fd, &mh, MSG_NOSIGNAL) < 0) - return -errno; - - return 0; -} - static int handle_request(int out_fd, const Packet *packet, size_t length) { const RHeader *req; @@ -437,29 +383,6 @@ static int handle_request(int out_fd, const Packet *packet, size_t length) { errno, h_errno); } - case REQUEST_RES_QUERY: - case REQUEST_RES_SEARCH: { - const ResRequest *res_req = &packet->res_request; - union { - HEADER header; - uint8_t space[BUFSIZE]; - } answer; - const char *dname; - int ret; - - assert(length >= sizeof(ResRequest)); - assert(length == sizeof(ResRequest) + res_req->dname_len); - - dname = (const char *) res_req + sizeof(ResRequest); - - if (req->type == REQUEST_RES_QUERY) - ret = res_query(dname, res_req->class, res_req->type, (unsigned char *) &answer, BUFSIZE); - else - ret = res_search(dname, res_req->class, res_req->type, (unsigned char *) &answer, BUFSIZE); - - return send_res_reply(out_fd, req->id, (unsigned char *) &answer, ret, errno, h_errno); - } - case REQUEST_TERMINATE: /* Quit */ return -ECONNRESET; @@ -752,11 +675,6 @@ static int complete_query(sd_resolve *resolve, sd_resolve_query *q) { r = getnameinfo_done(q); break; - case REQUEST_RES_QUERY: - case REQUEST_RES_SEARCH: - r = res_query_done(q); - break; - default: assert_not_reached("Cannot complete unknown query type"); } @@ -923,28 +841,6 @@ static int handle_response(sd_resolve *resolve, const Packet *packet, size_t len return complete_query(resolve, q); } - case RESPONSE_RES: { - const ResResponse *res_resp = &packet->res_response; - - assert(length >= sizeof(ResResponse)); - assert(q->type == REQUEST_RES_QUERY || q->type == REQUEST_RES_SEARCH); - - q->ret = res_resp->ret; - q->_errno = res_resp->_errno; - q->_h_errno = res_resp->_h_errno; - - if (res_resp->ret >= 0) { - q->answer = memdup((const char *)resp + sizeof(ResResponse), res_resp->ret); - if (!q->answer) { - q->ret = -1; - q->_errno = ENOMEM; - q->_h_errno = 0; - } - } - - return complete_query(resolve, q); - } - default: return 0; } @@ -1181,79 +1077,6 @@ static int getnameinfo_done(sd_resolve_query *q) { return q->getnameinfo_handler(q, q->ret, q->host, q->serv, q->userdata); } -static int resolve_res( - sd_resolve *resolve, - sd_resolve_query **_q, - QueryType qtype, - const char *dname, - int class, int type, - sd_resolve_res_handler_t callback, void *userdata) { - - struct msghdr mh = {}; - struct iovec iov[2]; - ResRequest req = {}; - sd_resolve_query *q; - int r; - - assert_return(resolve, -EINVAL); - assert_return(dname, -EINVAL); - assert_return(callback, -EINVAL); - assert_return(!resolve_pid_changed(resolve), -ECHILD); - - r = alloc_query(resolve, !_q, &q); - if (r < 0) - return r; - - q->type = qtype; - q->res_handler = callback; - q->userdata = userdata; - - req.dname_len = strlen(dname) + 1; - req.class = class; - req.type = type; - - req.header.id = q->id; - req.header.type = qtype; - req.header.length = sizeof(ResRequest) + req.dname_len; - - iov[0] = (struct iovec) { .iov_base = &req, .iov_len = sizeof(ResRequest) }; - iov[1] = (struct iovec) { .iov_base = (void*) dname, .iov_len = req.dname_len }; - - mh.msg_iov = iov; - mh.msg_iovlen = 2; - - if (sendmsg(resolve->fds[REQUEST_SEND_FD], &mh, MSG_NOSIGNAL) < 0) { - sd_resolve_query_unref(q); - return -errno; - } - - resolve->n_outstanding++; - - if (_q) - *_q = q; - - return 0; -} - -_public_ int sd_resolve_res_query(sd_resolve *resolve, sd_resolve_query** q, const char *dname, int class, int type, sd_resolve_res_handler_t callback, void *userdata) { - return resolve_res(resolve, q, REQUEST_RES_QUERY, dname, class, type, callback, userdata); -} - -_public_ int sd_resolve_res_search(sd_resolve *resolve, sd_resolve_query** q, const char *dname, int class, int type, sd_resolve_res_handler_t callback, void *userdata) { - return resolve_res(resolve, q, REQUEST_RES_SEARCH, dname, class, type, callback, userdata); -} - -static int res_query_done(sd_resolve_query* q) { - assert(q); - assert(q->done); - assert(q->res_handler); - - errno = q->_errno; - h_errno = q->_h_errno; - - return q->res_handler(q, q->ret, q->answer, q->userdata); -} - _public_ sd_resolve_query* sd_resolve_query_ref(sd_resolve_query *q) { assert_return(q, NULL); @@ -1310,7 +1133,6 @@ static void resolve_query_free(sd_resolve_query *q) { resolve_freeaddrinfo(q->addrinfo); free(q->host); free(q->serv); - free(q->answer); free(q); } diff --git a/src/libsystemd/sd-resolve/test-resolve.c b/src/libsystemd/sd-resolve/test-resolve.c index 354a4071b7..e8056529f5 100644 --- a/src/libsystemd/sd-resolve/test-resolve.c +++ b/src/libsystemd/sd-resolve/test-resolve.c @@ -67,59 +67,8 @@ static int getnameinfo_handler(sd_resolve_query *q, int ret, const char *host, c return 0; } -static int res_handler(sd_resolve_query *q, int ret, unsigned char *answer, void *userdata) { - int qdcount, ancount, len; - const unsigned char *pos = answer + sizeof(HEADER); - unsigned char *end = answer + ret; - HEADER *head = (HEADER *) answer; - char name[256]; - assert_se(q); - - if (ret < 0) { - log_error("res_query() error: %s %i", strerror(errno), errno); - return 0; - } - - if (ret == 0) { - log_error("No reply for SRV lookup"); - return 0; - } - - qdcount = ntohs(head->qdcount); - ancount = ntohs(head->ancount); - - printf("%d answers for srv lookup:\n", ancount); - - /* Ignore the questions */ - while (qdcount-- > 0 && (len = dn_expand(answer, end, pos, name, 255)) >= 0) { - assert_se(len >= 0); - pos += len + QFIXEDSZ; - } - - /* Parse the answers */ - while (ancount-- > 0 && (len = dn_expand(answer, end, pos, name, 255)) >= 0) { - /* Ignore the initial string */ - uint16_t pref, weight, port; - assert_se(len >= 0); - pos += len; - /* Ignore type, ttl, class and dlen */ - pos += 10; - - GETSHORT(pref, pos); - GETSHORT(weight, pos); - GETSHORT(port, pos); - len = dn_expand(answer, end, pos, name, 255); - printf("\tpreference: %2d weight: %2d port: %d host: %s\n", - pref, weight, port, name); - - pos += len; - } - - return 0; -} - int main(int argc, char *argv[]) { - _cleanup_resolve_query_unref_ sd_resolve_query *q1 = NULL, *q2 = NULL, *q3 = NULL; + _cleanup_resolve_query_unref_ sd_resolve_query *q1 = NULL, *q2 = NULL; _cleanup_resolve_unref_ sd_resolve *resolve = NULL; int r = 0; @@ -150,15 +99,9 @@ int main(int argc, char *argv[]) { if (r < 0) log_error_errno(r, "sd_resolve_getnameinfo(): %m"); - /* Make a res_query() call */ - r = sd_resolve_res_query(resolve, &q3, "_xmpp-client._tcp.gmail.com", C_IN, T_SRV, res_handler, NULL); - if (r < 0) - log_error_errno(r, "sd_resolve_res_query(): %m"); - - /* Wait until the three queries are completed */ + /* Wait until the two queries are completed */ while (sd_resolve_query_is_done(q1) == 0 || - sd_resolve_query_is_done(q2) == 0 || - sd_resolve_query_is_done(q3) == 0) { + sd_resolve_query_is_done(q2) == 0) { r = sd_resolve_wait(resolve, (uint64_t) -1); if (r < 0) { |