chiark / gitweb /
core, systemctl: add support for irreversible jobs
authorMichal Schmidt <mschmidt@redhat.com>
Fri, 22 Feb 2013 10:21:37 +0000 (11:21 +0100)
committerMichal Schmidt <mschmidt@redhat.com>
Fri, 22 Feb 2013 15:06:17 +0000 (16:06 +0100)
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.

man/systemctl.xml
src/core/job.c
src/core/job.h
src/core/manager.c
src/core/transaction.c
src/core/transaction.h
src/systemctl/systemctl.c

index c233543d7d2224c67b415d4b0dc129173c7e0847..0ceb26d59b40406bbc3182ee1f58fb2be5417eda 100644 (file)
@@ -170,6 +170,17 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
         </listitem>
       </varlistentry>
 
         </listitem>
       </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>
 
       <varlistentry>
         <term><option>--ignore-dependencies</option></term>
 
index 2bafbc15894b9a636b6d762698758aa5b8c05c41..990607f990d9eaffcb175e0e358a210c0111f5e1 100644 (file)
@@ -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;
                 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;
 }
 
         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-> 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, 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-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
         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;
                                 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)
                 } 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",
 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"
         [JOB_ISOLATE] = "isolate",
         [JOB_IGNORE_DEPENDENCIES] = "ignore-dependencies",
         [JOB_IGNORE_REQUIREMENTS] = "ignore-requirements"
index d10e6b6b0eff674edd86c4b8ce47166c7ccef695..45d04874516dd0aa54d94c54620cd563fc0e1b1f 100644 (file)
@@ -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 */
 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 */
         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 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);
 };
 
 JobBusClient* job_bus_client_new(DBusConnection *connection, const char *name);
index 28f169daabed42fa4ac54fecc0a7b800d396d330..a578813617fba45d229ff65714844be30a9468af 100644 (file)
@@ -766,7 +766,7 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool ove
 
         job_type_collapse(&type, unit);
 
 
         job_type_collapse(&type, unit);
 
-        tr = transaction_new();
+        tr = transaction_new(mode == JOB_REPLACE_IRREVERSIBLY);
         if (!tr)
                 return -ENOMEM;
 
         if (!tr)
                 return -ENOMEM;
 
index dbc30af7d1c90c23f3bce82f2b4d29a1ad1be693..03293663501fe14a27e6d831853d86479e782eb1 100644 (file)
@@ -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->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;
 
 
         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;
 
         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);
 
                 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.");
                     !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 */
         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 */
         }
 
         /* 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->marker = NULL;
         j->matters_to_anchor = false;
         j->override = override;
+        j->irreversible = tr->irreversible;
 
         LIST_PREPEND(Job, transaction, f, j);
 
 
         LIST_PREPEND(Job, transaction, f, j);
 
@@ -1106,7 +1106,7 @@ int transaction_add_isolate_jobs(Transaction *tr, Manager *m) {
         return 0;
 }
 
         return 0;
 }
 
-Transaction *transaction_new(void) {
+Transaction *transaction_new(bool irreversible) {
         Transaction *tr;
 
         tr = new0(Transaction, 1);
         Transaction *tr;
 
         tr = new0(Transaction, 1);
@@ -1119,6 +1119,8 @@ Transaction *transaction_new(void) {
                 return NULL;
         }
 
                 return NULL;
         }
 
+        tr->irreversible = irreversible;
+
         return tr;
 }
 
         return tr;
 }
 
index 67ace4da0ba8e18336ecc352a35544e3cb7cb097..12f9194927c5b3c1ab33064418f9eb006b8bcec6 100644 (file)
@@ -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 */
         /* 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(
 void transaction_free(Transaction *tr);
 
 int transaction_add_job_and_dependencies(
index 0f19c25ce594a0336ea2abc8306769a67d09c062..723be76cdbad6a7b168d9a2224d4677a69d5596c 100644 (file)
@@ -4306,6 +4306,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
 
         enum {
                 ARG_FAIL = 0x100,
 
         enum {
                 ARG_FAIL = 0x100,
+                ARG_IRREVERSIBLE,
                 ARG_IGNORE_DEPENDENCIES,
                 ARG_VERSION,
                 ARG_USER,
                 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      },
                 { "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      },
                 { "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;
 
                         arg_job_mode = "fail";
                         break;
 
+                case ARG_IRREVERSIBLE:
+                        arg_job_mode = "replace-irreversibly";
+                        break;
+
                 case ARG_IGNORE_DEPENDENCIES:
                         arg_job_mode = "ignore-dependencies";
                         break;
                 case ARG_IGNORE_DEPENDENCIES:
                         arg_job_mode = "ignore-dependencies";
                         break;