]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/machine/machine-dbus.c
machined: introduce polkit for OpenLogin() call
[thirdparty/systemd.git] / src / machine / machine-dbus.c
CommitLineData
9444b1f2
LP
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>
556089dc 24#include <sys/capability.h>
878cd7e9 25#include <arpa/inet.h>
9444b1f2 26
c3350683 27#include "bus-util.h"
a6278b88 28#include "bus-label.h"
927b1649 29#include "strv.h"
96aad8d1 30#include "bus-common-errors.h"
717603e3
LP
31#include "copy.h"
32#include "fileio.h"
3b653205 33#include "in-addr-util.h"
496a5a69 34#include "local-addresses.h"
5f8cc96a
LP
35#include "path-util.h"
36#include "bus-internal.h"
717603e3 37#include "machine.h"
9444b1f2 38
c3350683
LP
39static int property_get_id(
40 sd_bus *bus,
41 const char *path,
42 const char *interface,
43 const char *property,
44 sd_bus_message *reply,
ebcf1f97
LP
45 void *userdata,
46 sd_bus_error *error) {
9444b1f2 47
c3350683
LP
48 Machine *m = userdata;
49 int r;
9444b1f2 50
c3350683
LP
51 assert(bus);
52 assert(reply);
53 assert(m);
54
55 r = sd_bus_message_append_array(reply, 'y', &m->id, 16);
56 if (r < 0)
57 return r;
9444b1f2 58
c3350683 59 return 1;
9444b1f2
LP
60}
61
c3350683
LP
62static int property_get_state(
63 sd_bus *bus,
64 const char *path,
65 const char *interface,
66 const char *property,
67 sd_bus_message *reply,
ebcf1f97
LP
68 void *userdata,
69 sd_bus_error *error) {
c3350683
LP
70
71 Machine *m = userdata;
fb6becb4 72 const char *state;
c3350683 73 int r;
fb6becb4 74
c3350683
LP
75 assert(bus);
76 assert(reply);
fb6becb4
LP
77 assert(m);
78
79 state = machine_state_to_string(machine_get_state(m));
80
c3350683
LP
81 r = sd_bus_message_append_basic(reply, 's', state);
82 if (r < 0)
83 return r;
fb6becb4 84
c3350683 85 return 1;
fb6becb4
LP
86}
87
9b5ed6fe
LP
88static int property_get_netif(
89 sd_bus *bus,
90 const char *path,
91 const char *interface,
92 const char *property,
93 sd_bus_message *reply,
94 void *userdata,
95 sd_bus_error *error) {
96
97 Machine *m = userdata;
98 int r;
99
100 assert(bus);
101 assert(reply);
102 assert(m);
103
104 assert_cc(sizeof(int) == sizeof(int32_t));
105
106 r = sd_bus_message_append_array(reply, 'i', m->netif, m->n_netif * sizeof(int));
107 if (r < 0)
108 return r;
109
110 return 1;
111}
112
c3350683 113static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class, machine_class, MachineClass);
9444b1f2 114
878cd7e9 115int bus_machine_method_terminate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
116 Machine *m = userdata;
117 int r;
9444b1f2 118
c3350683
LP
119 assert(bus);
120 assert(message);
121 assert(m);
9444b1f2 122
c3350683
LP
123 r = machine_stop(m);
124 if (r < 0)
ebcf1f97 125 return r;
9444b1f2 126
df2d202e 127 return sd_bus_reply_method_return(message, NULL);
9444b1f2
LP
128}
129
878cd7e9 130int bus_machine_method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
131 Machine *m = userdata;
132 const char *swho;
133 int32_t signo;
134 KillWho who;
9444b1f2
LP
135 int r;
136
c3350683 137 assert(bus);
9444b1f2 138 assert(message);
c3350683 139 assert(m);
9444b1f2 140
c3350683
LP
141 r = sd_bus_message_read(message, "si", &swho, &signo);
142 if (r < 0)
ebcf1f97 143 return r;
9444b1f2 144
c3350683
LP
145 if (isempty(swho))
146 who = KILL_ALL;
147 else {
148 who = kill_who_from_string(swho);
149 if (who < 0)
ebcf1f97 150 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
9444b1f2
LP
151 }
152
c3350683 153 if (signo <= 0 || signo >= _NSIG)
ebcf1f97 154 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
9444b1f2 155
c3350683
LP
156 r = machine_kill(m, who, signo);
157 if (r < 0)
ebcf1f97 158 return r;
9444b1f2 159
df2d202e 160 return sd_bus_reply_method_return(message, NULL);
9444b1f2
LP
161}
162
878cd7e9
LP
163int bus_machine_method_get_addresses(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
164 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
165 _cleanup_close_pair_ int pair[2] = { -1, -1 };
166 _cleanup_free_ char *us = NULL, *them = NULL;
167 _cleanup_close_ int netns_fd = -1;
168 Machine *m = userdata;
169 const char *p;
170 siginfo_t si;
171 pid_t child;
172 int r;
173
174 assert(bus);
175 assert(message);
176 assert(m);
177
178 r = readlink_malloc("/proc/self/ns/net", &us);
179 if (r < 0)
180 return sd_bus_error_set_errno(error, r);
181
182 p = procfs_file_alloca(m->leader, "ns/net");
183 r = readlink_malloc(p, &them);
184 if (r < 0)
185 return sd_bus_error_set_errno(error, r);
186
187 if (streq(us, them))
188 return sd_bus_error_setf(error, BUS_ERROR_NO_PRIVATE_NETWORKING, "Machine %s does not use private networking", m->name);
189
190 r = namespace_open(m->leader, NULL, NULL, &netns_fd, NULL);
191 if (r < 0)
192 return sd_bus_error_set_errno(error, r);
193
194 if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
195 return sd_bus_error_set_errno(error, -errno);
196
197 child = fork();
198 if (child < 0)
199 return sd_bus_error_set_errno(error, -errno);
200
201 if (child == 0) {
496a5a69
LP
202 _cleanup_free_ struct local_address *addresses = NULL;
203 struct local_address *a;
204 int i, n;
878cd7e9
LP
205
206 pair[0] = safe_close(pair[0]);
207
208 r = namespace_enter(-1, -1, netns_fd, -1);
209 if (r < 0)
210 _exit(EXIT_FAILURE);
211
1d050e1e 212 n = local_addresses(NULL, 0, AF_UNSPEC, &addresses);
496a5a69 213 if (n < 0)
878cd7e9
LP
214 _exit(EXIT_FAILURE);
215
496a5a69
LP
216 for (a = addresses, i = 0; i < n; a++, i++) {
217 struct iovec iov[2] = {
218 { .iov_base = &a->family, .iov_len = sizeof(a->family) },
9d485985 219 { .iov_base = &a->address, .iov_len = FAMILY_ADDRESS_SIZE(a->family) },
496a5a69 220 };
878cd7e9
LP
221
222 r = writev(pair[1], iov, 2);
223 if (r < 0)
224 _exit(EXIT_FAILURE);
225 }
226
496a5a69
LP
227 pair[1] = safe_close(pair[1]);
228
878cd7e9
LP
229 _exit(EXIT_SUCCESS);
230 }
231
232 pair[1] = safe_close(pair[1]);
233
234 r = sd_bus_message_new_method_return(message, &reply);
235 if (r < 0)
236 return sd_bus_error_set_errno(error, r);
237
0dd25fb9 238 r = sd_bus_message_open_container(reply, 'a', "(iay)");
878cd7e9
LP
239 if (r < 0)
240 return sd_bus_error_set_errno(error, r);
241
242 for (;;) {
0dd25fb9 243 int family;
878cd7e9 244 ssize_t n;
bb62fb68 245 union in_addr_union in_addr;
878cd7e9
LP
246 struct iovec iov[2];
247 struct msghdr mh = {
248 .msg_iov = iov,
249 .msg_iovlen = 2,
250 };
251
252 iov[0] = (struct iovec) { .iov_base = &family, .iov_len = sizeof(family) };
253 iov[1] = (struct iovec) { .iov_base = &in_addr, .iov_len = sizeof(in_addr) };
254
255 n = recvmsg(pair[0], &mh, 0);
256 if (n < 0)
257 return sd_bus_error_set_errno(error, -errno);
258 if ((size_t) n < sizeof(family))
259 break;
260
0dd25fb9 261 r = sd_bus_message_open_container(reply, 'r', "iay");
878cd7e9
LP
262 if (r < 0)
263 return sd_bus_error_set_errno(error, r);
264
0dd25fb9 265 r = sd_bus_message_append(reply, "i", family);
878cd7e9
LP
266 if (r < 0)
267 return sd_bus_error_set_errno(error, r);
268
269 switch (family) {
270
271 case AF_INET:
272 if (n != sizeof(struct in_addr) + sizeof(family))
273 return sd_bus_error_set_errno(error, EIO);
274
275 r = sd_bus_message_append_array(reply, 'y', &in_addr.in, sizeof(in_addr.in));
276 break;
277
278 case AF_INET6:
279 if (n != sizeof(struct in6_addr) + sizeof(family))
280 return sd_bus_error_set_errno(error, EIO);
281
282 r = sd_bus_message_append_array(reply, 'y', &in_addr.in6, sizeof(in_addr.in6));
283 break;
284 }
285 if (r < 0)
286 return sd_bus_error_set_errno(error, r);
287
288 r = sd_bus_message_close_container(reply);
289 if (r < 0)
290 return sd_bus_error_set_errno(error, r);
291 }
292
293 r = wait_for_terminate(child, &si);
294 if (r < 0)
295 return sd_bus_error_set_errno(error, r);
296 if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
297 return sd_bus_error_set_errno(error, EIO);
298
299 r = sd_bus_message_close_container(reply);
300 if (r < 0)
301 return sd_bus_error_set_errno(error, r);
302
303 return sd_bus_send(bus, reply, NULL);
304}
305
717603e3
LP
306int bus_machine_method_get_os_release(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
307 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
308 _cleanup_close_ int mntns_fd = -1, root_fd = -1;
309 _cleanup_close_pair_ int pair[2] = { -1, -1 };
310 _cleanup_strv_free_ char **l = NULL;
311 _cleanup_fclose_ FILE *f = NULL;
312 Machine *m = userdata;
313 char **k, **v;
314 siginfo_t si;
315 pid_t child;
316 int r;
317
318 assert(bus);
319 assert(message);
320 assert(m);
321
322 r = namespace_open(m->leader, NULL, &mntns_fd, NULL, &root_fd);
323 if (r < 0)
40205d70 324 return r;
717603e3
LP
325
326 if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
40205d70 327 return -errno;
717603e3
LP
328
329 child = fork();
330 if (child < 0)
40205d70 331 return -errno;
717603e3
LP
332
333 if (child == 0) {
334 _cleanup_close_ int fd = -1;
335
336 pair[0] = safe_close(pair[0]);
337
338 r = namespace_enter(-1, mntns_fd, -1, root_fd);
339 if (r < 0)
340 _exit(EXIT_FAILURE);
341
342 fd = open("/etc/os-release", O_RDONLY|O_CLOEXEC);
343 if (fd < 0) {
344 fd = open("/usr/lib/os-release", O_RDONLY|O_CLOEXEC);
345 if (fd < 0)
346 _exit(EXIT_FAILURE);
347 }
348
7430ec6a 349 r = copy_bytes(fd, pair[1], (off_t) -1, false);
717603e3
LP
350 if (r < 0)
351 _exit(EXIT_FAILURE);
352
353 _exit(EXIT_SUCCESS);
354 }
355
356 pair[1] = safe_close(pair[1]);
357
358 f = fdopen(pair[0], "re");
359 if (!f)
40205d70 360 return -errno;
717603e3
LP
361
362 pair[0] = -1;
363
364 r = load_env_file_pairs(f, "/etc/os-release", NULL, &l);
365 if (r < 0)
40205d70 366 return r;
717603e3
LP
367
368 r = wait_for_terminate(child, &si);
369 if (r < 0)
40205d70 370 return r;
717603e3 371 if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
40205d70 372 return -EIO;
717603e3
LP
373
374 r = sd_bus_message_new_method_return(message, &reply);
375 if (r < 0)
40205d70 376 return r;
717603e3
LP
377
378 r = sd_bus_message_open_container(reply, 'a', "{ss}");
379 if (r < 0)
40205d70 380 return r;
717603e3
LP
381
382 STRV_FOREACH_PAIR(k, v, l) {
383 r = sd_bus_message_append(reply, "{ss}", *k, *v);
384 if (r < 0)
40205d70 385 return r;
717603e3
LP
386 }
387
388 r = sd_bus_message_close_container(reply);
389 if (r < 0)
40205d70
LP
390 return r;
391
392 return sd_bus_send(bus, reply, NULL);
393}
394
395int bus_machine_method_open_pty(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
40205d70 396 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
5f8cc96a 397 _cleanup_free_ char *pty_name = NULL;
40205d70 398 _cleanup_close_ int master = -1;
40205d70 399 Machine *m = userdata;
40205d70
LP
400 int r;
401
402 assert(bus);
403 assert(message);
404 assert(m);
405
5f8cc96a
LP
406 master = openpt_in_namespace(m->leader, O_RDWR|O_NOCTTY|O_CLOEXEC);
407 if (master < 0)
408 return master;
409
410 r = ptsname_malloc(master, &pty_name);
40205d70
LP
411 if (r < 0)
412 return r;
413
5f8cc96a
LP
414 r = sd_bus_message_new_method_return(message, &reply);
415 if (r < 0)
416 return r;
40205d70 417
5f8cc96a
LP
418 r = sd_bus_message_append(reply, "hs", master, pty_name);
419 if (r < 0)
420 return r;
40205d70 421
5f8cc96a
LP
422 return sd_bus_send(bus, reply, NULL);
423}
40205d70 424
5f8cc96a
LP
425int bus_machine_method_open_login(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
426 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
427 _cleanup_free_ char *pty_name = NULL, *getty = NULL;
428 _cleanup_bus_unref_ sd_bus *container_bus = NULL;
429 _cleanup_close_ int master = -1;
430 Machine *m = userdata;
431 const char *p;
432 int r;
40205d70 433
d04c1fb8
LP
434 r = bus_verify_polkit_async(
435 message,
436 CAP_SYS_ADMIN,
437 "org.freedesktop.machine1.login",
438 false,
439 &m->manager->polkit_registry,
440 error);
441 if (r < 0)
442 return r;
443 if (r == 0)
444 return 1; /* Will call us back */
445
5f8cc96a
LP
446 master = openpt_in_namespace(m->leader, O_RDWR|O_NOCTTY|O_CLOEXEC);
447 if (master < 0)
448 return master;
40205d70 449
5f8cc96a 450 r = ptsname_malloc(master, &pty_name);
40205d70
LP
451 if (r < 0)
452 return r;
40205d70 453
5f8cc96a
LP
454 p = path_startswith(pty_name, "/dev/pts/");
455 if (!p)
456 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "PTS name %s is invalid", pty_name);
40205d70 457
5f8cc96a
LP
458 if (unlockpt(master) < 0)
459 return -errno;
40205d70 460
5f8cc96a
LP
461 r = sd_bus_new(&container_bus);
462 if (r < 0)
463 return r;
40205d70 464
5f8cc96a
LP
465#ifdef ENABLE_KDBUS
466 asprintf(&container_bus->address, "x-container-kernel:pid=" PID_FMT ";x-container-unix:pid=" PID_FMT, m->leader, m->leader);
467#else
468 asprintf(&container_bus->address, "x-container-kernel:pid=" PID_FMT, m->leader);
469#endif
470 if (!container_bus->address)
471 return -ENOMEM;
40205d70 472
5f8cc96a
LP
473 container_bus->bus_client = true;
474 container_bus->trusted = false;
475 container_bus->is_system = true;
40205d70 476
5f8cc96a
LP
477 r = sd_bus_start(container_bus);
478 if (r < 0)
479 return r;
40205d70 480
5f8cc96a
LP
481 getty = strjoin("container-getty@", p, ".service", NULL);
482 if (!getty)
483 return -ENOMEM;
484
485 r = sd_bus_call_method(
486 container_bus,
487 "org.freedesktop.systemd1",
488 "/org/freedesktop/systemd1",
489 "org.freedesktop.systemd1.Manager",
490 "StartUnit",
491 error, NULL,
492 "ss", getty, "replace");
ee451d76
LP
493 if (r < 0)
494 return r;
495
5f8cc96a
LP
496 container_bus = sd_bus_unref(container_bus);
497
40205d70
LP
498 r = sd_bus_message_new_method_return(message, &reply);
499 if (r < 0)
500 return r;
501
ee451d76 502 r = sd_bus_message_append(reply, "hs", master, pty_name);
40205d70
LP
503 if (r < 0)
504 return r;
717603e3
LP
505
506 return sd_bus_send(bus, reply, NULL);
507}
508
c3350683
LP
509const sd_bus_vtable machine_vtable[] = {
510 SD_BUS_VTABLE_START(0),
556089dc
LP
511 SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Machine, name), SD_BUS_VTABLE_PROPERTY_CONST),
512 SD_BUS_PROPERTY("Id", "ay", property_get_id, 0, SD_BUS_VTABLE_PROPERTY_CONST),
513 BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Machine, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
514 SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Machine, service), SD_BUS_VTABLE_PROPERTY_CONST),
89f7c846
LP
515 SD_BUS_PROPERTY("Unit", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST),
516 SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
556089dc
LP
517 SD_BUS_PROPERTY("Leader", "u", NULL, offsetof(Machine, leader), SD_BUS_VTABLE_PROPERTY_CONST),
518 SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Machine, class), SD_BUS_VTABLE_PROPERTY_CONST),
519 SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(Machine, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
9b5ed6fe 520 SD_BUS_PROPERTY("NetworkInterfaces", "ai", property_get_netif, 0, SD_BUS_VTABLE_PROPERTY_CONST),
c3350683 521 SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
878cd7e9
LP
522 SD_BUS_METHOD("Terminate", NULL, NULL, bus_machine_method_terminate, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
523 SD_BUS_METHOD("Kill", "si", NULL, bus_machine_method_kill, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
0dd25fb9 524 SD_BUS_METHOD("GetAddresses", NULL, "a(iay)", bus_machine_method_get_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
717603e3 525 SD_BUS_METHOD("GetOSRelease", NULL, "a{ss}", bus_machine_method_get_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
40205d70 526 SD_BUS_METHOD("OpenPTY", NULL, "hs", bus_machine_method_open_pty, 0),
d04c1fb8 527 SD_BUS_METHOD("OpenLogin", NULL, "hs", bus_machine_method_open_login, SD_BUS_VTABLE_UNPRIVILEGED),
717603e3 528 SD_BUS_VTABLE_END
c3350683 529};
9444b1f2 530
f00c3121 531int machine_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
c3350683
LP
532 Manager *m = userdata;
533 Machine *machine;
927b1649 534 int r;
9444b1f2 535
c3350683
LP
536 assert(bus);
537 assert(path);
538 assert(interface);
539 assert(found);
540 assert(m);
9444b1f2 541
927b1649 542 if (streq(path, "/org/freedesktop/machine1/machine/self")) {
5b12334d 543 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
927b1649
LP
544 sd_bus_message *message;
545 pid_t pid;
9444b1f2 546
19befb2d 547 message = sd_bus_get_current_message(bus);
927b1649
LP
548 if (!message)
549 return 0;
550
5b12334d 551 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
927b1649 552 if (r < 0)
5b12334d
LP
553 return r;
554
555 r = sd_bus_creds_get_pid(creds, &pid);
556 if (r < 0)
557 return r;
9444b1f2 558
927b1649
LP
559 r = manager_get_machine_by_pid(m, pid, &machine);
560 if (r <= 0)
561 return 0;
562 } else {
563 _cleanup_free_ char *e = NULL;
564 const char *p;
565
566 p = startswith(path, "/org/freedesktop/machine1/machine/");
567 if (!p)
568 return 0;
569
a6278b88 570 e = bus_label_unescape(p);
927b1649
LP
571 if (!e)
572 return -ENOMEM;
573
574 machine = hashmap_get(m->machines, e);
575 if (!machine)
576 return 0;
577 }
9444b1f2 578
c3350683
LP
579 *found = machine;
580 return 1;
9444b1f2
LP
581}
582
9444b1f2
LP
583char *machine_bus_path(Machine *m) {
584 _cleanup_free_ char *e = NULL;
585
586 assert(m);
587
a6278b88 588 e = bus_label_escape(m->name);
9444b1f2
LP
589 if (!e)
590 return NULL;
591
1ee306e1 592 return strappend("/org/freedesktop/machine1/machine/", e);
9444b1f2
LP
593}
594
f00c3121 595int machine_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
927b1649
LP
596 _cleanup_strv_free_ char **l = NULL;
597 Machine *machine = NULL;
598 Manager *m = userdata;
599 Iterator i;
600 int r;
601
602 assert(bus);
603 assert(path);
604 assert(nodes);
605
606 HASHMAP_FOREACH(machine, m->machines, i) {
607 char *p;
608
609 p = machine_bus_path(machine);
610 if (!p)
611 return -ENOMEM;
612
6e18964d
ZJS
613 r = strv_consume(&l, p);
614 if (r < 0)
927b1649 615 return r;
927b1649
LP
616 }
617
618 *nodes = l;
619 l = NULL;
620
621 return 1;
622}
623
9444b1f2 624int machine_send_signal(Machine *m, bool new_machine) {
9444b1f2
LP
625 _cleanup_free_ char *p = NULL;
626
627 assert(m);
628
9444b1f2
LP
629 p = machine_bus_path(m);
630 if (!p)
631 return -ENOMEM;
632
c3350683
LP
633 return sd_bus_emit_signal(
634 m->manager->bus,
635 "/org/freedesktop/machine1",
636 "org.freedesktop.machine1.Manager",
637 new_machine ? "MachineNew" : "MachineRemoved",
638 "so", m->name, p);
9444b1f2
LP
639}
640
c3350683
LP
641int machine_send_create_reply(Machine *m, sd_bus_error *error) {
642 _cleanup_bus_message_unref_ sd_bus_message *c = NULL;
9444b1f2
LP
643 _cleanup_free_ char *p = NULL;
644
645 assert(m);
646
fb6becb4
LP
647 if (!m->create_message)
648 return 0;
649
c3350683
LP
650 c = m->create_message;
651 m->create_message = NULL;
fb6becb4 652
a658cafa 653 if (error)
df2d202e 654 return sd_bus_reply_method_error(c, error);
a658cafa 655
76e66585
LP
656 /* Update the machine state file before we notify the client
657 * about the result. */
658 machine_save(m);
659
c3350683
LP
660 p = machine_bus_path(m);
661 if (!p)
662 return -ENOMEM;
fb6becb4 663
df2d202e 664 return sd_bus_reply_method_return(c, "o", p);
fb6becb4 665}