]>
Commit | Line | Data |
---|---|---|
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 | |
37 | static 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 |
60 | static 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 |
86 | static 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 |
111 | static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class, machine_class, MachineClass); |
112 | ||
113 | int 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 |
128 | int 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 |
161 | int 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 |
304 | int 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 |
393 | const 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 |
413 | int 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 |
465 | char *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 |
477 | int 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 | 506 | int 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 |
523 | int 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 | } |