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>
29 #include "bus-label.h"
31 #include "rtnl-util.h"
32 #include "bus-errors.h"
35 #include "in-addr-util.h"
38 static int property_get_id(
41 const char *interface,
43 sd_bus_message *reply,
45 sd_bus_error *error) {
47 Machine *m = userdata;
54 r = sd_bus_message_append_array(reply, 'y', &m->id, 16);
61 static int property_get_state(
64 const char *interface,
66 sd_bus_message *reply,
68 sd_bus_error *error) {
70 Machine *m = userdata;
78 state = machine_state_to_string(machine_get_state(m));
80 r = sd_bus_message_append_basic(reply, 's', state);
87 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class, machine_class, MachineClass);
89 int bus_machine_method_terminate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
90 Machine *m = userdata;
101 return sd_bus_reply_method_return(message, NULL);
104 int bus_machine_method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
105 Machine *m = userdata;
115 r = sd_bus_message_read(message, "si", &swho, &signo);
122 who = kill_who_from_string(swho);
124 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
127 if (signo <= 0 || signo >= _NSIG)
128 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
130 r = machine_kill(m, who, signo);
134 return sd_bus_reply_method_return(message, NULL);
137 int bus_machine_method_get_addresses(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
138 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
139 _cleanup_close_pair_ int pair[2] = { -1, -1 };
140 _cleanup_free_ char *us = NULL, *them = NULL;
141 _cleanup_close_ int netns_fd = -1;
142 Machine *m = userdata;
152 r = readlink_malloc("/proc/self/ns/net", &us);
154 return sd_bus_error_set_errno(error, r);
156 p = procfs_file_alloca(m->leader, "ns/net");
157 r = readlink_malloc(p, &them);
159 return sd_bus_error_set_errno(error, r);
162 return sd_bus_error_setf(error, BUS_ERROR_NO_PRIVATE_NETWORKING, "Machine %s does not use private networking", m->name);
164 r = namespace_open(m->leader, NULL, NULL, &netns_fd, NULL);
166 return sd_bus_error_set_errno(error, r);
168 if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
169 return sd_bus_error_set_errno(error, -errno);
173 return sd_bus_error_set_errno(error, -errno);
176 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *resp = NULL;
177 _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
178 sd_rtnl_message *addr;
180 pair[0] = safe_close(pair[0]);
182 r = namespace_enter(-1, -1, netns_fd, -1);
186 r = sd_rtnl_open(&rtnl, 0);
190 r = sd_rtnl_message_new_addr(rtnl, &req, RTM_GETADDR, 0, AF_UNSPEC);
194 r = sd_rtnl_call(rtnl, req, 0, &resp);
198 for (addr = resp; addr; addr = sd_rtnl_message_next(addr)) {
200 unsigned char family, scope;
201 union in_addr_union in_addr;
205 r = sd_rtnl_message_get_errno(addr);
209 r = sd_rtnl_message_get_type(addr, &type);
213 if (type != RTM_NEWADDR)
216 r = sd_rtnl_message_addr_get_flags(addr, &flags);
220 if (flags & IFA_F_DEPRECATED)
223 r = sd_rtnl_message_addr_get_scope(addr, &scope);
227 if (scope == RT_SCOPE_HOST || scope == RT_SCOPE_NOWHERE)
230 r = sd_rtnl_message_addr_get_family(addr, &family);
234 iov[0] = (struct iovec) { .iov_base = &family, .iov_len = sizeof(family) };
240 r = sd_rtnl_message_read_in_addr(addr, IFA_LOCAL, &in_addr.in);
242 r = sd_rtnl_message_read_in_addr(addr, IFA_ADDRESS, &in_addr.in);
247 if (in_addr.in.s_addr == htobe32(INADDR_LOOPBACK))
250 iov[1] = (struct iovec) { .iov_base = &in_addr.in, .iov_len = sizeof(in_addr.in) };
255 r = sd_rtnl_message_read_in6_addr(addr, IFA_LOCAL, &in_addr.in6);
257 r = sd_rtnl_message_read_in6_addr(addr, IFA_ADDRESS, &in_addr.in6);
262 if (IN6_IS_ADDR_LOOPBACK(&in_addr.in6))
265 iov[1] = (struct iovec) { .iov_base = &in_addr.in6, .iov_len = sizeof(in_addr.in6) };
272 r = writev(pair[1], iov, 2);
280 pair[1] = safe_close(pair[1]);
282 r = sd_bus_message_new_method_return(message, &reply);
284 return sd_bus_error_set_errno(error, r);
286 r = sd_bus_message_open_container(reply, 'a', "(yay)");
288 return sd_bus_error_set_errno(error, r);
291 unsigned char family;
293 union in_addr_union in_addr;
300 iov[0] = (struct iovec) { .iov_base = &family, .iov_len = sizeof(family) };
301 iov[1] = (struct iovec) { .iov_base = &in_addr, .iov_len = sizeof(in_addr) };
303 n = recvmsg(pair[0], &mh, 0);
305 return sd_bus_error_set_errno(error, -errno);
306 if ((size_t) n < sizeof(family))
309 r = sd_bus_message_open_container(reply, 'r', "yay");
311 return sd_bus_error_set_errno(error, r);
313 r = sd_bus_message_append(reply, "y", family);
315 return sd_bus_error_set_errno(error, r);
320 if (n != sizeof(struct in_addr) + sizeof(family))
321 return sd_bus_error_set_errno(error, EIO);
323 r = sd_bus_message_append_array(reply, 'y', &in_addr.in, sizeof(in_addr.in));
327 if (n != sizeof(struct in6_addr) + sizeof(family))
328 return sd_bus_error_set_errno(error, EIO);
330 r = sd_bus_message_append_array(reply, 'y', &in_addr.in6, sizeof(in_addr.in6));
334 return sd_bus_error_set_errno(error, r);
336 r = sd_bus_message_close_container(reply);
338 return sd_bus_error_set_errno(error, r);
341 r = wait_for_terminate(child, &si);
343 return sd_bus_error_set_errno(error, r);
344 if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
345 return sd_bus_error_set_errno(error, EIO);
347 r = sd_bus_message_close_container(reply);
349 return sd_bus_error_set_errno(error, r);
351 return sd_bus_send(bus, reply, NULL);
354 int bus_machine_method_get_os_release(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
355 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
356 _cleanup_close_ int mntns_fd = -1, root_fd = -1;
357 _cleanup_close_pair_ int pair[2] = { -1, -1 };
358 _cleanup_strv_free_ char **l = NULL;
359 _cleanup_fclose_ FILE *f = NULL;
360 Machine *m = userdata;
370 r = namespace_open(m->leader, NULL, &mntns_fd, NULL, &root_fd);
372 return sd_bus_error_set_errno(error, r);
374 if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
375 return sd_bus_error_set_errno(error, -errno);
379 return sd_bus_error_set_errno(error, -errno);
382 _cleanup_close_ int fd = -1;
384 pair[0] = safe_close(pair[0]);
386 r = namespace_enter(-1, mntns_fd, -1, root_fd);
390 fd = open("/etc/os-release", O_RDONLY|O_CLOEXEC);
392 fd = open("/usr/lib/os-release", O_RDONLY|O_CLOEXEC);
397 r = copy_bytes(fd, pair[1], (off_t) -1);
404 pair[1] = safe_close(pair[1]);
406 f = fdopen(pair[0], "re");
408 return sd_bus_error_set_errno(error, -errno);
412 r = load_env_file_pairs(f, "/etc/os-release", NULL, &l);
414 return sd_bus_error_set_errno(error, r);
416 r = wait_for_terminate(child, &si);
418 return sd_bus_error_set_errno(error, r);
419 if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
420 return sd_bus_error_set_errno(error, EIO);
422 r = sd_bus_message_new_method_return(message, &reply);
424 return sd_bus_error_set_errno(error, r);
426 r = sd_bus_message_open_container(reply, 'a', "{ss}");
428 return sd_bus_error_set_errno(error, r);
430 STRV_FOREACH_PAIR(k, v, l) {
431 r = sd_bus_message_append(reply, "{ss}", *k, *v);
433 return sd_bus_error_set_errno(error, r);
436 r = sd_bus_message_close_container(reply);
438 return sd_bus_error_set_errno(error, r);
440 return sd_bus_send(bus, reply, NULL);
443 const sd_bus_vtable machine_vtable[] = {
444 SD_BUS_VTABLE_START(0),
445 SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Machine, name), SD_BUS_VTABLE_PROPERTY_CONST),
446 SD_BUS_PROPERTY("Id", "ay", property_get_id, 0, SD_BUS_VTABLE_PROPERTY_CONST),
447 BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Machine, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
448 SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Machine, service), SD_BUS_VTABLE_PROPERTY_CONST),
449 SD_BUS_PROPERTY("Unit", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST),
450 SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
451 SD_BUS_PROPERTY("Leader", "u", NULL, offsetof(Machine, leader), SD_BUS_VTABLE_PROPERTY_CONST),
452 SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Machine, class), SD_BUS_VTABLE_PROPERTY_CONST),
453 SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(Machine, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
454 SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
455 SD_BUS_METHOD("Terminate", NULL, NULL, bus_machine_method_terminate, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
456 SD_BUS_METHOD("Kill", "si", NULL, bus_machine_method_kill, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
457 SD_BUS_METHOD("GetAddresses", NULL, "a(yay)", bus_machine_method_get_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
458 SD_BUS_METHOD("GetOSRelease", NULL, "a{ss}", bus_machine_method_get_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
462 int machine_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
463 Manager *m = userdata;
473 if (streq(path, "/org/freedesktop/machine1/machine/self")) {
474 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
475 sd_bus_message *message;
478 message = sd_bus_get_current_message(bus);
482 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
486 r = sd_bus_creds_get_pid(creds, &pid);
490 r = manager_get_machine_by_pid(m, pid, &machine);
494 _cleanup_free_ char *e = NULL;
497 p = startswith(path, "/org/freedesktop/machine1/machine/");
501 e = bus_label_unescape(p);
505 machine = hashmap_get(m->machines, e);
514 char *machine_bus_path(Machine *m) {
515 _cleanup_free_ char *e = NULL;
519 e = bus_label_escape(m->name);
523 return strappend("/org/freedesktop/machine1/machine/", e);
526 int machine_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
527 _cleanup_strv_free_ char **l = NULL;
528 Machine *machine = NULL;
529 Manager *m = userdata;
537 HASHMAP_FOREACH(machine, m->machines, i) {
540 p = machine_bus_path(machine);
544 r = strv_consume(&l, p);
555 int machine_send_signal(Machine *m, bool new_machine) {
556 _cleanup_free_ char *p = NULL;
560 p = machine_bus_path(m);
564 return sd_bus_emit_signal(
566 "/org/freedesktop/machine1",
567 "org.freedesktop.machine1.Manager",
568 new_machine ? "MachineNew" : "MachineRemoved",
572 int machine_send_create_reply(Machine *m, sd_bus_error *error) {
573 _cleanup_bus_message_unref_ sd_bus_message *c = NULL;
574 _cleanup_free_ char *p = NULL;
578 if (!m->create_message)
581 c = m->create_message;
582 m->create_message = NULL;
585 return sd_bus_reply_method_error(c, error);
587 /* Update the machine state file before we notify the client
588 * about the result. */
591 p = machine_bus_path(m);
595 return sd_bus_reply_method_return(c, "o", p);