]>
Commit | Line | Data |
---|---|---|
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 |
39 | static 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 |
62 | static 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 |
88 | static 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 | 113 | static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class, machine_class, MachineClass); |
9444b1f2 | 114 | |
878cd7e9 | 115 | int 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 | 130 | int 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 |
163 | int 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 |
306 | int 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 | ||
395 | int 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 |
425 | int 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 |
509 | const 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 | 531 | int 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 |
583 | char *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 | 595 | int 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 | 624 | int 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 |
641 | int 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 | } |