mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-02-10 13:57:25 +03:00
Merge pull request #12115 from poettering/verbose-job-enqueue
add "systemctl --show-transaction start" as a more verbose "systemctl start" that shows enqueued jobs
This commit is contained in:
commit
c6335c3b51
@ -299,6 +299,20 @@
|
||||
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-T</option></term>
|
||||
<term><option>--show-transaction</option></term>
|
||||
|
||||
<listitem>
|
||||
<para>When enqueuing a unit job (for example as effect of a <command>systemctl start</command>
|
||||
invocation or similar), show brief information about all jobs enqueued, covering both the requested
|
||||
job and any added because of unit dependencies. Note that the output will only include jobs
|
||||
immediately part of the transaction requested. It is possible that service start-up program code
|
||||
run as effect of the enqueued jobs might request further jobs to be pulled in. This means that
|
||||
completion of the listed jobs might ultimately entail more jobs than the listed ones.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--fail</option></term>
|
||||
|
||||
|
@ -202,7 +202,7 @@ static int verify_unit(Unit *u, bool check_man) {
|
||||
unit_dump(u, stdout, "\t");
|
||||
|
||||
log_unit_debug(u, "Creating %s/start job", u->id);
|
||||
r = manager_add_job(u->manager, JOB_START, u, JOB_REPLACE, &err, NULL);
|
||||
r = manager_add_job(u->manager, JOB_START, u, JOB_REPLACE, NULL, &err, NULL);
|
||||
if (r < 0)
|
||||
log_unit_error_errno(u, r, "Failed to create %s/start: %s", u->id, bus_error_message(&err, r));
|
||||
|
||||
|
@ -781,7 +781,7 @@ static void automount_enter_running(Automount *a) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = manager_add_job(UNIT(a)->manager, JOB_START, trigger, JOB_REPLACE, &error, NULL);
|
||||
r = manager_add_job(UNIT(a)->manager, JOB_START, trigger, JOB_REPLACE, NULL, &error, NULL);
|
||||
if (r < 0) {
|
||||
log_unit_warning(UNIT(a), "Failed to queue mount startup job: %s", bus_error_message(&error, r));
|
||||
goto fail;
|
||||
@ -1035,7 +1035,7 @@ static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, vo
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = manager_add_job(UNIT(a)->manager, JOB_STOP, trigger, JOB_REPLACE, &error, NULL);
|
||||
r = manager_add_job(UNIT(a)->manager, JOB_STOP, trigger, JOB_REPLACE, NULL, &error, NULL);
|
||||
if (r < 0) {
|
||||
log_unit_warning(UNIT(a), "Failed to queue umount startup job: %s", bus_error_message(&error, r));
|
||||
goto fail;
|
||||
|
@ -574,6 +574,26 @@ static int method_reload_or_try_restart_unit(sd_bus_message *message, void *user
|
||||
return method_start_unit_generic(message, userdata, JOB_TRY_RESTART, true, error);
|
||||
}
|
||||
|
||||
static int method_enqueue_unit_job(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
Manager *m = userdata;
|
||||
const char *name;
|
||||
Unit *u;
|
||||
int r;
|
||||
|
||||
assert(message);
|
||||
assert(m);
|
||||
|
||||
r = sd_bus_message_read(message, "s", &name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = manager_load_unit(m, name, NULL, error, &u);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return bus_unit_method_enqueue_job(message, u, error);
|
||||
}
|
||||
|
||||
static int method_start_unit_replace(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
Manager *m = userdata;
|
||||
const char *old_name;
|
||||
@ -955,7 +975,7 @@ static int method_start_transient_unit(sd_bus_message *message, void *userdata,
|
||||
return r;
|
||||
|
||||
/* Finally, start it */
|
||||
return bus_unit_queue_job(message, u, JOB_START, mode, false, error);
|
||||
return bus_unit_queue_job(message, u, JOB_START, mode, 0, error);
|
||||
}
|
||||
|
||||
static int method_get_job(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
@ -2553,6 +2573,7 @@ const sd_bus_vtable bus_manager_vtable[] = {
|
||||
SD_BUS_METHOD("TryRestartUnit", "ss", "o", method_try_restart_unit, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("ReloadOrRestartUnit", "ss", "o", method_reload_or_restart_unit, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("ReloadOrTryRestartUnit", "ss", "o", method_reload_or_try_restart_unit, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("EnqueueUnitJob", "sss", "uososa(uosos)", method_enqueue_unit_job, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("KillUnit", "ssi", NULL, method_kill_unit, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("ResetFailedUnit", "s", NULL, method_reset_failed_unit, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("SetUnitProperties", "sba(sv)", NULL, method_set_unit_properties, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
|
@ -312,6 +312,14 @@ static int bus_verify_manage_units_async_full(
|
||||
error);
|
||||
}
|
||||
|
||||
static const char *const polkit_message_for_job[_JOB_TYPE_MAX] = {
|
||||
[JOB_START] = N_("Authentication is required to start '$(unit)'."),
|
||||
[JOB_STOP] = N_("Authentication is required to stop '$(unit)'."),
|
||||
[JOB_RELOAD] = N_("Authentication is required to reload '$(unit)'."),
|
||||
[JOB_RESTART] = N_("Authentication is required to restart '$(unit)'."),
|
||||
[JOB_TRY_RESTART] = N_("Authentication is required to restart '$(unit)'."),
|
||||
};
|
||||
|
||||
int bus_unit_method_start_generic(
|
||||
sd_bus_message *message,
|
||||
Unit *u,
|
||||
@ -321,13 +329,6 @@ int bus_unit_method_start_generic(
|
||||
|
||||
const char *smode, *verb;
|
||||
JobMode mode;
|
||||
static const char *const polkit_message_for_job[_JOB_TYPE_MAX] = {
|
||||
[JOB_START] = N_("Authentication is required to start '$(unit)'."),
|
||||
[JOB_STOP] = N_("Authentication is required to stop '$(unit)'."),
|
||||
[JOB_RELOAD] = N_("Authentication is required to reload '$(unit)'."),
|
||||
[JOB_RESTART] = N_("Authentication is required to restart '$(unit)'."),
|
||||
[JOB_TRY_RESTART] = N_("Authentication is required to restart '$(unit)'."),
|
||||
};
|
||||
int r;
|
||||
|
||||
assert(message);
|
||||
@ -367,7 +368,8 @@ int bus_unit_method_start_generic(
|
||||
if (r == 0)
|
||||
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
|
||||
|
||||
return bus_unit_queue_job(message, u, job_type, mode, reload_if_possible, error);
|
||||
return bus_unit_queue_job(message, u, job_type, mode,
|
||||
reload_if_possible ? BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE : 0, error);
|
||||
}
|
||||
|
||||
static int method_start(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
@ -398,6 +400,62 @@ static int method_reload_or_try_restart(sd_bus_message *message, void *userdata,
|
||||
return bus_unit_method_start_generic(message, userdata, JOB_TRY_RESTART, true, error);
|
||||
}
|
||||
|
||||
int bus_unit_method_enqueue_job(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
BusUnitQueueFlags flags = BUS_UNIT_QUEUE_VERBOSE_REPLY;
|
||||
const char *jtype, *smode;
|
||||
Unit *u = userdata;
|
||||
JobType type;
|
||||
JobMode mode;
|
||||
int r;
|
||||
|
||||
assert(message);
|
||||
assert(u);
|
||||
|
||||
r = sd_bus_message_read(message, "ss", &jtype, &smode);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Parse the two magic reload types "reload-or-…" manually */
|
||||
if (streq(jtype, "reload-or-restart")) {
|
||||
type = JOB_RESTART;
|
||||
flags |= BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE;
|
||||
} else if (streq(jtype, "reload-or-try-restart")) {
|
||||
type = JOB_TRY_RESTART;
|
||||
flags |= BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE;
|
||||
} else {
|
||||
/* And the rest generically */
|
||||
type = job_type_from_string(jtype);
|
||||
if (type < 0)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Job type %s invalid", jtype);
|
||||
}
|
||||
|
||||
mode = job_mode_from_string(smode);
|
||||
if (mode < 0)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Job mode %s invalid", smode);
|
||||
|
||||
r = mac_selinux_unit_access_check(
|
||||
u, message,
|
||||
job_type_to_access_method(type),
|
||||
error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = bus_verify_manage_units_async_full(
|
||||
u,
|
||||
jtype,
|
||||
CAP_SYS_ADMIN,
|
||||
polkit_message_for_job[type],
|
||||
true,
|
||||
message,
|
||||
error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
|
||||
|
||||
return bus_unit_queue_job(message, u, type, mode, flags, error);
|
||||
}
|
||||
|
||||
int bus_unit_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
Unit *u = userdata;
|
||||
const char *swho;
|
||||
@ -683,6 +741,7 @@ const sd_bus_vtable bus_unit_vtable[] = {
|
||||
SD_BUS_METHOD("TryRestart", "s", "o", method_try_restart, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("ReloadOrRestart", "s", "o", method_reload_or_restart, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("ReloadOrTryRestart", "s", "o", method_reload_or_try_restart, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("EnqueueJob", "ss", "uososa(uosos)", bus_unit_method_enqueue_job, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("Kill", "si", NULL, bus_unit_method_kill, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("ResetFailed", NULL, NULL, bus_unit_method_reset_failed, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("SetProperties", "ba(sv)", NULL, bus_unit_method_set_properties, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
@ -1269,11 +1328,14 @@ int bus_unit_queue_job(
|
||||
Unit *u,
|
||||
JobType type,
|
||||
JobMode mode,
|
||||
bool reload_if_possible,
|
||||
BusUnitQueueFlags flags,
|
||||
sd_bus_error *error) {
|
||||
|
||||
_cleanup_free_ char *path = NULL;
|
||||
Job *j;
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
_cleanup_free_ char *job_path = NULL, *unit_path = NULL;
|
||||
_cleanup_(set_freep) Set *affected = NULL;
|
||||
Iterator i;
|
||||
Job *j, *a;
|
||||
int r;
|
||||
|
||||
assert(message);
|
||||
@ -1288,7 +1350,7 @@ int bus_unit_queue_job(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (reload_if_possible && unit_can_reload(u)) {
|
||||
if (FLAGS_SET(flags, BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE) && unit_can_reload(u)) {
|
||||
if (type == JOB_RESTART)
|
||||
type = JOB_RELOAD_OR_START;
|
||||
else if (type == JOB_TRY_RESTART)
|
||||
@ -1306,7 +1368,13 @@ int bus_unit_queue_job(
|
||||
(type == JOB_RELOAD_OR_START && job_type_collapse(type, u) == JOB_START && u->refuse_manual_start))
|
||||
return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only (it is configured to refuse manual start/stop).", u->id);
|
||||
|
||||
r = manager_add_job(u->manager, type, u, mode, error, &j);
|
||||
if (FLAGS_SET(flags, BUS_UNIT_QUEUE_VERBOSE_REPLY)) {
|
||||
affected = set_new(NULL);
|
||||
if (!affected)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
r = manager_add_job(u->manager, type, u, mode, affected, error, &j);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -1314,14 +1382,67 @@ int bus_unit_queue_job(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
path = job_dbus_path(j);
|
||||
if (!path)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Before we send the method reply, force out the announcement JobNew for this job */
|
||||
bus_job_send_pending_change_signal(j, true);
|
||||
|
||||
return sd_bus_reply_method_return(message, "o", path);
|
||||
job_path = job_dbus_path(j);
|
||||
if (!job_path)
|
||||
return -ENOMEM;
|
||||
|
||||
/* The classic response is just a job object path */
|
||||
if (!FLAGS_SET(flags, BUS_UNIT_QUEUE_VERBOSE_REPLY))
|
||||
return sd_bus_reply_method_return(message, "o", job_path);
|
||||
|
||||
/* In verbose mode respond with the anchor job plus everything that has been affected */
|
||||
r = sd_bus_message_new_method_return(message, &reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
unit_path = unit_dbus_path(j->unit);
|
||||
if (!unit_path)
|
||||
return -ENOMEM;
|
||||
|
||||
r = sd_bus_message_append(reply, "uosos",
|
||||
j->id, job_path,
|
||||
j->unit->id, unit_path,
|
||||
job_type_to_string(j->type));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_open_container(reply, 'a', "(uosos)");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
SET_FOREACH(a, affected, i) {
|
||||
|
||||
if (a->id == j->id)
|
||||
continue;
|
||||
|
||||
/* Free paths from previous iteration */
|
||||
job_path = mfree(job_path);
|
||||
unit_path = mfree(unit_path);
|
||||
|
||||
job_path = job_dbus_path(a);
|
||||
if (!job_path)
|
||||
return -ENOMEM;
|
||||
|
||||
unit_path = unit_dbus_path(a->unit);
|
||||
if (!unit_path)
|
||||
return -ENOMEM;
|
||||
|
||||
r = sd_bus_message_append(reply, "(uosos)",
|
||||
a->id, job_path,
|
||||
a->unit->id, unit_path,
|
||||
job_type_to_string(a->type));
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_bus_message_close_container(reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_bus_send(NULL, reply, NULL);
|
||||
}
|
||||
|
||||
static int bus_unit_set_live_property(
|
||||
|
@ -15,6 +15,7 @@ void bus_unit_send_pending_change_signal(Unit *u, bool including_new);
|
||||
void bus_unit_send_removed_signal(Unit *u);
|
||||
|
||||
int bus_unit_method_start_generic(sd_bus_message *message, Unit *u, JobType job_type, bool reload_if_possible, sd_bus_error *error);
|
||||
int bus_unit_method_enqueue_job(sd_bus_message *message, void *userdata, sd_bus_error *error);
|
||||
int bus_unit_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error);
|
||||
int bus_unit_method_reset_failed(sd_bus_message *message, void *userdata, sd_bus_error *error);
|
||||
|
||||
@ -25,7 +26,12 @@ int bus_unit_method_attach_processes(sd_bus_message *message, void *userdata, sd
|
||||
int bus_unit_method_ref(sd_bus_message *message, void *userdata, sd_bus_error *error);
|
||||
int bus_unit_method_unref(sd_bus_message *message, void *userdata, sd_bus_error *error);
|
||||
|
||||
int bus_unit_queue_job(sd_bus_message *message, Unit *u, JobType type, JobMode mode, bool reload_if_possible, sd_bus_error *error);
|
||||
typedef enum BusUnitQueueFlags {
|
||||
BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE = 1 << 0,
|
||||
BUS_UNIT_QUEUE_VERBOSE_REPLY = 1 << 1,
|
||||
} BusUnitQueueFlags;
|
||||
|
||||
int bus_unit_queue_job(sd_bus_message *message, Unit *u, JobType type, JobMode mode, BusUnitQueueFlags flags, sd_bus_error *error);
|
||||
int bus_unit_validate_load_state(Unit *u, sd_bus_error *error);
|
||||
|
||||
int bus_unit_track_add_name(Unit *u, const char *name);
|
||||
|
@ -177,7 +177,7 @@ static int signal_activation_request(sd_bus_message *message, void *userdata, sd
|
||||
goto failed;
|
||||
}
|
||||
|
||||
r = manager_add_job(m, JOB_START, u, JOB_REPLACE, &error, NULL);
|
||||
r = manager_add_job(m, JOB_START, u, JOB_REPLACE, NULL, &error, NULL);
|
||||
if (r < 0)
|
||||
goto failed;
|
||||
|
||||
|
@ -433,7 +433,7 @@ static int device_add_udev_wants(Unit *u, sd_device *dev) {
|
||||
if (strv_contains(d->wants_property, *i)) /* Was this unit already listed before? */
|
||||
continue;
|
||||
|
||||
r = manager_add_job_by_name(u->manager, JOB_START, *i, JOB_FAIL, &error, NULL);
|
||||
r = manager_add_job_by_name(u->manager, JOB_START, *i, JOB_FAIL, NULL, &error, NULL);
|
||||
if (r < 0)
|
||||
log_unit_warning_errno(u, r, "Failed to enqueue SYSTEMD_WANTS= job, ignoring: %s", bus_error_message(&error, r));
|
||||
}
|
||||
|
@ -48,8 +48,7 @@ void emergency_action(
|
||||
log_and_status(m, warn, "Rebooting", reason);
|
||||
|
||||
(void) update_reboot_parameter_and_warn(reboot_arg, true);
|
||||
(void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL);
|
||||
|
||||
(void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL, NULL);
|
||||
break;
|
||||
|
||||
case EMERGENCY_ACTION_REBOOT_FORCE:
|
||||
@ -82,7 +81,7 @@ void emergency_action(
|
||||
|
||||
if (MANAGER_IS_USER(m) || detect_container() > 0) {
|
||||
log_and_status(m, warn, "Exiting", reason);
|
||||
(void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_EXIT_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL);
|
||||
(void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_EXIT_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -91,7 +90,7 @@ void emergency_action(
|
||||
|
||||
case EMERGENCY_ACTION_POWEROFF:
|
||||
log_and_status(m, warn, "Powering off", reason);
|
||||
(void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_POWEROFF_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL);
|
||||
(void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_POWEROFF_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL, NULL);
|
||||
break;
|
||||
|
||||
case EMERGENCY_ACTION_EXIT_FORCE:
|
||||
|
@ -2121,13 +2121,13 @@ static int do_queue_default_job(
|
||||
|
||||
assert(target->load_state == UNIT_LOADED);
|
||||
|
||||
r = manager_add_job(m, JOB_START, target, JOB_ISOLATE, &error, &default_unit_job);
|
||||
r = manager_add_job(m, JOB_START, target, JOB_ISOLATE, NULL, &error, &default_unit_job);
|
||||
if (r == -EPERM) {
|
||||
log_debug_errno(r, "Default target could not be isolated, starting instead: %s", bus_error_message(&error, r));
|
||||
|
||||
sd_bus_error_free(&error);
|
||||
|
||||
r = manager_add_job(m, JOB_START, target, JOB_REPLACE, &error, &default_unit_job);
|
||||
r = manager_add_job(m, JOB_START, target, JOB_REPLACE, NULL, &error, &default_unit_job);
|
||||
if (r < 0) {
|
||||
*ret_error_message = "Failed to start default target";
|
||||
return log_emergency_errno(r, "Failed to start default target: %s", bus_error_message(&error, r));
|
||||
|
@ -1253,7 +1253,7 @@ static unsigned manager_dispatch_stop_when_unneeded_queue(Manager *m) {
|
||||
}
|
||||
|
||||
/* Ok, nobody needs us anymore. Sniff. Then let's commit suicide */
|
||||
r = manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, &error, NULL);
|
||||
r = manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, NULL, &error, NULL);
|
||||
if (r < 0)
|
||||
log_unit_warning_errno(u, r, "Failed to enqueue stop job, ignoring: %s", bus_error_message(&error, r));
|
||||
}
|
||||
@ -1730,9 +1730,17 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, sd_bus_error *e, Job **_ret) {
|
||||
int r;
|
||||
int manager_add_job(
|
||||
Manager *m,
|
||||
JobType type,
|
||||
Unit *unit,
|
||||
JobMode mode,
|
||||
Set *affected_jobs,
|
||||
sd_bus_error *error,
|
||||
Job **ret) {
|
||||
|
||||
Transaction *tr;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(type < _JOB_TYPE_MAX);
|
||||
@ -1740,10 +1748,10 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, sd_bus_e
|
||||
assert(mode < _JOB_MODE_MAX);
|
||||
|
||||
if (mode == JOB_ISOLATE && type != JOB_START)
|
||||
return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Isolate is only valid for start.");
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Isolate is only valid for start.");
|
||||
|
||||
if (mode == JOB_ISOLATE && !unit->allow_isolate)
|
||||
return sd_bus_error_setf(e, BUS_ERROR_NO_ISOLATION, "Operation refused, unit may not be isolated.");
|
||||
return sd_bus_error_setf(error, BUS_ERROR_NO_ISOLATION, "Operation refused, unit may not be isolated.");
|
||||
|
||||
log_unit_debug(unit, "Trying to enqueue job %s/%s/%s", unit->id, job_type_to_string(type), job_mode_to_string(mode));
|
||||
|
||||
@ -1755,7 +1763,7 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, sd_bus_e
|
||||
|
||||
r = transaction_add_job_and_dependencies(tr, type, unit, NULL, true, false,
|
||||
IN_SET(mode, JOB_IGNORE_DEPENDENCIES, JOB_IGNORE_REQUIREMENTS),
|
||||
mode == JOB_IGNORE_DEPENDENCIES, e);
|
||||
mode == JOB_IGNORE_DEPENDENCIES, error);
|
||||
if (r < 0)
|
||||
goto tr_abort;
|
||||
|
||||
@ -1765,7 +1773,7 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, sd_bus_e
|
||||
goto tr_abort;
|
||||
}
|
||||
|
||||
r = transaction_activate(tr, m, mode, e);
|
||||
r = transaction_activate(tr, m, mode, affected_jobs, error);
|
||||
if (r < 0)
|
||||
goto tr_abort;
|
||||
|
||||
@ -1773,8 +1781,8 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, sd_bus_e
|
||||
"Enqueued job %s/%s as %u", unit->id,
|
||||
job_type_to_string(type), (unsigned) tr->anchor_job->id);
|
||||
|
||||
if (_ret)
|
||||
*_ret = tr->anchor_job;
|
||||
if (ret)
|
||||
*ret = tr->anchor_job;
|
||||
|
||||
transaction_free(tr);
|
||||
return 0;
|
||||
@ -1785,7 +1793,7 @@ tr_abort:
|
||||
return r;
|
||||
}
|
||||
|
||||
int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, sd_bus_error *e, Job **ret) {
|
||||
int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, Set *affected_jobs, sd_bus_error *e, Job **ret) {
|
||||
Unit *unit = NULL; /* just to appease gcc, initialization is not really necessary */
|
||||
int r;
|
||||
|
||||
@ -1799,10 +1807,10 @@ int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode
|
||||
return r;
|
||||
assert(unit);
|
||||
|
||||
return manager_add_job(m, type, unit, mode, e, ret);
|
||||
return manager_add_job(m, type, unit, mode, affected_jobs, e, ret);
|
||||
}
|
||||
|
||||
int manager_add_job_by_name_and_warn(Manager *m, JobType type, const char *name, JobMode mode, Job **ret) {
|
||||
int manager_add_job_by_name_and_warn(Manager *m, JobType type, const char *name, JobMode mode, Set *affected_jobs, Job **ret) {
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
int r;
|
||||
|
||||
@ -1811,7 +1819,7 @@ int manager_add_job_by_name_and_warn(Manager *m, JobType type, const char *name,
|
||||
assert(name);
|
||||
assert(mode < _JOB_MODE_MAX);
|
||||
|
||||
r = manager_add_job_by_name(m, type, name, mode, &error, ret);
|
||||
r = manager_add_job_by_name(m, type, name, mode, affected_jobs, &error, ret);
|
||||
if (r < 0)
|
||||
return log_warning_errno(r, "Failed to enqueue %s job for %s: %s", job_mode_to_string(mode), name, bus_error_message(&error, r));
|
||||
|
||||
@ -1839,7 +1847,7 @@ int manager_propagate_reload(Manager *m, Unit *unit, JobMode mode, sd_bus_error
|
||||
/* Failure in adding individual dependencies is ignored, so this always succeeds. */
|
||||
transaction_add_propagate_reload_jobs(tr, unit, tr->anchor_job, mode == JOB_IGNORE_DEPENDENCIES, e);
|
||||
|
||||
r = transaction_activate(tr, m, mode, e);
|
||||
r = transaction_activate(tr, m, mode, NULL, e);
|
||||
if (r < 0)
|
||||
goto tr_abort;
|
||||
|
||||
@ -2549,7 +2557,7 @@ static void manager_start_target(Manager *m, const char *name, JobMode mode) {
|
||||
|
||||
log_debug("Activating special unit %s", name);
|
||||
|
||||
r = manager_add_job_by_name(m, JOB_START, name, mode, &error, NULL);
|
||||
r = manager_add_job_by_name(m, JOB_START, name, mode, NULL, &error, NULL);
|
||||
if (r < 0)
|
||||
log_error("Failed to enqueue %s job: %s", name, bus_error_message(&error, r));
|
||||
}
|
||||
|
@ -425,9 +425,9 @@ int manager_load_unit(Manager *m, const char *name, const char *path, sd_bus_err
|
||||
int manager_load_startable_unit_or_warn(Manager *m, const char *name, const char *path, Unit **ret);
|
||||
int manager_load_unit_from_dbus_path(Manager *m, const char *s, sd_bus_error *e, Unit **_u);
|
||||
|
||||
int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, sd_bus_error *e, Job **_ret);
|
||||
int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, sd_bus_error *e, Job **_ret);
|
||||
int manager_add_job_by_name_and_warn(Manager *m, JobType type, const char *name, JobMode mode, Job **ret);
|
||||
int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, Set *affected_jobs, sd_bus_error *e, Job **_ret);
|
||||
int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, Set *affected_jobs, sd_bus_error *e, Job **_ret);
|
||||
int manager_add_job_by_name_and_warn(Manager *m, JobType type, const char *name, JobMode mode, Set *affected_jobs, Job **ret);
|
||||
int manager_propagate_reload(Manager *m, Unit *unit, JobMode mode, sd_bus_error *e);
|
||||
|
||||
void manager_dump_units(Manager *s, FILE *f, const char *prefix);
|
||||
|
@ -474,7 +474,7 @@ static void path_enter_running(Path *p) {
|
||||
return;
|
||||
}
|
||||
|
||||
r = manager_add_job(UNIT(p)->manager, JOB_START, trigger, JOB_REPLACE, &error, NULL);
|
||||
r = manager_add_job(UNIT(p)->manager, JOB_START, trigger, JOB_REPLACE, NULL, &error, NULL);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
|
@ -2183,7 +2183,7 @@ static void service_enter_restart(Service *s) {
|
||||
* restarted. We use JOB_RESTART (instead of the more obvious
|
||||
* JOB_START) here so that those dependency jobs will be added
|
||||
* as well. */
|
||||
r = manager_add_job(UNIT(s)->manager, JOB_RESTART, UNIT(s), JOB_REPLACE, &error, NULL);
|
||||
r = manager_add_job(UNIT(s)->manager, JOB_RESTART, UNIT(s), JOB_REPLACE, NULL, &error, NULL);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
|
@ -2310,7 +2310,7 @@ static void socket_enter_running(Socket *s, int cfd) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT_DEREF(s->service), JOB_REPLACE, &error, NULL);
|
||||
r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT_DEREF(s->service), JOB_REPLACE, NULL, &error, NULL);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
}
|
||||
@ -2385,7 +2385,7 @@ static void socket_enter_running(Socket *s, int cfd) {
|
||||
|
||||
service->peer = TAKE_PTR(p); /* Pass ownership of the peer reference */
|
||||
|
||||
r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT(service), JOB_REPLACE, &error, NULL);
|
||||
r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT(service), JOB_REPLACE, NULL, &error, NULL);
|
||||
if (r < 0) {
|
||||
/* We failed to activate the new service, but it still exists. Let's make sure the service
|
||||
* closes and forgets the connection fd again, immediately. */
|
||||
|
@ -579,7 +579,7 @@ static void timer_enter_running(Timer *t) {
|
||||
return;
|
||||
}
|
||||
|
||||
r = manager_add_job(UNIT(t)->manager, JOB_START, trigger, JOB_REPLACE, &error, NULL);
|
||||
r = manager_add_job(UNIT(t)->manager, JOB_START, trigger, JOB_REPLACE, NULL, &error, NULL);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
|
@ -589,7 +589,12 @@ rescan:
|
||||
}
|
||||
}
|
||||
|
||||
static int transaction_apply(Transaction *tr, Manager *m, JobMode mode) {
|
||||
static int transaction_apply(
|
||||
Transaction *tr,
|
||||
Manager *m,
|
||||
JobMode mode,
|
||||
Set *affected_jobs) {
|
||||
|
||||
Iterator i;
|
||||
Job *j;
|
||||
int r;
|
||||
@ -646,6 +651,11 @@ static int transaction_apply(Transaction *tr, Manager *m, JobMode mode) {
|
||||
job_add_to_dbus_queue(j);
|
||||
job_start_timer(j, false);
|
||||
job_shutdown_magic(j);
|
||||
|
||||
/* When 'affected' is specified, let's track all in it all jobs that were touched because of
|
||||
* this transaction. */
|
||||
if (affected_jobs)
|
||||
(void) set_put(affected_jobs, j);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -658,7 +668,13 @@ rollback:
|
||||
return r;
|
||||
}
|
||||
|
||||
int transaction_activate(Transaction *tr, Manager *m, JobMode mode, sd_bus_error *e) {
|
||||
int transaction_activate(
|
||||
Transaction *tr,
|
||||
Manager *m,
|
||||
JobMode mode,
|
||||
Set *affected_jobs,
|
||||
sd_bus_error *e) {
|
||||
|
||||
Iterator i;
|
||||
Job *j;
|
||||
int r;
|
||||
@ -735,7 +751,7 @@ int transaction_activate(Transaction *tr, Manager *m, JobMode mode, sd_bus_error
|
||||
return log_notice_errno(r, "Requested transaction contradicts existing jobs: %s", bus_error_message(e, r));
|
||||
|
||||
/* Tenth step: apply changes */
|
||||
r = transaction_apply(tr, m, mode);
|
||||
r = transaction_apply(tr, m, mode, affected_jobs);
|
||||
if (r < 0)
|
||||
return log_warning_errno(r, "Failed to apply transaction: %m");
|
||||
|
||||
|
@ -29,6 +29,6 @@ int transaction_add_job_and_dependencies(
|
||||
bool ignore_requirements,
|
||||
bool ignore_order,
|
||||
sd_bus_error *e);
|
||||
int transaction_activate(Transaction *tr, Manager *m, JobMode mode, sd_bus_error *e);
|
||||
int transaction_activate(Transaction *tr, Manager *m, JobMode mode, Set *affected, sd_bus_error *e);
|
||||
int transaction_add_isolate_jobs(Transaction *tr, Manager *m);
|
||||
void transaction_abort(Transaction *tr);
|
||||
|
@ -2035,7 +2035,7 @@ static void unit_check_binds_to(Unit *u) {
|
||||
log_unit_info(u, "Unit is bound to inactive unit %s. Stopping, too.", other->id);
|
||||
|
||||
/* A unit we need to run is gone. Sniff. Let's stop this. */
|
||||
r = manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, &error, NULL);
|
||||
r = manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, NULL, &error, NULL);
|
||||
if (r < 0)
|
||||
log_unit_warning_errno(u, r, "Failed to enqueue stop job, ignoring: %s", bus_error_message(&error, r));
|
||||
}
|
||||
@ -2051,25 +2051,25 @@ static void retroactively_start_dependencies(Unit *u) {
|
||||
HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_REQUIRES], i)
|
||||
if (!hashmap_get(u->dependencies[UNIT_AFTER], other) &&
|
||||
!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
|
||||
manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, NULL, NULL);
|
||||
manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, NULL, NULL, NULL);
|
||||
|
||||
HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_BINDS_TO], i)
|
||||
if (!hashmap_get(u->dependencies[UNIT_AFTER], other) &&
|
||||
!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
|
||||
manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, NULL, NULL);
|
||||
manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, NULL, NULL, NULL);
|
||||
|
||||
HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_WANTS], i)
|
||||
if (!hashmap_get(u->dependencies[UNIT_AFTER], other) &&
|
||||
!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
|
||||
manager_add_job(u->manager, JOB_START, other, JOB_FAIL, NULL, NULL);
|
||||
manager_add_job(u->manager, JOB_START, other, JOB_FAIL, NULL, NULL, NULL);
|
||||
|
||||
HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_CONFLICTS], i)
|
||||
if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
|
||||
manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, NULL, NULL);
|
||||
manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, NULL, NULL, NULL);
|
||||
|
||||
HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_CONFLICTED_BY], i)
|
||||
if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
|
||||
manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, NULL, NULL);
|
||||
manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static void retroactively_stop_dependencies(Unit *u) {
|
||||
@ -2083,7 +2083,7 @@ static void retroactively_stop_dependencies(Unit *u) {
|
||||
/* Pull down units which are bound to us recursively if enabled */
|
||||
HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_BOUND_BY], i)
|
||||
if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
|
||||
manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, NULL, NULL);
|
||||
manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
void unit_start_on_failure(Unit *u) {
|
||||
@ -2102,7 +2102,7 @@ void unit_start_on_failure(Unit *u) {
|
||||
HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_ON_FAILURE], i) {
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
|
||||
r = manager_add_job(u->manager, JOB_START, other, u->on_failure_job_mode, &error, NULL);
|
||||
r = manager_add_job(u->manager, JOB_START, other, u->on_failure_job_mode, NULL, &error, NULL);
|
||||
if (r < 0)
|
||||
log_unit_warning_errno(u, r, "Failed to enqueue OnFailure= job, ignoring: %s", bus_error_message(&error, r));
|
||||
}
|
||||
|
@ -114,6 +114,7 @@ static bool arg_dry_run = false;
|
||||
static bool arg_quiet = false;
|
||||
static bool arg_full = false;
|
||||
static bool arg_recursive = false;
|
||||
static bool arg_show_transaction = false;
|
||||
static int arg_force = 0;
|
||||
static bool arg_ask_password = false;
|
||||
static bool arg_runtime = false;
|
||||
@ -728,7 +729,6 @@ static int get_unit_list_recursive(
|
||||
*_machines = NULL;
|
||||
|
||||
*_unit_infos = TAKE_PTR(unit_infos);
|
||||
|
||||
*_replies = TAKE_PTR(replies);
|
||||
|
||||
return c;
|
||||
@ -2741,25 +2741,26 @@ static int check_triggering_units(sd_bus *bus, const char *name) {
|
||||
}
|
||||
|
||||
static const struct {
|
||||
const char *verb;
|
||||
const char *method;
|
||||
const char *verb; /* systemctl verb */
|
||||
const char *method; /* Name of the specific D-Bus method */
|
||||
const char *job_type; /* Job type when passing to the generic EnqueueUnitJob() method */
|
||||
} unit_actions[] = {
|
||||
{ "start", "StartUnit" },
|
||||
{ "stop", "StopUnit" },
|
||||
{ "condstop", "StopUnit" },
|
||||
{ "reload", "ReloadUnit" },
|
||||
{ "restart", "RestartUnit" },
|
||||
{ "try-restart", "TryRestartUnit" },
|
||||
{ "condrestart", "TryRestartUnit" },
|
||||
{ "reload-or-restart", "ReloadOrRestartUnit" },
|
||||
{ "try-reload-or-restart", "ReloadOrTryRestartUnit" },
|
||||
{ "reload-or-try-restart", "ReloadOrTryRestartUnit" },
|
||||
{ "condreload", "ReloadOrTryRestartUnit" },
|
||||
{ "force-reload", "ReloadOrTryRestartUnit" }
|
||||
{ "start", "StartUnit", "start" },
|
||||
{ "stop", "StopUnit", "stop" },
|
||||
{ "condstop", "StopUnit", "stop" }, /* legacy alias */
|
||||
{ "reload", "ReloadUnit", "reload" },
|
||||
{ "restart", "RestartUnit", "restart" },
|
||||
{ "try-restart", "TryRestartUnit", "try-restart" },
|
||||
{ "condrestart", "TryRestartUnit", "try-restart" }, /* legacy alias */
|
||||
{ "reload-or-restart", "ReloadOrRestartUnit", "reload-or-restart" },
|
||||
{ "try-reload-or-restart", "ReloadOrTryRestartUnit", "reload-or-try-restart" },
|
||||
{ "reload-or-try-restart", "ReloadOrTryRestartUnit", "reload-or-try-restart" }, /* legacy alias */
|
||||
{ "condreload", "ReloadOrTryRestartUnit", "reload-or-try-restart" }, /* legacy alias */
|
||||
{ "force-reload", "ReloadOrTryRestartUnit", "reload-or-try-restart" }, /* legacy alias */
|
||||
};
|
||||
|
||||
static const char *verb_to_method(const char *verb) {
|
||||
uint i;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < ELEMENTSOF(unit_actions); i++)
|
||||
if (streq_ptr(unit_actions[i].verb, verb))
|
||||
@ -2768,14 +2769,14 @@ static const char *verb_to_method(const char *verb) {
|
||||
return "StartUnit";
|
||||
}
|
||||
|
||||
static const char *method_to_verb(const char *method) {
|
||||
uint i;
|
||||
static const char *verb_to_job_type(const char *verb) {
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < ELEMENTSOF(unit_actions); i++)
|
||||
if (streq_ptr(unit_actions[i].method, method))
|
||||
return unit_actions[i].verb;
|
||||
if (streq_ptr(unit_actions[i].verb, verb))
|
||||
return unit_actions[i].job_type;
|
||||
|
||||
return "n/a";
|
||||
return "start";
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
@ -2932,7 +2933,8 @@ static int wait_context_watch(
|
||||
|
||||
static int start_unit_one(
|
||||
sd_bus *bus,
|
||||
const char *method,
|
||||
const char *method, /* When using classic per-job bus methods */
|
||||
const char *job_type, /* When using new-style EnqueueUnitJob() */
|
||||
const char *name,
|
||||
const char *mode,
|
||||
sd_bus_error *error,
|
||||
@ -2941,6 +2943,7 @@ static int start_unit_one(
|
||||
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
const char *path;
|
||||
bool done = false;
|
||||
int r;
|
||||
|
||||
assert(method);
|
||||
@ -2957,44 +2960,80 @@ static int start_unit_one(
|
||||
log_debug("%s dbus call org.freedesktop.systemd1.Manager %s(%s, %s)",
|
||||
arg_dry_run ? "Would execute" : "Executing",
|
||||
method, name, mode);
|
||||
|
||||
if (arg_dry_run)
|
||||
return 0;
|
||||
|
||||
r = sd_bus_call_method(
|
||||
bus,
|
||||
"org.freedesktop.systemd1",
|
||||
"/org/freedesktop/systemd1",
|
||||
"org.freedesktop.systemd1.Manager",
|
||||
method,
|
||||
error,
|
||||
&reply,
|
||||
"ss", name, mode);
|
||||
if (r < 0) {
|
||||
const char *verb;
|
||||
if (arg_show_transaction) {
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error enqueue_error = SD_BUS_ERROR_NULL;
|
||||
|
||||
/* There's always a fallback possible for legacy actions. */
|
||||
if (arg_action != ACTION_SYSTEMCTL)
|
||||
return r;
|
||||
/* Use the new, fancy EnqueueUnitJob() API if the user wants us to print the transaction */
|
||||
r = sd_bus_call_method(
|
||||
bus,
|
||||
"org.freedesktop.systemd1",
|
||||
"/org/freedesktop/systemd1",
|
||||
"org.freedesktop.systemd1.Manager",
|
||||
"EnqueueUnitJob",
|
||||
&enqueue_error,
|
||||
&reply,
|
||||
"sss",
|
||||
name, job_type, mode);
|
||||
if (r < 0) {
|
||||
if (!sd_bus_error_has_name(&enqueue_error, SD_BUS_ERROR_UNKNOWN_METHOD)) {
|
||||
(void) sd_bus_error_move(error, &enqueue_error);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
verb = method_to_verb(method);
|
||||
/* Hmm, the API is not yet available. Let's use the classic API instead (see below). */
|
||||
log_notice("--show-transaction not supported by this service manager, proceeding without.");
|
||||
} else {
|
||||
const char *u, *jt;
|
||||
uint32_t id;
|
||||
|
||||
log_error("Failed to %s %s: %s", verb, name, bus_error_message(error, r));
|
||||
r = sd_bus_message_read(reply, "uosos", &id, &path, &u, NULL, &jt);
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
if (!sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) &&
|
||||
!sd_bus_error_has_name(error, BUS_ERROR_UNIT_MASKED) &&
|
||||
!sd_bus_error_has_name(error, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE))
|
||||
log_error("See %s logs and 'systemctl%s status%s %s' for details.",
|
||||
arg_scope == UNIT_FILE_SYSTEM ? "system" : "user",
|
||||
arg_scope == UNIT_FILE_SYSTEM ? "" : " --user",
|
||||
name[0] == '-' ? " --" : "",
|
||||
name);
|
||||
log_info("Enqueued anchor job %" PRIu32 " %s/%s.", id, u, jt);
|
||||
|
||||
return r;
|
||||
r = sd_bus_message_enter_container(reply, 'a', "(uosos)");
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
for (;;) {
|
||||
r = sd_bus_message_read(reply, "(uosos)", &id, NULL, &u, NULL, &jt);
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
log_info("Enqueued auxiliary job %" PRIu32 " %s/%s.", id, u, jt);
|
||||
}
|
||||
|
||||
r = sd_bus_message_exit_container(reply);
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
|
||||
r = sd_bus_message_read(reply, "o", &path);
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
if (!done) {
|
||||
r = sd_bus_call_method(
|
||||
bus,
|
||||
"org.freedesktop.systemd1",
|
||||
"/org/freedesktop/systemd1",
|
||||
"org.freedesktop.systemd1.Manager",
|
||||
method,
|
||||
error,
|
||||
&reply,
|
||||
"ss", name, mode);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
r = sd_bus_message_read(reply, "o", &path);
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
}
|
||||
|
||||
if (need_daemon_reload(bus, name) > 0)
|
||||
warn_unit_file_changed(name);
|
||||
@ -3007,6 +3046,24 @@ static int start_unit_one(
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
/* There's always a fallback possible for legacy actions. */
|
||||
if (arg_action != ACTION_SYSTEMCTL)
|
||||
return r;
|
||||
|
||||
log_error_errno(r, "Failed to %s %s: %s", job_type, name, bus_error_message(error, r));
|
||||
|
||||
if (!sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) &&
|
||||
!sd_bus_error_has_name(error, BUS_ERROR_UNIT_MASKED) &&
|
||||
!sd_bus_error_has_name(error, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE))
|
||||
log_error("See %s logs and 'systemctl%s status%s %s' for details.",
|
||||
arg_scope == UNIT_FILE_SYSTEM ? "system" : "user",
|
||||
arg_scope == UNIT_FILE_SYSTEM ? "" : " --user",
|
||||
name[0] == '-' ? " --" : "",
|
||||
name);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int expand_names(sd_bus *bus, char **names, const char* suffix, char ***ret) {
|
||||
@ -3063,7 +3120,6 @@ static int expand_names(sd_bus *bus, char **names, const char* suffix, char ***r
|
||||
}
|
||||
|
||||
*ret = TAKE_PTR(mangled);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -3072,21 +3128,21 @@ static const struct {
|
||||
const char *verb;
|
||||
const char *mode;
|
||||
} action_table[_ACTION_MAX] = {
|
||||
[ACTION_HALT] = { SPECIAL_HALT_TARGET, "halt", "replace-irreversibly" },
|
||||
[ACTION_POWEROFF] = { SPECIAL_POWEROFF_TARGET, "poweroff", "replace-irreversibly" },
|
||||
[ACTION_REBOOT] = { SPECIAL_REBOOT_TARGET, "reboot", "replace-irreversibly" },
|
||||
[ACTION_KEXEC] = { SPECIAL_KEXEC_TARGET, "kexec", "replace-irreversibly" },
|
||||
[ACTION_RUNLEVEL2] = { SPECIAL_MULTI_USER_TARGET, NULL, "isolate" },
|
||||
[ACTION_RUNLEVEL3] = { SPECIAL_MULTI_USER_TARGET, NULL, "isolate" },
|
||||
[ACTION_RUNLEVEL4] = { SPECIAL_MULTI_USER_TARGET, NULL, "isolate" },
|
||||
[ACTION_RUNLEVEL5] = { SPECIAL_GRAPHICAL_TARGET, NULL, "isolate" },
|
||||
[ACTION_RESCUE] = { SPECIAL_RESCUE_TARGET, "rescue", "isolate" },
|
||||
[ACTION_EMERGENCY] = { SPECIAL_EMERGENCY_TARGET, "emergency", "isolate" },
|
||||
[ACTION_DEFAULT] = { SPECIAL_DEFAULT_TARGET, "default", "isolate" },
|
||||
[ACTION_EXIT] = { SPECIAL_EXIT_TARGET, "exit", "replace-irreversibly" },
|
||||
[ACTION_SUSPEND] = { SPECIAL_SUSPEND_TARGET, "suspend", "replace-irreversibly" },
|
||||
[ACTION_HIBERNATE] = { SPECIAL_HIBERNATE_TARGET, "hibernate", "replace-irreversibly" },
|
||||
[ACTION_HYBRID_SLEEP] = { SPECIAL_HYBRID_SLEEP_TARGET, "hybrid-sleep", "replace-irreversibly" },
|
||||
[ACTION_HALT] = { SPECIAL_HALT_TARGET, "halt", "replace-irreversibly" },
|
||||
[ACTION_POWEROFF] = { SPECIAL_POWEROFF_TARGET, "poweroff", "replace-irreversibly" },
|
||||
[ACTION_REBOOT] = { SPECIAL_REBOOT_TARGET, "reboot", "replace-irreversibly" },
|
||||
[ACTION_KEXEC] = { SPECIAL_KEXEC_TARGET, "kexec", "replace-irreversibly" },
|
||||
[ACTION_RUNLEVEL2] = { SPECIAL_MULTI_USER_TARGET, NULL, "isolate" },
|
||||
[ACTION_RUNLEVEL3] = { SPECIAL_MULTI_USER_TARGET, NULL, "isolate" },
|
||||
[ACTION_RUNLEVEL4] = { SPECIAL_MULTI_USER_TARGET, NULL, "isolate" },
|
||||
[ACTION_RUNLEVEL5] = { SPECIAL_GRAPHICAL_TARGET, NULL, "isolate" },
|
||||
[ACTION_RESCUE] = { SPECIAL_RESCUE_TARGET, "rescue", "isolate" },
|
||||
[ACTION_EMERGENCY] = { SPECIAL_EMERGENCY_TARGET, "emergency", "isolate" },
|
||||
[ACTION_DEFAULT] = { SPECIAL_DEFAULT_TARGET, "default", "isolate" },
|
||||
[ACTION_EXIT] = { SPECIAL_EXIT_TARGET, "exit", "replace-irreversibly" },
|
||||
[ACTION_SUSPEND] = { SPECIAL_SUSPEND_TARGET, "suspend", "replace-irreversibly" },
|
||||
[ACTION_HIBERNATE] = { SPECIAL_HIBERNATE_TARGET, "hibernate", "replace-irreversibly" },
|
||||
[ACTION_HYBRID_SLEEP] = { SPECIAL_HYBRID_SLEEP_TARGET, "hybrid-sleep", "replace-irreversibly" },
|
||||
[ACTION_SUSPEND_THEN_HIBERNATE] = { SPECIAL_SUSPEND_THEN_HIBERNATE_TARGET, "suspend-then-hibernate", "replace-irreversibly" },
|
||||
};
|
||||
|
||||
@ -3100,10 +3156,29 @@ static enum action verb_to_action(const char *verb) {
|
||||
return _ACTION_INVALID;
|
||||
}
|
||||
|
||||
static const char** make_extra_args(const char *extra_args[static 4]) {
|
||||
size_t n = 0;
|
||||
|
||||
if (arg_scope != UNIT_FILE_SYSTEM)
|
||||
extra_args[n++] = "--user";
|
||||
|
||||
if (arg_transport == BUS_TRANSPORT_REMOTE) {
|
||||
extra_args[n++] = "-H";
|
||||
extra_args[n++] = arg_host;
|
||||
} else if (arg_transport == BUS_TRANSPORT_MACHINE) {
|
||||
extra_args[n++] = "-M";
|
||||
extra_args[n++] = arg_host;
|
||||
} else
|
||||
assert(arg_transport == BUS_TRANSPORT_LOCAL);
|
||||
|
||||
extra_args[n] = NULL;
|
||||
return extra_args;
|
||||
}
|
||||
|
||||
static int start_unit(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
|
||||
_cleanup_(wait_context_free) WaitContext wait_context = {};
|
||||
const char *method, *mode, *one_name, *suffix = NULL;
|
||||
const char *method, *job_type, *mode, *one_name, *suffix = NULL;
|
||||
_cleanup_free_ char **stopped_units = NULL; /* Do not use _cleanup_strv_free_ */
|
||||
_cleanup_strv_free_ char **names = NULL;
|
||||
int r, ret = EXIT_SUCCESS;
|
||||
@ -3129,27 +3204,34 @@ static int start_unit(int argc, char *argv[], void *userdata) {
|
||||
action = verb_to_action(argv[0]);
|
||||
|
||||
if (action != _ACTION_INVALID) {
|
||||
/* A command in style "systemctl reboot", "systemctl poweroff", … */
|
||||
method = "StartUnit";
|
||||
job_type = "start";
|
||||
mode = action_table[action].mode;
|
||||
one_name = action_table[action].target;
|
||||
} else {
|
||||
if (streq(argv[0], "isolate")) {
|
||||
/* A "systemctl isolate <unit1> <unit2> …" command */
|
||||
method = "StartUnit";
|
||||
job_type = "start";
|
||||
mode = "isolate";
|
||||
|
||||
suffix = ".target";
|
||||
} else {
|
||||
/* A command in style of "systemctl start <unit1> <unit2> …", "sysemctl stop <unit1> <unit2> …" and so on */
|
||||
method = verb_to_method(argv[0]);
|
||||
job_type = verb_to_job_type(argv[0]);
|
||||
mode = arg_job_mode;
|
||||
}
|
||||
one_name = NULL;
|
||||
}
|
||||
} else {
|
||||
/* A SysV legacy command such as "halt", "reboot", "poweroff", … */
|
||||
assert(arg_action >= 0 && arg_action < _ACTION_MAX);
|
||||
assert(action_table[arg_action].target);
|
||||
assert(action_table[arg_action].mode);
|
||||
|
||||
method = "StartUnit";
|
||||
job_type = "start";
|
||||
mode = action_table[arg_action].mode;
|
||||
one_name = action_table[arg_action].target;
|
||||
}
|
||||
@ -3182,9 +3264,11 @@ static int start_unit(int argc, char *argv[], void *userdata) {
|
||||
NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to enable subscription: %m");
|
||||
|
||||
r = sd_event_default(&wait_context.event);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to allocate event loop: %m");
|
||||
|
||||
r = sd_bus_attach_event(bus, wait_context.event, 0);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to attach bus to event loop: %m");
|
||||
@ -3193,7 +3277,7 @@ static int start_unit(int argc, char *argv[], void *userdata) {
|
||||
STRV_FOREACH(name, names) {
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
|
||||
r = start_unit_one(bus, method, *name, mode, &error, w, arg_wait ? &wait_context : NULL);
|
||||
r = start_unit_one(bus, method, job_type, *name, mode, &error, w, arg_wait ? &wait_context : NULL);
|
||||
if (ret == EXIT_SUCCESS && r < 0)
|
||||
ret = translate_bus_error_to_exit_status(r, &error);
|
||||
|
||||
@ -3205,22 +3289,9 @@ static int start_unit(int argc, char *argv[], void *userdata) {
|
||||
}
|
||||
|
||||
if (!arg_no_block) {
|
||||
const char* extra_args[4] = {};
|
||||
int arg_count = 0;
|
||||
const char* extra_args[4];
|
||||
|
||||
if (arg_scope != UNIT_FILE_SYSTEM)
|
||||
extra_args[arg_count++] = "--user";
|
||||
|
||||
assert(IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_REMOTE, BUS_TRANSPORT_MACHINE));
|
||||
if (arg_transport == BUS_TRANSPORT_REMOTE) {
|
||||
extra_args[arg_count++] = "-H";
|
||||
extra_args[arg_count++] = arg_host;
|
||||
} else if (arg_transport == BUS_TRANSPORT_MACHINE) {
|
||||
extra_args[arg_count++] = "-M";
|
||||
extra_args[arg_count++] = arg_host;
|
||||
}
|
||||
|
||||
r = bus_wait_for_jobs(w, arg_quiet, extra_args);
|
||||
r = bus_wait_for_jobs(w, arg_quiet, make_extra_args(extra_args));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -3279,64 +3350,38 @@ static int logind_set_wall_message(void) {
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Ask systemd-logind, which might grant access to unprivileged users
|
||||
* through polkit */
|
||||
/* Ask systemd-logind, which might grant access to unprivileged users through polkit */
|
||||
static int logind_reboot(enum action a) {
|
||||
#if ENABLE_LOGIND
|
||||
static const struct {
|
||||
const char *method;
|
||||
const char *description;
|
||||
} actions[_ACTION_MAX] = {
|
||||
[ACTION_POWEROFF] = { "PowerOff", "power off system" },
|
||||
[ACTION_REBOOT] = { "Reboot", "reboot system" },
|
||||
[ACTION_HALT] = { "Halt", "halt system" },
|
||||
[ACTION_SUSPEND] = { "Suspend", "suspend system" },
|
||||
[ACTION_HIBERNATE] = { "Hibernate", "hibernate system" },
|
||||
[ACTION_HYBRID_SLEEP] = { "HybridSleep", "put system into hybrid sleep" },
|
||||
[ACTION_SUSPEND_THEN_HIBERNATE] = { "SuspendThenHibernate", "suspend system, hibernate later" },
|
||||
};
|
||||
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
const char *method, *description;
|
||||
sd_bus *bus;
|
||||
int r;
|
||||
|
||||
if (a < 0 || a >= _ACTION_MAX || !actions[a].method)
|
||||
return -EINVAL;
|
||||
|
||||
r = acquire_bus(BUS_FULL, &bus);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
switch (a) {
|
||||
|
||||
case ACTION_POWEROFF:
|
||||
method = "PowerOff";
|
||||
description = "power off system";
|
||||
break;
|
||||
|
||||
case ACTION_REBOOT:
|
||||
method = "Reboot";
|
||||
description = "reboot system";
|
||||
break;
|
||||
|
||||
case ACTION_HALT:
|
||||
method = "Halt";
|
||||
description = "halt system";
|
||||
break;
|
||||
|
||||
case ACTION_SUSPEND:
|
||||
method = "Suspend";
|
||||
description = "suspend system";
|
||||
break;
|
||||
|
||||
case ACTION_HIBERNATE:
|
||||
method = "Hibernate";
|
||||
description = "hibernate system";
|
||||
break;
|
||||
|
||||
case ACTION_HYBRID_SLEEP:
|
||||
method = "HybridSleep";
|
||||
description = "put system into hybrid sleep";
|
||||
break;
|
||||
|
||||
case ACTION_SUSPEND_THEN_HIBERNATE:
|
||||
method = "SuspendThenHibernate";
|
||||
description = "put system into suspend followed by hibernate";
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
polkit_agent_open_maybe();
|
||||
(void) logind_set_wall_message();
|
||||
|
||||
log_debug("%s org.freedesktop.login1.Manager %s dbus call.", arg_dry_run ? "Would execute" : "Executing", method);
|
||||
log_debug("%s org.freedesktop.login1.Manager %s dbus call.", arg_dry_run ? "Would execute" : "Executing", actions[a].method);
|
||||
|
||||
if (arg_dry_run)
|
||||
return 0;
|
||||
|
||||
@ -3345,12 +3390,12 @@ static int logind_reboot(enum action a) {
|
||||
"org.freedesktop.login1",
|
||||
"/org/freedesktop/login1",
|
||||
"org.freedesktop.login1.Manager",
|
||||
method,
|
||||
actions[a].method,
|
||||
&error,
|
||||
NULL,
|
||||
"b", arg_ask_password);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to %s via logind: %s", description, bus_error_message(&error, r));
|
||||
return log_error_errno(r, "Failed to %s via logind: %s", actions[a].description, bus_error_message(&error, r));
|
||||
|
||||
return 0;
|
||||
#else
|
||||
@ -3571,8 +3616,8 @@ static int prepare_boot_loader_entry(void) {
|
||||
|
||||
return 0;
|
||||
#else
|
||||
log_error("Booting into boot loader entry not supported.");
|
||||
return -ENOSYS;
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
|
||||
"Booting into boot loader entry not supported.");
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -7554,6 +7599,8 @@ static int systemctl_help(void) {
|
||||
" --reverse Show reverse dependencies with 'list-dependencies'\n"
|
||||
" --job-mode=MODE Specify how to deal with already queued jobs, when\n"
|
||||
" queueing a new job\n"
|
||||
" -T --show-transaction\n"
|
||||
" When enqueuing a unit job, show full transaction\n"
|
||||
" --show-types When showing sockets, explicitly show their type\n"
|
||||
" --value When showing properties, only print the value\n"
|
||||
" -i --ignore-inhibitors\n"
|
||||
@ -7961,6 +8008,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
|
||||
{ "boot-loader-entry", required_argument, NULL, ARG_BOOT_LOADER_ENTRY },
|
||||
{ "now", no_argument, NULL, ARG_NOW },
|
||||
{ "message", required_argument, NULL, ARG_MESSAGE },
|
||||
{ "show-transaction", no_argument, NULL, 'T' },
|
||||
{}
|
||||
};
|
||||
|
||||
@ -7972,7 +8020,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
|
||||
/* we default to allowing interactive authorization only in systemctl (not in the legacy commands) */
|
||||
arg_ask_password = true;
|
||||
|
||||
while ((c = getopt_long(argc, argv, "ht:p:alqfs:H:M:n:o:ir.::", options, NULL)) >= 0)
|
||||
while ((c = getopt_long(argc, argv, "ht:p:alqfs:H:M:n:o:iTr.::", options, NULL)) >= 0)
|
||||
|
||||
switch (c) {
|
||||
|
||||
@ -8309,6 +8357,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
|
||||
return log_oom();
|
||||
break;
|
||||
|
||||
case 'T':
|
||||
arg_show_transaction = true;
|
||||
break;
|
||||
|
||||
case '.':
|
||||
/* Output an error mimicking getopt, and print a hint afterwards */
|
||||
log_error("%s: invalid option -- '.'", program_invocation_name);
|
||||
|
@ -40,7 +40,7 @@ int main(int argc, char *argv[]) {
|
||||
manager_dump_units(m, stdout, "\t");
|
||||
|
||||
printf("Test1: (Trivial)\n");
|
||||
r = manager_add_job(m, JOB_START, c, JOB_REPLACE, &err, &j);
|
||||
r = manager_add_job(m, JOB_START, c, JOB_REPLACE, NULL, &err, &j);
|
||||
if (sd_bus_error_is_set(&err))
|
||||
log_error("error: %s: %s", err.name, err.message);
|
||||
assert_se(r == 0);
|
||||
@ -53,15 +53,15 @@ int main(int argc, char *argv[]) {
|
||||
manager_dump_units(m, stdout, "\t");
|
||||
|
||||
printf("Test2: (Cyclic Order, Unfixable)\n");
|
||||
assert_se(manager_add_job(m, JOB_START, d, JOB_REPLACE, NULL, &j) == -EDEADLK);
|
||||
assert_se(manager_add_job(m, JOB_START, d, JOB_REPLACE, NULL, NULL, &j) == -EDEADLK);
|
||||
manager_dump_jobs(m, stdout, "\t");
|
||||
|
||||
printf("Test3: (Cyclic Order, Fixable, Garbage Collector)\n");
|
||||
assert_se(manager_add_job(m, JOB_START, e, JOB_REPLACE, NULL, &j) == 0);
|
||||
assert_se(manager_add_job(m, JOB_START, e, JOB_REPLACE, NULL, NULL, &j) == 0);
|
||||
manager_dump_jobs(m, stdout, "\t");
|
||||
|
||||
printf("Test4: (Identical transaction)\n");
|
||||
assert_se(manager_add_job(m, JOB_START, e, JOB_FAIL, NULL, &j) == 0);
|
||||
assert_se(manager_add_job(m, JOB_START, e, JOB_FAIL, NULL, NULL, &j) == 0);
|
||||
manager_dump_jobs(m, stdout, "\t");
|
||||
|
||||
printf("Load3:\n");
|
||||
@ -69,21 +69,21 @@ int main(int argc, char *argv[]) {
|
||||
manager_dump_units(m, stdout, "\t");
|
||||
|
||||
printf("Test5: (Colliding transaction, fail)\n");
|
||||
assert_se(manager_add_job(m, JOB_START, g, JOB_FAIL, NULL, &j) == -EDEADLK);
|
||||
assert_se(manager_add_job(m, JOB_START, g, JOB_FAIL, NULL, NULL, &j) == -EDEADLK);
|
||||
|
||||
printf("Test6: (Colliding transaction, replace)\n");
|
||||
assert_se(manager_add_job(m, JOB_START, g, JOB_REPLACE, NULL, &j) == 0);
|
||||
assert_se(manager_add_job(m, JOB_START, g, JOB_REPLACE, NULL, NULL, &j) == 0);
|
||||
manager_dump_jobs(m, stdout, "\t");
|
||||
|
||||
printf("Test7: (Unmergeable job type, fail)\n");
|
||||
assert_se(manager_add_job(m, JOB_STOP, g, JOB_FAIL, NULL, &j) == -EDEADLK);
|
||||
assert_se(manager_add_job(m, JOB_STOP, g, JOB_FAIL, NULL, NULL, &j) == -EDEADLK);
|
||||
|
||||
printf("Test8: (Mergeable job type, fail)\n");
|
||||
assert_se(manager_add_job(m, JOB_RESTART, g, JOB_FAIL, NULL, &j) == 0);
|
||||
assert_se(manager_add_job(m, JOB_RESTART, g, JOB_FAIL, NULL, NULL, &j) == 0);
|
||||
manager_dump_jobs(m, stdout, "\t");
|
||||
|
||||
printf("Test9: (Unmergeable job type, replace)\n");
|
||||
assert_se(manager_add_job(m, JOB_STOP, g, JOB_REPLACE, NULL, &j) == 0);
|
||||
assert_se(manager_add_job(m, JOB_STOP, g, JOB_REPLACE, NULL, NULL, &j) == 0);
|
||||
manager_dump_jobs(m, stdout, "\t");
|
||||
|
||||
printf("Load4:\n");
|
||||
@ -91,7 +91,7 @@ int main(int argc, char *argv[]) {
|
||||
manager_dump_units(m, stdout, "\t");
|
||||
|
||||
printf("Test10: (Unmergeable job type of auxiliary job, fail)\n");
|
||||
assert_se(manager_add_job(m, JOB_START, h, JOB_FAIL, NULL, &j) == 0);
|
||||
assert_se(manager_add_job(m, JOB_START, h, JOB_FAIL, NULL, NULL, &j) == 0);
|
||||
manager_dump_jobs(m, stdout, "\t");
|
||||
|
||||
assert_se(!hashmap_get(a->dependencies[UNIT_PROPAGATES_RELOAD_TO], b));
|
||||
|
@ -26,6 +26,13 @@ grep 'sleep\.service.*running' /root/list-jobs.txt
|
||||
grep 'hello\.service' /root/list-jobs.txt && exit 1
|
||||
systemctl stop sleep.service hello-after-sleep.target
|
||||
|
||||
# Some basic testing that --show-transaction does something useful
|
||||
! systemctl is-active systemd-importd
|
||||
systemctl -T start systemd-importd
|
||||
systemctl is-active systemd-importd
|
||||
systemctl --show-transaction stop systemd-importd
|
||||
! systemctl is-active systemd-importd
|
||||
|
||||
# Test for a crash when enqueuing a JOB_NOP when other job already exists
|
||||
systemctl start --no-block hello-after-sleep.target
|
||||
# hello.service should still be waiting, so these try-restarts will collapse
|
||||
|
Loading…
x
Reference in New Issue
Block a user