mirror of
https://github.com/systemd/systemd.git
synced 2024-12-17 22:23:39 +08:00
machined: port over to libsystemd-bus
This commit is contained in:
parent
07459db69f
commit
c335068380
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user