1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
26 #include "bus-internal.h"
27 #include "bus-message.h"
28 #include "bus-kernel.h"
30 #define KDBUS_MSG_FOREACH_DATA(d, k) \
31 for ((d) = (k)->data; \
32 (uint8_t*) (d) < (uint8_t*) (k) + (k)->size; \
33 (d) = (struct kdbus_msg_data*) ((uint8_t*) (d) + ALIGN8((d)->size)))
37 static int parse_unique_name(const char *s
, uint64_t *id
) {
43 if (!startswith(s
, ":1."))
46 r
= safe_atou64(s
+ 3, id
);
53 static void append_payload_vec(struct kdbus_msg_data
**d
, const void *p
, size_t sz
) {
58 (*d
)->size
= offsetof(struct kdbus_msg_data
, vec
) + sizeof(struct kdbus_vec
);
59 (*d
)->type
= KDBUS_MSG_PAYLOAD_VEC
;
60 (*d
)->vec
.address
= (uint64_t) p
;
63 *d
= (struct kdbus_msg_data
*) ((uint8_t*) *d
+ ALIGN8((*d
)->size
));
66 static void append_destination(struct kdbus_msg_data
**d
, const char *s
, size_t length
) {
70 (*d
)->size
= offsetof(struct kdbus_msg_data
, data
) + length
+ 1;
71 (*d
)->type
= KDBUS_MSG_DST_NAME
;
72 memcpy((*d
)->data
, s
, length
+ 1);
74 *d
= (struct kdbus_msg_data
*) ((uint8_t*) *d
+ ALIGN8((*d
)->size
));
77 static int bus_message_setup_kmsg(sd_bus_message
*m
) {
78 struct kdbus_msg_data
*d
;
91 r
= parse_unique_name(m
->destination
, &unique
);
99 sz
= offsetof(struct kdbus_msg
, data
);
101 /* Add in fixed header, fields header, fields header padding and payload */
102 sz
+= 4 * ALIGN8(offsetof(struct kdbus_msg_data
, vec
) + sizeof(struct kdbus_vec
));
104 /* Add in well-known destination header */
106 dl
= strlen(m
->destination
);
107 sz
+= ALIGN8(offsetof(struct kdbus_msg
, data
) + dl
+ 1);
110 m
->kdbus
= malloc0(sz
);
115 ((m
->header
->flags
& SD_BUS_MESSAGE_NO_REPLY_EXPECTED
) ? 0 : KDBUS_MSG_FLAGS_EXPECT_REPLY
) |
116 ((m
->header
->flags
& SD_BUS_MESSAGE_NO_AUTO_START
) ? KDBUS_MSG_FLAGS_NO_AUTO_START
: 0);
119 m
->destination
? unique
: (uint64_t) -1;
120 m
->kdbus
->payload_type
= KDBUS_PAYLOAD_DBUS1
;
121 m
->kdbus
->cookie
= m
->header
->serial
;
123 m
->kdbus
->timeout_ns
= m
->timeout
* NSEC_PER_USEC
;
128 append_destination(&d
, m
->destination
, dl
);
130 append_payload_vec(&d
, m
->header
, sizeof(*m
->header
));
133 append_payload_vec(&d
, m
->fields
, m
->header
->fields_size
);
135 if (m
->header
->fields_size
% 8 != 0) {
136 static const uint8_t padding
[7] = {};
138 append_payload_vec(&d
, padding
, 8 - (m
->header
->fields_size
% 8));
143 append_payload_vec(&d
, m
->body
, m
->header
->body_size
);
145 m
->kdbus
->size
= (uint8_t*) d
- (uint8_t*) m
->kdbus
;
146 assert(m
->kdbus
->size
<= sz
);
148 m
->free_kdbus
= true;
153 int bus_kernel_take_fd(sd_bus
*b
) {
154 struct kdbus_cmd_hello hello
= {};
159 r
= ioctl(b
->input_fd
, KDBUS_CMD_HELLO
, &hello
);
163 if (asprintf(&b
->unique_name
, ":1.%llu", (unsigned long long) hello
.id
) < 0)
168 r
= bus_start_running(b
);
175 int bus_kernel_connect(sd_bus
*b
) {
177 assert(b
->input_fd
< 0);
178 assert(b
->output_fd
< 0);
181 b
->input_fd
= open(b
->kernel
, O_RDWR
|O_NOCTTY
|O_CLOEXEC
);
185 b
->output_fd
= b
->input_fd
;
187 return bus_kernel_take_fd(b
);
190 int bus_kernel_write_message(sd_bus
*bus
, sd_bus_message
*m
) {
195 assert(bus
->state
== BUS_RUNNING
);
197 r
= bus_message_setup_kmsg(m
);
201 r
= ioctl(bus
->output_fd
, KDBUS_CMD_MSG_SEND
, m
->kdbus
);
203 return errno
== EAGAIN
? 0 : -errno
;
208 static void close_kdbus_msg(struct kdbus_msg
*k
) {
209 struct kdbus_msg_data
*d
;
211 KDBUS_MSG_FOREACH_DATA(d
, k
) {
213 if (d
->type
!= KDBUS_MSG_UNIX_FDS
)
216 close_many(d
->fds
, (d
->size
- offsetof(struct kdbus_msg_data
, fds
)) / sizeof(int));
220 static int bus_kernel_make_message(sd_bus
*bus
, struct kdbus_msg
*k
, sd_bus_message
**ret
) {
221 sd_bus_message
*m
= NULL
;
222 struct kdbus_msg_data
*d
;
223 unsigned n_payload
= 0, n_fds
= 0;
224 _cleanup_free_
int *fds
= NULL
;
225 struct bus_header
*h
= NULL
;
226 size_t total
, n_bytes
= 0, idx
= 0;
233 if (k
->payload_type
!= KDBUS_PAYLOAD_DBUS1
)
236 KDBUS_MSG_FOREACH_DATA(d
, k
) {
239 l
= d
->size
- offsetof(struct kdbus_msg_data
, data
);
241 if (d
->type
== KDBUS_MSG_PAYLOAD
) {
244 if (l
< sizeof(struct bus_header
))
247 h
= (struct bus_header
*) d
->data
;
253 } else if (d
->type
== KDBUS_MSG_UNIX_FDS
) {
258 f
= realloc(fds
, sizeof(int) * (n_fds
+ j
));
263 memcpy(fds
+ n_fds
, d
->fds
, j
);
271 r
= bus_header_size(h
, &total
);
275 if (n_bytes
!= total
)
278 r
= bus_message_from_header(h
, sizeof(struct bus_header
), fds
, n_fds
, NULL
, NULL
, 0, &m
);
282 KDBUS_MSG_FOREACH_DATA(d
, k
) {
285 if (d
->type
!= KDBUS_MSG_PAYLOAD
)
288 l
= d
->size
- offsetof(struct kdbus_msg_data
, data
);
289 if (idx
== sizeof(struct bus_header
) &&
290 l
== BUS_MESSAGE_FIELDS_SIZE(m
))
292 else if (idx
== sizeof(struct bus_header
) + ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m
)) &&
293 l
== BUS_MESSAGE_BODY_SIZE(m
))
295 else if (!(idx
== 0 && l
== sizeof(struct bus_header
)) &&
296 !(idx
== sizeof(struct bus_header
) + BUS_MESSAGE_FIELDS_SIZE(m
))) {
297 sd_bus_message_unref(m
);
304 r
= bus_message_parse_fields(m
);
306 sd_bus_message_unref(m
);
310 /* We take possession of the kmsg struct now */
312 m
->free_kdbus
= true;
321 int bus_kernel_read_message(sd_bus
*bus
, sd_bus_message
**m
) {
332 q
= realloc(bus
->rbuffer
, sz
);
336 k
= bus
->rbuffer
= q
;
339 r
= ioctl(bus
->input_fd
, KDBUS_CMD_MSG_RECV
, bus
->rbuffer
);
346 if (errno
!= ENOBUFS
)
352 r
= bus_kernel_make_message(bus
, k
, m
);
361 int bus_kernel_create(const char *name
, char **s
) {
362 struct kdbus_cmd_fname
*fname
;
370 fd
= open("/dev/kdbus/control", O_RDWR
|O_NOCTTY
|O_CLOEXEC
);
375 fname
= alloca(offsetof(struct kdbus_cmd_fname
, name
) + DECIMAL_STR_MAX(uid_t
) + 1 + l
+ 1);
376 sprintf(fname
->name
, "%lu-%s", (unsigned long) getuid(), name
);
377 fname
->size
= offsetof(struct kdbus_cmd_fname
, name
) + strlen(fname
->name
) + 1;
378 fname
->kernel_flags
= KDBUS_CMD_FNAME_ACCESS_WORLD
;
379 fname
->user_flags
= 0;
381 p
= strjoin("/dev/kdbus/", fname
->name
, "/bus", NULL
);
385 if (ioctl(fd
, KDBUS_CMD_BUS_MAKE
, fname
) < 0) {
386 close_nointr_nofail(fd
);