From: Michal Schmidt Date: Fri, 22 Feb 2013 10:21:37 +0000 (+0100) Subject: core, systemctl: add support for irreversible jobs X-Git-Tag: v198~195 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=commitdiff_plain;h=23ade460e5a118daa575a961b405d089f95e0617 core, systemctl: add support for irreversible jobs Add a new job mode: replace-irreversibly. Jobs enqueued using this mode cannot be implicitly canceled by later enqueued conflicting jobs. They can however still be canceled with an explicit "systemctl cancel" call. --- diff --git a/man/systemctl.xml b/man/systemctl.xml index c233543d7..0ceb26d59 100644 --- a/man/systemctl.xml +++ b/man/systemctl.xml @@ -170,6 +170,17 @@ along with systemd; If not, see . + + + + + Mark this transaction's jobs as irreversible. This prevents + future conflicting transactions from replacing these jobs. + The jobs can still be cancelled using the cancel + command. + + + diff --git a/src/core/job.c b/src/core/job.c index 2bafbc158..990607f99 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 d10e6b6b0..45d048745 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 28f169daa..a57881361 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 dbc30af7d..032936635 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 67ace4da0..12f919492 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 0f19c25ce..723be76cd 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;