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-common-errors.h"
33 #include "in-addr-util.h"
34 #include "local-addresses.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 int property_get_netif(
90 const char *interface,
92 sd_bus_message *reply,
94 sd_bus_error *error) {
96 Machine *m = userdata;
103 assert_cc(sizeof(int) == sizeof(int32_t));
105 r = sd_bus_message_append_array(reply, 'i', m->netif, m->n_netif * sizeof(int));
112 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class, machine_class, MachineClass);
114 int bus_machine_method_terminate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
115 Machine *m = userdata;
126 return sd_bus_reply_method_return(message, NULL);
129 int bus_machine_method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
130 Machine *m = userdata;
140 r = sd_bus_message_read(message, "si", &swho, &signo);
147 who = kill_who_from_string(swho);
149 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
152 if (signo <= 0 || signo >= _NSIG)
153 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
155 r = machine_kill(m, who, signo);
159 return sd_bus_reply_method_return(message, NULL);
162 int bus_machine_method_get_addresses(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
163 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
164 _cleanup_close_pair_ int pair[2] = { -1, -1 };
165 _cleanup_free_ char *us = NULL, *them = NULL;
166 _cleanup_close_ int netns_fd = -1;
167 Machine *m = userdata;
177 r = readlink_malloc("/proc/self/ns/net", &us);
179 return sd_bus_error_set_errno(error, r);
181 p = procfs_file_alloca(m->leader, "ns/net");
182 r = readlink_malloc(p, &them);
184 return sd_bus_error_set_errno(error, r);
187 return sd_bus_error_setf(error, BUS_ERROR_NO_PRIVATE_NETWORKING, "Machine %s does not use private networking", m->name);
189 r = namespace_open(m->leader, NULL, NULL, &netns_fd, NULL);
191 return sd_bus_error_set_errno(error, r);
193 if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
194 return sd_bus_error_set_errno(error, -errno);
198 return sd_bus_error_set_errno(error, -errno);
201 _cleanup_free_ struct local_address *addresses = NULL;
202 struct local_address *a;
205 pair[0] = safe_close(pair[0]);
207 r = namespace_enter(-1, -1, netns_fd, -1);
211 n = local_addresses(NULL, 0, AF_UNSPEC, &addresses);
215 for (a = addresses, i = 0; i < n; a++, i++) {
216 struct iovec iov[2] = {
217 { .iov_base = &a->family, .iov_len = sizeof(a->family) },
218 { .iov_base = &a->address, .iov_len = FAMILY_ADDRESS_SIZE(a->family) },
221 r = writev(pair[1], iov, 2);
226 pair[1] = safe_close(pair[1]);
231 pair[1] = safe_close(pair[1]);
233 r = sd_bus_message_new_method_return(message, &reply);
235 return sd_bus_error_set_errno(error, r);
237 r = sd_bus_message_open_container(reply, 'a', "(iay)");
239 return sd_bus_error_set_errno(error, r);
244 union in_addr_union in_addr;
251 iov[0] = (struct iovec) { .iov_base = &family, .iov_len = sizeof(family) };
252 iov[1] = (struct iovec) { .iov_base = &in_addr, .iov_len = sizeof(in_addr) };
254 n = recvmsg(pair[0], &mh, 0);
256 return sd_bus_error_set_errno(error, -errno);
257 if ((size_t) n < sizeof(family))
260 r = sd_bus_message_open_container(reply, 'r', "iay");
262 return sd_bus_error_set_errno(error, r);
264 r = sd_bus_message_append(reply, "i", family);
266 return sd_bus_error_set_errno(error, r);
271 if (n != sizeof(struct in_addr) + sizeof(family))
272 return sd_bus_error_set_errno(error, EIO);
274 r = sd_bus_message_append_array(reply, 'y', &in_addr.in, sizeof(in_addr.in));
278 if (n != sizeof(struct in6_addr) + sizeof(family))
279 return sd_bus_error_set_errno(error, EIO);
281 r = sd_bus_message_append_array(reply, 'y', &in_addr.in6, sizeof(in_addr.in6));
285 return sd_bus_error_set_errno(error, r);
287 r = sd_bus_message_close_container(reply);
289 return sd_bus_error_set_errno(error, r);
292 r = wait_for_terminate(child, &si);
294 return sd_bus_error_set_errno(error, r);
295 if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
296 return sd_bus_error_set_errno(error, EIO);
298 r = sd_bus_message_close_container(reply);
300 return sd_bus_error_set_errno(error, r);
302 return sd_bus_send(bus, reply, NULL);
305 int bus_machine_method_get_os_release(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
306 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
307 _cleanup_close_ int mntns_fd = -1, root_fd = -1;
308 _cleanup_close_pair_ int pair[2] = { -1, -1 };
309 _cleanup_strv_free_ char **l = NULL;
310 _cleanup_fclose_ FILE *f = NULL;
311 Machine *m = userdata;
321 r = namespace_open(m->leader, NULL, &mntns_fd, NULL, &root_fd);
323 return sd_bus_error_set_errno(error, r);
325 if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
326 return sd_bus_error_set_errno(error, -errno);
330 return sd_bus_error_set_errno(error, -errno);
333 _cleanup_close_ int fd = -1;
335 pair[0] = safe_close(pair[0]);
337 r = namespace_enter(-1, mntns_fd, -1, root_fd);
341 fd = open("/etc/os-release", O_RDONLY|O_CLOEXEC);
343 fd = open("/usr/lib/os-release", O_RDONLY|O_CLOEXEC);
348 r = copy_bytes(fd, pair[1], (off_t) -1, false);
355 pair[1] = safe_close(pair[1]);
357 f = fdopen(pair[0], "re");
359 return sd_bus_error_set_errno(error, -errno);
363 r = load_env_file_pairs(f, "/etc/os-release", NULL, &l);
365 return sd_bus_error_set_errno(error, r);
367 r = wait_for_terminate(child, &si);
369 return sd_bus_error_set_errno(error, r);
370 if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
371 return sd_bus_error_set_errno(error, EIO);
373 r = sd_bus_message_new_method_return(message, &reply);
375 return sd_bus_error_set_errno(error, r);
377 r = sd_bus_message_open_container(reply, 'a', "{ss}");
379 return sd_bus_error_set_errno(error, r);
381 STRV_FOREACH_PAIR(k, v, l) {
382 r = sd_bus_message_append(reply, "{ss}", *k, *v);
384 return sd_bus_error_set_errno(error, r);
387 r = sd_bus_message_close_container(reply);
389 return sd_bus_error_set_errno(error, r);
391 return sd_bus_send(bus, reply, NULL);
394 const sd_bus_vtable machine_vtable[] = {
395 SD_BUS_VTABLE_START(0),
396 SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Machine, name), SD_BUS_VTABLE_PROPERTY_CONST),
397 SD_BUS_PROPERTY("Id", "ay", property_get_id, 0, SD_BUS_VTABLE_PROPERTY_CONST),
398 BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Machine, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
399 SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Machine, service), SD_BUS_VTABLE_PROPERTY_CONST),
400 SD_BUS_PROPERTY("Unit", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST),
401 SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
402 SD_BUS_PROPERTY("Leader", "u", NULL, offsetof(Machine, leader), SD_BUS_VTABLE_PROPERTY_CONST),
403 SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Machine, class), SD_BUS_VTABLE_PROPERTY_CONST),
404 SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(Machine, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
405 SD_BUS_PROPERTY("NetworkInterfaces", "ai", property_get_netif, 0, SD_BUS_VTABLE_PROPERTY_CONST),
406 SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
407 SD_BUS_METHOD("Terminate", NULL, NULL, bus_machine_method_terminate, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
408 SD_BUS_METHOD("Kill", "si", NULL, bus_machine_method_kill, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
409 SD_BUS_METHOD("GetAddresses", NULL, "a(iay)", bus_machine_method_get_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
410 SD_BUS_METHOD("GetOSRelease", NULL, "a{ss}", bus_machine_method_get_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
414 int machine_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
415 Manager *m = userdata;
425 if (streq(path, "/org/freedesktop/machine1/machine/self")) {
426 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
427 sd_bus_message *message;
430 message = sd_bus_get_current_message(bus);
434 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
438 r = sd_bus_creds_get_pid(creds, &pid);
442 r = manager_get_machine_by_pid(m, pid, &machine);
446 _cleanup_free_ char *e = NULL;
449 p = startswith(path, "/org/freedesktop/machine1/machine/");
453 e = bus_label_unescape(p);
457 machine = hashmap_get(m->machines, e);
466 char *machine_bus_path(Machine *m) {
467 _cleanup_free_ char *e = NULL;
471 e = bus_label_escape(m->name);
475 return strappend("/org/freedesktop/machine1/machine/", e);
478 int machine_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
479 _cleanup_(image_hashmap_freep) Hashmap *images = NULL;
480 _cleanup_strv_free_ char **l = NULL;
481 Machine *machine = NULL;
482 Manager *m = userdata;
491 HASHMAP_FOREACH(machine, m->machines, i) {
494 p = machine_bus_path(machine);
498 r = strv_consume(&l, p);
503 images = hashmap_new(&string_hash_ops);
507 r = image_discover(images);
511 HASHMAP_FOREACH(image, images, i) {
514 p = image_bus_path(image->name);
518 r = strv_consume(&l, p);
529 int machine_send_signal(Machine *m, bool new_machine) {
530 _cleanup_free_ char *p = NULL;
534 p = machine_bus_path(m);
538 return sd_bus_emit_signal(
540 "/org/freedesktop/machine1",
541 "org.freedesktop.machine1.Manager",
542 new_machine ? "MachineNew" : "MachineRemoved",
546 int machine_send_create_reply(Machine *m, sd_bus_error *error) {
547 _cleanup_bus_message_unref_ sd_bus_message *c = NULL;
548 _cleanup_free_ char *p = NULL;
552 if (!m->create_message)
555 c = m->create_message;
556 m->create_message = NULL;
559 return sd_bus_reply_method_error(c, error);
561 /* Update the machine state file before we notify the client
562 * about the result. */
565 p = machine_bus_path(m);
569 return sd_bus_reply_method_return(c, "o", p);