[systemd-commits] 5 commits - Makefile.am TODO src/libsystemd src/machine src/systemctl units/graphical.target units/machines.target units/systemd-nspawn at .service.in
Lennart Poettering
lennart at kemper.freedesktop.org
Mon Dec 29 08:00:11 PST 2014
Makefile.am | 1
TODO | 5
src/libsystemd/sd-bus/bus-util.c | 254 ++++++++++++++++++++++++++++++++++++++-
src/libsystemd/sd-bus/bus-util.h | 11 +
src/machine/machinectl.c | 188 ++++++++++++++++++++++++++++
src/systemctl/systemctl.c | 253 +-------------------------------------
units/graphical.target | 4
units/machines.target | 17 ++
units/systemd-nspawn at .service.in | 8 -
9 files changed, 489 insertions(+), 252 deletions(-)
New commits:
commit 8ede9794fdc8e659a6adc1dad4e68e03a36efe13
Author: Lennart Poettering <lennart at poettering.net>
Date: Mon Dec 29 14:06:25 2014 +0100
Update TODO
diff --git a/TODO b/TODO
index 799bcae..6c0b05a 100644
--- a/TODO
+++ b/TODO
@@ -39,8 +39,6 @@ Features:
* Check all invocations of access() and consider turning them into laccess()
-* "machinectl start/enable/disable foo" as aliases for "systemctl start/enable/disable systemd-nspawn at foo.service"
-
* "machinectl history"
* "machinectl diff"
@@ -49,6 +47,8 @@ Features:
* "machinectl status" should show 10 most recent log lines of both the host logs of the unit of the machine, plus the logs generated in the machine
+* machinectl terminate doesn't work
+
* add transparent btrfs pool in a loopback file in /var if btrfs operations (such as systemd-import pull-dkr) are used and /var is not a btrfs file system
* systemd-nspawn -x should support ephemeral instances of gpt images
@@ -582,7 +582,6 @@ Features:
* nspawn:
- bind mount read-only the cgroup tree higher than nspawn
- refuses to boot containers without /etc/machine-id (OK?), and with empty /etc/machine-id (not OK).
- - introduce machines.target to order after all nspawn instances
- systemd-nspawn at .service should fail if some nspawn arg is invalid, with Type=notify
- PID 1 doesn't apply nspawns devices cgroup policy
commit d8f52ed25a9edce75fda5251c977b7898e33887e
Author: Lennart Poettering <lennart at poettering.net>
Date: Mon Dec 29 14:05:17 2014 +0100
machinectl: add "enable" and "disable" verbs for enabling/disabling systemd-nspawn for containers
This is basically just a shortcut for "systemctl enable
systemd-nspawn@<foobar>.service", but does escaping.
diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c
index c264f2d..29520f9 100644
--- a/src/libsystemd/sd-bus/bus-util.c
+++ b/src/libsystemd/sd-bus/bus-util.c
@@ -1776,3 +1776,29 @@ int bus_wait_for_jobs_add(BusWaitForJobs *d, const char *path) {
return set_put_strdup(d->jobs, path);
}
+
+int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet) {
+ const char *type, *path, *source;
+ int r;
+
+ r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)");
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) {
+ if (!quiet) {
+ if (streq(type, "symlink"))
+ log_info("Created symlink from %s to %s.", path, source);
+ else
+ log_info("Removed symlink %s.", path);
+ }
+ }
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ r = sd_bus_message_exit_container(m);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ return 0;
+}
diff --git a/src/libsystemd/sd-bus/bus-util.h b/src/libsystemd/sd-bus/bus-util.h
index 31e7fad..e8a97ce 100644
--- a/src/libsystemd/sd-bus/bus-util.h
+++ b/src/libsystemd/sd-bus/bus-util.h
@@ -210,3 +210,5 @@ int bus_wait_for_jobs_add(BusWaitForJobs *d, const char *path);
int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet);
DEFINE_TRIVIAL_CLEANUP_FUNC(BusWaitForJobs*, bus_wait_for_jobs_free);
+
+int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet);
diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c
index b0c1533..0abc251 100644
--- a/src/machine/machinectl.c
+++ b/src/machine/machinectl.c
@@ -63,6 +63,7 @@ static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
static char *arg_host = NULL;
static bool arg_read_only = false;
static bool arg_mkdir = false;
+static bool arg_quiet = false;
static void pager_open_if_enabled(void) {
@@ -1480,13 +1481,116 @@ static int start_machine(int argc, char *argv[], void *userdata) {
return log_oom();
}
- r = bus_wait_for_jobs(w, false);
+ r = bus_wait_for_jobs(w, arg_quiet);
if (r < 0)
return r;
return 0;
}
+static int enable_machine(int argc, char *argv[], void *userdata) {
+ _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ int carries_install_info = 0;
+ const char *method = NULL;
+ sd_bus *bus = userdata;
+ int r, i;
+
+ assert(bus);
+
+ method = streq(argv[0], "enable") ? "EnableUnitFiles" : "DisableUnitFiles";
+
+ r = sd_bus_message_new_method_call(
+ bus,
+ &m,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ method);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_set_allow_interactive_authorization(m, true);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'a', "s");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ for (i = 1; i < argc; i++) {
+ _cleanup_free_ char *e = NULL, *unit = NULL;
+
+ if (!machine_name_is_valid(argv[i])) {
+ log_error("Invalid machine name %s.", argv[i]);
+ return -EINVAL;
+ }
+
+ e = unit_name_escape(argv[i]);
+ if (!e)
+ return log_oom();
+
+ unit = unit_name_build("systemd-nspawn", e, ".service");
+ if (!unit)
+ return log_oom();
+
+ r = sd_bus_message_append(m, "s", unit);
+ if (r < 0)
+ return bus_log_create_error(r);
+ }
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ if (streq(argv[0], "enable"))
+ r = sd_bus_message_append(m, "bb", false, false);
+ else
+ r = sd_bus_message_append(m, "b", false);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_call(bus, m, 0, &error, &reply);
+ if (r < 0) {
+ log_error("Failed to enable or disable unit: %s", bus_error_message(&error, -r));
+ return r;
+ }
+
+ if (streq(argv[0], "enable")) {
+ r = sd_bus_message_read(reply, "b", carries_install_info);
+ if (r < 0)
+ return bus_log_parse_error(r);
+ }
+
+ r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet);
+ if (r < 0)
+ return r;
+
+ m = sd_bus_message_unref(m);
+
+ r = sd_bus_message_new_method_call(
+ bus,
+ &m,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "Reload");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_set_allow_interactive_authorization(m, true);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_call(bus, m, 0, &error, NULL);
+ if (r < 0) {
+ log_error("Failed to reload daemon: %s", bus_error_message(&error, -r));
+ return r;
+ }
+
+ return 0;
+}
+
static int help(int argc, char *argv[], void *userdata) {
printf("%s [OPTIONS...] {COMMAND} ...\n\n"
@@ -1499,6 +1603,7 @@ static int help(int argc, char *argv[], void *userdata) {
" -H --host=[USER@]HOST Operate on remote host\n"
" -M --machine=CONTAINER Operate on local container\n"
" -p --property=NAME Show only properties by this name\n"
+ " -q --quiet Suppress output\n"
" -a --all Show all properties, including empty ones\n"
" -l --full Do not ellipsize output\n"
" --kill-who=WHO Who to send signal to\n"
@@ -1511,6 +1616,8 @@ static int help(int argc, char *argv[], void *userdata) {
" show NAME... Show properties of one or more VMs/containers\n"
" login NAME Get a login prompt on a container\n"
" start NAME... Start container as a service\n"
+ " enable NAME... Enable automatic container start at boot\n"
+ " disable NAME... Disable automatic container start at boot\n"
" poweroff NAME... Power off one or more containers\n"
" reboot NAME... Reboot one or more containers\n"
" terminate NAME... Terminate one or more VMs/containers\n"
@@ -1556,6 +1663,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "machine", required_argument, NULL, 'M' },
{ "read-only", no_argument, NULL, ARG_READ_ONLY },
{ "mkdir", no_argument, NULL, ARG_MKDIR },
+ { "quiet", no_argument, NULL, 'q' },
{}
};
@@ -1564,7 +1672,7 @@ static int parse_argv(int argc, char *argv[]) {
assert(argc >= 0);
assert(argv);
- while ((c = getopt_long(argc, argv, "hp:als:H:M:", options, NULL)) >= 0)
+ while ((c = getopt_long(argc, argv, "hp:als:H:M:q", options, NULL)) >= 0)
switch (c) {
@@ -1633,6 +1741,10 @@ static int parse_argv(int argc, char *argv[]) {
arg_mkdir = true;
break;
+ case 'q':
+ arg_quiet = true;
+ break;
+
case '?':
return -EINVAL;
@@ -1666,6 +1778,8 @@ static int machinectl_main(int argc, char *argv[], sd_bus *bus) {
{ "clone", 3, 3, 0, clone_image },
{ "read-only", 2, 3, 0, read_only_image },
{ "start", 2, VERB_ANY, 0, start_machine },
+ { "enable", 2, VERB_ANY, 0, enable_machine },
+ { "disable", 2, VERB_ANY, 0, enable_machine },
{}
};
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 060bfe2..a6c7e91 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -1951,32 +1951,6 @@ static void dump_unit_file_changes(const UnitFileChange *changes, unsigned n_cha
}
}
-static int deserialize_and_dump_unit_file_changes(sd_bus_message *m) {
- const char *type, *path, *source;
- int r;
-
- r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)");
- if (r < 0)
- return bus_log_parse_error(r);
-
- while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) {
- if (!arg_quiet) {
- if (streq(type, "symlink"))
- log_info("Created symlink from %s to %s.", path, source);
- else
- log_info("Removed symlink %s.", path);
- }
- }
- if (r < 0)
- return bus_log_parse_error(r);
-
- r = sd_bus_message_exit_container(m);
- if (r < 0)
- return bus_log_parse_error(r);
-
- return 0;
-}
-
static int set_default(sd_bus *bus, char **args) {
_cleanup_free_ char *unit = NULL;
UnitFileChange *changes = NULL;
@@ -2024,7 +1998,7 @@ static int set_default(sd_bus *bus, char **args) {
return r;
}
- r = deserialize_and_dump_unit_file_changes(reply);
+ r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet);
if (r < 0)
return r;
@@ -5389,7 +5363,7 @@ static int enable_unit(sd_bus *bus, char **args) {
return bus_log_parse_error(r);
}
- r = deserialize_and_dump_unit_file_changes(reply);
+ r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet);
if (r < 0)
return r;
@@ -5488,7 +5462,7 @@ static int add_dependency(sd_bus *bus, char **args) {
return r;
}
- r = deserialize_and_dump_unit_file_changes(reply);
+ r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet);
if (r < 0)
return r;
@@ -5552,7 +5526,7 @@ static int preset_all(sd_bus *bus, char **args) {
return r;
}
- r = deserialize_and_dump_unit_file_changes(reply);
+ r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet);
if (r < 0)
return r;
commit ebd011d95b61a86258dece9864f65b7c4af721c0
Author: Lennart Poettering <lennart at poettering.net>
Date: Mon Dec 29 12:41:26 2014 +0100
machinectl: add new "start" verb to start a container as a service in nspawn
diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c
index 2c3da3c..c264f2d 100644
--- a/src/libsystemd/sd-bus/bus-util.c
+++ b/src/libsystemd/sd-bus/bus-util.c
@@ -21,16 +21,16 @@
#include <sys/socket.h>
-#include "systemd/sd-daemon.h"
-
+#include "sd-daemon.h"
+#include "sd-event.h"
#include "util.h"
#include "strv.h"
#include "macro.h"
#include "def.h"
#include "path-util.h"
#include "missing.h"
+#include "set.h"
-#include "sd-event.h"
#include "sd-bus.h"
#include "bus-error.h"
#include "bus-message.h"
@@ -1554,3 +1554,225 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
return 0;
}
+
+typedef struct BusWaitForJobs {
+ sd_bus *bus;
+ Set *jobs;
+
+ char *name;
+ char *result;
+
+ sd_bus_slot *slot_job_removed;
+ sd_bus_slot *slot_disconnected;
+} BusWaitForJobs;
+
+static int match_disconnected(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
+ assert(bus);
+ assert(m);
+
+ log_error("Warning! D-Bus connection terminated.");
+ sd_bus_close(bus);
+
+ return 0;
+}
+
+static int match_job_removed(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
+ const char *path, *unit, *result;
+ BusWaitForJobs *d = userdata;
+ uint32_t id;
+ char *found;
+ int r;
+
+ assert(bus);
+ assert(m);
+ assert(d);
+
+ r = sd_bus_message_read(m, "uoss", &id, &path, &unit, &result);
+ if (r < 0) {
+ bus_log_parse_error(r);
+ return 0;
+ }
+
+ found = set_remove(d->jobs, (char*) path);
+ if (!found)
+ return 0;
+
+ free(found);
+
+ if (!isempty(result))
+ d->result = strdup(result);
+
+ if (!isempty(unit))
+ d->name = strdup(unit);
+
+ return 0;
+}
+
+void bus_wait_for_jobs_free(BusWaitForJobs *d) {
+ if (!d)
+ return;
+
+ set_free_free(d->jobs);
+
+ sd_bus_slot_unref(d->slot_disconnected);
+ sd_bus_slot_unref(d->slot_job_removed);
+
+ sd_bus_unref(d->bus);
+
+ free(d->name);
+ free(d->result);
+
+ free(d);
+}
+
+int bus_wait_for_jobs_new(sd_bus *bus, BusWaitForJobs **ret) {
+ _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *d = NULL;
+ int r;
+
+ assert(bus);
+ assert(ret);
+
+ d = new0(BusWaitForJobs, 1);
+ if (!d)
+ return -ENOMEM;
+
+ d->bus = sd_bus_ref(bus);
+
+ r = sd_bus_add_match(
+ bus,
+ &d->slot_job_removed,
+ "type='signal',"
+ "sender='org.freedesktop.systemd1',"
+ "interface='org.freedesktop.systemd1.Manager',"
+ "member='JobRemoved',"
+ "path='/org/freedesktop/systemd1'",
+ match_job_removed, d);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_add_match(
+ bus,
+ &d->slot_disconnected,
+ "type='signal',"
+ "sender='org.freedesktop.DBus.Local',"
+ "interface='org.freedesktop.DBus.Local',"
+ "member='Disconnected'",
+ match_disconnected, d);
+ if (r < 0)
+ return r;
+
+ *ret = d;
+ d = NULL;
+
+ return 0;
+}
+
+static int bus_process_wait(sd_bus *bus) {
+ int r;
+
+ for (;;) {
+ r = sd_bus_process(bus, NULL);
+ if (r < 0)
+ return r;
+ if (r > 0)
+ return 0;
+
+ r = sd_bus_wait(bus, (uint64_t) -1);
+ if (r < 0)
+ return r;
+ }
+}
+
+static int check_wait_response(BusWaitForJobs *d, bool quiet) {
+ int r = 0;
+
+ assert(d->result);
+
+ if (!quiet) {
+ if (streq(d->result, "canceled"))
+ log_error("Job for %s canceled.", strna(d->name));
+ else if (streq(d->result, "timeout"))
+ log_error("Job for %s timed out.", strna(d->name));
+ else if (streq(d->result, "dependency"))
+ log_error("A dependency job for %s failed. See 'journalctl -xe' for details.", strna(d->name));
+ else if (streq(d->result, "invalid"))
+ log_error("Job for %s invalid.", strna(d->name));
+ else if (streq(d->result, "assert"))
+ log_error("Assertion failed on job for %s.", strna(d->name));
+ else if (streq(d->result, "unsupported"))
+ log_error("Operation on or unit type of %s not supported on this system.", strna(d->name));
+ else if (!streq(d->result, "done") && !streq(d->result, "skipped")) {
+ if (d->name) {
+ bool quotes;
+
+ quotes = chars_intersect(d->name, SHELL_NEED_QUOTES);
+
+ log_error("Job for %s failed. See \"systemctl status %s%s%s\" and \"journalctl -xe\" for details.",
+ d->name,
+ quotes ? "'" : "", d->name, quotes ? "'" : "");
+ } else
+ log_error("Job failed. See \"journalctl -xe\" for details.");
+ }
+ }
+
+ if (streq(d->result, "canceled"))
+ r = -ECANCELED;
+ else if (streq(d->result, "timeout"))
+ r = -ETIME;
+ else if (streq(d->result, "dependency"))
+ r = -EIO;
+ else if (streq(d->result, "invalid"))
+ r = -ENOEXEC;
+ else if (streq(d->result, "assert"))
+ r = -EPROTO;
+ else if (streq(d->result, "unsupported"))
+ r = -ENOTSUP;
+ else if (!streq(d->result, "done") && !streq(d->result, "skipped"))
+ r = -EIO;
+
+ return r;
+}
+
+int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet) {
+ int r = 0;
+
+ assert(d);
+
+ while (!set_isempty(d->jobs)) {
+ int q;
+
+ q = bus_process_wait(d->bus);
+ if (q < 0)
+ return log_error_errno(q, "Failed to wait for response: %m");
+
+ if (d->result) {
+ q = check_wait_response(d, quiet);
+ /* Return the first error as it is most likely to be
+ * meaningful. */
+ if (q < 0 && r == 0)
+ r = q;
+
+ log_debug_errno(q, "Got result %s/%m for job %s", strna(d->result), strna(d->name));
+ }
+
+ free(d->name);
+ d->name = NULL;
+
+ free(d->result);
+ d->result = NULL;
+ }
+
+ return r;
+}
+
+int bus_wait_for_jobs_add(BusWaitForJobs *d, const char *path) {
+ int r;
+
+ assert(d);
+
+ r = set_ensure_allocated(&d->jobs, &string_hash_ops);
+ if (r < 0)
+ return r;
+
+ return set_put_strdup(d->jobs, path);
+}
diff --git a/src/libsystemd/sd-bus/bus-util.h b/src/libsystemd/sd-bus/bus-util.h
index 0609882..31e7fad 100644
--- a/src/libsystemd/sd-bus/bus-util.h
+++ b/src/libsystemd/sd-bus/bus-util.h
@@ -201,3 +201,12 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_track*, sd_bus_track_unref);
int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error);
int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignment);
+
+typedef struct BusWaitForJobs BusWaitForJobs;
+
+int bus_wait_for_jobs_new(sd_bus *bus, BusWaitForJobs **ret);
+void bus_wait_for_jobs_free(BusWaitForJobs *d);
+int bus_wait_for_jobs_add(BusWaitForJobs *d, const char *path);
+int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet);
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(BusWaitForJobs*, bus_wait_for_jobs_free);
diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c
index 17fbe51..b0c1533 100644
--- a/src/machine/machinectl.c
+++ b/src/machine/machinectl.c
@@ -1417,6 +1417,76 @@ static int read_only_image(int argc, char *argv[], void *userdata) {
return 0;
}
+static int start_machine(int argc, char *argv[], void *userdata) {
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
+ sd_bus *bus = userdata;
+ int r, i;
+
+ assert(bus);
+
+ r = bus_wait_for_jobs_new(bus, &w);
+ if (r < 0)
+ return log_oom();
+
+ for (i = 1; i < argc; i++) {
+ _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
+ _cleanup_free_ char *e = NULL, *unit = NULL;
+ const char *object;
+
+ if (!machine_name_is_valid(argv[i])) {
+ log_error("Invalid machine name %s.", argv[i]);
+ return -EINVAL;
+ }
+
+ e = unit_name_escape(argv[i]);
+ if (!e)
+ return log_oom();
+
+ unit = unit_name_build("systemd-nspawn", e, ".service");
+ if (!unit)
+ return log_oom();
+
+ r = sd_bus_message_new_method_call(
+ bus,
+ &m,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "StartUnit");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_set_allow_interactive_authorization(m, true);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append(m, "ss", unit, "fail");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_call(bus, m, 0, &error, &reply);
+ if (r < 0) {
+ log_error("Failed to start unit: %s", bus_error_message(&error, -r));
+ return r;
+ }
+
+ r = sd_bus_message_read(reply, "o", &object);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ r = bus_wait_for_jobs_add(w, object);
+ if (r < 0)
+ return log_oom();
+ }
+
+ r = bus_wait_for_jobs(w, false);
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
static int help(int argc, char *argv[], void *userdata) {
printf("%s [OPTIONS...] {COMMAND} ...\n\n"
@@ -1440,6 +1510,7 @@ static int help(int argc, char *argv[], void *userdata) {
" status NAME... Show VM/container details\n"
" show NAME... Show properties of one or more VMs/containers\n"
" login NAME Get a login prompt on a container\n"
+ " start NAME... Start container as a service\n"
" poweroff NAME... Power off one or more containers\n"
" reboot NAME... Reboot one or more containers\n"
" terminate NAME... Terminate one or more VMs/containers\n"
@@ -1594,6 +1665,7 @@ static int machinectl_main(int argc, char *argv[], sd_bus *bus) {
{ "rename", 3, 3, 0, rename_image },
{ "clone", 3, 3, 0, clone_image },
{ "read-only", 2, 3, 0, read_only_image },
+ { "start", 2, VERB_ANY, 0, start_machine },
{}
};
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index abe23ec..060bfe2 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -2406,197 +2406,6 @@ static int unit_find_paths(sd_bus *bus,
return r;
}
-typedef struct WaitData {
- Set *set;
-
- char *name;
- char *result;
-} WaitData;
-
-static int wait_filter(sd_bus *bus, sd_bus_message *m, void *data, sd_bus_error *error) {
- WaitData *d = data;
-
- assert(bus);
- assert(m);
- assert(d);
-
- log_debug("Got D-Bus request: %s.%s() on %s",
- sd_bus_message_get_interface(m),
- sd_bus_message_get_member(m),
- sd_bus_message_get_path(m));
-
- if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
- log_error("Warning! D-Bus connection terminated.");
- sd_bus_close(bus);
- } else if (sd_bus_message_is_signal(m, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
- uint32_t id;
- const char *path, *result, *unit;
- char *ret;
- int r;
-
- r = sd_bus_message_read(m, "uoss", &id, &path, &unit, &result);
- if (r >= 0) {
- ret = set_remove(d->set, (char*) path);
- if (!ret)
- return 0;
-
- free(ret);
-
- if (!isempty(result))
- d->result = strdup(result);
-
- if (!isempty(unit))
- d->name = strdup(unit);
-
- return 0;
- }
-#ifndef NOLEGACY
- r = sd_bus_message_read(m, "uos", &id, &path, &result);
- if (r >= 0) {
- ret = set_remove(d->set, (char*) path);
- if (!ret)
- return 0;
-
- free(ret);
-
- if (*result)
- d->result = strdup(result);
-
- return 0;
- }
-#endif
-
- bus_log_parse_error(r);
- }
-
- return 0;
-}
-
-static int enable_wait_for_jobs(sd_bus *bus) {
- int r;
-
- assert(bus);
-
- r = sd_bus_add_match(
- bus,
- NULL,
- "type='signal',"
- "sender='org.freedesktop.systemd1',"
- "interface='org.freedesktop.systemd1.Manager',"
- "member='JobRemoved',"
- "path='/org/freedesktop/systemd1'",
- NULL, NULL);
- if (r < 0) {
- log_error("Failed to add match");
- return -EIO;
- }
-
- /* This is slightly dirty, since we don't undo the match registrations. */
- return 0;
-}
-
-static int bus_process_wait(sd_bus *bus) {
- int r;
-
- for (;;) {
- r = sd_bus_process(bus, NULL);
- if (r < 0)
- return r;
- if (r > 0)
- return 0;
- r = sd_bus_wait(bus, (uint64_t) -1);
- if (r < 0)
- return r;
- }
-}
-
-static int check_wait_response(WaitData *d) {
- int r = 0;
-
- assert(d->result);
-
- if (!arg_quiet) {
- if (streq(d->result, "canceled"))
- log_error("Job for %s canceled.", strna(d->name));
- else if (streq(d->result, "timeout"))
- log_error("Job for %s timed out.", strna(d->name));
- else if (streq(d->result, "dependency"))
- log_error("A dependency job for %s failed. See 'journalctl -xe' for details.", strna(d->name));
- else if (streq(d->result, "invalid"))
- log_error("Job for %s invalid.", strna(d->name));
- else if (streq(d->result, "assert"))
- log_error("Assertion failed on job for %s.", strna(d->name));
- else if (streq(d->result, "unsupported"))
- log_error("Operation on or unit type of %s not supported on this system.", strna(d->name));
- else if (!streq(d->result, "done") && !streq(d->result, "skipped")) {
- if (d->name) {
- bool quotes;
-
- quotes = chars_intersect(d->name, SHELL_NEED_QUOTES);
-
- log_error("Job for %s failed. See \"systemctl status %s%s%s\" and \"journalctl -xe\" for details.",
- d->name,
- quotes ? "'" : "", d->name, quotes ? "'" : "");
- } else
- log_error("Job failed. See \"journalctl -xe\" for details.");
- }
- }
-
- if (streq(d->result, "canceled"))
- r = -ECANCELED;
- else if (streq(d->result, "timeout"))
- r = -ETIME;
- else if (streq(d->result, "dependency"))
- r = -EIO;
- else if (streq(d->result, "invalid"))
- r = -ENOEXEC;
- else if (streq(d->result, "assert"))
- r = -EPROTO;
- else if (streq(d->result, "unsupported"))
- r = -ENOTSUP;
- else if (!streq(d->result, "done") && !streq(d->result, "skipped"))
- r = -EIO;
-
- return r;
-}
-
-static int wait_for_jobs(sd_bus *bus, Set *s) {
- _cleanup_bus_slot_unref_ sd_bus_slot *slot = NULL;
- WaitData d = { .set = s };
- int r = 0, q;
-
- assert(bus);
- assert(s);
-
- q = sd_bus_add_filter(bus, &slot, wait_filter, &d);
- if (q < 0)
- return log_oom();
-
- while (!set_isempty(s)) {
- q = bus_process_wait(bus);
- if (q < 0)
- return log_error_errno(q, "Failed to wait for response: %m");
-
- if (d.result) {
- q = check_wait_response(&d);
- /* Return the first error as it is most likely to be
- * meaningful. */
- if (q < 0 && r == 0)
- r = q;
- log_debug("Got result %s/%s for job %s",
- strna(d.result), strerror(-q), strna(d.name));
- }
-
- free(d.name);
- d.name = NULL;
-
- free(d.result);
- d.result = NULL;
- }
-
- return r;
-}
-
static int check_one_unit(sd_bus *bus, const char *name, const char *good_states, bool quiet) {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
_cleanup_free_ char *n = NULL, *state = NULL;
@@ -2761,7 +2570,7 @@ static int start_unit_one(
const char *name,
const char *mode,
sd_bus_error *error,
- Set *s) {
+ BusWaitForJobs *w) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
const char *path;
@@ -2814,15 +2623,9 @@ static int start_unit_one(
if (need_daemon_reload(bus, name) > 0)
warn_unit_file_changed(name);
- if (s) {
- char *p;
-
- p = strdup(path);
- if (!p)
- return log_oom();
-
- log_debug("Adding %s to the set", p);
- r = set_consume(s, p);
+ if (w) {
+ log_debug("Adding %s to the set", path);
+ r = bus_wait_for_jobs_add(w, path);
if (r < 0)
return log_oom();
}
@@ -2911,9 +2714,9 @@ static enum action verb_to_action(const char *verb) {
}
static int start_unit(sd_bus *bus, char **args) {
- _cleanup_set_free_free_ Set *s = NULL;
- _cleanup_strv_free_ char **names = NULL;
+ _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
const char *method, *mode, *one_name, *suffix = NULL;
+ _cleanup_strv_free_ char **names = NULL;
char **name;
int r = 0;
@@ -2952,20 +2755,16 @@ static int start_unit(sd_bus *bus, char **args) {
}
if (!arg_no_block) {
- r = enable_wait_for_jobs(bus);
+ r = bus_wait_for_jobs_new(bus, &w);
if (r < 0)
return log_error_errno(r, "Could not watch jobs: %m");
-
- s = set_new(&string_hash_ops);
- if (!s)
- return log_oom();
}
STRV_FOREACH(name, names) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
int q;
- q = start_unit_one(bus, method, *name, mode, &error, s);
+ q = start_unit_one(bus, method, *name, mode, &error, w);
if (r >= 0 && q < 0)
r = translate_bus_error_to_exit_status(q, &error);
}
@@ -2973,7 +2772,7 @@ static int start_unit(sd_bus *bus, char **args) {
if (!arg_no_block) {
int q;
- q = wait_for_jobs(bus, s);
+ q = bus_wait_for_jobs(w, arg_quiet);
if (q < 0)
return q;
commit 6a140df0048c99e62339d97effbe16a1bba42d45
Author: Lennart Poettering <lennart at poettering.net>
Date: Mon Dec 29 12:38:26 2014 +0100
units: rework systemd-nspawn at .service unit
- Unescape instance name so that we can take almost anything as instance
name.
- Introduce "machines.target" which consists of all enabled nspawns and
can be used to start/stop them altogether
- Look for container directory using -M instead of harcoding the path in
/var/lib/container
diff --git a/Makefile.am b/Makefile.am
index e1e0843..28d2e4b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -549,6 +549,7 @@ nodist_systemunit_DATA = \
units/initrd-udevadm-cleanup-db.service \
units/initrd-switch-root.service \
units/systemd-nspawn at .service \
+ units/machines.target \
units/systemd-update-done.service
if HAVE_UTMP
diff --git a/units/machines.target b/units/machines.target
new file mode 100644
index 0000000..99618a1
--- /dev/null
+++ b/units/machines.target
@@ -0,0 +1,17 @@
+# This file is part of systemd.
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+
+[Unit]
+Description=Containers
+Documentation=man:systemd.special(7)
+Requires=basic.target
+Conflicts=rescue.service rescue.target
+After=basic.target rescue.service rescue.target
+Before=multi-user.target
+
+[Install]
+WantedBy=multi-user.target
diff --git a/units/systemd-nspawn at .service.in b/units/systemd-nspawn at .service.in
index e3eaa53..02d663d 100644
--- a/units/systemd-nspawn at .service.in
+++ b/units/systemd-nspawn at .service.in
@@ -6,11 +6,13 @@
# (at your option) any later version.
[Unit]
-Description=Container %i
+Description=Container %I
Documentation=man:systemd-nspawn(1)
+PartOf=machines.target
+Before=machines.target
[Service]
-ExecStart=@bindir@/systemd-nspawn --quiet --keep-unit --boot --link-journal=try-guest --directory=/var/lib/container/%i
+ExecStart=@bindir@/systemd-nspawn --quiet --keep-unit --boot --link-journal=try-guest --machine=%I
KillMode=mixed
Type=notify
RestartForceExitStatus=133
@@ -18,4 +20,4 @@ SuccessExitStatus=133
Delegate=yes
[Install]
-WantedBy=multi-user.target
+WantedBy=machines.target
commit 8fa844dccff70824ff063bfe5f409c47f5699d73
Author: Lennart Poettering <lennart at poettering.net>
Date: Mon Dec 29 12:34:50 2014 +0100
units: make graphical.target dependencies more complete and similar to those of multi-user.target
diff --git a/units/graphical.target b/units/graphical.target
index a2c4532..87be97e 100644
--- a/units/graphical.target
+++ b/units/graphical.target
@@ -9,7 +9,7 @@
Description=Graphical Interface
Documentation=man:systemd.special(7)
Requires=multi-user.target
-After=multi-user.target
-Conflicts=rescue.target
Wants=display-manager.service
+Conflicts=rescue.service rescue.target
+After=multi-user.target rescue.service rescue.target display-manager.service
AllowIsolate=yes
More information about the systemd-commits
mailing list