summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--man/systemctl.xml11
-rw-r--r--src/core/job.c15
-rw-r--r--src/core/job.h2
-rw-r--r--src/core/manager.c2
-rw-r--r--src/core/transaction.c20
-rw-r--r--src/core/transaction.h3
-rw-r--r--src/systemctl/systemctl.c6
7 files changed, 46 insertions, 13 deletions
diff --git a/man/systemctl.xml b/man/systemctl.xml
index c233543d7d..0ceb26d59b 100644
--- a/man/systemctl.xml
+++ b/man/systemctl.xml
@@ -171,6 +171,17 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
</varlistentry>
<varlistentry>
+ <term><option>--irreversible</option></term>
+
+ <listitem>
+ <para>Mark this transaction's jobs as irreversible. This prevents
+ future conflicting transactions from replacing these jobs.
+ The jobs can still be cancelled using the <command>cancel</command>
+ command.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>--ignore-dependencies</option></term>
<listitem>
diff --git a/src/core/job.c b/src/core/job.c
index 2bafbc1589..990607f990 100644
--- a/src/core/job.c
+++ b/src/core/job.c
@@ -169,6 +169,7 @@ static void job_merge_into_installed(Job *j, Job *other) {
assert(other->type == JOB_NOP);
j->override = j->override || other->override;
+ j->irreversible = j->irreversible || other->irreversible;
j->ignore_order = j->ignore_order || other->ignore_order;
}
@@ -294,11 +295,13 @@ void job_dump(Job *j, FILE*f, const char *prefix) {
"%s-> Job %u:\n"
"%s\tAction: %s -> %s\n"
"%s\tState: %s\n"
- "%s\tForced: %s\n",
+ "%s\tForced: %s\n"
+ "%s\tIrreversible: %s\n",
prefix, j->id,
prefix, j->unit->id, job_type_to_string(j->type),
prefix, job_state_to_string(j->state),
- prefix, yes_no(j->override));
+ prefix, yes_no(j->override),
+ prefix, yes_no(j->irreversible));
}
/*
@@ -947,6 +950,7 @@ int job_serialize(Job *j, FILE *f, FDSet *fds) {
fprintf(f, "job-type=%s\n", job_type_to_string(j->type));
fprintf(f, "job-state=%s\n", job_state_to_string(j->state));
fprintf(f, "job-override=%s\n", yes_no(j->override));
+ fprintf(f, "job-irreversible=%s\n", yes_no(j->irreversible));
fprintf(f, "job-sent-dbus-new-signal=%s\n", yes_no(j->sent_dbus_new_signal));
fprintf(f, "job-ignore-order=%s\n", yes_no(j->ignore_order));
/* Cannot save bus clients. Just note the fact that we're losing
@@ -1014,6 +1018,12 @@ int job_deserialize(Job *j, FILE *f, FDSet *fds) {
log_debug("Failed to parse job override flag %s", v);
else
j->override = j->override || b;
+ } else if (streq(l, "job-irreversible")) {
+ int b = parse_boolean(v);
+ if (b < 0)
+ log_debug("Failed to parse job irreversible flag %s", v);
+ else
+ j->irreversible = j->irreversible || b;
} else if (streq(l, "job-sent-dbus-new-signal")) {
int b = parse_boolean(v);
if (b < 0)
@@ -1110,6 +1120,7 @@ DEFINE_STRING_TABLE_LOOKUP(job_type, JobType);
static const char* const job_mode_table[_JOB_MODE_MAX] = {
[JOB_FAIL] = "fail",
[JOB_REPLACE] = "replace",
+ [JOB_REPLACE_IRREVERSIBLY] = "replace-irreversibly",
[JOB_ISOLATE] = "isolate",
[JOB_IGNORE_DEPENDENCIES] = "ignore-dependencies",
[JOB_IGNORE_REQUIREMENTS] = "ignore-requirements"
diff --git a/src/core/job.h b/src/core/job.h
index d10e6b6b0e..45d0487451 100644
--- a/src/core/job.h
+++ b/src/core/job.h
@@ -83,6 +83,7 @@ enum JobState {
enum JobMode {
JOB_FAIL, /* Fail if a conflicting job is already queued */
JOB_REPLACE, /* Replace an existing conflicting job */
+ JOB_REPLACE_IRREVERSIBLY, /* Like JOB_REPLACE + produce irreversible jobs */
JOB_ISOLATE, /* Start a unit, and stop all others */
JOB_IGNORE_DEPENDENCIES, /* Ignore both requirement and ordering dependencies */
JOB_IGNORE_REQUIREMENTS, /* Ignore requirement dependencies */
@@ -161,6 +162,7 @@ struct Job {
bool sent_dbus_new_signal:1;
bool ignore_order:1;
bool forgot_bus_clients:1;
+ bool irreversible:1;
};
JobBusClient* job_bus_client_new(DBusConnection *connection, const char *name);
diff --git a/src/core/manager.c b/src/core/manager.c
index 28f169daab..a578813617 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -766,7 +766,7 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool ove
job_type_collapse(&type, unit);
- tr = transaction_new();
+ tr = transaction_new(mode == JOB_REPLACE_IRREVERSIBLY);
if (!tr)
return -ENOMEM;
diff --git a/src/core/transaction.c b/src/core/transaction.c
index dbc30af7d1..0329366350 100644
--- a/src/core/transaction.c
+++ b/src/core/transaction.c
@@ -97,6 +97,7 @@ static void transaction_merge_and_delete_job(Transaction *tr, Job *j, Job *other
j->type = t;
j->state = JOB_WAITING;
j->override = j->override || other->override;
+ j->irreversible = j->irreversible || other->irreversible;
j->matters_to_anchor = j->matters_to_anchor || other->matters_to_anchor;
@@ -488,7 +489,7 @@ rescan:
}
}
-static int transaction_is_destructive(Transaction *tr, DBusError *e) {
+static int transaction_is_destructive(Transaction *tr, JobMode mode, DBusError *e) {
Iterator i;
Job *j;
@@ -503,7 +504,7 @@ static int transaction_is_destructive(Transaction *tr, DBusError *e) {
assert(!j->transaction_prev);
assert(!j->transaction_next);
- if (j->unit->job &&
+ if (j->unit->job && (mode == JOB_FAIL || j->unit->job->irreversible) &&
!job_type_is_superset(j->type, j->unit->job->type)) {
dbus_set_error(e, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE, "Transaction is destructive.");
@@ -709,12 +710,10 @@ int transaction_activate(Transaction *tr, Manager *m, JobMode mode, DBusError *e
transaction_drop_redundant(tr);
/* Ninth step: check whether we can actually apply this */
- if (mode == JOB_FAIL) {
- r = transaction_is_destructive(tr, e);
- if (r < 0) {
- log_notice("Requested transaction contradicts existing jobs: %s", bus_error(e, r));
- return r;
- }
+ r = transaction_is_destructive(tr, mode, e);
+ if (r < 0) {
+ log_notice("Requested transaction contradicts existing jobs: %s", bus_error(e, r));
+ return r;
}
/* Tenth step: apply changes */
@@ -770,6 +769,7 @@ static Job* transaction_add_one_job(Transaction *tr, JobType type, Unit *unit, b
j->marker = NULL;
j->matters_to_anchor = false;
j->override = override;
+ j->irreversible = tr->irreversible;
LIST_PREPEND(Job, transaction, f, j);
@@ -1106,7 +1106,7 @@ int transaction_add_isolate_jobs(Transaction *tr, Manager *m) {
return 0;
}
-Transaction *transaction_new(void) {
+Transaction *transaction_new(bool irreversible) {
Transaction *tr;
tr = new0(Transaction, 1);
@@ -1119,6 +1119,8 @@ Transaction *transaction_new(void) {
return NULL;
}
+ tr->irreversible = irreversible;
+
return tr;
}
diff --git a/src/core/transaction.h b/src/core/transaction.h
index 67ace4da0b..12f9194927 100644
--- a/src/core/transaction.h
+++ b/src/core/transaction.h
@@ -33,9 +33,10 @@ struct Transaction {
/* Jobs to be added */
Hashmap *jobs; /* Unit object => Job object list 1:1 */
Job *anchor_job; /* the job the user asked for */
+ bool irreversible;
};
-Transaction *transaction_new(void);
+Transaction *transaction_new(bool irreversible);
void transaction_free(Transaction *tr);
int transaction_add_job_and_dependencies(
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 0f19c25ce5..723be76cdb 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -4306,6 +4306,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
enum {
ARG_FAIL = 0x100,
+ ARG_IRREVERSIBLE,
ARG_IGNORE_DEPENDENCIES,
ARG_VERSION,
ARG_USER,
@@ -4334,6 +4335,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
{ "failed", no_argument, NULL, ARG_FAILED },
{ "full", no_argument, NULL, ARG_FULL },
{ "fail", no_argument, NULL, ARG_FAIL },
+ { "irreversible", no_argument, NULL, ARG_IRREVERSIBLE },
{ "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES },
{ "ignore-inhibitors", no_argument, NULL, 'i' },
{ "user", no_argument, NULL, ARG_USER },
@@ -4433,6 +4435,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
arg_job_mode = "fail";
break;
+ case ARG_IRREVERSIBLE:
+ arg_job_mode = "replace-irreversibly";
+ break;
+
case ARG_IGNORE_DEPENDENCIES:
arg_job_mode = "ignore-dependencies";
break;