machined: optionally, allow registration of pre-existing units (scopes
or services) as machine with machined
This commit is contained in:
parent
2d2ebd6b8f
commit
89f7c8465c
|
@ -465,8 +465,8 @@
|
||||||
should be enabled when the container
|
should be enabled when the container
|
||||||
runs a full Operating System (more
|
runs a full Operating System (more
|
||||||
specifically: an init system), and is
|
specifically: an init system), and is
|
||||||
useful to ensure the container is
|
useful to ensure that the container is
|
||||||
accesible via
|
accessible via
|
||||||
<citerefentry><refentrytitle>machinectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
<citerefentry><refentrytitle>machinectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||||
and shown by tools such as
|
and shown by tools such as
|
||||||
<citerefentry><refentrytitle>ps</refentrytitle><manvolnum>1</manvolnum></citerefentry>. If
|
<citerefentry><refentrytitle>ps</refentrytitle><manvolnum>1</manvolnum></citerefentry>. If
|
||||||
|
@ -478,6 +478,30 @@
|
||||||
<option>--register=no</option>.
|
<option>--register=no</option>.
|
||||||
</para></listitem>
|
</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>--keep-unit</option></term>
|
||||||
|
|
||||||
|
<listitem><para>Instead of creating a
|
||||||
|
transient scope unit to run the
|
||||||
|
container in, simply register the
|
||||||
|
service or scope unit
|
||||||
|
<command>systemd-nspawn</command> has
|
||||||
|
been invoked in in
|
||||||
|
<citerefentry><refentrytitle>systemd-machined</refentrytitle><manvolnum>8</manvolnum></citerefentry>. This
|
||||||
|
has no effect if
|
||||||
|
<option>--register=no</option> is
|
||||||
|
used. This switch should be used if
|
||||||
|
<command>systemd-nspawn</command> is
|
||||||
|
invoked from within an a service unit,
|
||||||
|
and the service unit's sole purpose
|
||||||
|
is to run a single
|
||||||
|
<command>systemd-nspawn</command>
|
||||||
|
container. This option is not
|
||||||
|
available if run from a user
|
||||||
|
session.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
</variablelist>
|
</variablelist>
|
||||||
|
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
|
@ -630,7 +630,32 @@ _public_ int sd_get_uids(uid_t **users) {
|
||||||
}
|
}
|
||||||
|
|
||||||
_public_ int sd_get_machine_names(char ***machines) {
|
_public_ int sd_get_machine_names(char ***machines) {
|
||||||
return get_files_in_directory("/run/systemd/machines/", machines);
|
char **l = NULL, **a, **b;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = get_files_in_directory("/run/systemd/machines/", &l);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (l) {
|
||||||
|
r = 0;
|
||||||
|
|
||||||
|
/* Filter out the unit: symlinks */
|
||||||
|
for (a = l, b = l; *a; a++) {
|
||||||
|
if (startswith(*a, "unit:"))
|
||||||
|
free(*a);
|
||||||
|
else {
|
||||||
|
*b = *a;
|
||||||
|
b++;
|
||||||
|
r++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*b = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*machines = l;
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int MONITOR_TO_FD(sd_login_monitor *m) {
|
static inline int MONITOR_TO_FD(sd_login_monitor *m) {
|
||||||
|
|
|
@ -132,7 +132,8 @@ const sd_bus_vtable machine_vtable[] = {
|
||||||
SD_BUS_PROPERTY("Id", "ay", property_get_id, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("Id", "ay", property_get_id, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Machine, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
|
BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Machine, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Machine, service), SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Machine, service), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Machine, scope), SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("Unit", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
|
SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
|
||||||
SD_BUS_PROPERTY("Leader", "u", NULL, offsetof(Machine, leader), SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("Leader", "u", NULL, offsetof(Machine, leader), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Machine, class), SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Machine, class), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(Machine, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(Machine, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
|
|
|
@ -76,9 +76,9 @@ void machine_free(Machine *m) {
|
||||||
if (m->in_gc_queue)
|
if (m->in_gc_queue)
|
||||||
LIST_REMOVE(gc_queue, m->manager->machine_gc_queue, m);
|
LIST_REMOVE(gc_queue, m->manager->machine_gc_queue, m);
|
||||||
|
|
||||||
if (m->scope) {
|
if (m->unit) {
|
||||||
hashmap_remove(m->manager->machine_units, m->scope);
|
hashmap_remove(m->manager->machine_units, m->unit);
|
||||||
free(m->scope);
|
free(m->unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(m->scope_job);
|
free(m->scope_job);
|
||||||
|
@ -123,8 +123,8 @@ int machine_save(Machine *m) {
|
||||||
"NAME=%s\n",
|
"NAME=%s\n",
|
||||||
m->name);
|
m->name);
|
||||||
|
|
||||||
if (m->scope)
|
if (m->unit)
|
||||||
fprintf(f, "SCOPE=%s\n", m->scope);
|
fprintf(f, "SCOPE=%s\n", m->unit); /* We continue to call this "SCOPE=" because it is internal only, and we want to stay compatible with old files */
|
||||||
|
|
||||||
if (m->scope_job)
|
if (m->scope_job)
|
||||||
fprintf(f, "SCOPE_JOB=%s\n", m->scope_job);
|
fprintf(f, "SCOPE_JOB=%s\n", m->scope_job);
|
||||||
|
@ -159,6 +159,16 @@ int machine_save(Machine *m) {
|
||||||
unlink(temp_path);
|
unlink(temp_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m->unit) {
|
||||||
|
char *sl;
|
||||||
|
|
||||||
|
/* Create a symlink from the unit name to the machine
|
||||||
|
* name, so that we can quickly find the machine for
|
||||||
|
* each given unit */
|
||||||
|
sl = strappenda("/run/systemd/machines/unit:", m->unit);
|
||||||
|
symlink(m->name, sl);
|
||||||
|
}
|
||||||
|
|
||||||
finish:
|
finish:
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_error("Failed to save machine data %s: %s", m->state_file, strerror(-r));
|
log_error("Failed to save machine data %s: %s", m->state_file, strerror(-r));
|
||||||
|
@ -166,6 +176,21 @@ finish:
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void machine_unlink(Machine *m) {
|
||||||
|
assert(m);
|
||||||
|
|
||||||
|
if (m->unit) {
|
||||||
|
|
||||||
|
char *sl;
|
||||||
|
|
||||||
|
sl = strappenda("/run/systemd/machines/unit:", m->unit);
|
||||||
|
unlink(sl);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m->state_file)
|
||||||
|
unlink(m->state_file);
|
||||||
|
}
|
||||||
|
|
||||||
int machine_load(Machine *m) {
|
int machine_load(Machine *m) {
|
||||||
_cleanup_free_ char *realtime = NULL, *monotonic = NULL, *id = NULL, *leader = NULL, *class = NULL;
|
_cleanup_free_ char *realtime = NULL, *monotonic = NULL, *id = NULL, *leader = NULL, *class = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
@ -173,7 +198,7 @@ int machine_load(Machine *m) {
|
||||||
assert(m);
|
assert(m);
|
||||||
|
|
||||||
r = parse_env_file(m->state_file, NEWLINE,
|
r = parse_env_file(m->state_file, NEWLINE,
|
||||||
"SCOPE", &m->scope,
|
"SCOPE", &m->unit,
|
||||||
"SCOPE_JOB", &m->scope_job,
|
"SCOPE_JOB", &m->scope_job,
|
||||||
"SERVICE", &m->service,
|
"SERVICE", &m->service,
|
||||||
"ROOT", &m->root_directory,
|
"ROOT", &m->root_directory,
|
||||||
|
@ -225,7 +250,7 @@ static int machine_start_scope(Machine *m, sd_bus_message *properties, sd_bus_er
|
||||||
|
|
||||||
assert(m);
|
assert(m);
|
||||||
|
|
||||||
if (!m->scope) {
|
if (!m->unit) {
|
||||||
_cleanup_free_ char *escaped = NULL;
|
_cleanup_free_ char *escaped = NULL;
|
||||||
char *scope, *description, *job;
|
char *scope, *description, *job;
|
||||||
|
|
||||||
|
@ -245,15 +270,15 @@ static int machine_start_scope(Machine *m, sd_bus_message *properties, sd_bus_er
|
||||||
free(scope);
|
free(scope);
|
||||||
return r;
|
return r;
|
||||||
} else {
|
} else {
|
||||||
m->scope = scope;
|
m->unit = scope;
|
||||||
|
|
||||||
free(m->scope_job);
|
free(m->scope_job);
|
||||||
m->scope_job = job;
|
m->scope_job = job;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m->scope)
|
if (m->unit)
|
||||||
hashmap_put(m->manager->machine_units, m->scope, m);
|
hashmap_put(m->manager->machine_units, m->unit, m);
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -302,10 +327,10 @@ static int machine_stop_scope(Machine *m) {
|
||||||
|
|
||||||
assert(m);
|
assert(m);
|
||||||
|
|
||||||
if (!m->scope)
|
if (!m->unit)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
r = manager_stop_unit(m->manager, m->scope, &error, &job);
|
r = manager_stop_unit(m->manager, m->unit, &error, &job);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_error("Failed to stop machine scope: %s", bus_error_message(&error, r));
|
log_error("Failed to stop machine scope: %s", bus_error_message(&error, r));
|
||||||
return r;
|
return r;
|
||||||
|
@ -334,7 +359,7 @@ int machine_stop(Machine *m) {
|
||||||
if (k < 0)
|
if (k < 0)
|
||||||
r = k;
|
r = k;
|
||||||
|
|
||||||
unlink(m->state_file);
|
machine_unlink(m);
|
||||||
machine_add_to_gc_queue(m);
|
machine_add_to_gc_queue(m);
|
||||||
|
|
||||||
if (m->started)
|
if (m->started)
|
||||||
|
@ -354,7 +379,7 @@ bool machine_check_gc(Machine *m, bool drop_not_started) {
|
||||||
if (m->scope_job && manager_job_is_active(m->manager, m->scope_job))
|
if (m->scope_job && manager_job_is_active(m->manager, m->scope_job))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (m->scope && manager_unit_is_active(m->manager, m->scope))
|
if (m->unit && manager_unit_is_active(m->manager, m->unit))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -382,10 +407,10 @@ MachineState machine_get_state(Machine *s) {
|
||||||
int machine_kill(Machine *m, KillWho who, int signo) {
|
int machine_kill(Machine *m, KillWho who, int signo) {
|
||||||
assert(m);
|
assert(m);
|
||||||
|
|
||||||
if (!m->scope)
|
if (!m->unit)
|
||||||
return -ESRCH;
|
return -ESRCH;
|
||||||
|
|
||||||
return manager_kill_unit(m->manager, m->scope, who, signo, NULL);
|
return manager_kill_unit(m->manager, m->unit, who, signo, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char* const machine_class_table[_MACHINE_CLASS_MAX] = {
|
static const char* const machine_class_table[_MACHINE_CLASS_MAX] = {
|
||||||
|
|
|
@ -63,7 +63,7 @@ struct Machine {
|
||||||
char *service;
|
char *service;
|
||||||
char *root_directory;
|
char *root_directory;
|
||||||
|
|
||||||
char *scope;
|
char *unit;
|
||||||
char *scope_job;
|
char *scope_job;
|
||||||
|
|
||||||
pid_t leader;
|
pid_t leader;
|
||||||
|
|
|
@ -107,7 +107,7 @@ static int list_machines(sd_bus *bus, char **args, unsigned n) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int show_scope_cgroup(sd_bus *bus, const char *unit, pid_t leader) {
|
static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) {
|
||||||
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
|
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
|
||||||
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
|
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||||
_cleanup_free_ char *path = NULL;
|
_cleanup_free_ char *path = NULL;
|
||||||
|
@ -129,7 +129,7 @@ static int show_scope_cgroup(sd_bus *bus, const char *unit, pid_t leader) {
|
||||||
bus,
|
bus,
|
||||||
"org.freedesktop.systemd1",
|
"org.freedesktop.systemd1",
|
||||||
path,
|
path,
|
||||||
"org.freedesktop.systemd1.Scope",
|
endswith(unit, ".scope") ? "org.freedesktop.systemd1.Scope" : "org.freedesktop.systemd1.Service",
|
||||||
"ControlGroup",
|
"ControlGroup",
|
||||||
&error,
|
&error,
|
||||||
&reply,
|
&reply,
|
||||||
|
@ -168,7 +168,7 @@ typedef struct MachineStatusInfo {
|
||||||
sd_id128_t id;
|
sd_id128_t id;
|
||||||
char *class;
|
char *class;
|
||||||
char *service;
|
char *service;
|
||||||
char *scope;
|
char *unit;
|
||||||
char *root_directory;
|
char *root_directory;
|
||||||
pid_t leader;
|
pid_t leader;
|
||||||
usec_t timestamp;
|
usec_t timestamp;
|
||||||
|
@ -219,9 +219,9 @@ static void print_machine_status_info(sd_bus *bus, MachineStatusInfo *i) {
|
||||||
if (i->root_directory)
|
if (i->root_directory)
|
||||||
printf("\t Root: %s\n", i->root_directory);
|
printf("\t Root: %s\n", i->root_directory);
|
||||||
|
|
||||||
if (i->scope) {
|
if (i->unit) {
|
||||||
printf("\t Unit: %s\n", i->scope);
|
printf("\t Unit: %s\n", i->unit);
|
||||||
show_scope_cgroup(bus, i->scope, i->leader);
|
show_unit_cgroup(bus, i->unit, i->leader);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,7 +231,7 @@ static int show_info(const char *verb, sd_bus *bus, const char *path, bool *new_
|
||||||
{ "Name", "s", NULL, offsetof(MachineStatusInfo, name) },
|
{ "Name", "s", NULL, offsetof(MachineStatusInfo, name) },
|
||||||
{ "Class", "s", NULL, offsetof(MachineStatusInfo, class) },
|
{ "Class", "s", NULL, offsetof(MachineStatusInfo, class) },
|
||||||
{ "Service", "s", NULL, offsetof(MachineStatusInfo, service) },
|
{ "Service", "s", NULL, offsetof(MachineStatusInfo, service) },
|
||||||
{ "Scope", "s", NULL, offsetof(MachineStatusInfo, scope) },
|
{ "Unit", "s", NULL, offsetof(MachineStatusInfo, unit) },
|
||||||
{ "RootDirectory", "s", NULL, offsetof(MachineStatusInfo, root_directory) },
|
{ "RootDirectory", "s", NULL, offsetof(MachineStatusInfo, root_directory) },
|
||||||
{ "Leader", "u", NULL, offsetof(MachineStatusInfo, leader) },
|
{ "Leader", "u", NULL, offsetof(MachineStatusInfo, leader) },
|
||||||
{ "Timestamp", "t", NULL, offsetof(MachineStatusInfo, timestamp) },
|
{ "Timestamp", "t", NULL, offsetof(MachineStatusInfo, timestamp) },
|
||||||
|
@ -264,7 +264,7 @@ static int show_info(const char *verb, sd_bus *bus, const char *path, bool *new_
|
||||||
free(info.name);
|
free(info.name);
|
||||||
free(info.class);
|
free(info.class);
|
||||||
free(info.service);
|
free(info.service);
|
||||||
free(info.scope);
|
free(info.unit);
|
||||||
free(info.root_directory);
|
free(info.root_directory);
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
|
|
|
@ -169,9 +169,8 @@ static int method_list_machines(sd_bus *bus, sd_bus_message *message, void *user
|
||||||
return sd_bus_send(bus, reply, NULL);
|
return sd_bus_send(bus, reply, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int method_create_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
static int method_create_or_register_machine(Manager *manager, sd_bus_message *message, Machine **_m, sd_bus_error *error) {
|
||||||
const char *name, *service, *class, *root_directory;
|
const char *name, *service, *class, *root_directory;
|
||||||
Manager *manager = userdata;
|
|
||||||
MachineClass c;
|
MachineClass c;
|
||||||
uint32_t leader;
|
uint32_t leader;
|
||||||
sd_id128_t id;
|
sd_id128_t id;
|
||||||
|
@ -180,9 +179,9 @@ static int method_create_machine(sd_bus *bus, sd_bus_message *message, void *use
|
||||||
size_t n;
|
size_t n;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(bus);
|
|
||||||
assert(message);
|
|
||||||
assert(manager);
|
assert(manager);
|
||||||
|
assert(message);
|
||||||
|
assert(_m);
|
||||||
|
|
||||||
r = sd_bus_message_read(message, "s", &name);
|
r = sd_bus_message_read(message, "s", &name);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
@ -218,10 +217,6 @@ static int method_create_machine(sd_bus *bus, sd_bus_message *message, void *use
|
||||||
if (!isempty(root_directory) && !path_is_absolute(root_directory))
|
if (!isempty(root_directory) && !path_is_absolute(root_directory))
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root directory must be empty or an absolute path");
|
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root directory must be empty or an absolute path");
|
||||||
|
|
||||||
r = sd_bus_message_enter_container(message, 'a', "(sv)");
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
if (leader == 0) {
|
if (leader == 0) {
|
||||||
_cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
|
_cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
|
||||||
|
|
||||||
|
@ -263,17 +258,70 @@ static int method_create_machine(sd_bus *bus, sd_bus_message *message, void *use
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
r = machine_start(m, message, error);
|
*_m = m;
|
||||||
if (r < 0)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
m->create_message = sd_bus_message_ref(message);
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
machine_add_to_gc_queue(m);
|
machine_add_to_gc_queue(m);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int method_create_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||||
|
Manager *manager = userdata;
|
||||||
|
Machine *m = NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = method_create_or_register_machine(manager, message, &m, error);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = sd_bus_message_enter_container(message, 'a', "(sv)");
|
||||||
|
if (r < 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
r = machine_start(m, message, error);
|
||||||
|
if (r < 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
m->create_message = sd_bus_message_ref(message);
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
machine_add_to_gc_queue(m);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int method_register_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||||
|
Manager *manager = userdata;
|
||||||
|
_cleanup_free_ char *p = NULL;
|
||||||
|
Machine *m = NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = method_create_or_register_machine(manager, message, &m, error);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = cg_pid_get_unit(m->leader, &m->unit);
|
||||||
|
if (r < 0) {
|
||||||
|
r = sd_bus_error_set_errnof(error, r, "Failed to determine unit of process "PID_FMT" : %s", m->leader, strerror(-r));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = machine_start(m, NULL, error);
|
||||||
|
if (r < 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
p = machine_bus_path(m);
|
||||||
|
if (!p) {
|
||||||
|
r = -ENOMEM;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sd_bus_reply_method_return(message, "o", p);
|
||||||
|
|
||||||
|
fail:
|
||||||
|
machine_add_to_gc_queue(m);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -347,6 +395,7 @@ const sd_bus_vtable manager_vtable[] = {
|
||||||
SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
|
SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||||
SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
|
SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||||
SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
|
SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
|
||||||
|
SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
|
||||||
SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
|
SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
|
||||||
SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
|
SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
|
||||||
SD_BUS_SIGNAL("MachineNew", "so", 0),
|
SD_BUS_SIGNAL("MachineNew", "so", 0),
|
||||||
|
|
|
@ -120,6 +120,7 @@ static char **arg_setenv = NULL;
|
||||||
static bool arg_quiet = false;
|
static bool arg_quiet = false;
|
||||||
static bool arg_share_system = false;
|
static bool arg_share_system = false;
|
||||||
static bool arg_register = true;
|
static bool arg_register = true;
|
||||||
|
static bool arg_keep_unit = false;
|
||||||
|
|
||||||
static int help(void) {
|
static int help(void) {
|
||||||
|
|
||||||
|
@ -152,6 +153,8 @@ static int help(void) {
|
||||||
" --bind-ro=PATH[:PATH] Similar, but creates a read-only bind mount\n"
|
" --bind-ro=PATH[:PATH] Similar, but creates a read-only bind mount\n"
|
||||||
" --setenv=NAME=VALUE Pass an environment variable to PID 1\n"
|
" --setenv=NAME=VALUE Pass an environment variable to PID 1\n"
|
||||||
" --register=BOOLEAN Register container as machine\n"
|
" --register=BOOLEAN Register container as machine\n"
|
||||||
|
" --keep-unit Do not register a scope for the machine, reuse\n"
|
||||||
|
" the service unit nspawn is running in\n"
|
||||||
" -q --quiet Do not show status information\n",
|
" -q --quiet Do not show status information\n",
|
||||||
program_invocation_short_name);
|
program_invocation_short_name);
|
||||||
|
|
||||||
|
@ -172,7 +175,8 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
ARG_BIND_RO,
|
ARG_BIND_RO,
|
||||||
ARG_SETENV,
|
ARG_SETENV,
|
||||||
ARG_SHARE_SYSTEM,
|
ARG_SHARE_SYSTEM,
|
||||||
ARG_REGISTER
|
ARG_REGISTER,
|
||||||
|
ARG_KEEP_UNIT
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct option options[] = {
|
static const struct option options[] = {
|
||||||
|
@ -197,6 +201,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
{ "quiet", no_argument, NULL, 'q' },
|
{ "quiet", no_argument, NULL, 'q' },
|
||||||
{ "share-system", no_argument, NULL, ARG_SHARE_SYSTEM },
|
{ "share-system", no_argument, NULL, ARG_SHARE_SYSTEM },
|
||||||
{ "register", required_argument, NULL, ARG_REGISTER },
|
{ "register", required_argument, NULL, ARG_REGISTER },
|
||||||
|
{ "keep-unit", no_argument, NULL, ARG_KEEP_UNIT },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -410,6 +415,10 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
arg_register = r;
|
arg_register = r;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ARG_KEEP_UNIT:
|
||||||
|
arg_keep_unit = true;
|
||||||
|
break;
|
||||||
|
|
||||||
case '?':
|
case '?':
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
@ -426,6 +435,11 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (arg_keep_unit && cg_pid_get_owner_uid(0, NULL) >= 0) {
|
||||||
|
log_error("--keep-unit may not be used when invoked from a user session.");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1086,22 +1100,41 @@ static int register_machine(pid_t pid) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = sd_bus_call_method(
|
if (arg_keep_unit) {
|
||||||
bus,
|
r = sd_bus_call_method(
|
||||||
"org.freedesktop.machine1",
|
bus,
|
||||||
"/org/freedesktop/machine1",
|
"org.freedesktop.machine1",
|
||||||
"org.freedesktop.machine1.Manager",
|
"/org/freedesktop/machine1",
|
||||||
"CreateMachine",
|
"org.freedesktop.machine1.Manager",
|
||||||
&error,
|
"RegisterMachine",
|
||||||
NULL,
|
&error,
|
||||||
"sayssusa(sv)",
|
NULL,
|
||||||
arg_machine,
|
"sayssus",
|
||||||
SD_BUS_MESSAGE_APPEND_ID128(arg_uuid),
|
arg_machine,
|
||||||
"nspawn",
|
SD_BUS_MESSAGE_APPEND_ID128(arg_uuid),
|
||||||
"container",
|
"nspawn",
|
||||||
(uint32_t) pid,
|
"container",
|
||||||
strempty(arg_directory),
|
(uint32_t) pid,
|
||||||
!isempty(arg_slice), "Slice", "s", arg_slice);
|
strempty(arg_directory));
|
||||||
|
} else {
|
||||||
|
r = sd_bus_call_method(
|
||||||
|
bus,
|
||||||
|
"org.freedesktop.machine1",
|
||||||
|
"/org/freedesktop/machine1",
|
||||||
|
"org.freedesktop.machine1.Manager",
|
||||||
|
"CreateMachine",
|
||||||
|
&error,
|
||||||
|
NULL,
|
||||||
|
"sayssusa(sv)",
|
||||||
|
arg_machine,
|
||||||
|
SD_BUS_MESSAGE_APPEND_ID128(arg_uuid),
|
||||||
|
"nspawn",
|
||||||
|
"container",
|
||||||
|
(uint32_t) pid,
|
||||||
|
strempty(arg_directory),
|
||||||
|
!isempty(arg_slice), "Slice", "s", arg_slice);
|
||||||
|
}
|
||||||
|
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_error("Failed to register machine: %s", bus_error_message(&error, r));
|
log_error("Failed to register machine: %s", bus_error_message(&error, r));
|
||||||
return r;
|
return r;
|
||||||
|
|
|
@ -1282,39 +1282,18 @@ int cg_pid_get_user_unit(pid_t pid, char **unit) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int cg_path_get_machine_name(const char *path, char **machine) {
|
int cg_path_get_machine_name(const char *path, char **machine) {
|
||||||
const char *e, *n, *x;
|
_cleanup_free_ char *u = NULL, *sl = NULL;
|
||||||
char *s, *r;
|
int r;
|
||||||
size_t l;
|
|
||||||
|
|
||||||
assert(path);
|
r = cg_path_get_unit(path, &u);
|
||||||
assert(machine);
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
/* Skip slices, if there are any */
|
sl = strjoin("/run/systemd/machines/unit:", u, NULL);
|
||||||
e = skip_slices(path);
|
if (!sl)
|
||||||
|
|
||||||
n = strchrnul(e, '/');
|
|
||||||
if (e == n)
|
|
||||||
return -ENOENT;
|
|
||||||
|
|
||||||
s = strndupa(e, n - e);
|
|
||||||
s = cg_unescape(s);
|
|
||||||
|
|
||||||
x = startswith(s, "machine-");
|
|
||||||
if (!x)
|
|
||||||
return -ENOENT;
|
|
||||||
if (!endswith(x, ".scope"))
|
|
||||||
return -ENOENT;
|
|
||||||
|
|
||||||
l = strlen(x);
|
|
||||||
if (l <= 6)
|
|
||||||
return -ENOENT;
|
|
||||||
|
|
||||||
r = strndup(x, l - 6);
|
|
||||||
if (!r)
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
*machine = r;
|
return readlink_malloc(sl, machine);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int cg_pid_get_machine_name(pid_t pid, char **machine) {
|
int cg_pid_get_machine_name(pid_t pid, char **machine) {
|
||||||
|
|
Loading…
Reference in a new issue