+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;
+
+ if (!m->user_unit) {
+ r = cg_path_get_user_unit(m->cgroup, &m->user_unit);
+ if (r < 0)
+ return r;
+ }
+
+ *ret = m->user_unit;
+ return 0;
+}
+
+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;
+
+ if (!m->session) {
+ r = cg_path_get_session(m->cgroup, &m->session);
+ if (r < 0)
+ return r;
+ }
+
+ *ret = m->session;
+ 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;
+
+ return cg_path_get_owner_uid(m->cgroup, uid);
+}
+
+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;
+
+ for (p = m->cmdline, n = 0; p < m->cmdline + m->cmdline_length; p++)
+ if (*p == 0)
+ n++;
+
+ m->cmdline_array = new(char*, n + 1);
+ if (!m->cmdline_array)
+ return -ENOMEM;
+
+ for (p = m->cmdline, i = 0, first = true; p < m->cmdline + m->cmdline_length; p++) {
+ if (first)
+ m->cmdline_array[i++] = (char*) p;
+
+ first = *p == 0;
+ }
+
+ m->cmdline_array[i] = NULL;
+ *cmdline = m->cmdline_array;
+
+ 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;
+
+ *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;
+
+ *uid = m->audit->loginuid;
+ return 0;
+}
+
+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;
+
+ sz = m->capability_size / 4;
+ if ((unsigned) capability >= sz*8)
+ return 0;
+
+ 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;
+
+ if (m->header->type != SD_BUS_MESSAGE_SIGNAL)
+ return 0;
+
+ if (interface && (!m->interface || !streq(m->interface, interface)))
+ return 0;
+
+ if (member && (!m->member || !streq(m->member, member)))
+ return 0;
+
+ return 1;
+}
+
+int sd_bus_message_is_method_call(sd_bus_message *m, const char *interface, const char *member) {
+ if (!m)
+ return -EINVAL;
+
+ if (m->header->type != SD_BUS_MESSAGE_METHOD_CALL)
+ return 0;
+
+ if (interface && (!m->interface || !streq(m->interface, interface)))
+ return 0;
+
+ if (member && (!m->member || !streq(m->member, member)))
+ return 0;
+
+ return 1;
+}
+
+int sd_bus_message_is_method_error(sd_bus_message *m, const char *name) {
+ if (!m)
+ return -EINVAL;
+
+ if (m->header->type != SD_BUS_MESSAGE_METHOD_ERROR)
+ return 0;
+
+ if (name && (!m->error.name || !streq(m->error.name, name)))
+ return 0;
+
+ 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;
+
+ if (b)
+ m->header->flags |= SD_BUS_MESSAGE_NO_REPLY_EXPECTED;
+ else
+ m->header->flags &= ~SD_BUS_MESSAGE_NO_REPLY_EXPECTED;
+
+ return 0;
+}
+
+static struct bus_container *message_get_container(sd_bus_message *m) {
+ assert(m);
+
+ if (m->n_containers == 0)
+ return &m->root_container;
+
+ assert(m->containers);
+ return m->containers + m->n_containers - 1;
+}
+
+struct bus_body_part *message_append_part(sd_bus_message *m) {
+ struct bus_body_part *part;
+
+ assert(m);
+
+ if (m->poisoned)
+ return NULL;
+
+ if (m->n_body_parts <= 0) {
+ part = &m->body;
+ zero(*part);
+ } else {
+ assert(m->body_end);
+
+ part = new0(struct bus_body_part, 1);
+ if (!part) {
+ m->poisoned = true;
+ return NULL;
+ }
+
+ m->body_end->next = part;
+ }
+
+ part->memfd = -1;
+ m->body_end = part;
+ m->n_body_parts ++;
+
+ return part;
+}
+
+static void part_zero(struct bus_body_part *part, size_t sz) {
+ assert(part);
+ assert(sz > 0);
+ assert(sz < 8);
+
+ /* All other fields can be left in their defaults */
+ assert(!part->data);
+ assert(part->memfd < 0);
+
+ part->size = sz;
+ part->is_zero = true;
+ part->sealed = true;
+}
+
+static int part_make_space(
+ struct sd_bus_message *m,
+ struct bus_body_part *part,
+ size_t sz,
+ void **q) {
+
+ void *n;
+ int r;
+
+ assert(m);
+ assert(part);
+ assert(!part->sealed);
+
+ if (m->poisoned)
+ return -ENOMEM;
+
+ if (!part->data && part->memfd < 0)
+ part->memfd = bus_kernel_pop_memfd(m->bus, &part->data, &part->mapped);
+
+ if (part->memfd >= 0) {
+ uint64_t u = sz;
+
+ r = ioctl(part->memfd, KDBUS_CMD_MEMFD_SIZE_SET, &u);
+ if (r < 0) {
+ m->poisoned = true;
+ return -errno;
+ }
+
+ if (!part->data || sz > part->mapped) {
+ size_t psz = PAGE_ALIGN(sz > 0 ? sz : 1);
+
+ if (part->mapped <= 0)
+ n = mmap(NULL, psz, PROT_READ|PROT_WRITE, MAP_SHARED, part->memfd, 0);
+ else
+ n = mremap(part->data, part->mapped, psz, MREMAP_MAYMOVE);
+
+ if (n == MAP_FAILED) {
+ m->poisoned = true;
+ return -errno;
+ }
+
+ part->mapped = psz;
+ part->data = n;
+ }
+
+ part->munmap_this = true;
+ } else {
+ n = realloc(part->data, MAX(sz, 1u));
+ if (!n) {
+ m->poisoned = true;
+ return -ENOMEM;
+ }
+
+ part->data = n;
+ part->free_this = true;
+ }
+
+ if (q)
+ *q = part->data ? (uint8_t*) part->data + part->size : NULL;
+
+ part->size = sz;
+ return 0;
+}
+
+static void message_extend_containers(sd_bus_message *m, size_t expand) {