X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Flibsystemd-bus%2Fbus-message.c;h=f698b2ee9989b537b11bd34d4eac116253917b20;hp=511bdf503e78852430eccba3c49e8a0b8eebbfc2;hb=51b4ea6f485a852671a2a95122121ecb494de331;hpb=1daf8121524246932b18be8dd7d63e792dee5de2 diff --git a/src/libsystemd-bus/bus-message.c b/src/libsystemd-bus/bus-message.c index 511bdf503..f698b2ee9 100644 --- a/src/libsystemd-bus/bus-message.c +++ b/src/libsystemd-bus/bus-message.c @@ -305,6 +305,7 @@ static int message_append_field_uint32(sd_bus_message *m, uint8_t h, uint32_t x) } int bus_message_from_header( + sd_bus *bus, void *buffer, size_t length, int *fds, @@ -368,11 +369,15 @@ int bus_message_from_header( memcpy(m->label, label, label_sz + 1); } + if (bus) + m->bus = sd_bus_ref(bus); + *ret = m; return 0; } int bus_message_from_malloc( + sd_bus *bus, void *buffer, size_t length, int *fds, @@ -384,7 +389,7 @@ int bus_message_from_malloc( sd_bus_message *m; int r; - r = bus_message_from_header(buffer, length, fds, n_fds, ucred, label, 0, &m); + r = bus_message_from_header(bus, buffer, length, fds, n_fds, ucred, label, 0, &m); if (r < 0) return r; @@ -440,7 +445,7 @@ static sd_bus_message *message_new(sd_bus *bus, uint8_t type) { return m; } -int sd_bus_message_new_signal( +_public_ int sd_bus_message_new_signal( sd_bus *bus, const char *path, const char *interface, @@ -450,16 +455,11 @@ int sd_bus_message_new_signal( sd_bus_message *t; int r; - if (!path) - return -EINVAL; - if (!interface) - return -EINVAL; - if (!member) - return -EINVAL; - if (!m) - return -EINVAL; - if (bus && bus->state == BUS_UNSET) - return -ENOTCONN; + assert_return(!bus || bus->state != BUS_UNSET, -ENOTCONN); + assert_return(object_path_is_valid(path), -EINVAL); + assert_return(interface_name_is_valid(interface), -EINVAL); + assert_return(member_name_is_valid(member), -EINVAL); + assert_return(m, -EINVAL); t = message_new(bus, SD_BUS_MESSAGE_SIGNAL); if (!t) @@ -485,7 +485,7 @@ fail: return r; } -int sd_bus_message_new_method_call( +_public_ int sd_bus_message_new_method_call( sd_bus *bus, const char *destination, const char *path, @@ -496,18 +496,12 @@ int sd_bus_message_new_method_call( sd_bus_message *t; int r; - if (destination && !service_name_is_valid(destination)) - return -EINVAL; - if (!object_path_is_valid(path)) - return -EINVAL; - if (interface && !interface_name_is_valid(interface)) - return -EINVAL; - if (!member_name_is_valid(member)) - return -EINVAL; - if (!m) - return -EINVAL; - if (bus && bus->state == BUS_UNSET) - return -ENOTCONN; + assert_return(!bus || bus->state != BUS_UNSET, -ENOTCONN); + assert_return(!destination || service_name_is_valid(destination), -EINVAL); + assert_return(object_path_is_valid(path), -EINVAL); + assert_return(!interface || interface_name_is_valid(interface), -EINVAL); + assert_return(member_name_is_valid(member), -EINVAL); + assert_return(m, -EINVAL); t = message_new(bus, SD_BUS_MESSAGE_METHOD_CALL); if (!t) @@ -541,7 +535,6 @@ fail: } static int message_new_reply( - sd_bus *bus, sd_bus_message *call, uint8_t type, sd_bus_message **m) { @@ -549,18 +542,13 @@ static int message_new_reply( sd_bus_message *t; int r; - if (!call) - return -EINVAL; - if (!call->sealed) - return -EPERM; - if (call->header->type != SD_BUS_MESSAGE_METHOD_CALL) - return -EINVAL; - if (!m) - return -EINVAL; - if (bus && bus->state == BUS_UNSET) - return -ENOTCONN; + assert_return(call, -EINVAL); + assert_return(call->sealed, -EPERM); + assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL); + assert_return(!call->bus || call->bus->state != BUS_UNSET, -ENOTCONN); + assert_return(m, -EINVAL); - t = message_new(bus, type); + t = message_new(call->bus, type); if (!t) return -ENOMEM; @@ -587,16 +575,14 @@ fail: return r; } -int sd_bus_message_new_method_return( - sd_bus *bus, +_public_ int sd_bus_message_new_method_return( sd_bus_message *call, sd_bus_message **m) { - return message_new_reply(bus, call, SD_BUS_MESSAGE_METHOD_RETURN, m); + return message_new_reply(call, SD_BUS_MESSAGE_METHOD_RETURN, m); } -int sd_bus_message_new_method_error( - sd_bus *bus, +_public_ int sd_bus_message_new_method_error( sd_bus_message *call, const sd_bus_error *e, sd_bus_message **m) { @@ -604,12 +590,10 @@ int sd_bus_message_new_method_error( sd_bus_message *t; int r; - if (!sd_bus_error_is_set(e)) - return -EINVAL; - if (!m) - return -EINVAL; + assert_return(sd_bus_error_is_set(e), -EINVAL); + assert_return(m, -EINVAL); - r = message_new_reply(bus, call, SD_BUS_MESSAGE_METHOD_ERROR, &t); + r = message_new_reply(call, SD_BUS_MESSAGE_METHOD_ERROR, &t); if (r < 0) return r; @@ -631,8 +615,7 @@ fail: return r; } -int sd_bus_message_new_method_errorf( - sd_bus *bus, +_public_ int sd_bus_message_new_method_errorf( sd_bus_message *call, sd_bus_message **m, const char *name, @@ -653,11 +636,10 @@ int sd_bus_message_new_method_errorf( if (r < 0) return r; - return sd_bus_message_new_method_error(bus, call, &error, m); + return sd_bus_message_new_method_error(call, &error, m); } -int sd_bus_message_new_method_errno( - sd_bus *bus, +_public_ int sd_bus_message_new_method_errno( sd_bus_message *call, int error, const sd_bus_error *p, @@ -666,15 +648,14 @@ int sd_bus_message_new_method_errno( _cleanup_free_ sd_bus_error berror = SD_BUS_ERROR_NULL; if (sd_bus_error_is_set(p)) - return sd_bus_message_new_method_error(bus, call, p, m); + return sd_bus_message_new_method_error(call, p, m); sd_bus_error_set_errno(&berror, error); - return sd_bus_message_new_method_error(bus, call, &berror, m); + return sd_bus_message_new_method_error(call, &berror, m); } -int sd_bus_message_new_method_errnof( - sd_bus *bus, +_public_ int sd_bus_message_new_method_errnof( sd_bus_message *call, sd_bus_message **m, int error, @@ -692,7 +673,7 @@ int sd_bus_message_new_method_errnof( if (r < 0) return r; - return sd_bus_message_new_method_error(bus, call, &berror, m); + return sd_bus_message_new_method_error(call, &berror, m); } int bus_message_new_synthetic_error( @@ -742,9 +723,8 @@ fail: return r; } -sd_bus_message* sd_bus_message_ref(sd_bus_message *m) { - if (!m) - return NULL; +_public_ sd_bus_message* sd_bus_message_ref(sd_bus_message *m) { + assert_return(m, NULL); assert(m->n_ref > 0); m->n_ref++; @@ -752,9 +732,8 @@ sd_bus_message* sd_bus_message_ref(sd_bus_message *m) { return m; } -sd_bus_message* sd_bus_message_unref(sd_bus_message *m) { - if (!m) - return NULL; +_public_ sd_bus_message* sd_bus_message_unref(sd_bus_message *m) { + assert_return(m, NULL); assert(m->n_ref > 0); m->n_ref--; @@ -765,242 +744,194 @@ sd_bus_message* sd_bus_message_unref(sd_bus_message *m) { return NULL; } -int sd_bus_message_get_type(sd_bus_message *m, uint8_t *type) { - if (!m) - return -EINVAL; - if (!type) - return -EINVAL; +_public_ int sd_bus_message_get_type(sd_bus_message *m, uint8_t *type) { + assert_return(m, -EINVAL); + assert_return(type, -EINVAL); *type = m->header->type; return 0; } -int sd_bus_message_get_serial(sd_bus_message *m, uint64_t *serial) { - if (!m) - return -EINVAL; - if (!serial) - return -EINVAL; - if (m->header->serial == 0) - return -ENOENT; +_public_ int sd_bus_message_get_serial(sd_bus_message *m, uint64_t *serial) { + assert_return(m, -EINVAL); + assert_return(serial, -EINVAL); + assert_return(m->header->serial != 0, -ENOENT); *serial = BUS_MESSAGE_SERIAL(m); return 0; } -int sd_bus_message_get_reply_serial(sd_bus_message *m, uint64_t *serial) { - if (!m) - return -EINVAL; - if (!serial) - return -EINVAL; - if (m->reply_serial == 0) - return -ENOENT; +_public_ int sd_bus_message_get_reply_serial(sd_bus_message *m, uint64_t *serial) { + assert_return(m, -EINVAL); + assert_return(serial, -EINVAL); + assert_return(m->reply_serial != 0, -ENOENT); *serial = m->reply_serial; return 0; } -int sd_bus_message_get_no_reply(sd_bus_message *m) { - if (!m) - return -EINVAL; +_public_ int sd_bus_message_get_no_reply(sd_bus_message *m) { + assert_return(m, -EINVAL); return m->header->type == SD_BUS_MESSAGE_METHOD_CALL ? !!(m->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED) : 0; } -const char *sd_bus_message_get_path(sd_bus_message *m) { - if (!m) - return NULL; +_public_ int sd_bus_message_get_no_auto_start(sd_bus_message *m) { + assert_return(m, -EINVAL); + + return !!(m->header->flags & SD_BUS_MESSAGE_NO_AUTO_START); +} + +_public_ const char *sd_bus_message_get_path(sd_bus_message *m) { + assert_return(m, NULL); return m->path; } -const char *sd_bus_message_get_interface(sd_bus_message *m) { - if (!m) - return NULL; +_public_ const char *sd_bus_message_get_interface(sd_bus_message *m) { + assert_return(m, NULL); return m->interface; } -const char *sd_bus_message_get_member(sd_bus_message *m) { - if (!m) - return NULL; +_public_ const char *sd_bus_message_get_member(sd_bus_message *m) { + assert_return(m, NULL); return m->member; } -const char *sd_bus_message_get_destination(sd_bus_message *m) { - if (!m) - return NULL; + +_public_ const char *sd_bus_message_get_destination(sd_bus_message *m) { + assert_return(m, NULL); return m->destination; } -const char *sd_bus_message_get_sender(sd_bus_message *m) { - if (!m) - return NULL; +_public_ const char *sd_bus_message_get_sender(sd_bus_message *m) { + assert_return(m, NULL); return m->sender; } -const sd_bus_error *sd_bus_message_get_error(sd_bus_message *m) { - if (!m) - return NULL; - - if (!sd_bus_error_is_set(&m->error)) - return NULL; +_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); return &m->error; } -int sd_bus_message_get_uid(sd_bus_message *m, uid_t *uid) { - if (!m) - return -EINVAL; - if (!uid) - return -EINVAL; - if (!m->uid_valid) - return -ESRCH; +_public_ int sd_bus_message_get_uid(sd_bus_message *m, uid_t *uid) { + assert_return(m, -EINVAL); + assert_return(uid, -EINVAL); + assert_return(m->uid_valid, -ESRCH); *uid = m->uid; return 0; } -int sd_bus_message_get_gid(sd_bus_message *m, gid_t *gid) { - if (!m) - return -EINVAL; - if (!gid) - return -EINVAL; - if (!m->gid_valid) - return -ESRCH; +_public_ int sd_bus_message_get_gid(sd_bus_message *m, gid_t *gid) { + assert_return(m, -EINVAL); + assert_return(gid, -EINVAL); + assert_return(m->gid_valid, -ESRCH); *gid = m->gid; return 0; } -int sd_bus_message_get_pid(sd_bus_message *m, pid_t *pid) { - if (!m) - return -EINVAL; - if (!pid) - return -EINVAL; - if (m->pid <= 0) - return -ESRCH; +_public_ int sd_bus_message_get_pid(sd_bus_message *m, pid_t *pid) { + assert_return(m, -EINVAL); + assert_return(pid, -EINVAL); + assert_return(m->pid > 0, -ESRCH); *pid = m->pid; return 0; } -int sd_bus_message_get_tid(sd_bus_message *m, pid_t *tid) { - if (!m) - return -EINVAL; - if (!tid) - return -EINVAL; - if (m->tid <= 0) - return -ESRCH; +_public_ int sd_bus_message_get_tid(sd_bus_message *m, pid_t *tid) { + assert_return(m, -EINVAL); + assert_return(tid, -EINVAL); + assert_return(m->tid > 0, -ESRCH); *tid = m->tid; return 0; } -int sd_bus_message_get_pid_starttime(sd_bus_message *m, uint64_t *usec) { - if (!m) - return -EINVAL; - if (!usec) - return -EINVAL; - if (m->pid_starttime <= 0) - return -ESRCH; +_public_ int sd_bus_message_get_pid_starttime(sd_bus_message *m, uint64_t *usec) { + assert_return(m, -EINVAL); + assert_return(usec, -EINVAL); + assert_return(m->pid_starttime > 0, -ESRCH); *usec = m->pid_starttime; return 0; } -int sd_bus_message_get_selinux_context(sd_bus_message *m, const char **ret) { - if (!m) - return -EINVAL; - if (!m->label) - return -ESRCH; +_public_ int sd_bus_message_get_selinux_context(sd_bus_message *m, const char **ret) { + assert_return(m, -EINVAL); + assert_return(m->label, -ESRCH); *ret = m->label; return 0; } -int sd_bus_message_get_monotonic_timestamp(sd_bus_message *m, uint64_t *usec) { - if (!m) - return -EINVAL; - if (!usec) - return -EINVAL; - if (m->monotonic <= 0) - return -ESRCH; +_public_ int sd_bus_message_get_monotonic_timestamp(sd_bus_message *m, uint64_t *usec) { + assert_return(m, -EINVAL); + assert_return(usec, -EINVAL); + assert_return(m->monotonic > 0, -ESRCH); *usec = m->monotonic; return 0; } -int sd_bus_message_get_realtime_timestamp(sd_bus_message *m, uint64_t *usec) { - if (!m) - return -EINVAL; - if (!usec) - return -EINVAL; - if (m->realtime <= 0) - return -ESRCH; +_public_ int sd_bus_message_get_realtime_timestamp(sd_bus_message *m, uint64_t *usec) { + assert_return(m, -EINVAL); + assert_return(usec, -EINVAL); + assert_return(m->realtime > 0, -ESRCH); *usec = m->realtime; return 0; } -int sd_bus_message_get_comm(sd_bus_message *m, const char **ret) { - if (!m) - return -EINVAL; - if (!ret) - return -EINVAL; - if (!m->comm) - return -ESRCH; +_public_ int sd_bus_message_get_comm(sd_bus_message *m, const char **ret) { + assert_return(m, -EINVAL); + assert_return(ret, -EINVAL); + assert_return(m->comm, -ESRCH); *ret = m->comm; return 0; } -int sd_bus_message_get_tid_comm(sd_bus_message *m, const char **ret) { - if (!m) - return -EINVAL; - if (!ret) - return -EINVAL; - if (!m->tid_comm) - return -ESRCH; +_public_ int sd_bus_message_get_tid_comm(sd_bus_message *m, const char **ret) { + assert_return(m, -EINVAL); + assert_return(ret, -EINVAL); + assert_return(m->tid_comm, -ESRCH); *ret = m->tid_comm; return 0; } -int sd_bus_message_get_exe(sd_bus_message *m, const char **ret) { - if (!m) - return -EINVAL; - if (!ret) - return -EINVAL; - if (!m->exe) - return -ESRCH; +_public_ int sd_bus_message_get_exe(sd_bus_message *m, const char **ret) { + assert_return(m, -EINVAL); + assert_return(ret, -EINVAL); + assert_return(m->exe, -ESRCH); *ret = m->exe; return 0; } -int sd_bus_message_get_cgroup(sd_bus_message *m, const char **ret) { - if (!m) - return -EINVAL; - if (!ret) - return -EINVAL; - if (!m->cgroup) - return -ESRCH; +_public_ int sd_bus_message_get_cgroup(sd_bus_message *m, const char **ret) { + assert_return(m, -EINVAL); + assert_return(ret, -EINVAL); + assert_return(m->cgroup, -ESRCH); *ret = m->cgroup; return 0; } -int sd_bus_message_get_unit(sd_bus_message *m, const char **ret) { +_public_ int sd_bus_message_get_unit(sd_bus_message *m, const char **ret) { int r; - if (!m) - return -EINVAL; - if (!ret) - return -EINVAL; - if (!m->cgroup) - return -ESRCH; + assert_return(m, -EINVAL); + assert_return(ret, -EINVAL); + assert_return(m->cgroup, -ESRCH); if (!m->unit) { r = cg_path_get_unit(m->cgroup, &m->unit); @@ -1012,15 +943,12 @@ int sd_bus_message_get_unit(sd_bus_message *m, const char **ret) { return 0; } -int sd_bus_message_get_user_unit(sd_bus_message *m, const char **ret) { +_public_ int sd_bus_message_get_user_unit(sd_bus_message *m, const char **ret) { int r; - if (!m) - return -EINVAL; - if (!ret) - return -EINVAL; - if (!m->cgroup) - return -ESRCH; + assert_return(m, -EINVAL); + assert_return(ret, -EINVAL); + assert_return(m->cgroup, -ESRCH); if (!m->user_unit) { r = cg_path_get_user_unit(m->cgroup, &m->user_unit); @@ -1032,15 +960,12 @@ int sd_bus_message_get_user_unit(sd_bus_message *m, const char **ret) { return 0; } -int sd_bus_message_get_session(sd_bus_message *m, const char **ret) { +_public_ int sd_bus_message_get_session(sd_bus_message *m, const char **ret) { int r; - if (!m) - return -EINVAL; - if (!ret) - return -EINVAL; - if (!m->cgroup) - return -ESRCH; + assert_return(m, -EINVAL); + assert_return(ret, -EINVAL); + assert_return(m->cgroup, -ESRCH); if (!m->session) { r = cg_path_get_session(m->cgroup, &m->session); @@ -1052,27 +977,21 @@ int sd_bus_message_get_session(sd_bus_message *m, const char **ret) { return 0; } -int sd_bus_message_get_owner_uid(sd_bus_message *m, uid_t *uid) { - if (!m) - return -EINVAL; - if (!uid) - return -EINVAL; - if (!m->cgroup) - return -ESRCH; +_public_ int sd_bus_message_get_owner_uid(sd_bus_message *m, uid_t *uid) { + assert_return(m, -EINVAL); + assert_return(uid, -EINVAL); + assert_return(m->cgroup, -ESRCH); return cg_path_get_owner_uid(m->cgroup, uid); } -int sd_bus_message_get_cmdline(sd_bus_message *m, char ***cmdline) { +_public_ int sd_bus_message_get_cmdline(sd_bus_message *m, char ***cmdline) { size_t n, i; const char *p; bool first; - if (!m) - return -EINVAL; - - if (!m->cmdline) - return -ENOENT; + assert_return(m, -EINVAL); + assert_return(m->cmdline, -ESRCH); for (p = m->cmdline, n = 0; p < m->cmdline + m->cmdline_length; p++) if (*p == 0) @@ -1095,39 +1014,30 @@ int sd_bus_message_get_cmdline(sd_bus_message *m, char ***cmdline) { return 0; } -int sd_bus_message_get_audit_sessionid(sd_bus_message *m, uint32_t *sessionid) { - if (!m) - return -EINVAL; - if (!sessionid) - return -EINVAL; - if (!m->audit) - return -ESRCH; +_public_ int sd_bus_message_get_audit_sessionid(sd_bus_message *m, uint32_t *sessionid) { + assert_return(m, -EINVAL); + assert_return(sessionid, -EINVAL); + assert_return(m->audit, -ESRCH); *sessionid = m->audit->sessionid; return 0; } -int sd_bus_message_get_audit_loginuid(sd_bus_message *m, uid_t *uid) { - if (!m) - return -EINVAL; - if (!uid) - return -EINVAL; - if (!m->audit) - return -ESRCH; +_public_ int sd_bus_message_get_audit_loginuid(sd_bus_message *m, uid_t *uid) { + assert_return(m, -EINVAL); + assert_return(uid, -EINVAL); + assert_return(m->audit, -ESRCH); *uid = m->audit->loginuid; return 0; } -int sd_bus_message_has_effective_cap(sd_bus_message *m, int capability) { +_public_ int sd_bus_message_has_effective_cap(sd_bus_message *m, int capability) { unsigned sz; - if (!m) - return -EINVAL; - if (capability < 0) - return -EINVAL; - if (!m->capability) - return -ESRCH; + assert_return(m, -EINVAL); + assert_return(capability < 0, -EINVAL); + assert_return(!m->capability, -ESRCH); sz = m->capability_size / 4; if ((unsigned) capability >= sz*8) @@ -1136,9 +1046,10 @@ int sd_bus_message_has_effective_cap(sd_bus_message *m, int capability) { return !!(m->capability[2 * sz + (capability / 8)] & (1 << (capability % 8))); } -int sd_bus_message_is_signal(sd_bus_message *m, const char *interface, const char *member) { - if (!m) - return -EINVAL; +_public_ int sd_bus_message_is_signal(sd_bus_message *m, + const char *interface, + const char *member) { + assert_return(m, -EINVAL); if (m->header->type != SD_BUS_MESSAGE_SIGNAL) return 0; @@ -1152,9 +1063,10 @@ int sd_bus_message_is_signal(sd_bus_message *m, const char *interface, const cha return 1; } -int sd_bus_message_is_method_call(sd_bus_message *m, const char *interface, const char *member) { - if (!m) - return -EINVAL; +_public_ int sd_bus_message_is_method_call(sd_bus_message *m, + const char *interface, + const char *member) { + assert_return(m, -EINVAL); if (m->header->type != SD_BUS_MESSAGE_METHOD_CALL) return 0; @@ -1168,9 +1080,8 @@ int sd_bus_message_is_method_call(sd_bus_message *m, const char *interface, cons return 1; } -int sd_bus_message_is_method_error(sd_bus_message *m, const char *name) { - if (!m) - return -EINVAL; +_public_ int sd_bus_message_is_method_error(sd_bus_message *m, const char *name) { + assert_return(m, -EINVAL); if (m->header->type != SD_BUS_MESSAGE_METHOD_ERROR) return 0; @@ -1181,13 +1092,10 @@ int sd_bus_message_is_method_error(sd_bus_message *m, const char *name) { return 1; } -int sd_bus_message_set_no_reply(sd_bus_message *m, int b) { - if (!m) - return -EINVAL; - if (m->sealed) - return -EPERM; - if (m->header->type != SD_BUS_MESSAGE_METHOD_CALL) - return -EPERM; +_public_ int sd_bus_message_set_no_reply(sd_bus_message *m, int b) { + assert_return(m, -EINVAL); + assert_return(!m->sealed, -EPERM); + assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EPERM); if (b) m->header->flags |= SD_BUS_MESSAGE_NO_REPLY_EXPECTED; @@ -1197,6 +1105,18 @@ int sd_bus_message_set_no_reply(sd_bus_message *m, int b) { return 0; } +_public_ int sd_bus_message_set_no_auto_start(sd_bus_message *m, int b) { + assert_return(m, -EINVAL); + assert_return(!m->sealed, -EPERM); + + if (b) + m->header->flags |= SD_BUS_MESSAGE_NO_AUTO_START; + else + m->header->flags &= ~SD_BUS_MESSAGE_NO_AUTO_START; + + return 0; +} + static struct bus_container *message_get_container(sd_bus_message *m) { assert(m); @@ -1419,16 +1339,10 @@ int message_append_basic(sd_bus_message *m, char type, const void *p, const void uint32_t fdi = 0; int r; - if (!m) - return -EINVAL; - if (!p) - return -EINVAL; - if (m->sealed) - return -EPERM; - if (!bus_type_is_basic(type)) - return -EINVAL; - if (m->poisoned) - return -ESTALE; + assert_return(m, -EINVAL); + assert_return(!m->sealed, -EPERM); + assert_return(bus_type_is_basic(type), -EINVAL); + assert_return(!m->poisoned, -ESTALE); c = message_get_container(m); @@ -1454,19 +1368,40 @@ int message_append_basic(sd_bus_message *m, char type, const void *p, const void switch (type) { case SD_BUS_TYPE_STRING: + /* To make things easy we'll serialize a NULL string + * into the empty string */ + p = strempty(p); + + /* Fall through... */ case SD_BUS_TYPE_OBJECT_PATH: + if (!p) { + r = -EINVAL; + goto fail; + } + align = 4; sz = 4 + strlen(p) + 1; break; case SD_BUS_TYPE_SIGNATURE: + if (!p) { + r = -EINVAL; + goto fail; + } + align = 1; sz = 1 + strlen(p) + 1; break; case SD_BUS_TYPE_BOOLEAN: + + if (!p) { + r = -EINVAL; + goto fail; + } + align = sz = 4; assert_cc(sizeof(int) == sizeof(uint32_t)); @@ -1478,6 +1413,11 @@ int message_append_basic(sd_bus_message *m, char type, const void *p, const void case SD_BUS_TYPE_UNIX_FD: { int z, *f; + if (!p) { + r = -EINVAL; + goto fail; + } + if (!m->allow_fds) { r = -ENOTSUP; goto fail; @@ -1512,6 +1452,11 @@ int message_append_basic(sd_bus_message *m, char type, const void *p, const void } default: + if (!p) { + r = -EINVAL; + goto fail; + } + align = bus_type_get_alignment(type); sz = bus_type_get_size(type); break; @@ -1566,22 +1511,22 @@ fail: return r; } -int sd_bus_message_append_basic(sd_bus_message *m, char type, const void *p) { +_public_ int sd_bus_message_append_basic(sd_bus_message *m, char type, const void *p) { return message_append_basic(m, type, p, NULL); } -int sd_bus_message_append_string_space(sd_bus_message *m, size_t size, char **s) { +_public_ int sd_bus_message_append_string_space( + sd_bus_message *m, + size_t size, + char **s) { + struct bus_container *c; void *a; - if (!m) - return -EINVAL; - if (!s) - return -EINVAL; - if (m->sealed) - return -EPERM; - if (m->poisoned) - return -ESTALE; + assert_return(m, -EINVAL); + assert_return(s, -EINVAL); + assert_return(!m->sealed, -EPERM); + assert_return(!m->poisoned, -ESTALE); c = message_get_container(m); @@ -1619,6 +1564,40 @@ int sd_bus_message_append_string_space(sd_bus_message *m, size_t size, char **s) return 0; } +_public_ int sd_bus_message_append_string_iovec( + sd_bus_message *m, + const struct iovec *iov, + unsigned n) { + + size_t size; + unsigned i; + char *p; + int r; + + assert_return(m, -EINVAL); + assert_return(!m->sealed, -EPERM); + assert_return(iov || n == 0, -EINVAL); + assert_return(!m->poisoned, -ESTALE); + + size = IOVEC_TOTAL_SIZE(iov, n); + + r = sd_bus_message_append_string_space(m, size, &p); + if (r < 0) + return r; + + for (i = 0; i < n; i++) { + + if (iov[i].iov_base) + memcpy(p, iov[i].iov_base, iov[i].iov_len); + else + memset(p, ' ', iov[i].iov_len); + + p += iov[i].iov_len; + } + + return 0; +} + static int bus_message_open_array( sd_bus_message *m, struct bus_container *c, @@ -1836,7 +1815,7 @@ static int bus_message_open_dict_entry( return 0; } -int sd_bus_message_open_container( +_public_ int sd_bus_message_open_container( sd_bus_message *m, char type, const char *contents) { @@ -1847,14 +1826,10 @@ int sd_bus_message_open_container( size_t before; int r; - if (!m) - return -EINVAL; - if (m->sealed) - return -EPERM; - if (!contents) - return -EINVAL; - if (m->poisoned) - return -ESTALE; + assert_return(m, -EINVAL); + assert_return(!m->sealed, -EPERM); + assert_return(contents, -EINVAL); + assert_return(!m->poisoned, -ESTALE); /* Make sure we have space for one more container */ w = realloc(m->containers, sizeof(struct bus_container) * (m->n_containers + 1)); @@ -1906,17 +1881,13 @@ int sd_bus_message_open_container( return 0; } -int sd_bus_message_close_container(sd_bus_message *m) { +_public_ int sd_bus_message_close_container(sd_bus_message *m) { struct bus_container *c; - if (!m) - return -EINVAL; - if (m->sealed) - return -EPERM; - if (m->n_containers <= 0) - return -EINVAL; - if (m->poisoned) - return -ESTALE; + assert_return(m, -EINVAL); + assert_return(!m->sealed, -EPERM); + assert_return(m->n_containers > 0, -EINVAL); + assert_return(!m->poisoned, -ESTALE); c = message_get_container(m); if (c->enclosing != SD_BUS_TYPE_ARRAY) @@ -2165,18 +2136,14 @@ int bus_message_append_ap( return 0; } -int sd_bus_message_append(sd_bus_message *m, const char *types, ...) { +_public_ int sd_bus_message_append(sd_bus_message *m, const char *types, ...) { va_list ap; int r; - if (!m) - return -EINVAL; - if (m->sealed) - return -EPERM; - if (m->poisoned) - return -ESTALE; - if (!types) - return 0; + assert_return(m, -EINVAL); + assert_return(types, -EINVAL); + assert_return(!m->sealed, -EPERM); + assert_return(!m->poisoned, -ESTALE); va_start(ap, types); r = bus_message_append_ap(m, types, ap); @@ -2185,21 +2152,19 @@ int sd_bus_message_append(sd_bus_message *m, const char *types, ...) { return r; } -int sd_bus_message_append_array_space(sd_bus_message *m, char type, size_t size, void **ptr) { +_public_ int sd_bus_message_append_array_space(sd_bus_message *m, + char type, + size_t size, + void **ptr) { ssize_t align, sz; void *a; int r; - if (!m) - return -EINVAL; - if (m->sealed) - return -EPERM; - if (!bus_type_is_trivial(type)) - return -EINVAL; - if (!ptr && size > 0) - return -EINVAL; - if (m->poisoned) - return -ESTALE; + assert_return(m, -EINVAL); + assert_return(!m->sealed, -EPERM); + assert_return(bus_type_is_trivial(type), -EINVAL); + assert_return(ptr || size == 0, -EINVAL); + assert_return(!m->poisoned, -ESTALE); align = bus_type_get_alignment(type); sz = bus_type_get_size(type); @@ -2226,12 +2191,18 @@ int sd_bus_message_append_array_space(sd_bus_message *m, char type, size_t size, return 0; } -int sd_bus_message_append_array(sd_bus_message *m, char type, const void *ptr, size_t size) { +_public_ int sd_bus_message_append_array(sd_bus_message *m, + char type, + const void *ptr, + size_t size) { int r; void *p; - if (!ptr && size > 0) - return -EINVAL; + assert_return(m, -EINVAL); + assert_return(!m->sealed, -EPERM); + assert_return(bus_type_is_trivial(type), -EINVAL); + assert_return(ptr || size == 0, -EINVAL); + assert_return(!m->poisoned, -ESTALE); r = sd_bus_message_append_array_space(m, type, size, &p); if (r < 0) @@ -2243,7 +2214,45 @@ int sd_bus_message_append_array(sd_bus_message *m, char type, const void *ptr, s return 0; } -int sd_bus_message_append_array_memfd(sd_bus_message *m, char type, sd_memfd *memfd) { +_public_ int sd_bus_message_append_array_iovec( + sd_bus_message *m, + char type, + const struct iovec *iov, + unsigned n) { + + size_t size; + unsigned i; + void *p; + int r; + + assert_return(m, -EINVAL); + assert_return(!m->sealed, -EPERM); + assert_return(bus_type_is_trivial(type), -EINVAL); + assert_return(iov || n == 0, -EINVAL); + assert_return(!m->poisoned, -ESTALE); + + size = IOVEC_TOTAL_SIZE(iov, n); + + r = sd_bus_message_append_array_space(m, type, size, &p); + if (r < 0) + return r; + + for (i = 0; i < n; i++) { + + if (iov[i].iov_base) + memcpy(p, iov[i].iov_base, iov[i].iov_len); + else + memset(p, 0, iov[i].iov_len); + + p = (uint8_t*) p + iov[i].iov_len; + } + + return 0; +} + +_public_ int sd_bus_message_append_array_memfd(sd_bus_message *m, + char type, + sd_memfd *memfd) { _cleanup_close_ int copy_fd = -1; struct bus_body_part *part; ssize_t align, sz; @@ -2309,7 +2318,7 @@ int sd_bus_message_append_array_memfd(sd_bus_message *m, char type, sd_memfd *me return sd_bus_message_close_container(m); } -int sd_bus_message_append_string_memfd(sd_bus_message *m, sd_memfd *memfd) { +_public_ int sd_bus_message_append_string_memfd(sd_bus_message *m, sd_memfd *memfd) { _cleanup_close_ int copy_fd = -1; struct bus_body_part *part; struct bus_container *c; @@ -2385,7 +2394,7 @@ int sd_bus_message_append_string_memfd(sd_bus_message *m, sd_memfd *memfd) { return 0; } -int sd_bus_message_append_strv(sd_bus_message *m, char **l) { +_public_ int sd_bus_message_append_strv(sd_bus_message *m, char **l) { char **i; int r; @@ -2491,6 +2500,15 @@ static int buffer_peek(const void *p, uint32_t sz, size_t *rindex, size_t align, return 1; } +static bool message_end_of_signature(sd_bus_message *m) { + struct bus_container *c; + + assert(m); + + c = message_get_container(m); + return !c->signature || c->signature[c->index] == 0; +} + static bool message_end_of_array(sd_bus_message *m, size_t index) { struct bus_container *c; @@ -2503,6 +2521,22 @@ static bool message_end_of_array(sd_bus_message *m, size_t index) { return index >= c->begin + BUS_MESSAGE_BSWAP32(m, *c->array_size); } +_public_ int sd_bus_message_at_end(sd_bus_message *m, int complete) { + assert_return(m, -EINVAL); + assert_return(m->sealed, -EPERM); + + if (complete && m->n_containers > 0) + return false; + + if (message_end_of_signature(m)) + return true; + + if (message_end_of_array(m, m->rindex)) + return true; + + return false; +} + static struct bus_body_part* find_part(sd_bus_message *m, size_t index, size_t sz, void **p) { struct bus_body_part *part; size_t begin; @@ -2640,28 +2674,22 @@ static bool validate_object_path(const char *s, size_t l) { return true; } -int sd_bus_message_read_basic(sd_bus_message *m, char type, void *p) { +_public_ int sd_bus_message_read_basic(sd_bus_message *m, char type, void *p) { struct bus_container *c; - int r; void *q; + int r; - if (!m) - return -EINVAL; - if (!m->sealed) - return -EPERM; - if (!bus_type_is_basic(type)) - return -EINVAL; - if (!p) - return -EINVAL; - - c = message_get_container(m); + assert_return(m, -EINVAL); + assert_return(m->sealed, -EPERM); + assert_return(bus_type_is_basic(type), -EINVAL); - if (!c->signature || c->signature[c->index] == 0) - return 0; + if (message_end_of_signature(m)) + return -ENXIO; if (message_end_of_array(m, m->rindex)) return 0; + c = message_get_container(m); if (c->signature[c->index] != type) return -ENXIO; @@ -2693,7 +2721,9 @@ int sd_bus_message_read_basic(sd_bus_message *m, char type, void *p) { } m->rindex = rindex; - *(const char**) p = q; + if (p) + *(const char**) p = q; + break; } @@ -2717,7 +2747,9 @@ int sd_bus_message_read_basic(sd_bus_message *m, char type, void *p) { return -EBADMSG; m->rindex = rindex; - *(const char**) p = q; + + if (p) + *(const char**) p = q; break; } @@ -2737,27 +2769,32 @@ int sd_bus_message_read_basic(sd_bus_message *m, char type, void *p) { switch (type) { case SD_BUS_TYPE_BYTE: - *(uint8_t*) p = *(uint8_t*) q; + if (p) + *(uint8_t*) p = *(uint8_t*) q; break; case SD_BUS_TYPE_BOOLEAN: - *(int*) p = !!*(uint32_t*) q; + if (p) + *(int*) p = !!*(uint32_t*) q; break; case SD_BUS_TYPE_INT16: case SD_BUS_TYPE_UINT16: - *(uint16_t*) p = BUS_MESSAGE_BSWAP16(m, *(uint16_t*) q); + if (p) + *(uint16_t*) p = BUS_MESSAGE_BSWAP16(m, *(uint16_t*) q); break; case SD_BUS_TYPE_INT32: case SD_BUS_TYPE_UINT32: - *(uint32_t*) p = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q); + if (p) + *(uint32_t*) p = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q); break; case SD_BUS_TYPE_INT64: case SD_BUS_TYPE_UINT64: case SD_BUS_TYPE_DOUBLE: - *(uint64_t*) p = BUS_MESSAGE_BSWAP64(m, *(uint64_t*) q); + if (p) + *(uint64_t*) p = BUS_MESSAGE_BSWAP64(m, *(uint64_t*) q); break; case SD_BUS_TYPE_UNIX_FD: { @@ -2767,7 +2804,8 @@ int sd_bus_message_read_basic(sd_bus_message *m, char type, void *p) { if (j >= m->n_fds) return -EBADMSG; - *(int*) p = m->fds[j]; + if (p) + *(int*) p = m->fds[j]; break; } @@ -2967,19 +3005,37 @@ static int bus_message_enter_dict_entry( return 1; } -int sd_bus_message_enter_container(sd_bus_message *m, char type, const char *contents) { +_public_ int sd_bus_message_enter_container(sd_bus_message *m, + char type, + const char *contents) { struct bus_container *c, *w; uint32_t *array_size = NULL; char *signature; size_t before; int r; - if (!m) - return -EINVAL; - if (!m->sealed) - return -EPERM; - if (!contents) - return -EINVAL; + assert_return(m, -EINVAL); + assert_return(m->sealed, -EPERM); + assert_return(type != 0 || !contents, -EINVAL); + + if (type == 0 || !contents) { + const char *cc; + char tt; + + /* Allow entering into anonymous containers */ + r = sd_bus_message_peek_type(m, &tt, &cc); + if (r <= 0) + return r; + + if (type != 0 && type != tt) + return -ENXIO; + + if (contents && !streq(contents, cc)) + return -ENXIO; + + type = tt; + contents = cc; + } /* * We enforce a global limit on container depth, that is much @@ -3005,14 +3061,14 @@ int sd_bus_message_enter_container(sd_bus_message *m, char type, const char *con return -ENOMEM; m->containers = w; - c = message_get_container(m); - - if (!c->signature || c->signature[c->index] == 0) - return 0; + if (message_end_of_signature(m)) + return -ENXIO; if (message_end_of_array(m, m->rindex)) return 0; + c = message_get_container(m); + signature = strdup(contents); if (!signature) return -ENOMEM; @@ -3048,15 +3104,12 @@ int sd_bus_message_enter_container(sd_bus_message *m, char type, const char *con return 1; } -int sd_bus_message_exit_container(sd_bus_message *m) { +_public_ int sd_bus_message_exit_container(sd_bus_message *m) { struct bus_container *c; - if (!m) - return -EINVAL; - if (!m->sealed) - return -EPERM; - if (m->n_containers <= 0) - return -EINVAL; + assert_return(m, -EINVAL); + assert_return(m->sealed, -EPERM); + assert_return(m->n_containers > 0, -ENXIO); c = message_get_container(m); if (c->enclosing == SD_BUS_TYPE_ARRAY) { @@ -3068,7 +3121,7 @@ int sd_bus_message_exit_container(sd_bus_message *m) { } else { if (c->signature && c->signature[c->index] != 0) - return -EINVAL; + return -EBUSY; } free(c->signature); @@ -3099,23 +3152,21 @@ static void message_quit_container(sd_bus_message *m) { c->index = c->saved_index; } -int sd_bus_message_peek_type(sd_bus_message *m, char *type, const char **contents) { +_public_ int sd_bus_message_peek_type(sd_bus_message *m, char *type, const char **contents) { struct bus_container *c; int r; - if (!m) - return -EINVAL; - if (!m->sealed) - return -EPERM; - - c = message_get_container(m); + assert_return(m, -EINVAL); + assert_return(m->sealed, -EPERM); - if (!c->signature || c->signature[c->index] == 0) + if (message_end_of_signature(m)) goto eof; if (message_end_of_array(m, m->rindex)) goto eof; + c = message_get_container(m); + if (bus_type_is_basic(c->signature[c->index])) { if (contents) *contents = NULL; @@ -3215,19 +3266,17 @@ int sd_bus_message_peek_type(sd_bus_message *m, char *type, const char **content eof: if (type) - *type = c->enclosing; + *type = 0; if (contents) *contents = NULL; return 0; } -int sd_bus_message_rewind(sd_bus_message *m, int complete) { +_public_ int sd_bus_message_rewind(sd_bus_message *m, int complete) { struct bus_container *c; - if (!m) - return -EINVAL; - if (!m->sealed) - return -EPERM; + assert_return(m, -EINVAL); + assert_return(m->sealed, -EPERM); if (complete) { message_reset_containers(m); @@ -3244,6 +3293,7 @@ int sd_bus_message_rewind(sd_bus_message *m, int complete) { return !isempty(c->signature); } + static int message_read_ap( sd_bus_message *m, const char *types, @@ -3252,11 +3302,12 @@ static int message_read_ap( unsigned n_array, n_struct; TypeStack stack[BUS_CONTAINER_DEPTH]; unsigned stack_ptr = 0; + unsigned n_loop = 0; int r; assert(m); - if (!types) + if (isempty(types)) return 0; /* Ideally, we'd just call ourselves recursively on every @@ -3266,12 +3317,14 @@ static int message_read_ap( * in a single stackframe. We hence implement our own * home-grown stack in an array. */ - n_array = (unsigned) -1; - n_struct = strlen(types); + n_array = (unsigned) -1; /* lenght of current array entries */ + n_struct = strlen(types); /* length of current struct contents signature */ for (;;) { const char *t; + n_loop++; + if (n_array == 0 || (n_array == (unsigned) -1 && n_struct == 0)) { r = type_stack_pop(stack, ELEMENTSOF(stack), &stack_ptr, &types, &n_struct, &n_array); if (r < 0) @@ -3315,8 +3368,12 @@ static int message_read_ap( r = sd_bus_message_read_basic(m, *t, p); if (r < 0) return r; - if (r == 0) + if (r == 0) { + if (n_loop <= 1) + return 0; + return -ENXIO; + } break; } @@ -3336,8 +3393,12 @@ static int message_read_ap( r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, s); if (r < 0) return r; - if (r == 0) + if (r == 0) { + if (n_loop <= 1) + return 0; + return -ENXIO; + } } if (n_array == (unsigned) -1) { @@ -3366,8 +3427,12 @@ static int message_read_ap( r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, s); if (r < 0) return r; - if (r == 0) + if (r == 0) { + if (n_loop <= 1) + return 0; + return -ENXIO; + } r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array); if (r < 0) @@ -3396,8 +3461,11 @@ static int message_read_ap( r = sd_bus_message_enter_container(m, *t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s); if (r < 0) return r; - if (r == 0) + if (r == 0) { + if (n_loop <= 1) + return 0; return -ENXIO; + } } if (n_array == (unsigned) -1) { @@ -3424,16 +3492,13 @@ static int message_read_ap( return 1; } -int sd_bus_message_read(sd_bus_message *m, const char *types, ...) { +_public_ int sd_bus_message_read(sd_bus_message *m, const char *types, ...) { va_list ap; int r; - if (!m) - return -EINVAL; - if (!m->sealed) - return -EPERM; - if (!types) - return -EINVAL; + assert_return(m, -EINVAL); + assert_return(m->sealed, -EPERM); + assert_return(types, -EINVAL); va_start(ap, types); r = message_read_ap(m, types, ap); @@ -3442,25 +3507,164 @@ int sd_bus_message_read(sd_bus_message *m, const char *types, ...) { return r; } -int sd_bus_message_read_array(sd_bus_message *m, char type, const void **ptr, size_t *size) { +_public_ int sd_bus_message_skip(sd_bus_message *m, const char *types) { + int r; + + assert_return(m, -EINVAL); + assert_return(m->sealed, -EPERM); + assert_return(types, -EINVAL); + + if (isempty(types)) + return 0; + + switch (*types) { + + case SD_BUS_TYPE_BYTE: + case SD_BUS_TYPE_BOOLEAN: + case SD_BUS_TYPE_INT16: + case SD_BUS_TYPE_UINT16: + case SD_BUS_TYPE_INT32: + case SD_BUS_TYPE_UINT32: + case SD_BUS_TYPE_INT64: + case SD_BUS_TYPE_UINT64: + case SD_BUS_TYPE_DOUBLE: + case SD_BUS_TYPE_STRING: + case SD_BUS_TYPE_OBJECT_PATH: + case SD_BUS_TYPE_SIGNATURE: + case SD_BUS_TYPE_UNIX_FD: + + r = sd_bus_message_read_basic(m, *types, NULL); + if (r <= 0) + return r; + + r = sd_bus_message_skip(m, types + 1); + if (r < 0) + return r; + + return 1; + + case SD_BUS_TYPE_ARRAY: { + size_t k; + + r = signature_element_length(types + 1, &k); + if (r < 0) + return r; + + { + char s[k+1]; + memcpy(s, types+1, k); + s[k] = 0; + + r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, s); + if (r <= 0) + return r; + + for (;;) { + r = sd_bus_message_skip(m, s); + if (r < 0) + return r; + if (r == 0) + break; + } + + r = sd_bus_message_exit_container(m); + if (r < 0) + return r; + } + + r = sd_bus_message_skip(m, types + 1 + k); + if (r < 0) + return r; + + return 1; + } + + case SD_BUS_TYPE_VARIANT: { + const char *contents; + char x; + + r = sd_bus_message_peek_type(m, &x, &contents); + if (r <= 0) + return r; + + if (x != SD_BUS_TYPE_VARIANT) + return -ENXIO; + + r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents); + if (r <= 0) + return r; + + r = sd_bus_message_skip(m, contents); + if (r < 0) + return r; + assert(r != 0); + + r = sd_bus_message_exit_container(m); + if (r < 0) + return r; + + r = sd_bus_message_skip(m, types + 1); + if (r < 0) + return r; + + return 1; + } + + case SD_BUS_TYPE_STRUCT_BEGIN: + case SD_BUS_TYPE_DICT_ENTRY_BEGIN: { + size_t k; + + r = signature_element_length(types, &k); + if (r < 0) + return r; + + { + char s[k-1]; + memcpy(s, types+1, k-2); + s[k-2] = 0; + + r = sd_bus_message_enter_container(m, *types == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s); + if (r <= 0) + return r; + + 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) + return r; + } + + r = sd_bus_message_skip(m, types + k); + if (r < 0) + return r; + + return 1; + } + + default: + return -EINVAL; + } +} + +_public_ int sd_bus_message_read_array(sd_bus_message *m, + char type, + const void **ptr, + size_t *size) { struct bus_container *c; void *p; size_t sz; ssize_t align; int r; - if (!m) - return -EINVAL; - if (!m->sealed) - return -EPERM; - if (!bus_type_is_trivial(type)) - return -EINVAL; - if (!ptr) - return -EINVAL; - if (!size) - return -EINVAL; - if (BUS_MESSAGE_NEED_BSWAP(m)) - return -ENOTSUP; + assert_return(m, -EINVAL); + assert_return(m->sealed, -EPERM); + assert_return(bus_type_is_trivial(type), -EINVAL); + assert_return(ptr, -EINVAL); + assert_return(size, -EINVAL); + assert_return(!BUS_MESSAGE_NEED_BSWAP(m), -ENOTSUP); align = bus_type_get_alignment(type); if (align < 0) @@ -3473,12 +3677,18 @@ int sd_bus_message_read_array(sd_bus_message *m, char type, const void **ptr, si c = message_get_container(m); sz = BUS_MESSAGE_BSWAP32(m, *c->array_size); - r = message_peek_body(m, &m->rindex, align, sz, &p); - if (r < 0) - goto fail; - if (r == 0) { - r = -EBADMSG; - goto fail; + if (sz == 0) + /* Zero length array, let's return some aligned + * pointer that is not NULL */ + p = (uint8_t*) NULL + align; + else { + r = message_peek_body(m, &m->rindex, align, sz, &p); + if (r < 0) + goto fail; + if (r == 0) { + r = -EBADMSG; + goto fail; + } } r = sd_bus_message_exit_container(m); @@ -3986,279 +4196,15 @@ int bus_message_seal(sd_bus_message *m, uint64_t serial) { return 0; } -int sd_bus_message_set_destination(sd_bus_message *m, const char *destination) { - if (!m) - return -EINVAL; - if (!destination) - return -EINVAL; - if (m->sealed) - return -EPERM; - if (m->destination) - return -EEXIST; +_public_ int sd_bus_message_set_destination(sd_bus_message *m, const char *destination) { + assert_return(m, -EINVAL); + assert_return(destination, -EINVAL); + assert_return(!m->sealed, -EPERM); + assert_return(!m->destination, -EEXIST); return message_append_field_string(m, SD_BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, destination, &m->destination); } -int bus_message_dump(sd_bus_message *m) { - const char *u = NULL, *uu = NULL, *s = NULL; - char **cmdline = NULL; - unsigned level = 1; - int r; - uid_t owner, audit_loginuid; - uint32_t audit_sessionid; - - assert(m); - - printf("Message %p\n" - "\tn_ref=%u\n" - "\tendian=%c\n" - "\ttype=%i\n" - "\tflags=%u\n" - "\tversion=%u\n" - "\tserial=%u\n" - "\tfields_size=%u\n" - "\tbody_size=%u\n" - "\tpath=%s\n" - "\tinterface=%s\n" - "\tmember=%s\n" - "\tdestination=%s\n" - "\tsender=%s\n" - "\tsignature=%s\n" - "\treply_serial=%u\n" - "\terror.name=%s\n" - "\terror.message=%s\n" - "\tsealed=%s\n" - "\tn_body_parts=%u\n", - m, - m->n_ref, - m->header->endian, - m->header->type, - m->header->flags, - m->header->version, - BUS_MESSAGE_SERIAL(m), - BUS_MESSAGE_FIELDS_SIZE(m), - BUS_MESSAGE_BODY_SIZE(m), - strna(m->path), - strna(m->interface), - strna(m->member), - strna(m->destination), - strna(m->sender), - strna(m->root_container.signature), - m->reply_serial, - strna(m->error.name), - strna(m->error.message), - yes_no(m->sealed), - m->n_body_parts); - - if (m->pid != 0) - printf("\tpid=%lu\n", (unsigned long) m->pid); - if (m->tid != 0) - printf("\ttid=%lu\n", (unsigned long) m->tid); - if (m->uid_valid) - printf("\tuid=%lu\n", (unsigned long) m->uid); - if (m->gid_valid) - printf("\tgid=%lu\n", (unsigned long) m->gid); - if (m->pid_starttime != 0) - printf("\tpid_starttime=%llu\n", (unsigned long long) m->pid_starttime); - if (m->monotonic != 0) - printf("\tmonotonic=%llu\n", (unsigned long long) m->monotonic); - if (m->realtime != 0) - printf("\trealtime=%llu\n", (unsigned long long) m->realtime); - if (m->exe) - printf("\texe=[%s]\n", m->exe); - if (m->comm) - printf("\tcomm=[%s]\n", m->comm); - if (m->tid_comm) - printf("\ttid_comm=[%s]\n", m->tid_comm); - if (m->label) - printf("\tlabel=[%s]\n", m->label); - if (m->cgroup) - printf("\tcgroup=[%s]\n", m->cgroup); - - sd_bus_message_get_unit(m, &u); - if (u) - printf("\tunit=[%s]\n", u); - sd_bus_message_get_user_unit(m, &uu); - if (uu) - printf("\tuser_unit=[%s]\n", uu); - sd_bus_message_get_session(m, &s); - if (s) - printf("\tsession=[%s]\n", s); - if (sd_bus_message_get_owner_uid(m, &owner) >= 0) - printf("\towner_uid=%lu\n", (unsigned long) owner); - if (sd_bus_message_get_audit_loginuid(m, &audit_loginuid) >= 0) - printf("\taudit_loginuid=%lu\n", (unsigned long) audit_loginuid); - if (sd_bus_message_get_audit_sessionid(m, &audit_sessionid) >= 0) - printf("\taudit_sessionid=%lu\n", (unsigned long) audit_sessionid); - - printf("\tCAP_KILL=%i\n", sd_bus_message_has_effective_cap(m, 5)); - - if (sd_bus_message_get_cmdline(m, &cmdline) >= 0) { - char **c; - - fputs("\tcmdline=[", stdout); - STRV_FOREACH(c, cmdline) { - if (c != cmdline) - putchar(' '); - - fputs(*c, stdout); - } - - fputs("]\n", stdout); - } - - r = sd_bus_message_rewind(m, true); - if (r < 0) { - log_error("Failed to rewind: %s", strerror(-r)); - return r; - } - - printf("BEGIN_MESSAGE \"%s\" {\n", strempty(m->root_container.signature)); - - for(;;) { - _cleanup_free_ char *prefix = NULL; - const char *contents = NULL; - char type; - union { - uint8_t u8; - uint16_t u16; - int16_t s16; - uint32_t u32; - int32_t s32; - uint64_t u64; - int64_t s64; - double d64; - const char *string; - int i; - } basic; - - r = sd_bus_message_peek_type(m, &type, &contents); - if (r < 0) { - log_error("Failed to peek type: %s", strerror(-r)); - return r; - } - if (r == 0) { - if (level <= 1) - break; - - r = sd_bus_message_exit_container(m); - if (r < 0) { - log_error("Failed to exit container: %s", strerror(-r)); - return r; - } - - level--; - - prefix = strrep("\t", level); - if (!prefix) - return log_oom(); - - if (type == SD_BUS_TYPE_ARRAY) - printf("%s} END_ARRAY \n", prefix); - else if (type == SD_BUS_TYPE_VARIANT) - printf("%s} END_VARIANT\n", prefix); - else if (type == SD_BUS_TYPE_STRUCT) - printf("%s} END_STRUCT\n", prefix); - else if (type == SD_BUS_TYPE_DICT_ENTRY) - printf("%s} END_DICT_ENTRY\n", prefix); - - continue; - } - - prefix = strrep("\t", level); - if (!prefix) - return log_oom(); - - if (bus_type_is_container(type) > 0) { - r = sd_bus_message_enter_container(m, type, contents); - if (r < 0) { - log_error("Failed to enter container: %s", strerror(-r)); - return r; - } - - if (type == SD_BUS_TYPE_ARRAY) - printf("%sBEGIN_ARRAY \"%s\" {\n", prefix, contents); - else if (type == SD_BUS_TYPE_VARIANT) - printf("%sBEGIN_VARIANT \"%s\" {\n", prefix, contents); - else if (type == SD_BUS_TYPE_STRUCT) - printf("%sBEGIN_STRUCT \"%s\" {\n", prefix, contents); - else if (type == SD_BUS_TYPE_DICT_ENTRY) - printf("%sBEGIN_DICT_ENTRY \"%s\" {\n", prefix, contents); - - level ++; - - continue; - } - - r = sd_bus_message_read_basic(m, type, &basic); - if (r < 0) { - log_error("Failed to get basic: %s", strerror(-r)); - return r; - } - - switch (type) { - - case SD_BUS_TYPE_BYTE: - printf("%sBYTE: %u\n", prefix, basic.u8); - break; - - case SD_BUS_TYPE_BOOLEAN: - printf("%sBOOLEAN: %s\n", prefix, yes_no(basic.i)); - break; - - case SD_BUS_TYPE_INT16: - printf("%sINT16: %i\n", prefix, basic.s16); - break; - - case SD_BUS_TYPE_UINT16: - printf("%sUINT16: %u\n", prefix, basic.u16); - break; - - case SD_BUS_TYPE_INT32: - printf("%sINT32: %i\n", prefix, basic.s32); - break; - - case SD_BUS_TYPE_UINT32: - printf("%sUINT32: %u\n", prefix, basic.u32); - break; - - case SD_BUS_TYPE_INT64: - printf("%sINT64: %lli\n", prefix, (long long) basic.s64); - break; - - case SD_BUS_TYPE_UINT64: - printf("%sUINT64: %llu\n", prefix, (unsigned long long) basic.u64); - break; - - case SD_BUS_TYPE_DOUBLE: - printf("%sDOUBLE: %g\n", prefix, basic.d64); - break; - - case SD_BUS_TYPE_STRING: - printf("%sSTRING: \"%s\"\n", prefix, basic.string); - break; - - case SD_BUS_TYPE_OBJECT_PATH: - printf("%sOBJECT_PATH: \"%s\"\n", prefix, basic.string); - break; - - case SD_BUS_TYPE_SIGNATURE: - printf("%sSIGNATURE: \"%s\"\n", prefix, basic.string); - break; - - case SD_BUS_TYPE_UNIX_FD: - printf("%sUNIX_FD: %i\n", prefix, basic.i); - break; - - default: - assert_not_reached("Unknown basic type."); - } - } - - printf("} END_MESSAGE\n"); - return 0; -} - int bus_message_get_blob(sd_bus_message *m, void **buffer, size_t *sz) { size_t total; void *p, *e; @@ -4294,7 +4240,7 @@ int bus_message_read_strv_extend(sd_bus_message *m, char ***l) { assert(l); r = sd_bus_message_enter_container(m, 'a', "s"); - if (r < 0) + if (r <= 0) return r; for (;;) { @@ -4315,7 +4261,25 @@ int bus_message_read_strv_extend(sd_bus_message *m, char ***l) { if (r < 0) return r; - return 0; + return 1; +} + +_public_ int sd_bus_message_read_strv(sd_bus_message *m, char ***l) { + char **strv = NULL; + int r; + + assert_return(m, -EINVAL); + assert_return(m->sealed, -EPERM); + assert_return(l, -EINVAL); + + r = bus_message_read_strv_extend(m, &strv); + if (r <= 0) { + strv_free(strv); + return r; + } + + *l = strv; + return 1; } const char* bus_message_get_arg(sd_bus_message *m, unsigned i) { @@ -4383,7 +4347,7 @@ int bus_header_message_size(struct bus_header *h, size_t *sum) { return 0; } -int sd_bus_message_get_errno(sd_bus_message *m) { +_public_ int sd_bus_message_get_errno(sd_bus_message *m) { assert_return(m, -EINVAL); if (m->header->type != SD_BUS_MESSAGE_METHOD_ERROR) @@ -4392,12 +4356,115 @@ int sd_bus_message_get_errno(sd_bus_message *m) { return sd_bus_error_get_errno(&m->error); } -const char* sd_bus_message_get_signature(sd_bus_message *m, int complete) { +_public_ const char* sd_bus_message_get_signature(sd_bus_message *m, int complete) { struct bus_container *c; - if (!m) - return NULL; + assert_return(m, NULL); c = complete ? &m->root_container : message_get_container(m); return c->signature ?: ""; } + +_public_ int sd_bus_message_copy(sd_bus_message *m, sd_bus_message *source, int all) { + bool done_something = false; + int r; + + assert_return(m, -EINVAL); + assert_return(source, -EINVAL); + assert_return(!m->sealed, -EPERM); + assert_return(source->sealed, -EPERM); + + do { + const char *contents; + char type; + union { + uint8_t u8; + uint16_t u16; + int16_t s16; + uint32_t u32; + int32_t s32; + uint64_t u64; + int64_t s64; + double d64; + const char *string; + int i; + } basic; + + r = sd_bus_message_peek_type(source, &type, &contents); + if (r < 0) + return r; + if (r == 0) + break; + + done_something = true; + + if (bus_type_is_container(type) > 0) { + + r = sd_bus_message_enter_container(source, type, contents); + if (r < 0) + return r; + + r = sd_bus_message_open_container(m, type, contents); + if (r < 0) + return r; + + r = sd_bus_message_copy(m, source, true); + if (r < 0) + return r; + + r = sd_bus_message_close_container(m); + if (r < 0) + return r; + + r = sd_bus_message_exit_container(source); + if (r < 0) + return r; + + continue; + } + + r = sd_bus_message_read_basic(source, type, &basic); + if (r < 0) + return r; + + assert(r > 0); + + if (type == SD_BUS_TYPE_OBJECT_PATH || + type == SD_BUS_TYPE_SIGNATURE || + type == SD_BUS_TYPE_STRING) + r = sd_bus_message_append_basic(m, type, basic.string); + else + r = sd_bus_message_append_basic(m, type, &basic); + + if (r < 0) + return r; + + } while (all); + + return done_something; +} + +_public_ int sd_bus_message_verify_type(sd_bus_message *m, char type, const char *contents) { + const char *c; + char t; + int r; + + assert_return(m, -EINVAL); + assert_return(m->sealed, -EPERM); + assert_return(!type || bus_type_is_valid(type), -EINVAL); + assert_return(!contents || signature_is_valid(contents, true), -EINVAL); + assert_return(type || contents, -EINVAL); + assert_return(!contents || !type || bus_type_is_container(type), -EINVAL); + + r = sd_bus_message_peek_type(m, &t, &c); + if (r <= 0) + return r; + + if (type != 0 && type != t) + return 0; + + if (contents && !streq_ptr(contents, c)) + return 0; + + return 1; +}