machined-dbus.c revision cba38758b4d49c6fe7c2f0eea255e11ee9df23eb
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik/***
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik This file is part of systemd.
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik Copyright 2011 Lennart Poettering
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik systemd is free software; you can redistribute it and/or modify it
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik under the terms of the GNU Lesser General Public License as published by
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik the Free Software Foundation; either version 2.1 of the License, or
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik (at your option) any later version.
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik systemd is distributed in the hope that it will be useful, but
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik WITHOUT ANY WARRANTY; without even the implied warranty of
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik Lesser General Public License for more details.
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik You should have received a copy of the GNU Lesser General Public License
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik along with systemd; If not, see <http://www.gnu.org/licenses/>.
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik***/
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#include <errno.h>
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#include <string.h>
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#include <unistd.h>
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#include <pwd.h>
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#include <systemd/sd-id128.h>
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#include <systemd/sd-messages.h>
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#include "machined.h"
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#include "dbus-common.h"
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#include "strv.h"
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#include "mkdir.h"
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#include "path-util.h"
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#include "special.h"
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#include "sleep-config.h"
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#include "fileio-label.h"
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#include "label.h"
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#include "utf8.h"
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#include "unit-name.h"
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#include "bus-errors.h"
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#include "virt.h"
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#define BUS_MANAGER_INTERFACE \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik " <interface name=\"org.freedesktop.machine1.Manager\">\n" \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik " <method name=\"GetMachine\">\n" \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik " <arg name=\"machine\" type=\"o\" direction=\"out\"/>\n" \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik " </method>\n" \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik " <method name=\"GetMachineByPID\">\n" \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik " <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n" \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik " <arg name=\"machine\" type=\"o\" direction=\"out\"/>\n" \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik " </method>\n" \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik " <method name=\"ListMachines\">\n" \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik " <arg name=\"machines\" type=\"a(ssso)\" direction=\"out\"/>\n" \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik " </method>\n" \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik " <method name=\"CreateMachine\">\n" \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik " <arg name=\"id\" type=\"ay\" direction=\"in\"/>\n" \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik " <arg name=\"service\" type=\"s\" direction=\"in\"/>\n" \
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik " <arg name=\"class\" type=\"s\" direction=\"in\"/>\n" \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik " <arg name=\"leader\" type=\"u\" direction=\"in\"/>\n" \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik " <arg name=\"root_directory\" type=\"s\" direction=\"in\"/>\n" \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik " <arg name=\"scope_properties\" type=\"a(sv)\" direction=\"in\"/>\n" \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik " <arg name=\"path\" type=\"o\" direction=\"out\"/>\n" \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik " </method>\n" \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik " <method name=\"KillMachine\">\n" \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik " </method>\n" \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik " <method name=\"TerminateMachine\">\n" \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik " </method>\n" \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik " <signal name=\"MachineNew\">\n" \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik " <arg name=\"machine\" type=\"s\"/>\n" \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik " <arg name=\"path\" type=\"o\"/>\n" \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik " </signal>\n" \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik " <signal name=\"MachineRemoved\">\n" \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik " <arg name=\"machine\" type=\"s\"/>\n" \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik " <arg name=\"path\" type=\"o\"/>\n" \
71e31fc573ba527f0d2be7929c2cb98037c860ecKnut Anders Hatlen " </signal>\n" \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik " </interface>\n"
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#define INTROSPECTION_BEGIN \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik "<node>\n" \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik BUS_MANAGER_INTERFACE \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik BUS_PROPERTIES_INTERFACE \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik BUS_PEER_INTERFACE \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik BUS_INTROSPECTABLE_INTERFACE
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#define INTROSPECTION_END \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik "</node>\n"
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#define INTERFACES_LIST \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik BUS_GENERIC_INTERFACES_LIST \
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik "org.freedesktop.machine1.Manager\0"
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvikstatic bool valid_machine_name(const char *p) {
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik size_t l;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik if (!filename_is_safe(p))
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik return false;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik if (!ascii_is_valid(p))
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik return false;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik l = strlen(p);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik if (l < 1 || l> 64)
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik return false;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik return true;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik}
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvikstatic int bus_manager_create_machine(Manager *manager, DBusMessage *message) {
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik const char *name, *service, *class, *root_directory;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik _cleanup_free_ char *p = NULL;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik DBusMessageIter iter, sub;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik MachineClass c;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik uint32_t leader;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik sd_id128_t id;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik Machine *m;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik int n, r;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik void *v;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik assert(manager);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik assert(message);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik if (!dbus_message_iter_init(message, &iter) ||
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik return -EINVAL;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik dbus_message_iter_get_basic(&iter, &name);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik if (!valid_machine_name(name) ||
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik !dbus_message_iter_next(&iter) ||
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_BYTE)
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik return -EINVAL;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik dbus_message_iter_recurse(&iter, &sub);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik dbus_message_iter_get_fixed_array(&sub, &v, &n);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik if (n == 0)
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik id = SD_ID128_NULL;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik else if (n == 16)
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik memcpy(&id, v, n);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik else
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik return -EINVAL;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik if (!dbus_message_iter_next(&iter) ||
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik return -EINVAL;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik dbus_message_iter_get_basic(&iter, &service);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik if (!dbus_message_iter_next(&iter) ||
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik return -EINVAL;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik dbus_message_iter_get_basic(&iter, &class);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik if (isempty(class))
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik c = _MACHINE_CLASS_INVALID;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik else {
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik c = machine_class_from_string(class);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik if (c < 0)
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik return -EINVAL;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik }
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik if (!dbus_message_iter_next(&iter) ||
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik return -EINVAL;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik dbus_message_iter_get_basic(&iter, &leader);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik if (!dbus_message_iter_next(&iter) ||
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik return -EINVAL;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik dbus_message_iter_get_basic(&iter, &root_directory);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik if (!(isempty(root_directory) || path_is_absolute(root_directory)))
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik return -EINVAL;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik if (!dbus_message_iter_next(&iter) ||
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik return -EINVAL;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik dbus_message_iter_recurse(&iter, &sub);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik if (hashmap_get(manager->machines, name))
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik return -EEXIST;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik if (leader <= 0) {
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik leader = bus_get_unix_process_id(manager->bus, dbus_message_get_sender(message), NULL);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik if (leader == 0)
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik return -EINVAL;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik }
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik r = manager_add_machine(manager, name, &m);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik if (r < 0)
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik goto fail;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik m->leader = leader;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik m->class = c;
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik m->id = id;
71e31fc573ba527f0d2be7929c2cb98037c860ecKnut Anders Hatlen
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik if (!isempty(service)) {
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik m->service = strdup(service);
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik if (!m->service) {
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik r = -ENOMEM;
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik goto fail;
71e31fc573ba527f0d2be7929c2cb98037c860ecKnut Anders Hatlen }
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik }
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik if (!isempty(root_directory)) {
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik m->root_directory = strdup(root_directory);
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik if (!m->root_directory) {
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik r = -ENOMEM;
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik goto fail;
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik }
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik }
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik r = machine_start(m, &sub);
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik if (r < 0)
71e31fc573ba527f0d2be7929c2cb98037c860ecKnut Anders Hatlen goto fail;
71e31fc573ba527f0d2be7929c2cb98037c860ecKnut Anders Hatlen
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik m->create_message = dbus_message_ref(message);
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik return 0;
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvikfail:
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik if (m)
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik machine_add_to_gc_queue(m);
71e31fc573ba527f0d2be7929c2cb98037c860ecKnut Anders Hatlen
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik return r;
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik}
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvikstatic DBusHandlerResult manager_message_handler(
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik DBusConnection *connection,
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik DBusMessage *message,
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik void *userdata) {
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik Manager *m = userdata;
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik DBusError error;
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik int r;
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik assert(connection);
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik assert(message);
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik assert(m);
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik dbus_error_init(&error);
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik
71e31fc573ba527f0d2be7929c2cb98037c860ecKnut Anders Hatlen if (dbus_message_is_method_call(message, "org.freedesktop.machine1.Manager", "GetMachine")) {
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik Machine *machine;
71e31fc573ba527f0d2be7929c2cb98037c860ecKnut Anders Hatlen const char *name;
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik char *p;
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik bool b;
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik if (!dbus_message_get_args(
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik message,
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik &error,
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik DBUS_TYPE_STRING, &name,
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik DBUS_TYPE_INVALID))
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik return bus_send_error_reply(connection, message, &error, -EINVAL);
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik
71e31fc573ba527f0d2be7929c2cb98037c860ecKnut Anders Hatlen machine = hashmap_get(m->machines, name);
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik if (!machine)
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik return bus_send_error_reply(connection, message, &error, -ENOENT);
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik reply = dbus_message_new_method_return(message);
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik if (!reply)
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik goto oom;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik p = machine_bus_path(machine);
if (!p)
goto oom;
b = dbus_message_append_args(
reply,
DBUS_TYPE_OBJECT_PATH, &p,
DBUS_TYPE_INVALID);
free(p);
if (!b)
goto oom;
} else if (dbus_message_is_method_call(message, "org.freedesktop.machine1.Manager", "GetMachineByPID")) {
uint32_t pid;
char *p;
Machine *machine;
bool b;
if (!dbus_message_get_args(
message,
&error,
DBUS_TYPE_UINT32, &pid,
DBUS_TYPE_INVALID))
return bus_send_error_reply(connection, message, &error, -EINVAL);
r = manager_get_machine_by_pid(m, pid, &machine);
if (r <= 0)
return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
reply = dbus_message_new_method_return(message);
if (!reply)
goto oom;
p = machine_bus_path(machine);
if (!p)
goto oom;
b = dbus_message_append_args(
reply,
DBUS_TYPE_OBJECT_PATH, &p,
DBUS_TYPE_INVALID);
free(p);
if (!b)
goto oom;
} else if (dbus_message_is_method_call(message, "org.freedesktop.machine1.Manager", "ListMachines")) {
Machine *machine;
Iterator i;
DBusMessageIter iter, sub;
reply = dbus_message_new_method_return(message);
if (!reply)
goto oom;
dbus_message_iter_init_append(reply, &iter);
if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssso)", &sub))
goto oom;
HASHMAP_FOREACH(machine, m->machines, i) {
_cleanup_free_ char *p = NULL;
DBusMessageIter sub2;
const char *class;
if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
goto oom;
p = machine_bus_path(machine);
if (!p)
goto oom;
class = strempty(machine_class_to_string(machine->class));
if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &machine->name) ||
!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &class) ||
!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &machine->service) ||
!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
free(p);
goto oom;
}
if (!dbus_message_iter_close_container(&sub, &sub2))
goto oom;
}
if (!dbus_message_iter_close_container(&iter, &sub))
goto oom;
} else if (dbus_message_is_method_call(message, "org.freedesktop.machine1.Manager", "CreateMachine")) {
r = bus_manager_create_machine(m, message);
if (r < 0)
return bus_send_error_reply(connection, message, NULL, r);
} else if (dbus_message_is_method_call(message, "org.freedesktop.machine1.Manager", "KillMachine")) {
const char *swho;
int32_t signo;
KillWho who;
const char *name;
Machine *machine;
if (!dbus_message_get_args(
message,
&error,
DBUS_TYPE_STRING, &name,
DBUS_TYPE_STRING, &swho,
DBUS_TYPE_INT32, &signo,
DBUS_TYPE_INVALID))
return bus_send_error_reply(connection, message, &error, -EINVAL);
if (isempty(swho))
who = KILL_ALL;
else {
who = kill_who_from_string(swho);
if (who < 0)
return bus_send_error_reply(connection, message, &error, -EINVAL);
}
if (signo <= 0 || signo >= _NSIG)
return bus_send_error_reply(connection, message, &error, -EINVAL);
machine = hashmap_get(m->machines, name);
if (!machine)
return bus_send_error_reply(connection, message, &error, -ENOENT);
r = machine_kill(machine, who, signo);
if (r < 0)
return bus_send_error_reply(connection, message, NULL, r);
reply = dbus_message_new_method_return(message);
if (!reply)
goto oom;
} else if (dbus_message_is_method_call(message, "org.freedesktop.machine1.Manager", "TerminateMachine")) {
const char *name;
Machine *machine;
if (!dbus_message_get_args(
message,
&error,
DBUS_TYPE_STRING, &name,
DBUS_TYPE_INVALID))
return bus_send_error_reply(connection, message, &error, -EINVAL);
machine = hashmap_get(m->machines, name);
if (!machine)
return bus_send_error_reply(connection, message, &error, -ENOENT);
r = machine_stop(machine);
if (r < 0)
return bus_send_error_reply(connection, message, NULL, r);
reply = dbus_message_new_method_return(message);
if (!reply)
goto oom;
} else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
char *introspection = NULL;
FILE *f;
Iterator i;
Machine *machine;
size_t size;
char *p;
reply = dbus_message_new_method_return(message);
if (!reply)
goto oom;
/* We roll our own introspection code here, instead of
* relying on bus_default_message_handler() because we
* need to generate our introspection string
* dynamically. */
f = open_memstream(&introspection, &size);
if (!f)
goto oom;
fputs(INTROSPECTION_BEGIN, f);
HASHMAP_FOREACH(machine, m->machines, i) {
p = bus_path_escape(machine->name);
if (p) {
fprintf(f, "<node name=\"machine/%s\"/>", p);
free(p);
}
}
fputs(INTROSPECTION_END, f);
if (ferror(f)) {
fclose(f);
free(introspection);
goto oom;
}
fclose(f);
if (!introspection)
goto oom;
if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
free(introspection);
goto oom;
}
free(introspection);
} else
return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, NULL);
if (reply) {
if (!bus_maybe_send_reply(connection, message, reply))
goto oom;
}
return DBUS_HANDLER_RESULT_HANDLED;
oom:
dbus_error_free(&error);
return DBUS_HANDLER_RESULT_NEED_MEMORY;
}
const DBusObjectPathVTable bus_manager_vtable = {
.message_function = manager_message_handler
};
DBusHandlerResult bus_message_filter(
DBusConnection *connection,
DBusMessage *message,
void *userdata) {
Manager *m = userdata;
DBusError error;
assert(m);
assert(connection);
assert(message);
dbus_error_init(&error);
log_debug("Got message: %s %s %s", strna(dbus_message_get_sender(message)), strna(dbus_message_get_interface(message)), strna(dbus_message_get_member(message)));
if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
const char *path, *result, *unit;
Machine *mm;
uint32_t id;
if (!dbus_message_get_args(message, &error,
DBUS_TYPE_UINT32, &id,
DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_STRING, &unit,
DBUS_TYPE_STRING, &result,
DBUS_TYPE_INVALID)) {
log_error("Failed to parse JobRemoved message: %s", bus_error_message(&error));
goto finish;
}
mm = hashmap_get(m->machine_units, unit);
if (mm) {
if (streq_ptr(path, mm->scope_job)) {
free(mm->scope_job);
mm->scope_job = NULL;
if (mm->started) {
if (streq(result, "done"))
machine_send_create_reply(mm, NULL);
else {
dbus_set_error(&error, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
machine_send_create_reply(mm, &error);
}
}
machine_save(mm);
}
machine_add_to_gc_queue(mm);
}
} else if (dbus_message_is_signal(message, "org.freedesktop.DBus.Properties", "PropertiesChanged")) {
_cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
_cleanup_free_ char *unit = NULL;
const char *path;
path = dbus_message_get_path(message);
if (!path)
goto finish;
unit_name_from_dbus_path(path, &unit);
if (unit) {
Machine *mm;
mm = hashmap_get(m->machine_units, unit);
if (mm)
machine_add_to_gc_queue(mm);
}
} else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "UnitRemoved")) {
const char *path, *unit;
Machine *mm;
if (!dbus_message_get_args(message, &error,
DBUS_TYPE_STRING, &unit,
DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_INVALID)) {
log_error("Failed to parse UnitRemoved message: %s", bus_error_message(&error));
goto finish;
}
mm = hashmap_get(m->machine_units, unit);
if (mm)
machine_add_to_gc_queue(mm);
} else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "Reloading")) {
dbus_bool_t b;
if (!dbus_message_get_args(message, &error,
DBUS_TYPE_BOOLEAN, &b,
DBUS_TYPE_INVALID)) {
log_error("Failed to parse Reloading message: %s", bus_error_message(&error));
goto finish;
}
/* systemd finished reloading, let's recheck all our machines */
if (!b) {
Machine *mm;
Iterator i;
log_debug("System manager has been reloaded, rechecking machines...");
HASHMAP_FOREACH(mm, m->machines, i)
machine_add_to_gc_queue(mm);
}
}
finish:
dbus_error_free(&error);
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
static int copy_many_fields(DBusMessageIter *dest, DBusMessageIter *src);
static int copy_one_field(DBusMessageIter *dest, DBusMessageIter *src) {
int type, r;
type = dbus_message_iter_get_arg_type(src);
switch (type) {
case DBUS_TYPE_STRUCT: {
DBusMessageIter dest_sub, src_sub;
dbus_message_iter_recurse(src, &src_sub);
if (!dbus_message_iter_open_container(dest, DBUS_TYPE_STRUCT, NULL, &dest_sub))
return log_oom();
r = copy_many_fields(&dest_sub, &src_sub);
if (r < 0)
return r;
if (!dbus_message_iter_close_container(dest, &dest_sub))
return log_oom();
return 0;
}
case DBUS_TYPE_ARRAY: {
DBusMessageIter dest_sub, src_sub;
dbus_message_iter_recurse(src, &src_sub);
if (!dbus_message_iter_open_container(dest, DBUS_TYPE_ARRAY, dbus_message_iter_get_signature(&src_sub), &dest_sub))
return log_oom();
r = copy_many_fields(&dest_sub, &src_sub);
if (r < 0)
return r;
if (!dbus_message_iter_close_container(dest, &dest_sub))
return log_oom();
return 0;
}
case DBUS_TYPE_VARIANT: {
DBusMessageIter dest_sub, src_sub;
dbus_message_iter_recurse(src, &src_sub);
if (!dbus_message_iter_open_container(dest, DBUS_TYPE_VARIANT, dbus_message_iter_get_signature(&src_sub), &dest_sub))
return log_oom();
r = copy_one_field(&dest_sub, &src_sub);
if (r < 0)
return r;
if (!dbus_message_iter_close_container(dest, &dest_sub))
return log_oom();
return 0;
}
case DBUS_TYPE_STRING:
case DBUS_TYPE_OBJECT_PATH:
case DBUS_TYPE_BYTE:
case DBUS_TYPE_BOOLEAN:
case DBUS_TYPE_UINT16:
case DBUS_TYPE_INT16:
case DBUS_TYPE_UINT32:
case DBUS_TYPE_INT32:
case DBUS_TYPE_UINT64:
case DBUS_TYPE_INT64:
case DBUS_TYPE_DOUBLE:
case DBUS_TYPE_SIGNATURE: {
const void *p;
dbus_message_iter_get_basic(src, &p);
dbus_message_iter_append_basic(dest, type, &p);
return 0;
}
default:
return -EINVAL;
}
}
static int copy_many_fields(DBusMessageIter *dest, DBusMessageIter *src) {
int r;
assert(dest);
assert(src);
while (dbus_message_iter_get_arg_type(src) != DBUS_TYPE_INVALID) {
r = copy_one_field(dest, src);
if (r < 0)
return r;
dbus_message_iter_next(src);
}
return 0;
}
int manager_start_scope(
Manager *manager,
const char *scope,
pid_t pid,
const char *slice,
const char *description,
DBusMessageIter *more_properties,
DBusError *error,
char **job) {
_cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
DBusMessageIter iter, sub, sub2, sub3, sub4;
const char *timeout_stop_property = "TimeoutStopUSec";
const char *pids_property = "PIDs";
uint64_t timeout = 500 * USEC_PER_MSEC;
const char *fail = "fail";
uint32_t u;
int r;
assert(manager);
assert(scope);
assert(pid > 1);
if (!slice)
slice = "";
m = dbus_message_new_method_call(
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
"StartTransientUnit");
if (!m)
return log_oom();
dbus_message_iter_init_append(m, &iter);
if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &scope) ||
!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &fail) ||
!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sv)", &sub))
return log_oom();
if (!isempty(slice)) {
const char *slice_property = "Slice";
if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &slice_property) ||
!dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "s", &sub3) ||
!dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &slice) ||
!dbus_message_iter_close_container(&sub2, &sub3) ||
!dbus_message_iter_close_container(&sub, &sub2))
return log_oom();
}
if (!isempty(description)) {
const char *description_property = "Description";
if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &description_property) ||
!dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "s", &sub3) ||
!dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &description) ||
!dbus_message_iter_close_container(&sub2, &sub3) ||
!dbus_message_iter_close_container(&sub, &sub2))
return log_oom();
}
/* cgroup empty notification is not available in containers
* currently. To make this less problematic, let's shorten the
* stop timeout for sessions, so that we don't wait
* forever. */
if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &timeout_stop_property) ||
!dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "t", &sub3) ||
!dbus_message_iter_append_basic(&sub3, DBUS_TYPE_UINT64, &timeout) ||
!dbus_message_iter_close_container(&sub2, &sub3) ||
!dbus_message_iter_close_container(&sub, &sub2))
return log_oom();
u = pid;
if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &pids_property) ||
!dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "au", &sub3) ||
!dbus_message_iter_open_container(&sub3, DBUS_TYPE_ARRAY, "u", &sub4) ||
!dbus_message_iter_append_basic(&sub4, DBUS_TYPE_UINT32, &u) ||
!dbus_message_iter_close_container(&sub3, &sub4) ||
!dbus_message_iter_close_container(&sub2, &sub3) ||
!dbus_message_iter_close_container(&sub, &sub2))
return log_oom();
if (more_properties) {
r = copy_many_fields(&sub, more_properties);
if (r < 0)
return r;
}
if (!dbus_message_iter_close_container(&iter, &sub))
return log_oom();
reply = dbus_connection_send_with_reply_and_block(manager->bus, m, -1, error);
if (!reply)
return -EIO;
if (job) {
const char *j;
char *copy;
if (!dbus_message_get_args(reply, error, DBUS_TYPE_OBJECT_PATH, &j, DBUS_TYPE_INVALID))
return -EIO;
copy = strdup(j);
if (!copy)
return -ENOMEM;
*job = copy;
}
return 0;
}
int manager_stop_unit(Manager *manager, const char *unit, DBusError *error, char **job) {
_cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
const char *fail = "fail";
int r;
assert(manager);
assert(unit);
r = bus_method_call_with_reply(
manager->bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
"StopUnit",
&reply,
error,
DBUS_TYPE_STRING, &unit,
DBUS_TYPE_STRING, &fail,
DBUS_TYPE_INVALID);
if (r < 0) {
if (dbus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
dbus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
if (job)
*job = NULL;
dbus_error_free(error);
return 0;
}
log_error("Failed to stop unit %s: %s", unit, bus_error(error, r));
return r;
}
if (job) {
const char *j;
char *copy;
if (!dbus_message_get_args(reply, error,
DBUS_TYPE_OBJECT_PATH, &j,
DBUS_TYPE_INVALID)) {
log_error("Failed to parse reply.");
return -EIO;
}
copy = strdup(j);
if (!copy)
return -ENOMEM;
*job = copy;
}
return 1;
}
int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, DBusError *error) {
_cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
const char *w;
int r;
assert(manager);
assert(unit);
w = who == KILL_LEADER ? "process" : "cgroup";
assert_cc(sizeof(signo) == sizeof(int32_t));
r = bus_method_call_with_reply(
manager->bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
"KillUnit",
&reply,
error,
DBUS_TYPE_STRING, &unit,
DBUS_TYPE_STRING, &w,
DBUS_TYPE_INT32, &signo,
DBUS_TYPE_INVALID);
if (r < 0) {
log_error("Failed to stop unit %s: %s", unit, bus_error(error, r));
return r;
}
return 0;
}
int manager_unit_is_active(Manager *manager, const char *unit) {
const char *interface = "org.freedesktop.systemd1.Unit";
const char *property = "ActiveState";
_cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
_cleanup_free_ char *path = NULL;
DBusMessageIter iter, sub;
const char *state;
DBusError error;
int r;
assert(manager);
assert(unit);
dbus_error_init(&error);
path = unit_dbus_path_from_name(unit);
if (!path)
return -ENOMEM;
r = bus_method_call_with_reply(
manager->bus,
"org.freedesktop.systemd1",
path,
"org.freedesktop.DBus.Properties",
"Get",
&reply,
&error,
DBUS_TYPE_STRING, &interface,
DBUS_TYPE_STRING, &property,
DBUS_TYPE_INVALID);
if (r < 0) {
if (dbus_error_has_name(&error, DBUS_ERROR_NO_REPLY) ||
dbus_error_has_name(&error, DBUS_ERROR_DISCONNECTED)) {
dbus_error_free(&error);
return true;
}
if (dbus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
dbus_error_has_name(&error, BUS_ERROR_LOAD_FAILED)) {
dbus_error_free(&error);
return false;
}
log_error("Failed to query ActiveState: %s", bus_error(&error, r));
dbus_error_free(&error);
return r;
}
if (!dbus_message_iter_init(reply, &iter) ||
dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
log_error("Failed to parse reply.");
return -EINVAL;
}
dbus_message_iter_recurse(&iter, &sub);
if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
log_error("Failed to parse reply.");
return -EINVAL;
}
dbus_message_iter_get_basic(&sub, &state);
return !streq(state, "inactive") && !streq(state, "failed");
}