mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-01-13 13:17:43 +03:00
machinectl: add new "start" verb to start a container as a service in nspawn
This commit is contained in:
parent
6a140df004
commit
ebd011d95b
@ -21,16 +21,16 @@
|
|||||||
|
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
|
||||||
#include "systemd/sd-daemon.h"
|
#include "sd-daemon.h"
|
||||||
|
#include "sd-event.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "strv.h"
|
#include "strv.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
#include "def.h"
|
#include "def.h"
|
||||||
#include "path-util.h"
|
#include "path-util.h"
|
||||||
#include "missing.h"
|
#include "missing.h"
|
||||||
|
#include "set.h"
|
||||||
|
|
||||||
#include "sd-event.h"
|
|
||||||
#include "sd-bus.h"
|
#include "sd-bus.h"
|
||||||
#include "bus-error.h"
|
#include "bus-error.h"
|
||||||
#include "bus-message.h"
|
#include "bus-message.h"
|
||||||
@ -1554,3 +1554,225 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
|
|||||||
|
|
||||||
return 0;
|
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);
|
||||||
|
}
|
||||||
|
@ -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_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);
|
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);
|
||||||
|
@ -1417,6 +1417,76 @@ static int read_only_image(int argc, char *argv[], void *userdata) {
|
|||||||
return 0;
|
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) {
|
static int help(int argc, char *argv[], void *userdata) {
|
||||||
|
|
||||||
printf("%s [OPTIONS...] {COMMAND} ...\n\n"
|
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"
|
" status NAME... Show VM/container details\n"
|
||||||
" show NAME... Show properties of one or more VMs/containers\n"
|
" show NAME... Show properties of one or more VMs/containers\n"
|
||||||
" login NAME Get a login prompt on a container\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"
|
" poweroff NAME... Power off one or more containers\n"
|
||||||
" reboot NAME... Reboot one or more containers\n"
|
" reboot NAME... Reboot one or more containers\n"
|
||||||
" terminate NAME... Terminate one or more VMs/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 },
|
{ "rename", 3, 3, 0, rename_image },
|
||||||
{ "clone", 3, 3, 0, clone_image },
|
{ "clone", 3, 3, 0, clone_image },
|
||||||
{ "read-only", 2, 3, 0, read_only_image },
|
{ "read-only", 2, 3, 0, read_only_image },
|
||||||
|
{ "start", 2, VERB_ANY, 0, start_machine },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2406,197 +2406,6 @@ static int unit_find_paths(sd_bus *bus,
|
|||||||
return r;
|
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) {
|
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_bus_message_unref_ sd_bus_message *reply = NULL;
|
||||||
_cleanup_free_ char *n = NULL, *state = NULL;
|
_cleanup_free_ char *n = NULL, *state = NULL;
|
||||||
@ -2761,7 +2570,7 @@ static int start_unit_one(
|
|||||||
const char *name,
|
const char *name,
|
||||||
const char *mode,
|
const char *mode,
|
||||||
sd_bus_error *error,
|
sd_bus_error *error,
|
||||||
Set *s) {
|
BusWaitForJobs *w) {
|
||||||
|
|
||||||
_cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
|
_cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
|
||||||
const char *path;
|
const char *path;
|
||||||
@ -2814,15 +2623,9 @@ static int start_unit_one(
|
|||||||
if (need_daemon_reload(bus, name) > 0)
|
if (need_daemon_reload(bus, name) > 0)
|
||||||
warn_unit_file_changed(name);
|
warn_unit_file_changed(name);
|
||||||
|
|
||||||
if (s) {
|
if (w) {
|
||||||
char *p;
|
log_debug("Adding %s to the set", path);
|
||||||
|
r = bus_wait_for_jobs_add(w, path);
|
||||||
p = strdup(path);
|
|
||||||
if (!p)
|
|
||||||
return log_oom();
|
|
||||||
|
|
||||||
log_debug("Adding %s to the set", p);
|
|
||||||
r = set_consume(s, p);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_oom();
|
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) {
|
static int start_unit(sd_bus *bus, char **args) {
|
||||||
_cleanup_set_free_free_ Set *s = NULL;
|
_cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
|
||||||
_cleanup_strv_free_ char **names = NULL;
|
|
||||||
const char *method, *mode, *one_name, *suffix = NULL;
|
const char *method, *mode, *one_name, *suffix = NULL;
|
||||||
|
_cleanup_strv_free_ char **names = NULL;
|
||||||
char **name;
|
char **name;
|
||||||
int r = 0;
|
int r = 0;
|
||||||
|
|
||||||
@ -2952,20 +2755,16 @@ static int start_unit(sd_bus *bus, char **args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!arg_no_block) {
|
if (!arg_no_block) {
|
||||||
r = enable_wait_for_jobs(bus);
|
r = bus_wait_for_jobs_new(bus, &w);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Could not watch jobs: %m");
|
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) {
|
STRV_FOREACH(name, names) {
|
||||||
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
|
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||||
int q;
|
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)
|
if (r >= 0 && q < 0)
|
||||||
r = translate_bus_error_to_exit_status(q, &error);
|
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) {
|
if (!arg_no_block) {
|
||||||
int q;
|
int q;
|
||||||
|
|
||||||
q = wait_for_jobs(bus, s);
|
q = bus_wait_for_jobs(w, arg_quiet);
|
||||||
if (q < 0)
|
if (q < 0)
|
||||||
return q;
|
return q;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user