]> git.proxmox.com Git - systemd.git/blame - src/machine/machine-dbus.c
Imported Upstream version 218
[systemd.git] / src / machine / machine-dbus.c
CommitLineData
14228c0d
MB
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2011 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 <errno.h>
23#include <string.h>
60f067b4
JS
24#include <sys/capability.h>
25#include <arpa/inet.h>
14228c0d 26
60f067b4
JS
27#include "bus-util.h"
28#include "bus-label.h"
29#include "strv.h"
f47781d8 30#include "bus-common-errors.h"
e842803a
MB
31#include "copy.h"
32#include "fileio.h"
5eef597e
MP
33#include "in-addr-util.h"
34#include "local-addresses.h"
e842803a 35#include "machine.h"
60f067b4
JS
36
37static int property_get_id(
38 sd_bus *bus,
39 const char *path,
40 const char *interface,
41 const char *property,
42 sd_bus_message *reply,
43 void *userdata,
44 sd_bus_error *error) {
45
46 Machine *m = userdata;
47 int r;
14228c0d 48
60f067b4
JS
49 assert(bus);
50 assert(reply);
51 assert(m);
14228c0d 52
60f067b4
JS
53 r = sd_bus_message_append_array(reply, 'y', &m->id, 16);
54 if (r < 0)
55 return r;
14228c0d 56
60f067b4 57 return 1;
14228c0d
MB
58}
59
60f067b4
JS
60static int property_get_state(
61 sd_bus *bus,
62 const char *path,
63 const char *interface,
64 const char *property,
65 sd_bus_message *reply,
66 void *userdata,
67 sd_bus_error *error) {
68
69 Machine *m = userdata;
14228c0d 70 const char *state;
60f067b4 71 int r;
14228c0d 72
60f067b4
JS
73 assert(bus);
74 assert(reply);
14228c0d
MB
75 assert(m);
76
77 state = machine_state_to_string(machine_get_state(m));
78
60f067b4
JS
79 r = sd_bus_message_append_basic(reply, 's', state);
80 if (r < 0)
81 return r;
14228c0d 82
60f067b4 83 return 1;
14228c0d
MB
84}
85
5eef597e
MP
86static int property_get_netif(
87 sd_bus *bus,
88 const char *path,
89 const char *interface,
90 const char *property,
91 sd_bus_message *reply,
92 void *userdata,
93 sd_bus_error *error) {
94
95 Machine *m = userdata;
96 int r;
97
98 assert(bus);
99 assert(reply);
100 assert(m);
101
102 assert_cc(sizeof(int) == sizeof(int32_t));
103
104 r = sd_bus_message_append_array(reply, 'i', m->netif, m->n_netif * sizeof(int));
105 if (r < 0)
106 return r;
107
108 return 1;
109}
110
60f067b4
JS
111static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class, machine_class, MachineClass);
112
113int bus_machine_method_terminate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
114 Machine *m = userdata;
115 int r;
14228c0d 116
60f067b4
JS
117 assert(bus);
118 assert(message);
14228c0d 119 assert(m);
14228c0d 120
60f067b4
JS
121 r = machine_stop(m);
122 if (r < 0)
123 return r;
14228c0d 124
60f067b4
JS
125 return sd_bus_reply_method_return(message, NULL);
126}
14228c0d 127
60f067b4
JS
128int bus_machine_method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
129 Machine *m = userdata;
130 const char *swho;
131 int32_t signo;
132 KillWho who;
133 int r;
14228c0d 134
60f067b4
JS
135 assert(bus);
136 assert(message);
137 assert(m);
14228c0d 138
60f067b4
JS
139 r = sd_bus_message_read(message, "si", &swho, &signo);
140 if (r < 0)
141 return r;
142
143 if (isempty(swho))
144 who = KILL_ALL;
145 else {
146 who = kill_who_from_string(swho);
147 if (who < 0)
148 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
149 }
150
151 if (signo <= 0 || signo >= _NSIG)
152 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
14228c0d 153
60f067b4
JS
154 r = machine_kill(m, who, signo);
155 if (r < 0)
156 return r;
157
158 return sd_bus_reply_method_return(message, NULL);
159}
14228c0d 160
60f067b4
JS
161int bus_machine_method_get_addresses(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
162 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
163 _cleanup_close_pair_ int pair[2] = { -1, -1 };
164 _cleanup_free_ char *us = NULL, *them = NULL;
165 _cleanup_close_ int netns_fd = -1;
166 Machine *m = userdata;
167 const char *p;
168 siginfo_t si;
169 pid_t child;
14228c0d
MB
170 int r;
171
60f067b4 172 assert(bus);
14228c0d 173 assert(message);
60f067b4
JS
174 assert(m);
175
176 r = readlink_malloc("/proc/self/ns/net", &us);
177 if (r < 0)
178 return sd_bus_error_set_errno(error, r);
179
180 p = procfs_file_alloca(m->leader, "ns/net");
181 r = readlink_malloc(p, &them);
182 if (r < 0)
183 return sd_bus_error_set_errno(error, r);
14228c0d 184
60f067b4
JS
185 if (streq(us, them))
186 return sd_bus_error_setf(error, BUS_ERROR_NO_PRIVATE_NETWORKING, "Machine %s does not use private networking", m->name);
14228c0d 187
60f067b4
JS
188 r = namespace_open(m->leader, NULL, NULL, &netns_fd, NULL);
189 if (r < 0)
190 return sd_bus_error_set_errno(error, r);
191
192 if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
193 return sd_bus_error_set_errno(error, -errno);
194
195 child = fork();
196 if (child < 0)
197 return sd_bus_error_set_errno(error, -errno);
198
199 if (child == 0) {
5eef597e
MP
200 _cleanup_free_ struct local_address *addresses = NULL;
201 struct local_address *a;
202 int i, n;
60f067b4
JS
203
204 pair[0] = safe_close(pair[0]);
205
206 r = namespace_enter(-1, -1, netns_fd, -1);
14228c0d 207 if (r < 0)
60f067b4 208 _exit(EXIT_FAILURE);
14228c0d 209
f47781d8 210 n = local_addresses(NULL, 0, AF_UNSPEC, &addresses);
5eef597e 211 if (n < 0)
60f067b4 212 _exit(EXIT_FAILURE);
14228c0d 213
5eef597e
MP
214 for (a = addresses, i = 0; i < n; a++, i++) {
215 struct iovec iov[2] = {
216 { .iov_base = &a->family, .iov_len = sizeof(a->family) },
217 { .iov_base = &a->address, .iov_len = FAMILY_ADDRESS_SIZE(a->family) },
218 };
60f067b4
JS
219
220 r = writev(pair[1], iov, 2);
221 if (r < 0)
222 _exit(EXIT_FAILURE);
223 }
224
5eef597e
MP
225 pair[1] = safe_close(pair[1]);
226
60f067b4 227 _exit(EXIT_SUCCESS);
14228c0d
MB
228 }
229
60f067b4
JS
230 pair[1] = safe_close(pair[1]);
231
232 r = sd_bus_message_new_method_return(message, &reply);
233 if (r < 0)
234 return sd_bus_error_set_errno(error, r);
235
5eef597e 236 r = sd_bus_message_open_container(reply, 'a', "(iay)");
60f067b4
JS
237 if (r < 0)
238 return sd_bus_error_set_errno(error, r);
239
240 for (;;) {
5eef597e 241 int family;
60f067b4 242 ssize_t n;
5eef597e 243 union in_addr_union in_addr;
60f067b4
JS
244 struct iovec iov[2];
245 struct msghdr mh = {
246 .msg_iov = iov,
247 .msg_iovlen = 2,
248 };
14228c0d 249
60f067b4
JS
250 iov[0] = (struct iovec) { .iov_base = &family, .iov_len = sizeof(family) };
251 iov[1] = (struct iovec) { .iov_base = &in_addr, .iov_len = sizeof(in_addr) };
14228c0d 252
60f067b4
JS
253 n = recvmsg(pair[0], &mh, 0);
254 if (n < 0)
255 return sd_bus_error_set_errno(error, -errno);
256 if ((size_t) n < sizeof(family))
257 break;
14228c0d 258
5eef597e 259 r = sd_bus_message_open_container(reply, 'r', "iay");
60f067b4
JS
260 if (r < 0)
261 return sd_bus_error_set_errno(error, r);
14228c0d 262
5eef597e 263 r = sd_bus_message_append(reply, "i", family);
60f067b4
JS
264 if (r < 0)
265 return sd_bus_error_set_errno(error, r);
14228c0d 266
60f067b4 267 switch (family) {
14228c0d 268
60f067b4
JS
269 case AF_INET:
270 if (n != sizeof(struct in_addr) + sizeof(family))
271 return sd_bus_error_set_errno(error, EIO);
14228c0d 272
60f067b4
JS
273 r = sd_bus_message_append_array(reply, 'y', &in_addr.in, sizeof(in_addr.in));
274 break;
14228c0d 275
60f067b4
JS
276 case AF_INET6:
277 if (n != sizeof(struct in6_addr) + sizeof(family))
278 return sd_bus_error_set_errno(error, EIO);
279
280 r = sd_bus_message_append_array(reply, 'y', &in_addr.in6, sizeof(in_addr.in6));
281 break;
14228c0d 282 }
60f067b4
JS
283 if (r < 0)
284 return sd_bus_error_set_errno(error, r);
14228c0d 285
60f067b4
JS
286 r = sd_bus_message_close_container(reply);
287 if (r < 0)
288 return sd_bus_error_set_errno(error, r);
14228c0d
MB
289 }
290
60f067b4
JS
291 r = wait_for_terminate(child, &si);
292 if (r < 0)
293 return sd_bus_error_set_errno(error, r);
294 if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
295 return sd_bus_error_set_errno(error, EIO);
296
297 r = sd_bus_message_close_container(reply);
298 if (r < 0)
299 return sd_bus_error_set_errno(error, r);
300
301 return sd_bus_send(bus, reply, NULL);
14228c0d
MB
302}
303
e842803a
MB
304int bus_machine_method_get_os_release(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
305 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
306 _cleanup_close_ int mntns_fd = -1, root_fd = -1;
307 _cleanup_close_pair_ int pair[2] = { -1, -1 };
308 _cleanup_strv_free_ char **l = NULL;
309 _cleanup_fclose_ FILE *f = NULL;
310 Machine *m = userdata;
311 char **k, **v;
312 siginfo_t si;
313 pid_t child;
314 int r;
315
316 assert(bus);
317 assert(message);
318 assert(m);
319
320 r = namespace_open(m->leader, NULL, &mntns_fd, NULL, &root_fd);
321 if (r < 0)
322 return sd_bus_error_set_errno(error, r);
323
324 if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
325 return sd_bus_error_set_errno(error, -errno);
326
327 child = fork();
328 if (child < 0)
329 return sd_bus_error_set_errno(error, -errno);
330
331 if (child == 0) {
332 _cleanup_close_ int fd = -1;
333
334 pair[0] = safe_close(pair[0]);
335
336 r = namespace_enter(-1, mntns_fd, -1, root_fd);
337 if (r < 0)
338 _exit(EXIT_FAILURE);
339
340 fd = open("/etc/os-release", O_RDONLY|O_CLOEXEC);
341 if (fd < 0) {
342 fd = open("/usr/lib/os-release", O_RDONLY|O_CLOEXEC);
343 if (fd < 0)
344 _exit(EXIT_FAILURE);
345 }
346
347 r = copy_bytes(fd, pair[1], (off_t) -1);
348 if (r < 0)
349 _exit(EXIT_FAILURE);
350
351 _exit(EXIT_SUCCESS);
352 }
353
354 pair[1] = safe_close(pair[1]);
355
356 f = fdopen(pair[0], "re");
357 if (!f)
358 return sd_bus_error_set_errno(error, -errno);
359
360 pair[0] = -1;
361
362 r = load_env_file_pairs(f, "/etc/os-release", NULL, &l);
363 if (r < 0)
364 return sd_bus_error_set_errno(error, r);
365
366 r = wait_for_terminate(child, &si);
367 if (r < 0)
368 return sd_bus_error_set_errno(error, r);
369 if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
370 return sd_bus_error_set_errno(error, EIO);
371
372 r = sd_bus_message_new_method_return(message, &reply);
373 if (r < 0)
374 return sd_bus_error_set_errno(error, r);
375
376 r = sd_bus_message_open_container(reply, 'a', "{ss}");
377 if (r < 0)
378 return sd_bus_error_set_errno(error, r);
379
380 STRV_FOREACH_PAIR(k, v, l) {
381 r = sd_bus_message_append(reply, "{ss}", *k, *v);
382 if (r < 0)
383 return sd_bus_error_set_errno(error, r);
384 }
385
386 r = sd_bus_message_close_container(reply);
387 if (r < 0)
388 return sd_bus_error_set_errno(error, r);
389
390 return sd_bus_send(bus, reply, NULL);
391}
392
60f067b4
JS
393const sd_bus_vtable machine_vtable[] = {
394 SD_BUS_VTABLE_START(0),
395 SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Machine, name), SD_BUS_VTABLE_PROPERTY_CONST),
396 SD_BUS_PROPERTY("Id", "ay", property_get_id, 0, SD_BUS_VTABLE_PROPERTY_CONST),
397 BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Machine, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
398 SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Machine, service), SD_BUS_VTABLE_PROPERTY_CONST),
399 SD_BUS_PROPERTY("Unit", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST),
400 SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
401 SD_BUS_PROPERTY("Leader", "u", NULL, offsetof(Machine, leader), SD_BUS_VTABLE_PROPERTY_CONST),
402 SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Machine, class), SD_BUS_VTABLE_PROPERTY_CONST),
403 SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(Machine, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
5eef597e 404 SD_BUS_PROPERTY("NetworkInterfaces", "ai", property_get_netif, 0, SD_BUS_VTABLE_PROPERTY_CONST),
60f067b4
JS
405 SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
406 SD_BUS_METHOD("Terminate", NULL, NULL, bus_machine_method_terminate, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
407 SD_BUS_METHOD("Kill", "si", NULL, bus_machine_method_kill, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
5eef597e 408 SD_BUS_METHOD("GetAddresses", NULL, "a(iay)", bus_machine_method_get_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
e842803a
MB
409 SD_BUS_METHOD("GetOSRelease", NULL, "a{ss}", bus_machine_method_get_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
410 SD_BUS_VTABLE_END
14228c0d
MB
411};
412
60f067b4
JS
413int machine_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
414 Manager *m = userdata;
415 Machine *machine;
416 int r;
417
418 assert(bus);
419 assert(path);
420 assert(interface);
421 assert(found);
422 assert(m);
423
424 if (streq(path, "/org/freedesktop/machine1/machine/self")) {
425 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
426 sd_bus_message *message;
427 pid_t pid;
428
429 message = sd_bus_get_current_message(bus);
430 if (!message)
431 return 0;
432
433 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
434 if (r < 0)
435 return r;
436
437 r = sd_bus_creds_get_pid(creds, &pid);
438 if (r < 0)
439 return r;
440
441 r = manager_get_machine_by_pid(m, pid, &machine);
442 if (r <= 0)
443 return 0;
444 } else {
445 _cleanup_free_ char *e = NULL;
446 const char *p;
447
448 p = startswith(path, "/org/freedesktop/machine1/machine/");
449 if (!p)
450 return 0;
451
452 e = bus_label_unescape(p);
453 if (!e)
454 return -ENOMEM;
455
456 machine = hashmap_get(m->machines, e);
457 if (!machine)
458 return 0;
459 }
460
461 *found = machine;
462 return 1;
463}
464
14228c0d
MB
465char *machine_bus_path(Machine *m) {
466 _cleanup_free_ char *e = NULL;
467
468 assert(m);
469
60f067b4 470 e = bus_label_escape(m->name);
14228c0d
MB
471 if (!e)
472 return NULL;
473
474 return strappend("/org/freedesktop/machine1/machine/", e);
475}
476
60f067b4
JS
477int machine_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
478 _cleanup_strv_free_ char **l = NULL;
479 Machine *machine = NULL;
480 Manager *m = userdata;
481 Iterator i;
482 int r;
14228c0d 483
60f067b4
JS
484 assert(bus);
485 assert(path);
486 assert(nodes);
14228c0d 487
60f067b4
JS
488 HASHMAP_FOREACH(machine, m->machines, i) {
489 char *p;
14228c0d 490
60f067b4
JS
491 p = machine_bus_path(machine);
492 if (!p)
493 return -ENOMEM;
14228c0d 494
60f067b4
JS
495 r = strv_consume(&l, p);
496 if (r < 0)
497 return r;
498 }
14228c0d 499
60f067b4
JS
500 *nodes = l;
501 l = NULL;
14228c0d 502
60f067b4 503 return 1;
14228c0d
MB
504}
505
60f067b4 506int machine_send_signal(Machine *m, bool new_machine) {
14228c0d
MB
507 _cleanup_free_ char *p = NULL;
508
509 assert(m);
510
14228c0d
MB
511 p = machine_bus_path(m);
512 if (!p)
513 return -ENOMEM;
514
60f067b4
JS
515 return sd_bus_emit_signal(
516 m->manager->bus,
517 "/org/freedesktop/machine1",
518 "org.freedesktop.machine1.Manager",
519 new_machine ? "MachineNew" : "MachineRemoved",
520 "so", m->name, p);
14228c0d
MB
521}
522
60f067b4
JS
523int machine_send_create_reply(Machine *m, sd_bus_error *error) {
524 _cleanup_bus_message_unref_ sd_bus_message *c = NULL;
525 _cleanup_free_ char *p = NULL;
14228c0d
MB
526
527 assert(m);
528
529 if (!m->create_message)
530 return 0;
531
60f067b4
JS
532 c = m->create_message;
533 m->create_message = NULL;
14228c0d 534
60f067b4
JS
535 if (error)
536 return sd_bus_reply_method_error(c, error);
14228c0d
MB
537
538 /* Update the machine state file before we notify the client
539 * about the result. */
540 machine_save(m);
541
60f067b4
JS
542 p = machine_bus_path(m);
543 if (!p)
544 return -ENOMEM;
14228c0d 545
60f067b4 546 return sd_bus_reply_method_return(c, "o", p);
14228c0d 547}