]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-bus/bus-kernel.c
b83dfcbc27bca1b37ecde52840b3302437d7b872
[thirdparty/systemd.git] / src / libsystemd-bus / bus-kernel.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2013 Lennart Poettering
7
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.
12
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.
17
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/>.
20 ***/
21
22 #include <fcntl.h>
23
24 #include "util.h"
25
26 #include "bus-internal.h"
27 #include "bus-message.h"
28 #include "bus-kernel.h"
29
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)))
34
35
36
37 static int parse_unique_name(const char *s, uint64_t *id) {
38 int r;
39
40 assert(s);
41 assert(id);
42
43 if (!startswith(s, ":1."))
44 return 0;
45
46 r = safe_atou64(s + 3, id);
47 if (r < 0)
48 return r;
49
50 return 1;
51 }
52
53 static void append_payload_vec(struct kdbus_msg_data **d, const void *p, size_t sz) {
54 assert(d);
55 assert(p);
56 assert(sz > 0);
57
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;
61 (*d)->vec.size = sz;
62
63 *d = (struct kdbus_msg_data*) ((uint8_t*) *d + ALIGN8((*d)->size));
64 }
65
66 static void append_destination(struct kdbus_msg_data **d, const char *s, size_t length) {
67 assert(d);
68 assert(d);
69
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);
73
74 *d = (struct kdbus_msg_data*) ((uint8_t*) *d + ALIGN8((*d)->size));
75 }
76
77 static int bus_message_setup_kmsg(sd_bus_message *m) {
78 struct kdbus_msg_data *d;
79 bool well_known;
80 uint64_t unique;
81 size_t sz, dl;
82 int r;
83
84 assert(m);
85 assert(m->sealed);
86 assert(!m->kdbus);
87
88 if (m->destination) {
89 r = parse_unique_name(m->destination, &unique);
90 if (r < 0)
91 return r;
92
93 well_known = r == 0;
94 } else
95 well_known = false;
96
97 sz = offsetof(struct kdbus_msg, data);
98
99 /* Add in fixed header, fields header, fields header padding and payload */
100 sz += 4 * ALIGN8(offsetof(struct kdbus_msg_data, vec) + sizeof(struct kdbus_vec));
101
102 /* Add in well-known destination header */
103 if (well_known) {
104 dl = strlen(m->destination);
105 sz += ALIGN8(offsetof(struct kdbus_msg, data) + dl + 1);
106 }
107
108 m->kdbus = malloc0(sz);
109 if (!m->kdbus)
110 return -ENOMEM;
111
112 m->kdbus->flags =
113 ((m->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED) ? 0 : KDBUS_MSG_FLAGS_EXPECT_REPLY) |
114 ((m->header->flags & SD_BUS_MESSAGE_NO_AUTO_START) ? KDBUS_MSG_FLAGS_NO_AUTO_START : 0);
115 m->kdbus->dst_id =
116 well_known ? 0 :
117 m->destination ? unique : (uint64_t) -1;
118 m->kdbus->payload_type = KDBUS_PAYLOAD_DBUS1;
119 m->kdbus->cookie = m->header->serial;
120
121 m->kdbus->timeout_ns = m->timeout * NSEC_PER_USEC;
122
123 d = m->kdbus->data;
124
125 if (well_known)
126 append_destination(&d, m->destination, dl);
127
128 append_payload_vec(&d, m->header, sizeof(*m->header));
129
130 if (m->fields) {
131 append_payload_vec(&d, m->fields, m->header->fields_size);
132
133 if (m->header->fields_size % 8 != 0) {
134 static const uint8_t padding[7] = {};
135
136 append_payload_vec(&d, padding, 8 - (m->header->fields_size % 8));
137 }
138 }
139
140 if (m->body)
141 append_payload_vec(&d, m->body, m->header->body_size);
142
143 m->kdbus->size = (uint8_t*) m - (uint8_t*) m->kdbus;
144 assert(m->kdbus->size <= sz);
145
146 return 0;
147 }
148
149 int bus_kernel_take_fd(sd_bus *b) {
150 struct kdbus_cmd_hello hello = {};
151 int r;
152
153 assert(b);
154
155 r = ioctl(b->input_fd, KDBUS_CMD_HELLO, &hello);
156 if (r < 0)
157 return -errno;
158
159 if (asprintf(&b->unique_name, ":1.%llu", (unsigned long long) hello.id) < 0)
160 return -ENOMEM;
161
162 b->is_kernel = true;
163
164 r = bus_start_running(b);
165 if (r < 0)
166 return r;
167
168 return 1;
169 }
170
171 int bus_kernel_connect(sd_bus *b) {
172 assert(b);
173 assert(b->input_fd < 0);
174 assert(b->output_fd < 0);
175 assert(b->kernel);
176
177 b->input_fd = open(b->kernel, O_RDWR|O_NOCTTY|O_CLOEXEC);
178 if (b->input_fd < 0)
179 return -errno;
180
181 b->output_fd = b->input_fd;
182
183 return bus_kernel_take_fd(b);
184 }
185
186 int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m) {
187 int r;
188
189 assert(bus);
190 assert(m);
191 assert(bus->state == BUS_RUNNING);
192
193 r = bus_message_setup_kmsg(m);
194 if (r < 0)
195 return r;
196
197 r = ioctl(bus->output_fd, KDBUS_CMD_MSG_SEND, m->kdbus);
198 if (r < 0)
199 return errno == EAGAIN ? 0 : -errno;
200
201 return 0;
202 }
203
204 static void close_kdbus_msg(struct kdbus_msg *k) {
205 struct kdbus_msg_data *d;
206
207 KDBUS_MSG_FOREACH_DATA(d, k) {
208
209 if (d->type != KDBUS_MSG_UNIX_FDS)
210 continue;
211
212 close_many(d->fds, (d->size - offsetof(struct kdbus_msg_data, fds)) / sizeof(int));
213 }
214 }
215
216 static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k, sd_bus_message **ret) {
217 sd_bus_message *m = NULL;
218 struct kdbus_msg_data *d;
219 unsigned n_payload = 0, n_fds = 0;
220 _cleanup_free_ int *fds = NULL;
221 struct bus_header *h = NULL;
222 size_t total, n_bytes = 0, idx = 0;
223 int r;
224
225 assert(bus);
226 assert(k);
227 assert(ret);
228
229 if (k->payload_type != KDBUS_PAYLOAD_DBUS1)
230 return 0;
231
232 KDBUS_MSG_FOREACH_DATA(d, k) {
233 size_t l;
234
235 l = d->size - offsetof(struct kdbus_msg_data, data);
236
237 if (d->type == KDBUS_MSG_PAYLOAD) {
238
239 if (!h) {
240 if (l < sizeof(struct bus_header))
241 return -EBADMSG;
242
243 h = (struct bus_header*) d->data;
244 }
245
246 n_payload++;
247 n_bytes += l;
248
249 } else if (d->type == KDBUS_MSG_UNIX_FDS) {
250 int *f;
251 unsigned j;
252
253 j = l / sizeof(int);
254 f = realloc(fds, sizeof(int) * (n_fds + j));
255 if (!f)
256 return -ENOMEM;
257
258 fds = f;
259 memcpy(fds + n_fds, d->fds, j);
260 n_fds += j;
261 }
262 }
263
264 if (!h)
265 return -EBADMSG;
266
267 r = bus_header_size(h, &total);
268 if (r < 0)
269 return r;
270
271 if (n_bytes != total)
272 return -EBADMSG;
273
274 r = bus_message_from_header(h, sizeof(struct bus_header), fds, n_fds, NULL, NULL, 0, &m);
275 if (r < 0)
276 return r;
277
278 KDBUS_MSG_FOREACH_DATA(d, k) {
279 size_t l;
280
281 if (d->type != KDBUS_MSG_PAYLOAD)
282 continue;
283
284 l = d->size - offsetof(struct kdbus_msg_data, data);
285
286 if (idx == sizeof(struct bus_header) &&
287 l == BUS_MESSAGE_FIELDS_SIZE(m))
288 m->fields = d->data;
289 else if (idx == sizeof(struct bus_header) + ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m)) &&
290 l == BUS_MESSAGE_BODY_SIZE(m))
291 m->body = d->data;
292 else {
293 sd_bus_message_unref(m);
294 return -EBADMSG;
295 }
296
297 idx += l;
298 }
299
300 r = bus_message_parse_fields(m);
301 if (r < 0) {
302 sd_bus_message_unref(m);
303 return r;
304 }
305
306 /* We take possession of the kmsg struct now */
307 m->kdbus = k;
308 m->free_kdbus = true;
309 m->free_fds = true;
310
311 fds = NULL;
312
313 *ret = m;
314 return 1;
315 }
316
317 int bus_kernel_read_message(sd_bus *bus, sd_bus_message **m) {
318 struct kdbus_msg *k;
319 size_t sz = 128;
320 int r;
321
322 assert(bus);
323 assert(m);
324
325 for (;;) {
326 void *q;
327
328 q = realloc(bus->rbuffer, sz);
329 if (!q)
330 return -errno;
331
332 k = bus->rbuffer = q;
333 k->size = sz;
334
335 r = ioctl(bus->input_fd, KDBUS_CMD_MSG_RECV, bus->rbuffer);
336 if (r >= 0)
337 break;
338
339 if (errno == EAGAIN)
340 return 0;
341
342 if (errno != EMSGSIZE)
343 return -errno;
344
345 sz *= 2;
346 }
347
348 r = bus_kernel_make_message(bus, k, m);
349 if (r > 0)
350 bus->rbuffer = NULL;
351 else
352 close_kdbus_msg(k);
353
354 return r;
355 }
356
357 int bus_kernel_create(const char *name, char **s) {
358 struct kdbus_cmd_fname *fname;
359 size_t l;
360 int fd;
361 char *p;
362
363 assert(name);
364 assert(s);
365
366 fd = open("/dev/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC);
367 if (fd < 0)
368 return -errno;
369
370 l = strlen(name);
371 fname = alloca(offsetof(struct kdbus_cmd_fname, name) + DECIMAL_STR_MAX(uid_t) + 1 + l + 1);
372 sprintf(fname->name, "%lu-%s", (unsigned long) getuid(), name);
373 fname->size = offsetof(struct kdbus_cmd_fname, name) + strlen(fname->name) + 1;
374 fname->kernel_flags = KDBUS_CMD_FNAME_ACCESS_WORLD;
375 fname->user_flags = 0;
376
377 p = strjoin("/dev/kdbus/", fname->name, "/bus", NULL);
378 if (!p)
379 return -ENOMEM;
380
381 if (ioctl(fd, KDBUS_CMD_BUS_MAKE, fname) < 0) {
382 close_nointr_nofail(fd);
383 free(p);
384 return -errno;
385 }
386
387 if (s)
388 *s = p;
389
390 return fd;
391 }