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"
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, AF_UNSPEC, &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);
324 if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
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, false);
354 pair[1] = safe_close(pair[1]);
356 f = fdopen(pair[0], "re");
362 r = load_env_file_pairs(f, "/etc/os-release", NULL, &l);
366 r = wait_for_terminate(child, &si);
369 if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
372 r = sd_bus_message_new_method_return(message, &reply);
376 r = sd_bus_message_open_container(reply, 'a', "{ss}");
380 STRV_FOREACH_PAIR(k, v, l) {
381 r = sd_bus_message_append(reply, "{ss}", *k, *v);
386 r = sd_bus_message_close_container(reply);
390 return sd_bus_send(bus, reply, NULL);
393 int bus_machine_method_open_pty(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
394 _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1;
395 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
396 _cleanup_close_pair_ int pair[2] = { -1, -1 };
397 _cleanup_close_ int master = -1;
399 struct cmsghdr cmsghdr;
400 uint8_t buf[CMSG_SPACE(sizeof(int))];
403 .msg_control = &control,
404 .msg_controllen = sizeof(control),
406 Machine *m = userdata;
407 struct cmsghdr *cmsg;
416 r = namespace_open(m->leader, &pidnsfd, &mntnsfd, NULL, &rootfd);
420 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
428 pair[0] = safe_close(pair[0]);
430 r = namespace_enter(pidnsfd, mntnsfd, -1, rootfd);
434 master = posix_openpt(O_RDWR|O_NOCTTY|O_CLOEXEC);
438 cmsg = CMSG_FIRSTHDR(&mh);
439 cmsg->cmsg_level = SOL_SOCKET;
440 cmsg->cmsg_type = SCM_RIGHTS;
441 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
442 memcpy(CMSG_DATA(cmsg), &master, sizeof(int));
444 mh.msg_controllen = cmsg->cmsg_len;
446 if (sendmsg(pair[1], &mh, MSG_NOSIGNAL) < 0)
452 pair[1] = safe_close(pair[1]);
454 r = wait_for_terminate(child, &si);
457 if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
460 if (recvmsg(pair[0], &mh, MSG_NOSIGNAL|MSG_CMSG_CLOEXEC) < 0)
463 for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg))
464 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
468 fds = (int*) CMSG_DATA(cmsg);
469 n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
472 close_many(fds, n_fds);
482 r = sd_bus_message_new_method_return(message, &reply);
486 r = sd_bus_message_append(reply, "hs", master, ptsname(master));
490 return sd_bus_send(bus, reply, NULL);
493 const sd_bus_vtable machine_vtable[] = {
494 SD_BUS_VTABLE_START(0),
495 SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Machine, name), SD_BUS_VTABLE_PROPERTY_CONST),
496 SD_BUS_PROPERTY("Id", "ay", property_get_id, 0, SD_BUS_VTABLE_PROPERTY_CONST),
497 BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Machine, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
498 SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Machine, service), SD_BUS_VTABLE_PROPERTY_CONST),
499 SD_BUS_PROPERTY("Unit", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST),
500 SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
501 SD_BUS_PROPERTY("Leader", "u", NULL, offsetof(Machine, leader), SD_BUS_VTABLE_PROPERTY_CONST),
502 SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Machine, class), SD_BUS_VTABLE_PROPERTY_CONST),
503 SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(Machine, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
504 SD_BUS_PROPERTY("NetworkInterfaces", "ai", property_get_netif, 0, SD_BUS_VTABLE_PROPERTY_CONST),
505 SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
506 SD_BUS_METHOD("Terminate", NULL, NULL, bus_machine_method_terminate, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
507 SD_BUS_METHOD("Kill", "si", NULL, bus_machine_method_kill, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
508 SD_BUS_METHOD("GetAddresses", NULL, "a(iay)", bus_machine_method_get_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
509 SD_BUS_METHOD("GetOSRelease", NULL, "a{ss}", bus_machine_method_get_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
510 SD_BUS_METHOD("OpenPTY", NULL, "hs", bus_machine_method_open_pty, 0),
514 int machine_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
515 Manager *m = userdata;
525 if (streq(path, "/org/freedesktop/machine1/machine/self")) {
526 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
527 sd_bus_message *message;
530 message = sd_bus_get_current_message(bus);
534 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
538 r = sd_bus_creds_get_pid(creds, &pid);
542 r = manager_get_machine_by_pid(m, pid, &machine);
546 _cleanup_free_ char *e = NULL;
549 p = startswith(path, "/org/freedesktop/machine1/machine/");
553 e = bus_label_unescape(p);
557 machine = hashmap_get(m->machines, e);
566 char *machine_bus_path(Machine *m) {
567 _cleanup_free_ char *e = NULL;
571 e = bus_label_escape(m->name);
575 return strappend("/org/freedesktop/machine1/machine/", e);
578 int machine_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
579 _cleanup_strv_free_ char **l = NULL;
580 Machine *machine = NULL;
581 Manager *m = userdata;
589 HASHMAP_FOREACH(machine, m->machines, i) {
592 p = machine_bus_path(machine);
596 r = strv_consume(&l, p);
607 int machine_send_signal(Machine *m, bool new_machine) {
608 _cleanup_free_ char *p = NULL;
612 p = machine_bus_path(m);
616 return sd_bus_emit_signal(
618 "/org/freedesktop/machine1",
619 "org.freedesktop.machine1.Manager",
620 new_machine ? "MachineNew" : "MachineRemoved",
624 int machine_send_create_reply(Machine *m, sd_bus_error *error) {
625 _cleanup_bus_message_unref_ sd_bus_message *c = NULL;
626 _cleanup_free_ char *p = NULL;
630 if (!m->create_message)
633 c = m->create_message;
634 m->create_message = NULL;
637 return sd_bus_reply_method_error(c, error);
639 /* Update the machine state file before we notify the client
640 * about the result. */
643 p = machine_bus_path(m);
647 return sd_bus_reply_method_return(c, "o", p);