1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2011 Lennart Poettering
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.
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.
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/>.
24 #include <sys/capability.h>
25 #include <arpa/inet.h>
28 #include "bus-label.h"
30 #include "bus-errors.h"
33 #include "in-addr-util.h"
34 #include "local-addresses.h"
37 static int property_get_id(
40 const char *interface,
42 sd_bus_message *reply,
44 sd_bus_error *error) {
46 Machine *m = userdata;
53 r = sd_bus_message_append_array(reply, 'y', &m->id, 16);
60 static int property_get_state(
63 const char *interface,
65 sd_bus_message *reply,
67 sd_bus_error *error) {
69 Machine *m = userdata;
77 state = machine_state_to_string(machine_get_state(m));
79 r = sd_bus_message_append_basic(reply, 's', state);
86 static int property_get_netif(
89 const char *interface,
91 sd_bus_message *reply,
93 sd_bus_error *error) {
95 Machine *m = userdata;
102 assert_cc(sizeof(int) == sizeof(int32_t));
104 r = sd_bus_message_append_array(reply, 'i', m->netif, m->n_netif * sizeof(int));
111 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class, machine_class, MachineClass);
113 int bus_machine_method_terminate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
114 Machine *m = userdata;
125 return sd_bus_reply_method_return(message, NULL);
128 int bus_machine_method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
129 Machine *m = userdata;
139 r = sd_bus_message_read(message, "si", &swho, &signo);
146 who = kill_who_from_string(swho);
148 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
151 if (signo <= 0 || signo >= _NSIG)
152 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
154 r = machine_kill(m, who, signo);
158 return sd_bus_reply_method_return(message, NULL);
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;
176 r = readlink_malloc("/proc/self/ns/net", &us);
178 return sd_bus_error_set_errno(error, r);
180 p = procfs_file_alloca(m->leader, "ns/net");
181 r = readlink_malloc(p, &them);
183 return sd_bus_error_set_errno(error, r);
186 return sd_bus_error_setf(error, BUS_ERROR_NO_PRIVATE_NETWORKING, "Machine %s does not use private networking", m->name);
188 r = namespace_open(m->leader, NULL, NULL, &netns_fd, NULL);
190 return sd_bus_error_set_errno(error, r);
192 if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
193 return sd_bus_error_set_errno(error, -errno);
197 return sd_bus_error_set_errno(error, -errno);
200 _cleanup_free_ struct local_address *addresses = NULL;
201 struct local_address *a;
204 pair[0] = safe_close(pair[0]);
206 r = namespace_enter(-1, -1, netns_fd, -1);
210 n = local_addresses(NULL, 0, &addresses);
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) },
220 r = writev(pair[1], iov, 2);
225 pair[1] = safe_close(pair[1]);
230 pair[1] = safe_close(pair[1]);
232 r = sd_bus_message_new_method_return(message, &reply);
234 return sd_bus_error_set_errno(error, r);
236 r = sd_bus_message_open_container(reply, 'a', "(iay)");
238 return sd_bus_error_set_errno(error, r);
243 union in_addr_union in_addr;
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) };
253 n = recvmsg(pair[0], &mh, 0);
255 return sd_bus_error_set_errno(error, -errno);
256 if ((size_t) n < sizeof(family))
259 r = sd_bus_message_open_container(reply, 'r', "iay");
261 return sd_bus_error_set_errno(error, r);
263 r = sd_bus_message_append(reply, "i", family);
265 return sd_bus_error_set_errno(error, r);
270 if (n != sizeof(struct in_addr) + sizeof(family))
271 return sd_bus_error_set_errno(error, EIO);
273 r = sd_bus_message_append_array(reply, 'y', &in_addr.in, sizeof(in_addr.in));
277 if (n != sizeof(struct in6_addr) + sizeof(family))
278 return sd_bus_error_set_errno(error, EIO);
280 r = sd_bus_message_append_array(reply, 'y', &in_addr.in6, sizeof(in_addr.in6));
284 return sd_bus_error_set_errno(error, r);
286 r = sd_bus_message_close_container(reply);
288 return sd_bus_error_set_errno(error, r);
291 r = wait_for_terminate(child, &si);
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);
297 r = sd_bus_message_close_container(reply);
299 return sd_bus_error_set_errno(error, r);
301 return sd_bus_send(bus, reply, NULL);
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;
320 r = namespace_open(m->leader, NULL, &mntns_fd, NULL, &root_fd);
322 return sd_bus_error_set_errno(error, r);
324 if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
325 return sd_bus_error_set_errno(error, -errno);
329 return sd_bus_error_set_errno(error, -errno);
332 _cleanup_close_ int fd = -1;
334 pair[0] = safe_close(pair[0]);
336 r = namespace_enter(-1, mntns_fd, -1, root_fd);
340 fd = open("/etc/os-release", O_RDONLY|O_CLOEXEC);
342 fd = open("/usr/lib/os-release", O_RDONLY|O_CLOEXEC);
347 r = copy_bytes(fd, pair[1], (off_t) -1);
354 pair[1] = safe_close(pair[1]);
356 f = fdopen(pair[0], "re");
358 return sd_bus_error_set_errno(error, -errno);
362 r = load_env_file_pairs(f, "/etc/os-release", NULL, &l);
364 return sd_bus_error_set_errno(error, r);
366 r = wait_for_terminate(child, &si);
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);
372 r = sd_bus_message_new_method_return(message, &reply);
374 return sd_bus_error_set_errno(error, r);
376 r = sd_bus_message_open_container(reply, 'a', "{ss}");
378 return sd_bus_error_set_errno(error, r);
380 STRV_FOREACH_PAIR(k, v, l) {
381 r = sd_bus_message_append(reply, "{ss}", *k, *v);
383 return sd_bus_error_set_errno(error, r);
386 r = sd_bus_message_close_container(reply);
388 return sd_bus_error_set_errno(error, r);
390 return sd_bus_send(bus, reply, NULL);
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),
404 SD_BUS_PROPERTY("NetworkInterfaces", "ai", property_get_netif, 0, SD_BUS_VTABLE_PROPERTY_CONST),
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)),
408 SD_BUS_METHOD("GetAddresses", NULL, "a(iay)", bus_machine_method_get_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
409 SD_BUS_METHOD("GetOSRelease", NULL, "a{ss}", bus_machine_method_get_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
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;
424 if (streq(path, "/org/freedesktop/machine1/machine/self")) {
425 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
426 sd_bus_message *message;
429 message = sd_bus_get_current_message(bus);
433 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
437 r = sd_bus_creds_get_pid(creds, &pid);
441 r = manager_get_machine_by_pid(m, pid, &machine);
445 _cleanup_free_ char *e = NULL;
448 p = startswith(path, "/org/freedesktop/machine1/machine/");
452 e = bus_label_unescape(p);
456 machine = hashmap_get(m->machines, e);
465 char *machine_bus_path(Machine *m) {
466 _cleanup_free_ char *e = NULL;
470 e = bus_label_escape(m->name);
474 return strappend("/org/freedesktop/machine1/machine/", e);
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;
488 HASHMAP_FOREACH(machine, m->machines, i) {
491 p = machine_bus_path(machine);
495 r = strv_consume(&l, p);
506 int machine_send_signal(Machine *m, bool new_machine) {
507 _cleanup_free_ char *p = NULL;
511 p = machine_bus_path(m);
515 return sd_bus_emit_signal(
517 "/org/freedesktop/machine1",
518 "org.freedesktop.machine1.Manager",
519 new_machine ? "MachineNew" : "MachineRemoved",
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;
529 if (!m->create_message)
532 c = m->create_message;
533 m->create_message = NULL;
536 return sd_bus_reply_method_error(c, error);
538 /* Update the machine state file before we notify the client
539 * about the result. */
542 p = machine_bus_path(m);
546 return sd_bus_reply_method_return(c, "o", p);