machined: port over to libsystemd-bus

This commit is contained in:
Lennart Poettering 2013-10-30 02:06:55 +01:00
parent 07459db69f
commit c335068380
9 changed files with 808 additions and 1236 deletions

View File

@ -3709,15 +3709,14 @@ libsystemd_machine_core_la_SOURCES = \
src/machine/machine-dbus.c
libsystemd_machine_core_la_CFLAGS = \
$(AM_CFLAGS) \
$(DBUS_CFLAGS)
$(AM_CFLAGS)
libsystemd_machine_core_la_LIBADD = \
libsystemd-label.la \
libsystemd-audit.la \
libsystemd-shared.la \
libsystemd-daemon.la \
libsystemd-dbus.la \
libsystemd-bus.la \
libsystemd-id128-internal.la \
libudev.la
@ -3743,8 +3742,7 @@ test_machine_tables_SOURCES = \
src/machine/test-machine-tables.c
test_machine_tables_CFLAGS = \
$(AM_CFLAGS) \
$(DBUS_CFLAGS)
$(AM_CFLAGS)
test_machine_tables_LDADD = \
libsystemd-machine-core.la

View File

@ -43,5 +43,40 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus*, sd_bus_unref);
DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_message*, sd_bus_message_unref);
#define _cleanup_bus_unref_ _cleanup_(sd_bus_unrefp)
#define _cleanup_bus_error_free_ _cleanup_(sd_bus_error_free)
#define _cleanup_bus_message_unref_ _cleanup_(sd_bus_message_unrefp)
#define _cleanup_bus_error_free_ _cleanup_(sd_bus_error_free)
#define BUS_DEFINE_PROPERTY_GET_ENUM(function, name, type) \
int function(sd_bus *bus, \
const char *path, \
const char *interface, \
const char *property, \
sd_bus_message *reply, \
sd_bus_error *error, \
void *userdata) { \
\
const char *value; \
type *field = userdata; \
int r; \
\
assert(bus); \
assert(reply); \
assert(field); \
\
value = strempty(name##_to_string(*field)); \
\
r = sd_bus_message_append_basic(reply, 's', value); \
if (r < 0) \
return r; \
\
return 1; \
} \
struct __useless_struct_to_allow_trailing_semicolon__
#define BUS_ERROR_NO_SUCH_UNIT "org.freedesktop.systemd1.NoSuchUnit"
#define BUS_ERROR_LOAD_FAILED "org.freedesktop.systemd1.LoadFailed"
#define BUS_ERROR_JOB_FAILED "org.freedesktop.systemd1.JobFailed"
#define BUS_ERROR_NO_SUCH_MACHINE "org.freedesktop.machine1.NoSuchMachine"
#define BUS_ERROR_NO_MACHINE_FOR_PID "org.freedesktop.machine1.NoMachineForPID"
#define BUS_ERROR_MACHINE_EXISTS "org.freedesktop.machine1.MachineExists"

View File

@ -22,231 +22,153 @@
#include <errno.h>
#include <string.h>
#include "machined.h"
#include "bus-util.h"
#include "machine.h"
#include "dbus-common.h"
#define BUS_MACHINE_INTERFACE \
" <interface name=\"org.freedesktop.machine1.Machine\">\n" \
" <method name=\"Terminate\"/>\n" \
" <method name=\"Kill\">\n" \
" <arg name=\"who\" type=\"s\"/>\n" \
" <arg name=\"signal\" type=\"s\"/>\n" \
" </method>\n" \
" <property name=\"Name\" type=\"s\" access=\"read\"/>\n" \
" <property name=\"Id\" type=\"ay\" access=\"read\"/>\n" \
" <property name=\"Timestamp\" type=\"t\" access=\"read\"/>\n" \
" <property name=\"TimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
" <property name=\"Service\" type=\"s\" access=\"read\"/>\n" \
" <property name=\"Scope\" type=\"s\" access=\"read\"/>\n" \
" <property name=\"Leader\" type=\"u\" access=\"read\"/>\n" \
" <property name=\"Class\" type=\"s\" access=\"read\"/>\n" \
" <property name=\"State\" type=\"s\" access=\"read\"/>\n" \
" <property name=\"RootDirectory\" type=\"s\" access=\"read\"/>\n" \
" </interface>\n"
static int property_get_id(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
sd_bus_error *error,
void *userdata) {
#define INTROSPECTION \
DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
"<node>\n" \
BUS_MACHINE_INTERFACE \
BUS_PROPERTIES_INTERFACE \
BUS_PEER_INTERFACE \
BUS_INTROSPECTABLE_INTERFACE \
"</node>\n"
Machine *m = userdata;
int r;
#define INTERFACES_LIST \
BUS_GENERIC_INTERFACES_LIST \
"org.freedesktop.machine1.Machine\0"
static int bus_machine_append_id(DBusMessageIter *i, const char *property, void *data) {
DBusMessageIter sub;
Machine *m = data;
dbus_bool_t b;
void *p;
assert(i);
assert(property);
assert(bus);
assert(reply);
assert(m);
if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "y", &sub))
return -ENOMEM;
r = sd_bus_message_append_array(reply, 'y', &m->id, 16);
if (r < 0)
return r;
p = &m->id;
b = dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &p, 16);
if (!b)
return -ENOMEM;
if (!dbus_message_iter_close_container(i, &sub))
return -ENOMEM;
return 0;
return 1;
}
static int bus_machine_append_state(DBusMessageIter *i, const char *property, void *data) {
Machine *m = data;
const char *state;
static int property_get_state(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
sd_bus_error *error,
void *userdata) {
assert(i);
assert(property);
Machine *m = userdata;
const char *state;
int r;
assert(bus);
assert(reply);
assert(m);
state = machine_state_to_string(machine_get_state(m));
if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &state))
return -ENOMEM;
r = sd_bus_message_append_basic(reply, 's', state);
if (r < 0)
return r;
return 0;
return 1;
}
static int get_machine_for_path(Manager *m, const char *path, Machine **_machine) {
_cleanup_free_ char *e = NULL;
Machine *machine;
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class, machine_class, MachineClass);
static int method_terminate(sd_bus *bus, sd_bus_message *message, void *userdata) {
Machine *m = userdata;
int r;
assert(bus);
assert(message);
assert(m);
r = machine_stop(m);
if (r < 0)
return sd_bus_reply_method_errno(bus, message, r, NULL);
return sd_bus_reply_method_return(bus, message, NULL);
}
static int method_kill(sd_bus *bus, sd_bus_message *message, void *userdata) {
Machine *m = userdata;
const char *swho;
int32_t signo;
KillWho who;
int r;
assert(bus);
assert(message);
assert(m);
r = sd_bus_message_read(message, "si", &swho, &signo);
if (r < 0)
return sd_bus_reply_method_errno(bus, message, r, NULL);
if (isempty(swho))
who = KILL_ALL;
else {
who = kill_who_from_string(swho);
if (who < 0)
return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
}
if (signo <= 0 || signo >= _NSIG)
return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
r = machine_kill(m, who, signo);
if (r < 0)
return sd_bus_reply_method_errno(bus, message, r, NULL);
return sd_bus_reply_method_return(bus, message, NULL);
}
const sd_bus_vtable machine_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Machine, name), 0),
SD_BUS_PROPERTY("Id", "ay", property_get_id, 0, 0),
SD_BUS_PROPERTY("Timestamp", "t", NULL, offsetof(Machine, timestamp.realtime), 0),
SD_BUS_PROPERTY("TimestampMonotonic", "t", NULL, offsetof(Machine, timestamp.monotonic), 0),
SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Machine, service), 0),
SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Machine, scope), 0),
SD_BUS_PROPERTY("Leader", "u", NULL, offsetof(Machine, leader), 0),
SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Machine, class), 0),
SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(Machine, root_directory), 0),
SD_BUS_METHOD("Terminate", NULL, NULL, method_terminate, 0),
SD_BUS_METHOD("Kill", "si", NULL, method_kill, 0),
SD_BUS_VTABLE_END
};
int machine_object_find(sd_bus *bus, const char *path, const char *interface, void **found, void *userdata) {
_cleanup_free_ char *e = NULL;
Manager *m = userdata;
Machine *machine;
const char *p;
assert(bus);
assert(path);
assert(_machine);
assert(interface);
assert(found);
assert(m);
if (!startswith(path, "/org/freedesktop/machine1/machine/"))
return -EINVAL;
p = startswith(path, "/org/freedesktop/machine1/machine/");
if (!p)
return 0;
e = bus_path_unescape(path + 34);
e = bus_path_unescape(p);
if (!e)
return -ENOMEM;
machine = hashmap_get(m->machines, e);
if (!machine)
return -ENOENT;
return 0;
*_machine = machine;
return 0;
*found = machine;
return 1;
}
static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_machine_append_class, machine_class, MachineClass);
static const BusProperty bus_machine_machine_properties[] = {
{ "Name", bus_property_append_string, "s", offsetof(Machine, name), true },
{ "Id", bus_machine_append_id, "ay", 0 },
{ "Timestamp", bus_property_append_usec, "t", offsetof(Machine, timestamp.realtime) },
{ "TimestampMonotonic", bus_property_append_usec, "t", offsetof(Machine, timestamp.monotonic) },
{ "Service", bus_property_append_string, "s", offsetof(Machine, service), true },
{ "Scope", bus_property_append_string, "s", offsetof(Machine, scope), true },
{ "Leader", bus_property_append_pid, "u", offsetof(Machine, leader) },
{ "Class", bus_machine_append_class, "s", offsetof(Machine, class) },
{ "State", bus_machine_append_state, "s", 0 },
{ "RootDirectory", bus_property_append_string, "s", offsetof(Machine, root_directory), true },
{ NULL, }
};
static DBusHandlerResult machine_message_dispatch(
Machine *m,
DBusConnection *connection,
DBusMessage *message) {
DBusError error;
_cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
int r;
assert(m);
assert(connection);
assert(message);
if (dbus_message_is_method_call(message, "org.freedesktop.machine1.Machine", "Terminate")) {
r = machine_stop(m);
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.Machine", "Kill")) {
const char *swho;
int32_t signo;
KillWho who;
if (!dbus_message_get_args(
message,
&error,
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);
r = machine_kill(m, 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 {
const BusBoundProperties bps[] = {
{ "org.freedesktop.machine1.Machine", bus_machine_machine_properties, m },
{ NULL, }
};
return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, bps);
}
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;
}
static DBusHandlerResult machine_message_handler(
DBusConnection *connection,
DBusMessage *message,
void *userdata) {
Manager *manager = userdata;
Machine *m;
int r;
r = get_machine_for_path(manager, dbus_message_get_path(message), &m);
if (r < 0) {
if (r == -ENOMEM)
return DBUS_HANDLER_RESULT_NEED_MEMORY;
if (r == -ENOENT) {
DBusError e;
dbus_error_init(&e);
dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown machine");
return bus_send_error_reply(connection, message, &e, r);
}
return bus_send_error_reply(connection, message, NULL, r);
}
return machine_message_dispatch(m, connection, message);
}
const DBusObjectPathVTable bus_machine_vtable = {
.message_function = machine_message_handler
};
char *machine_bus_path(Machine *m) {
_cleanup_free_ char *e = NULL;
@ -260,105 +182,44 @@ char *machine_bus_path(Machine *m) {
}
int machine_send_signal(Machine *m, bool new_machine) {
_cleanup_dbus_message_unref_ DBusMessage *msg = NULL;
_cleanup_free_ char *p = NULL;
assert(m);
msg = dbus_message_new_signal("/org/freedesktop/machine1",
"org.freedesktop.machine1.Manager",
new_machine ? "MachineNew" : "MachineRemoved");
if (!m)
return -ENOMEM;
p = machine_bus_path(m);
if (!p)
return -ENOMEM;
if (!dbus_message_append_args(
msg,
DBUS_TYPE_STRING, &m->name,
DBUS_TYPE_OBJECT_PATH, &p,
DBUS_TYPE_INVALID))
return -ENOMEM;
if (!dbus_connection_send(m->manager->bus, msg, NULL))
return -ENOMEM;
return 0;
return sd_bus_emit_signal(
m->manager->bus,
"/org/freedesktop/machine1",
"org.freedesktop.machine1.Manager",
new_machine ? "MachineNew" : "MachineRemoved",
"so", m->name, p);
}
int machine_send_changed(Machine *m, const char *properties) {
_cleanup_dbus_message_unref_ DBusMessage *msg = NULL;
int machine_send_create_reply(Machine *m, sd_bus_error *error) {
_cleanup_bus_message_unref_ sd_bus_message *c = NULL;
_cleanup_free_ char *p = NULL;
assert(m);
if (!m->started)
return 0;
p = machine_bus_path(m);
if (!p)
return -ENOMEM;
msg = bus_properties_changed_new(p, "org.freedesktop.machine1.Machine", properties);
if (!msg)
return -ENOMEM;
if (!dbus_connection_send(m->manager->bus, msg, NULL))
return -ENOMEM;
return 0;
}
int machine_send_create_reply(Machine *m, DBusError *error) {
_cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
assert(m);
if (!m->create_message)
return 0;
if (error) {
DBusError buffer;
dbus_error_init(&buffer);
if (!error || !dbus_error_is_set(error)) {
dbus_set_error_const(&buffer, DBUS_ERROR_INVALID_ARGS, "Invalid Arguments");
error = &buffer;
}
reply = dbus_message_new_error(m->create_message, error->name, error->message);
dbus_error_free(&buffer);
if (!reply)
return log_oom();
} else {
_cleanup_free_ char *p = NULL;
p = machine_bus_path(m);
if (!p)
return log_oom();
reply = dbus_message_new_method_return(m->create_message);
if (!reply)
return log_oom();
if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &p, DBUS_TYPE_INVALID))
return log_oom();
}
c = m->create_message;
m->create_message = NULL;
/* Update the machine state file before we notify the client
* about the result. */
machine_save(m);
if (!dbus_connection_send(m->manager->bus, reply, NULL))
return log_oom();
if (error)
return sd_bus_reply_method_error(m->manager->bus, c, error);
dbus_message_unref(m->create_message);
m->create_message = NULL;
p = machine_bus_path(m);
if (!p)
return -ENOMEM;
return 0;
return sd_bus_reply_method_return(m->manager->bus, c, "o", p);
}

View File

@ -23,7 +23,7 @@
#include <unistd.h>
#include <errno.h>
#include <systemd/sd-messages.h>
#include "sd-messages.h"
#include "util.h"
#include "mkdir.h"
@ -32,8 +32,9 @@
#include "fileio.h"
#include "special.h"
#include "unit-name.h"
#include "dbus-common.h"
#include "machine.h"
#include "bus-util.h"
#include "bus-error.h"
Machine* machine_new(Manager *manager, const char *name) {
Machine *m;
@ -84,8 +85,7 @@ void machine_free(Machine *m) {
hashmap_remove(m->manager->machines, m->name);
if (m->create_message)
dbus_message_unref(m->create_message);
sd_bus_message_unref(m->create_message);
free(m->name);
free(m->state_file);
@ -217,19 +217,14 @@ int machine_load(Machine *m) {
return r;
}
static int machine_start_scope(Machine *m, DBusMessageIter *iter) {
_cleanup_free_ char *description = NULL;
DBusError error;
char *job;
static int machine_start_scope(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
int r = 0;
assert(m);
dbus_error_init(&error);
if (!m->scope) {
_cleanup_free_ char *escaped = NULL;
char *scope;
char *scope, *description, *job;
escaped = unit_name_escape(m->name);
if (!escaped)
@ -239,13 +234,11 @@ static int machine_start_scope(Machine *m, DBusMessageIter *iter) {
if (!scope)
return log_oom();
description = strappend(m->class == MACHINE_VM ? "Virtual Machine " : "Container ", m->name);
description = strappenda(m->class == MACHINE_VM ? "Virtual Machine " : "Container ", m->name);
r = manager_start_scope(m->manager, scope, m->leader, SPECIAL_MACHINE_SLICE, description, iter, &error, &job);
r = manager_start_scope(m->manager, scope, m->leader, SPECIAL_MACHINE_SLICE, description, properties, error, &job);
if (r < 0) {
log_error("Failed to start machine scope: %s", bus_error(&error, r));
dbus_error_free(&error);
log_error("Failed to start machine scope: %s", bus_error_message(error, r));
free(scope);
return r;
} else {
@ -262,7 +255,7 @@ static int machine_start_scope(Machine *m, DBusMessageIter *iter) {
return r;
}
int machine_start(Machine *m, DBusMessageIter *iter) {
int machine_start(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
int r;
assert(m);
@ -271,7 +264,7 @@ int machine_start(Machine *m, DBusMessageIter *iter) {
return 0;
/* Create cgroup */
r = machine_start_scope(m, iter);
r = machine_start_scope(m, properties, error);
if (r < 0)
return r;
@ -296,21 +289,18 @@ int machine_start(Machine *m, DBusMessageIter *iter) {
}
static int machine_stop_scope(Machine *m) {
DBusError error;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
char *job;
int r;
assert(m);
dbus_error_init(&error);
if (!m->scope)
return 0;
r = manager_stop_unit(m->manager, m->scope, &error, &job);
if (r < 0) {
log_error("Failed to stop machine scope: %s", bus_error(&error, r));
dbus_error_free(&error);
log_error("Failed to stop machine scope: %s", bus_error_message(&error, r));
return r;
}
@ -352,15 +342,15 @@ int machine_check_gc(Machine *m, bool drop_not_started) {
assert(m);
if (drop_not_started && !m->started)
return 0;
return false;
if (m->scope_job)
return 1;
if (m->scope_job && manager_job_is_active(m->manager, m->scope_job))
return true;
if (m->scope)
return manager_unit_is_active(m->manager, m->scope) != 0;
if (m->scope && manager_unit_is_active(m->manager, m->scope))
return true;
return 0;
return false;
}
void machine_add_to_gc_queue(Machine *m) {

View File

@ -73,7 +73,7 @@ struct Machine {
bool in_gc_queue:1;
bool started:1;
DBusMessage *create_message;
sd_bus_message *create_message;
LIST_FIELDS(Machine, gc_queue);
};
@ -82,22 +82,21 @@ Machine* machine_new(Manager *manager, const char *name);
void machine_free(Machine *m);
int machine_check_gc(Machine *m, bool drop_not_started);
void machine_add_to_gc_queue(Machine *m);
int machine_start(Machine *m, DBusMessageIter *iter);
int machine_start(Machine *m, sd_bus_message *properties, sd_bus_error *error);
int machine_stop(Machine *m);
int machine_save(Machine *m);
int machine_load(Machine *m);
int machine_kill(Machine *m, KillWho who, int signo);
char *machine_bus_path(Machine *s);
MachineState machine_get_state(Machine *u);
extern const DBusObjectPathVTable bus_machine_vtable;
extern const sd_bus_vtable machine_vtable[];
char *machine_bus_path(Machine *s);
int machine_object_find(sd_bus *bus, const char *path, const char *interface, void **found, void *userdata);
int machine_send_signal(Machine *m, bool new_machine);
int machine_send_changed(Machine *m, const char *properties);
int machine_send_create_reply(Machine *m, DBusError *error);
int machine_send_create_reply(Machine *m, sd_bus_error *error);
const char* machine_class_to_string(MachineClass t) _const_;
MachineClass machine_class_from_string(const char *s) _pure_;

File diff suppressed because it is too large Load Diff

View File

@ -26,28 +26,33 @@
#include <unistd.h>
#include <sys/epoll.h>
#include <systemd/sd-daemon.h>
#include "sd-daemon.h"
#include "machined.h"
#include "dbus-common.h"
#include "dbus-loop.h"
#include "strv.h"
#include "conf-parser.h"
#include "cgroup-util.h"
#include "mkdir.h"
#include "bus-util.h"
#include "bus-error.h"
#include "machined.h"
Manager *manager_new(void) {
Manager *m;
int r;
m = new0(Manager, 1);
if (!m)
return NULL;
m->bus_fd = -1;
m->epoll_fd = -1;
m->machines = hashmap_new(string_hash_func, string_compare_func);
m->machine_units = hashmap_new(string_hash_func, string_compare_func);
r = sd_event_new(&m->event);
if (r < 0) {
manager_free(m);
return NULL;
}
if (!m->machines || !m->machine_units) {
manager_free(m);
return NULL;
@ -67,21 +72,52 @@ void manager_free(Manager *m) {
hashmap_free(m->machines);
hashmap_free(m->machine_units);
if (m->bus) {
dbus_connection_flush(m->bus);
dbus_connection_close(m->bus);
dbus_connection_unref(m->bus);
}
if (m->bus_fd >= 0)
close_nointr_nofail(m->bus_fd);
if (m->epoll_fd >= 0)
close_nointr_nofail(m->epoll_fd);
sd_bus_unref(m->bus);
sd_event_unref(m->event);
free(m);
}
int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
Machine *machine;
assert(m);
assert(name);
machine = hashmap_get(m->machines, name);
if (!machine) {
machine = machine_new(m, name);
if (!machine)
return -ENOMEM;
}
if (_machine)
*_machine = machine;
return 0;
}
int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
_cleanup_free_ char *unit = NULL;
Machine *mm;
int r;
assert(m);
assert(pid >= 1);
assert(machine);
r = cg_pid_get_unit(pid, &unit);
if (r < 0)
return r;
mm = hashmap_get(m->machine_units, unit);
if (!mm)
return 0;
*machine = mm;
return 1;
}
int manager_enumerate_machines(Manager *m) {
_cleanup_closedir_ DIR *d = NULL;
struct dirent *de;
@ -125,122 +161,118 @@ int manager_enumerate_machines(Manager *m) {
}
static int manager_connect_bus(Manager *m) {
DBusError error;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
struct epoll_event ev = {
.events = EPOLLIN,
.data.u32 = FD_BUS,
};
assert(m);
assert(!m->bus);
assert(m->bus_fd < 0);
dbus_error_init(&error);
m->bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
if (!m->bus) {
log_error("Failed to get system D-Bus connection: %s", bus_error_message(&error));
r = -ECONNREFUSED;
goto fail;
r = sd_bus_open_system(&m->bus);
if (r < 0) {
log_error("Failed to connect to system bus: %s", strerror(-r));
return r;
}
if (!dbus_connection_register_object_path(m->bus, "/org/freedesktop/machine1", &bus_manager_vtable, m) ||
!dbus_connection_register_fallback(m->bus, "/org/freedesktop/machine1/machine", &bus_machine_vtable, m) ||
!dbus_connection_add_filter(m->bus, bus_message_filter, m, NULL)) {
r = log_oom();
goto fail;
r = sd_bus_add_object_vtable(m->bus, "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", manager_vtable, m);
if (r < 0) {
log_error("Failed to add manager object vtable: %s", strerror(-r));
return r;
}
dbus_bus_add_match(m->bus,
"type='signal',"
"sender='org.freedesktop.systemd1',"
"interface='org.freedesktop.systemd1.Manager',"
"member='JobRemoved',"
"path='/org/freedesktop/systemd1'",
&error);
if (dbus_error_is_set(&error)) {
log_error("Failed to add match for JobRemoved: %s", bus_error_message(&error));
dbus_error_free(&error);
r = sd_bus_add_fallback_vtable(m->bus, "/org/freedesktop/machine1/machine", "org.freedesktop.machine1.Machine", machine_vtable, machine_object_find, m);
if (r < 0) {
log_error("Failed to add machine object vtable: %s", strerror(-r));
return r;
}
dbus_bus_add_match(m->bus,
"type='signal',"
"sender='org.freedesktop.systemd1',"
"interface='org.freedesktop.systemd1.Manager',"
"member='UnitRemoved',"
"path='/org/freedesktop/systemd1'",
&error);
if (dbus_error_is_set(&error)) {
log_error("Failed to add match for UnitRemoved: %s", bus_error_message(&error));
dbus_error_free(&error);
r = sd_bus_add_node_enumerator(m->bus, "/org/freedesktop/machine1/machine", machine_node_enumerator, m);
if (r < 0) {
log_error("Failed to add machine enumerator: %s", strerror(-r));
return r;
}
dbus_bus_add_match(m->bus,
"type='signal',"
"sender='org.freedesktop.systemd1',"
"interface='org.freedesktop.DBus.Properties',"
"member='PropertiesChanged'",
&error);
if (dbus_error_is_set(&error)) {
log_error("Failed to add match for PropertiesChanged: %s", bus_error_message(&error));
dbus_error_free(&error);
r = sd_bus_add_match(m->bus,
"type='signal',"
"sender='org.freedesktop.systemd1',"
"interface='org.freedesktop.systemd1.Manager',"
"member='JobRemoved',"
"path='/org/freedesktop/systemd1'",
match_job_removed,
m);
if (r < 0) {
log_error("Failed to add match for JobRemoved: %s", strerror(-r));
return r;
}
dbus_bus_add_match(m->bus,
"type='signal',"
"sender='org.freedesktop.systemd1',"
"interface='org.freedesktop.systemd1.Manager',"
"member='Reloading',"
"path='/org/freedesktop/systemd1'",
&error);
if (dbus_error_is_set(&error)) {
log_error("Failed to add match for Reloading: %s", bus_error_message(&error));
dbus_error_free(&error);
r = sd_bus_add_match(m->bus,
"type='signal',"
"sender='org.freedesktop.systemd1',"
"interface='org.freedesktop.systemd1.Manager',"
"member='UnitRemoved',"
"path='/org/freedesktop/systemd1'",
match_unit_removed,
m);
if (r < 0) {
log_error("Failed to add match for UnitRemoved: %s", strerror(-r));
return r;
}
r = bus_method_call_with_reply(
r = sd_bus_add_match(m->bus,
"type='signal',"
"sender='org.freedesktop.systemd1',"
"interface='org.freedesktop.DBus.Properties',"
"member='PropertiesChanged'",
match_properties_changed,
m);
if (r < 0) {
log_error("Failed to add match for PropertiesChanged: %s", strerror(-r));
return r;
}
r = sd_bus_add_match(m->bus,
"type='signal',"
"sender='org.freedesktop.systemd1',"
"interface='org.freedesktop.systemd1.Manager',"
"member='Reloading',"
"path='/org/freedesktop/systemd1'",
match_reloading,
m);
if (r < 0) {
log_error("Failed to add match for Reloading: %s", strerror(-r));
return r;
}
r = sd_bus_call_method(
m->bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
"Subscribe",
NULL,
&error,
DBUS_TYPE_INVALID);
NULL, NULL);
if (r < 0) {
log_error("Failed to enable subscription: %s", bus_error(&error, r));
dbus_error_free(&error);
log_error("Failed to enable subscription: %s", bus_error_message(&error, r));
return r;
}
r = dbus_bus_request_name(m->bus, "org.freedesktop.machine1", DBUS_NAME_FLAG_DO_NOT_QUEUE, &error);
if (dbus_error_is_set(&error)) {
log_error("Failed to register name on bus: %s", bus_error_message(&error));
r = -EIO;
goto fail;
r = sd_bus_request_name(m->bus, "org.freedesktop.machine1", SD_BUS_NAME_DO_NOT_QUEUE);
if (r < 0) {
log_error("Failed to register name: %s", strerror(-r));
return r;
}
if (r != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
if (r != SD_BUS_NAME_PRIMARY_OWNER) {
log_error("Failed to acquire name.");
r = -EEXIST;
goto fail;
return -EEXIST;
}
m->bus_fd = bus_loop_open(m->bus);
if (m->bus_fd < 0) {
r = m->bus_fd;
goto fail;
r = sd_bus_attach_event(m->bus, m->event, 0);
if (r < 0) {
log_error("Failed to attach bus to event loop: %s", strerror(-r));
return r;
}
if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->bus_fd, &ev) < 0)
goto fail;
return 0;
fail:
dbus_error_free(&error);
return r;
}
void manager_gc(Manager *m, bool drop_not_started) {
@ -260,16 +292,11 @@ void manager_gc(Manager *m, bool drop_not_started) {
}
int manager_startup(Manager *m) {
int r;
Machine *machine;
Iterator i;
int r;
assert(m);
assert(m->epoll_fd <= 0);
m->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
if (m->epoll_fd < 0)
return -errno;
/* Connect to the bus */
r = manager_connect_bus(m);
@ -284,46 +311,28 @@ int manager_startup(Manager *m) {
/* And start everything */
HASHMAP_FOREACH(machine, m->machines, i)
machine_start(machine, NULL);
machine_start(machine, NULL, NULL);
return 0;
}
int manager_run(Manager *m) {
int r;
assert(m);
for (;;) {
struct epoll_event event;
int n;
r = sd_event_get_state(m->event);
if (r < 0)
return r;
if (r == SD_EVENT_FINISHED)
return 0;
manager_gc(m, true);
if (dbus_connection_dispatch(m->bus) != DBUS_DISPATCH_COMPLETE)
continue;
manager_gc(m, true);
n = epoll_wait(m->epoll_fd, &event, 1, -1);
if (n < 0) {
if (errno == EINTR || errno == EAGAIN)
continue;
log_error("epoll() failed: %m");
return -errno;
}
if (n == 0)
continue;
switch (event.data.u32) {
case FD_BUS:
bus_loop_dispatch(m->bus_fd);
break;
default:
assert_not_reached("Unknown fd");
}
r = sd_event_run(m->event, (uint64_t) -1);
if (r < 0)
return r;
}
return 0;
@ -348,9 +357,9 @@ int main(int argc, char *argv[]) {
/* Always create the directories people can create inotify
* watches in. Note that some applications might check for the
* existence of /run/systemd/seats/ to determine whether
* machined is available, so please always make sure this check
* stays in. */
* existence of /run/systemd/machines/ to determine whether
* machined is available, so please always make sure this
* check stays in. */
mkdir_label("/run/systemd/machines", 0755);
m = manager_new();

View File

@ -23,21 +23,20 @@
#include <stdbool.h>
#include <inttypes.h>
#include <dbus/dbus.h>
#include "util.h"
#include "list.h"
#include "hashmap.h"
#include "sd-event.h"
#include "sd-bus.h"
typedef struct Manager Manager;
#include "machine.h"
struct Manager {
DBusConnection *bus;
int bus_fd;
int epoll_fd;
sd_event *event;
sd_bus *bus;
Hashmap *machines;
Hashmap *machine_units;
@ -45,10 +44,6 @@ struct Manager {
LIST_HEAD(Machine, machine_gc_queue);
};
enum {
FD_BUS
};
Manager *manager_new(void);
void manager_free(Manager *m);
@ -63,11 +58,17 @@ void manager_gc(Manager *m, bool drop_not_started);
int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine);
extern const DBusObjectPathVTable bus_manager_vtable;
extern const sd_bus_vtable manager_vtable[];
DBusHandlerResult bus_message_filter(DBusConnection *c, DBusMessage *message, void *userdata);
int machine_node_enumerator(sd_bus *bus, const char *path, char ***nodes, void *userdata);
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);
int manager_stop_unit(Manager *manager, const char *unit, DBusError *error, char **job);
int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, DBusError *error);
int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata);
int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata);
int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata);
int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata);
int manager_start_scope(Manager *manager, const char *scope, pid_t pid, const char *slice, const char *description, sd_bus_message *more_properties, sd_bus_error *error, char **job);
int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job);
int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, sd_bus_error *error);
int manager_unit_is_active(Manager *manager, const char *unit);
int manager_job_is_active(Manager *manager, const char *path);

View File

@ -82,7 +82,6 @@ bool strv_overlap(char **a, char **b) _pure_;
#define STRV_FOREACH_PAIR(x, y, l) \
for ((x) = (l), (y) = (x+1); (x) && *(x) && *(y); (x) += 2, (y) = (x + 1))
char **strv_sort(char **l);
void strv_print(char **l);