bus-kernel.c revision df2d202e6ed4001a21c6512c244acad5d4706c87
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2013 Lennart Poettering
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/>.
***/
#ifdef HAVE_VALGRIND_MEMCHECK_H
#include <valgrind/memcheck.h>
#endif
#include <fcntl.h>
#include <malloc.h>
#include "util.h"
#include "bus-internal.h"
#include "bus-message.h"
#include "bus-kernel.h"
#include "bus-bloom.h"
int r;
assert(s);
if (!startswith(s, ":1."))
return 0;
if (r < 0)
return r;
return 1;
}
assert(d);
*d = ALIGN8_PTR(*d);
/* Note that p can be NULL, which encodes a region full of
* zeroes, which is useful to optimize certain padding
* conditions */
(*d)->type = KDBUS_MSG_PAYLOAD_VEC;
}
assert(d);
*d = ALIGN8_PTR(*d);
(*d)->type = KDBUS_MSG_PAYLOAD_MEMFD;
}
assert(d);
assert(s);
*d = ALIGN8_PTR(*d);
(*d)->type = KDBUS_MSG_DST_NAME;
}
void *r;
assert(d);
*d = ALIGN8_PTR(*d);
(*d)->type = KDBUS_MSG_BLOOM;
r = (*d)->data;
return r;
}
assert(d);
*d = ALIGN8_PTR(*d);
(*d)->type = KDBUS_MSG_FDS;
}
unsigned i;
int r;
assert(m);
if (m->interface)
if (m->member)
if (m->path) {
}
r = sd_bus_message_rewind(m, true);
if (r < 0)
return r;
for (i = 0; i < 64; i++) {
char type;
const char *t;
char *e;
if (r < 0)
return r;
if (type != SD_BUS_TYPE_STRING &&
type != SD_BUS_TYPE_OBJECT_PATH &&
break;
r = sd_bus_message_read_basic(m, type, &t);
if (r < 0)
return r;
if (i < 10)
*(e++) = '0' + i;
else {
*(e++) = '0' + (i / 10);
*(e++) = '0' + (i % 10);
}
*e = 0;
strcpy(e, "-dot-prefix");
strcpy(e, "-slash-prefix");
}
return 0;
}
struct bus_body_part *part;
struct kdbus_item *d;
bool well_known;
unsigned i;
int r;
assert(b);
assert(m);
if (m->kdbus)
return 0;
if (m->destination) {
if (r < 0)
return r;
well_known = r == 0;
} else
well_known = false;
/* Add in fixed header, fields header and payload */
/* Add space for bloom filter */
/* Add in well-known destination header */
if (well_known) {
}
/* Add space for unix fds */
if (m->n_fds > 0)
if (!m->kdbus) {
r = -ENOMEM;
goto fail;
}
m->free_kdbus = true;
well_known ? 0 :
if (well_known)
MESSAGE_FOREACH_PART(part, i, m) {
/* If this is padding then simply send a
* vector with a NULL data pointer which the
* kernel will just pass through. This is the
* most efficient way to encode zeroes */
continue;
}
/* Try to send a memfd, if the part is
* sealed and this is not a broadcast. Since we can only */
continue;
}
/* Otherwise let's send a vector to the actual data,
* for that we need to map it first. */
r = bus_body_part_map(part);
if (r < 0)
goto fail;
}
void *p;
p = append_bloom(&d, BLOOM_SIZE);
r = bus_message_setup_bloom(m, p);
if (r < 0)
goto fail;
}
if (m->n_fds > 0)
return 0;
fail:
m->poisoned = true;
return r;
}
int bus_kernel_take_fd(sd_bus *b) {
struct kdbus_cmd_hello hello;
int r;
assert(b);
if (b->is_server)
return -EINVAL;
b->use_memfd = 1;
if (r < 0)
return -errno;
if (!b->kdbus_buffer) {
if (b->kdbus_buffer == MAP_FAILED) {
b->kdbus_buffer = NULL;
return -errno;
}
}
/* The higher 32bit of both flags fields are considered
* 'incompatible flags'. Refuse them all for now. */
return -ENOTSUP;
return -ENOTSUP;
return -ENOMEM;
b->is_kernel = true;
b->bus_client = true;
r = bus_start_running(b);
if (r < 0)
return r;
return 1;
}
int bus_kernel_connect(sd_bus *b) {
assert(b);
if (b->is_server)
return -EINVAL;
if (b->input_fd < 0)
return -errno;
return bus_kernel_take_fd(b);
}
int r;
assert(m);
r = bus_message_setup_kmsg(bus, m);
if (r < 0)
return r;
if (r < 0)
return 1;
}
struct kdbus_item *d;
assert(k);
KDBUS_ITEM_FOREACH(d, k) {
if (d->type == KDBUS_MSG_FDS)
else if (d->type == KDBUS_MSG_PAYLOAD_MEMFD)
}
}
sd_bus_message *m = NULL;
struct kdbus_item *d;
unsigned n_fds = 0;
struct bus_header *h = NULL;
int r;
assert(k);
if (k->payload_type != KDBUS_PAYLOAD_DBUS1)
return 0;
KDBUS_ITEM_FOREACH(d, k) {
size_t l;
if (d->type == KDBUS_MSG_PAYLOAD_OFF) {
if (!h) {
return -EBADMSG;
}
} else if (d->type == KDBUS_MSG_PAYLOAD_MEMFD) {
if (!h)
return -EBADMSG;
} else if (d->type == KDBUS_MSG_FDS) {
int *f;
unsigned j;
j = l / sizeof(int);
if (!f)
return -ENOMEM;
fds = f;
n_fds += j;
} else if (d->type == KDBUS_MSG_SRC_SECLABEL)
}
if (!h)
return -EBADMSG;
r = bus_header_message_size(h, &total);
if (r < 0)
return r;
return -EBADMSG;
if (r < 0)
return r;
KDBUS_ITEM_FOREACH(d, k) {
size_t l;
if (d->type == KDBUS_MSG_PAYLOAD_OFF) {
struct bus_body_part *part;
/* Contains body material */
part = message_append_part(m);
if (!part) {
r = -ENOMEM;
goto fail;
}
/* A -1 offset is NUL padding. */
if (idx >= begin_body) {
} else {
}
}
} else if (d->type == KDBUS_MSG_PAYLOAD_MEMFD) {
struct bus_body_part *part;
if (idx < BUS_MESSAGE_BODY_BEGIN(m)) {
r = -EBADMSG;
goto fail;
}
part = message_append_part(m);
if (!part) {
r = -ENOMEM;
goto fail;
}
} else if (d->type == KDBUS_MSG_SRC_CREDS) {
} else if (d->type == KDBUS_MSG_TIMESTAMP) {
} else if (d->type == KDBUS_MSG_SRC_PID_COMM)
else if (d->type == KDBUS_MSG_SRC_TID_COMM)
else if (d->type == KDBUS_MSG_SRC_EXE)
else if (d->type == KDBUS_MSG_SRC_CMDLINE) {
m->cmdline_length = l;
} else if (d->type == KDBUS_MSG_SRC_CGROUP)
else if (d->type == KDBUS_MSG_SRC_AUDIT)
else if (d->type == KDBUS_MSG_SRC_CAPS) {
m->capability = d->data;
m->capability_size = l;
} else if (d->type == KDBUS_MSG_DST_NAME)
destination = d->str;
else if (d->type != KDBUS_MSG_FDS &&
d->type != KDBUS_MSG_SRC_SECLABEL)
}
r = bus_message_parse_fields(m);
if (r < 0)
goto fail;
if (k->src_id == KDBUS_SRC_ID_KERNEL)
m->sender = "org.freedesktop.DBus";
else {
m->sender = m->sender_buffer;
}
if (!m->destination) {
if (destination)
m->destination = destination;
else if (k->dst_id != KDBUS_DST_ID_WELL_KNOWN_NAME &&
k->dst_id != KDBUS_DST_ID_BROADCAST) {
snprintf(m->destination_buffer, sizeof(m->destination_buffer), ":1.%llu", (unsigned long long) k->dst_id);
m->destination = m->destination_buffer;
}
}
/* We take possession of the kmsg struct now */
m->kdbus = k;
m->release_kdbus = true;
m->free_fds = true;
*ret = m;
return 1;
fail:
if (m) {
struct bus_body_part *part;
unsigned i;
/* Make sure the memfds are not freed twice */
MESSAGE_FOREACH_PART(part, i, m)
}
return r;
}
struct kdbus_msg *k;
int r;
assert(m);
if (r < 0) {
return 0;
return -errno;
}
r = bus_kernel_make_message(bus, k, m);
if (r <= 0)
close_kdbus_msg(bus, k);
return r < 0 ? r : 1;
}
int bus_kernel_create(const char *name, char **s) {
struct kdbus_cmd_bus_make *make;
struct kdbus_item *n;
size_t l;
int fd;
char *p;
assert(s);
if (fd < 0)
return -errno;
KDBUS_ITEM_HEADER_SIZE + sizeof(uint64_t) +
n->type = KDBUS_MAKE_NAME;
if (!p)
return -ENOMEM;
free(p);
return -errno;
}
if (s)
*s = p;
return fd;
}
struct memfd_cache *c;
int fd;
return -ENOTSUP;
if (bus->n_memfd_cache <= 0) {
int r;
if (r < 0)
return -errno;
*size = 0;
return fd;
}
return fd;
}
if (size > 0)
}
struct memfd_cache *c;
return;
}
return;
}
/* If overly long, let's return a bit to the OS */
} else
}
void bus_kernel_flush_memfd(sd_bus *b) {
unsigned i;
assert(b);
for (i = 0; i < b->n_memfd_cache; i++)
}