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 BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class, machine_class, MachineClass);
88 int bus_machine_method_terminate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
89 Machine *m = userdata;
100 return sd_bus_reply_method_return(message, NULL);
103 int bus_machine_method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
104 Machine *m = userdata;
114 r = sd_bus_message_read(message, "si", &swho, &signo);
121 who = kill_who_from_string(swho);
123 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
126 if (signo <= 0 || signo >= _NSIG)
127 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
129 r = machine_kill(m, who, signo);
133 return sd_bus_reply_method_return(message, NULL);
136 int bus_machine_method_get_addresses(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
137 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
138 _cleanup_close_pair_ int pair[2] = { -1, -1 };
139 _cleanup_free_ char *us = NULL, *them = NULL;
140 _cleanup_close_ int netns_fd = -1;
141 Machine *m = userdata;
151 r = readlink_malloc("/proc/self/ns/net", &us);
153 return sd_bus_error_set_errno(error, r);
155 p = procfs_file_alloca(m->leader, "ns/net");
156 r = readlink_malloc(p, &them);
158 return sd_bus_error_set_errno(error, r);
161 return sd_bus_error_setf(error, BUS_ERROR_NO_PRIVATE_NETWORKING, "Machine %s does not use private networking", m->name);
163 r = namespace_open(m->leader, NULL, NULL, &netns_fd, NULL);
165 return sd_bus_error_set_errno(error, r);
167 if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
168 return sd_bus_error_set_errno(error, -errno);
172 return sd_bus_error_set_errno(error, -errno);
175 _cleanup_free_ struct local_address *addresses = NULL;
176 struct local_address *a;
179 pair[0] = safe_close(pair[0]);
181 r = namespace_enter(-1, -1, netns_fd, -1);
185 n = local_addresses(&addresses);
189 for (a = addresses, i = 0; i < n; a++, i++) {
190 struct iovec iov[2] = {
191 { .iov_base = &a->family, .iov_len = sizeof(a->family) },
192 { .iov_base = &a->address, .iov_len = PROTO_ADDRESS_SIZE(a->family) },
195 r = writev(pair[1], iov, 2);
200 pair[1] = safe_close(pair[1]);
205 pair[1] = safe_close(pair[1]);
207 r = sd_bus_message_new_method_return(message, &reply);
209 return sd_bus_error_set_errno(error, r);
211 r = sd_bus_message_open_container(reply, 'a', "(yay)");
213 return sd_bus_error_set_errno(error, r);
216 unsigned char family;
218 union in_addr_union in_addr;
225 iov[0] = (struct iovec) { .iov_base = &family, .iov_len = sizeof(family) };
226 iov[1] = (struct iovec) { .iov_base = &in_addr, .iov_len = sizeof(in_addr) };
228 n = recvmsg(pair[0], &mh, 0);
230 return sd_bus_error_set_errno(error, -errno);
231 if ((size_t) n < sizeof(family))
234 r = sd_bus_message_open_container(reply, 'r', "yay");
236 return sd_bus_error_set_errno(error, r);
238 r = sd_bus_message_append(reply, "y", family);
240 return sd_bus_error_set_errno(error, r);
245 if (n != sizeof(struct in_addr) + sizeof(family))
246 return sd_bus_error_set_errno(error, EIO);
248 r = sd_bus_message_append_array(reply, 'y', &in_addr.in, sizeof(in_addr.in));
252 if (n != sizeof(struct in6_addr) + sizeof(family))
253 return sd_bus_error_set_errno(error, EIO);
255 r = sd_bus_message_append_array(reply, 'y', &in_addr.in6, sizeof(in_addr.in6));
259 return sd_bus_error_set_errno(error, r);
261 r = sd_bus_message_close_container(reply);
263 return sd_bus_error_set_errno(error, r);
266 r = wait_for_terminate(child, &si);
268 return sd_bus_error_set_errno(error, r);
269 if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
270 return sd_bus_error_set_errno(error, EIO);
272 r = sd_bus_message_close_container(reply);
274 return sd_bus_error_set_errno(error, r);
276 return sd_bus_send(bus, reply, NULL);
279 int bus_machine_method_get_os_release(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
280 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
281 _cleanup_close_ int mntns_fd = -1, root_fd = -1;
282 _cleanup_close_pair_ int pair[2] = { -1, -1 };
283 _cleanup_strv_free_ char **l = NULL;
284 _cleanup_fclose_ FILE *f = NULL;
285 Machine *m = userdata;
295 r = namespace_open(m->leader, NULL, &mntns_fd, NULL, &root_fd);
297 return sd_bus_error_set_errno(error, r);
299 if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
300 return sd_bus_error_set_errno(error, -errno);
304 return sd_bus_error_set_errno(error, -errno);
307 _cleanup_close_ int fd = -1;
309 pair[0] = safe_close(pair[0]);
311 r = namespace_enter(-1, mntns_fd, -1, root_fd);
315 fd = open("/etc/os-release", O_RDONLY|O_CLOEXEC);
317 fd = open("/usr/lib/os-release", O_RDONLY|O_CLOEXEC);
322 r = copy_bytes(fd, pair[1], (off_t) -1);
329 pair[1] = safe_close(pair[1]);
331 f = fdopen(pair[0], "re");
333 return sd_bus_error_set_errno(error, -errno);
337 r = load_env_file_pairs(f, "/etc/os-release", NULL, &l);
339 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_new_method_return(message, &reply);
349 return sd_bus_error_set_errno(error, r);
351 r = sd_bus_message_open_container(reply, 'a', "{ss}");
353 return sd_bus_error_set_errno(error, r);
355 STRV_FOREACH_PAIR(k, v, l) {
356 r = sd_bus_message_append(reply, "{ss}", *k, *v);
358 return sd_bus_error_set_errno(error, r);
361 r = sd_bus_message_close_container(reply);
363 return sd_bus_error_set_errno(error, r);
365 return sd_bus_send(bus, reply, NULL);
368 const sd_bus_vtable machine_vtable[] = {
369 SD_BUS_VTABLE_START(0),
370 SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Machine, name), SD_BUS_VTABLE_PROPERTY_CONST),
371 SD_BUS_PROPERTY("Id", "ay", property_get_id, 0, SD_BUS_VTABLE_PROPERTY_CONST),
372 BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Machine, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
373 SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Machine, service), SD_BUS_VTABLE_PROPERTY_CONST),
374 SD_BUS_PROPERTY("Unit", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST),
375 SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
376 SD_BUS_PROPERTY("Leader", "u", NULL, offsetof(Machine, leader), SD_BUS_VTABLE_PROPERTY_CONST),
377 SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Machine, class), SD_BUS_VTABLE_PROPERTY_CONST),
378 SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(Machine, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
379 SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
380 SD_BUS_METHOD("Terminate", NULL, NULL, bus_machine_method_terminate, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
381 SD_BUS_METHOD("Kill", "si", NULL, bus_machine_method_kill, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
382 SD_BUS_METHOD("GetAddresses", NULL, "a(yay)", bus_machine_method_get_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
383 SD_BUS_METHOD("GetOSRelease", NULL, "a{ss}", bus_machine_method_get_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
387 int machine_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
388 Manager *m = userdata;
398 if (streq(path, "/org/freedesktop/machine1/machine/self")) {
399 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
400 sd_bus_message *message;
403 message = sd_bus_get_current_message(bus);
407 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
411 r = sd_bus_creds_get_pid(creds, &pid);
415 r = manager_get_machine_by_pid(m, pid, &machine);
419 _cleanup_free_ char *e = NULL;
422 p = startswith(path, "/org/freedesktop/machine1/machine/");
426 e = bus_label_unescape(p);
430 machine = hashmap_get(m->machines, e);
439 char *machine_bus_path(Machine *m) {
440 _cleanup_free_ char *e = NULL;
444 e = bus_label_escape(m->name);
448 return strappend("/org/freedesktop/machine1/machine/", e);
451 int machine_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
452 _cleanup_strv_free_ char **l = NULL;
453 Machine *machine = NULL;
454 Manager *m = userdata;
462 HASHMAP_FOREACH(machine, m->machines, i) {
465 p = machine_bus_path(machine);
469 r = strv_consume(&l, p);
480 int machine_send_signal(Machine *m, bool new_machine) {
481 _cleanup_free_ char *p = NULL;
485 p = machine_bus_path(m);
489 return sd_bus_emit_signal(
491 "/org/freedesktop/machine1",
492 "org.freedesktop.machine1.Manager",
493 new_machine ? "MachineNew" : "MachineRemoved",
497 int machine_send_create_reply(Machine *m, sd_bus_error *error) {
498 _cleanup_bus_message_unref_ sd_bus_message *c = NULL;
499 _cleanup_free_ char *p = NULL;
503 if (!m->create_message)
506 c = m->create_message;
507 m->create_message = NULL;
510 return sd_bus_reply_method_error(c, error);
512 /* Update the machine state file before we notify the client
513 * about the result. */
516 p = machine_bus_path(m);
520 return sd_bus_reply_method_return(c, "o", p);