chiark / gitweb /
udev: set errno = ENOSYS for removed interfaces
[elogind.git] / src / job.c
index 20971da85294f67537e85541c346ccaa4bd5df7e..bae6ab9f32f5c4fd3d569e09f7da22a67adf6755 100644 (file)
--- a/src/job.c
+++ b/src/job.c
@@ -62,8 +62,8 @@ void job_free(Job *j) {
         if (j->installed) {
                 bus_job_send_removed_signal(j);
 
-                if (j->unit->meta.job == j) {
-                        j->unit->meta.job = NULL;
+                if (j->unit->job == j) {
+                        j->unit->job = NULL;
                         unit_add_to_gc_queue(j->unit);
                 }
 
@@ -147,7 +147,7 @@ void job_dump(Job *j, FILE*f, const char *prefix) {
                 "%s\tState: %s\n"
                 "%s\tForced: %s\n",
                 prefix, j->id,
-                prefix, j->unit->meta.id, job_type_to_string(j->type),
+                prefix, j->unit->id, job_type_to_string(j->type),
                 prefix, job_state_to_string(j->state),
                 prefix, yes_no(j->override));
 }
@@ -164,100 +164,47 @@ bool job_is_anchor(Job *j) {
         return false;
 }
 
-static bool types_match(JobType a, JobType b, JobType c, JobType d) {
-        return
-                (a == c && b == d) ||
-                (a == d && b == c);
-}
-
-int job_type_merge(JobType *a, JobType b) {
-        if (*a == b)
-                return 0;
-
-        /* Merging is associative! a merged with b merged with c is
-         * the same as a merged with c merged with b. */
-
-        /* Mergeability is transitive! if a can be merged with b and b
-         * with c then a also with c */
-
-        /* Also, if a merged with b cannot be merged with c, then
-         * either a or b cannot be merged with c either */
-
-        if (types_match(*a, b, JOB_START, JOB_VERIFY_ACTIVE))
-                *a = JOB_START;
-        else if (types_match(*a, b, JOB_START, JOB_RELOAD) ||
-                 types_match(*a, b, JOB_START, JOB_RELOAD_OR_START) ||
-                 types_match(*a, b, JOB_VERIFY_ACTIVE, JOB_RELOAD_OR_START) ||
-                 types_match(*a, b, JOB_RELOAD, JOB_RELOAD_OR_START))
-                *a = JOB_RELOAD_OR_START;
-        else if (types_match(*a, b, JOB_START, JOB_RESTART) ||
-                 types_match(*a, b, JOB_START, JOB_TRY_RESTART) ||
-                 types_match(*a, b, JOB_VERIFY_ACTIVE, JOB_RESTART) ||
-                 types_match(*a, b, JOB_RELOAD, JOB_RESTART) ||
-                 types_match(*a, b, JOB_RELOAD_OR_START, JOB_RESTART) ||
-                 types_match(*a, b, JOB_RELOAD_OR_START, JOB_TRY_RESTART) ||
-                 types_match(*a, b, JOB_RESTART, JOB_TRY_RESTART))
-                *a = JOB_RESTART;
-        else if (types_match(*a, b, JOB_VERIFY_ACTIVE, JOB_RELOAD))
-                *a = JOB_RELOAD;
-        else if (types_match(*a, b, JOB_VERIFY_ACTIVE, JOB_TRY_RESTART) ||
-                 types_match(*a, b, JOB_RELOAD, JOB_TRY_RESTART))
-                *a = JOB_TRY_RESTART;
-        else
-                return -EEXIST;
-
-        return 0;
-}
-
-bool job_type_is_mergeable(JobType a, JobType b) {
-        return job_type_merge(&a, b) >= 0;
-}
-
-bool job_type_is_superset(JobType a, JobType b) {
+/*
+ * Merging is commutative, so imagine the matrix as symmetric. We store only
+ * its lower triangle to avoid duplication. We don't store the main diagonal,
+ * because A merged with A is simply A.
+ *
+ * Merging is associative! A merged with B merged with C is the same as
+ * A merged with C merged with B.
+ *
+ * Mergeability is transitive! If A can be merged with B and B with C then
+ * A also with C.
+ *
+ * Also, if A merged with B cannot be merged with C, then either A or B cannot
+ * be merged with C either.
+ */
+static const JobType job_merging_table[] = {
+/* What \ With       *  JOB_START         JOB_VERIFY_ACTIVE  JOB_STOP JOB_RELOAD   JOB_RELOAD_OR_START  JOB_RESTART JOB_TRY_RESTART */
+/************************************************************************************************************************************/
+/*JOB_START          */
+/*JOB_VERIFY_ACTIVE  */ JOB_START,
+/*JOB_STOP           */ -1,                  -1,
+/*JOB_RELOAD         */ JOB_RELOAD_OR_START, JOB_RELOAD,          -1,
+/*JOB_RELOAD_OR_START*/ JOB_RELOAD_OR_START, JOB_RELOAD_OR_START, -1, JOB_RELOAD_OR_START,
+/*JOB_RESTART        */ JOB_RESTART,         JOB_RESTART,         -1, JOB_RESTART,         JOB_RESTART,
+/*JOB_TRY_RESTART    */ JOB_RESTART,         JOB_TRY_RESTART,     -1, JOB_TRY_RESTART,     JOB_RESTART, JOB_RESTART,
+};
 
-        /* Checks whether operation a is a "superset" of b in its
-         * actions */
+JobType job_type_lookup_merge(JobType a, JobType b) {
+        assert_cc(ELEMENTSOF(job_merging_table) == _JOB_TYPE_MAX * (_JOB_TYPE_MAX - 1) / 2);
+        assert(a >= 0 && a < _JOB_TYPE_MAX);
+        assert(b >= 0 && b < _JOB_TYPE_MAX);
 
         if (a == b)
-                return true;
-
-        switch (a) {
-                case JOB_START:
-                        return b == JOB_VERIFY_ACTIVE;
-
-                case JOB_RELOAD:
-                        return
-                                b == JOB_VERIFY_ACTIVE;
-
-                case JOB_RELOAD_OR_START:
-                        return
-                                b == JOB_RELOAD ||
-                                b == JOB_START ||
-                                b == JOB_VERIFY_ACTIVE;
-
-                case JOB_RESTART:
-                        return
-                                b == JOB_START ||
-                                b == JOB_VERIFY_ACTIVE ||
-                                b == JOB_RELOAD ||
-                                b == JOB_RELOAD_OR_START ||
-                                b == JOB_TRY_RESTART;
-
-                case JOB_TRY_RESTART:
-                        return
-                                b == JOB_VERIFY_ACTIVE ||
-                                b == JOB_RELOAD;
-                default:
-                        return false;
+                return a;
 
+        if (a < b) {
+                JobType tmp = a;
+                a = b;
+                b = tmp;
         }
-}
-
-bool job_type_is_conflicting(JobType a, JobType b) {
-        assert(a >= 0 && a < _JOB_TYPE_MAX);
-        assert(b >= 0 && b < _JOB_TYPE_MAX);
 
-        return (a == JOB_STOP) != (b == JOB_STOP);
+        return job_merging_table[(a - 1) * a / 2 + b];
 }
 
 bool job_type_is_redundant(JobType a, UnitActiveState b) {
@@ -326,19 +273,19 @@ bool job_is_runnable(Job *j) {
                  * dependencies, regardless whether they are
                  * starting or stopping something. */
 
-                SET_FOREACH(other, j->unit->meta.dependencies[UNIT_AFTER], i)
-                        if (other->meta.job)
+                SET_FOREACH(other, j->unit->dependencies[UNIT_AFTER], i)
+                        if (other->job)
                                 return false;
         }
 
         /* Also, if something else is being stopped and we should
          * change state after it, then lets wait. */
 
-        SET_FOREACH(other, j->unit->meta.dependencies[UNIT_BEFORE], i)
-                if (other->meta.job &&
-                    (other->meta.job->type == JOB_STOP ||
-                     other->meta.job->type == JOB_RESTART ||
-                     other->meta.job->type == JOB_TRY_RESTART))
+        SET_FOREACH(other, j->unit->dependencies[UNIT_BEFORE], i)
+                if (other->job &&
+                    (other->job->type == JOB_STOP ||
+                     other->job->type == JOB_RESTART ||
+                     other->job->type == JOB_TRY_RESTART))
                         return false;
 
         /* This means that for a service a and a service b where b
@@ -355,6 +302,14 @@ bool job_is_runnable(Job *j) {
         return true;
 }
 
+static void job_change_type(Job *j, JobType newtype) {
+        log_debug("Converting job %s/%s -> %s/%s",
+                  j->unit->id, job_type_to_string(j->type),
+                  j->unit->id, job_type_to_string(newtype));
+
+        j->type = newtype;
+}
+
 int job_run_and_invalidate(Job *j) {
         int r;
         uint32_t id;
@@ -387,14 +342,21 @@ int job_run_and_invalidate(Job *j) {
 
         switch (j->type) {
 
+                case JOB_RELOAD_OR_START:
+                        if (unit_active_state(j->unit) == UNIT_ACTIVE) {
+                                job_change_type(j, JOB_RELOAD);
+                                r = unit_reload(j->unit);
+                                break;
+                        }
+                        job_change_type(j, JOB_START);
+                        /* fall through */
+
                 case JOB_START:
                         r = unit_start(j->unit);
 
-                        /* If this unit cannot be started, then simply
-                         * wait */
+                        /* If this unit cannot be started, then simply wait */
                         if (r == -EBADR)
                                 r = 0;
-
                         break;
 
                 case JOB_VERIFY_ACTIVE: {
@@ -408,11 +370,19 @@ int job_run_and_invalidate(Job *j) {
                         break;
                 }
 
+                case JOB_TRY_RESTART:
+                        if (UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(j->unit))) {
+                                r = -ENOEXEC;
+                                break;
+                        }
+                        job_change_type(j, JOB_RESTART);
+                        /* fall through */
+
                 case JOB_STOP:
+                case JOB_RESTART:
                         r = unit_stop(j->unit);
 
-                        /* If this unit cannot stopped, then simply
-                         * wait. */
+                        /* If this unit cannot stopped, then simply wait. */
                         if (r == -EBADR)
                                 r = 0;
                         break;
@@ -421,43 +391,6 @@ int job_run_and_invalidate(Job *j) {
                         r = unit_reload(j->unit);
                         break;
 
-                case JOB_RELOAD_OR_START:
-                        if (unit_active_state(j->unit) == UNIT_ACTIVE) {
-                                j->type = JOB_RELOAD;
-                                r = unit_reload(j->unit);
-                        } else {
-                                j->type = JOB_START;
-                                r = unit_start(j->unit);
-
-                                if (r == -EBADR)
-                                        r = 0;
-                        }
-                        break;
-
-                case JOB_RESTART: {
-                        UnitActiveState t = unit_active_state(j->unit);
-                        if (t == UNIT_INACTIVE || t == UNIT_FAILED || t == UNIT_ACTIVATING) {
-                                j->type = JOB_START;
-                                r = unit_start(j->unit);
-                        } else
-                                r = unit_stop(j->unit);
-                        break;
-                }
-
-                case JOB_TRY_RESTART: {
-                        UnitActiveState t = unit_active_state(j->unit);
-                        if (t == UNIT_INACTIVE || t == UNIT_FAILED || t == UNIT_DEACTIVATING)
-                                r = -ENOEXEC;
-                        else if (t == UNIT_ACTIVATING) {
-                                j->type = JOB_START;
-                                r = unit_start(j->unit);
-                        } else {
-                                j->type = JOB_RESTART;
-                                r = unit_stop(j->unit);
-                        }
-                        break;
-                }
-
                 default:
                         assert_not_reached("Unknown job type");
         }
@@ -484,19 +417,20 @@ static void job_print_status_message(Unit *u, JobType t, JobResult result) {
                 switch (result) {
 
                 case JOB_DONE:
-                        unit_status_printf(u, "Started %s.\n", unit_description(u));
+                        unit_status_printf(u, ANSI_HIGHLIGHT_GREEN_ON "  OK  " ANSI_HIGHLIGHT_OFF, "Started %s", unit_description(u));
                         break;
 
                 case JOB_FAILED:
-                        unit_status_printf(u, "Starting %s " ANSI_HIGHLIGHT_ON "failed" ANSI_HIGHLIGHT_OFF ", see 'systemctl status %s' for details.\n", unit_description(u), u->meta.id);
+                        unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON "FAILED" ANSI_HIGHLIGHT_OFF, "Failed to start %s", unit_description(u));
+                        unit_status_printf(u, NULL, "See 'systemctl status %s' for details.", u->id);
                         break;
 
                 case JOB_DEPENDENCY:
-                        unit_status_printf(u, "Starting %s " ANSI_HIGHLIGHT_ON "aborted" ANSI_HIGHLIGHT_OFF " because a dependency failed.\n", unit_description(u));
+                        unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " ABORT" ANSI_HIGHLIGHT_OFF, "Dependency failed. Aborted start of %s", unit_description(u));
                         break;
 
                 case JOB_TIMEOUT:
-                        unit_status_printf(u, "Starting %s " ANSI_HIGHLIGHT_ON "timed out" ANSI_HIGHLIGHT_OFF ".\n", unit_description(u), u->meta.id);
+                        unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, "Timed out starting %s", unit_description(u));
                         break;
 
                 default:
@@ -508,12 +442,12 @@ static void job_print_status_message(Unit *u, JobType t, JobResult result) {
                 switch (result) {
 
                 case JOB_TIMEOUT:
-                        unit_status_printf(u, "Stopping %s " ANSI_HIGHLIGHT_ON "timed out" ANSI_HIGHLIGHT_OFF ".\n", unit_description(u), u->meta.id);
+                        unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, "Timed out stopping %s", unit_description(u));
                         break;
 
                 case JOB_DONE:
                 case JOB_FAILED:
-                        unit_status_printf(u, "Stopped %s.\n", unit_description(u));
+                        unit_status_printf(u, ANSI_HIGHLIGHT_GREEN_ON "  OK  " ANSI_HIGHLIGHT_OFF, "Stopped %s", unit_description(u));
                         break;
 
                 default:
@@ -535,14 +469,10 @@ int job_finish_and_invalidate(Job *j, JobResult result) {
         job_add_to_dbus_queue(j);
 
         /* Patch restart jobs so that they become normal start jobs */
-        if (result == JOB_DONE && (j->type == JOB_RESTART || j->type == JOB_TRY_RESTART)) {
-
-                log_debug("Converting job %s/%s -> %s/%s",
-                          j->unit->meta.id, job_type_to_string(j->type),
-                          j->unit->meta.id, job_type_to_string(JOB_START));
+        if (result == JOB_DONE && j->type == JOB_RESTART) {
 
+                job_change_type(j, JOB_START);
                 j->state = JOB_WAITING;
-                j->type = JOB_START;
 
                 job_add_to_run_queue(j);
 
@@ -552,7 +482,7 @@ int job_finish_and_invalidate(Job *j, JobResult result) {
 
         j->result = result;
 
-        log_debug("Job %s/%s finished, result=%s", j->unit->meta.id, job_type_to_string(j->type), job_result_to_string(result));
+        log_debug("Job %s/%s finished, result=%s", j->unit->id, job_type_to_string(j->type), job_result_to_string(result));
 
         if (result == JOB_FAILED)
                 j->manager->n_failed_jobs ++;
@@ -570,42 +500,42 @@ int job_finish_and_invalidate(Job *j, JobResult result) {
                     t == JOB_VERIFY_ACTIVE ||
                     t == JOB_RELOAD_OR_START) {
 
-                        SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRED_BY], i)
-                                if (other->meta.job &&
-                                    (other->meta.job->type == JOB_START ||
-                                     other->meta.job->type == JOB_VERIFY_ACTIVE ||
-                                     other->meta.job->type == JOB_RELOAD_OR_START)) {
-                                        job_finish_and_invalidate(other->meta.job, JOB_DEPENDENCY);
+                        SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY], i)
+                                if (other->job &&
+                                    (other->job->type == JOB_START ||
+                                     other->job->type == JOB_VERIFY_ACTIVE ||
+                                     other->job->type == JOB_RELOAD_OR_START)) {
+                                        job_finish_and_invalidate(other->job, JOB_DEPENDENCY);
                                         recursed = true;
                                 }
 
-                        SET_FOREACH(other, u->meta.dependencies[UNIT_BOUND_BY], i)
-                                if (other->meta.job &&
-                                    (other->meta.job->type == JOB_START ||
-                                     other->meta.job->type == JOB_VERIFY_ACTIVE ||
-                                     other->meta.job->type == JOB_RELOAD_OR_START)) {
-                                        job_finish_and_invalidate(other->meta.job, JOB_DEPENDENCY);
+                        SET_FOREACH(other, u->dependencies[UNIT_BOUND_BY], i)
+                                if (other->job &&
+                                    (other->job->type == JOB_START ||
+                                     other->job->type == JOB_VERIFY_ACTIVE ||
+                                     other->job->type == JOB_RELOAD_OR_START)) {
+                                        job_finish_and_invalidate(other->job, JOB_DEPENDENCY);
                                         recursed = true;
                                 }
 
-                        SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRED_BY_OVERRIDABLE], i)
-                                if (other->meta.job &&
-                                    !other->meta.job->override &&
-                                    (other->meta.job->type == JOB_START ||
-                                     other->meta.job->type == JOB_VERIFY_ACTIVE ||
-                                     other->meta.job->type == JOB_RELOAD_OR_START)) {
-                                        job_finish_and_invalidate(other->meta.job, JOB_DEPENDENCY);
+                        SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY_OVERRIDABLE], i)
+                                if (other->job &&
+                                    !other->job->override &&
+                                    (other->job->type == JOB_START ||
+                                     other->job->type == JOB_VERIFY_ACTIVE ||
+                                     other->job->type == JOB_RELOAD_OR_START)) {
+                                        job_finish_and_invalidate(other->job, JOB_DEPENDENCY);
                                         recursed = true;
                                 }
 
                 } else if (t == JOB_STOP) {
 
-                        SET_FOREACH(other, u->meta.dependencies[UNIT_CONFLICTED_BY], i)
-                                if (other->meta.job &&
-                                    (other->meta.job->type == JOB_START ||
-                                     other->meta.job->type == JOB_VERIFY_ACTIVE ||
-                                     other->meta.job->type == JOB_RELOAD_OR_START)) {
-                                        job_finish_and_invalidate(other->meta.job, JOB_DEPENDENCY);
+                        SET_FOREACH(other, u->dependencies[UNIT_CONFLICTED_BY], i)
+                                if (other->job &&
+                                    (other->job->type == JOB_START ||
+                                     other->job->type == JOB_VERIFY_ACTIVE ||
+                                     other->job->type == JOB_RELOAD_OR_START)) {
+                                        job_finish_and_invalidate(other->job, JOB_DEPENDENCY);
                                         recursed = true;
                                 }
                 }
@@ -617,7 +547,7 @@ int job_finish_and_invalidate(Job *j, JobResult result) {
          * unit itself. */
         if (result == JOB_TIMEOUT || result == JOB_DEPENDENCY) {
                 log_notice("Job %s/%s failed with result '%s'.",
-                           u->meta.id,
+                           u->id,
                            job_type_to_string(t),
                            job_result_to_string(result));
 
@@ -626,14 +556,14 @@ int job_finish_and_invalidate(Job *j, JobResult result) {
 
 finish:
         /* Try to start the next jobs that can be started */
-        SET_FOREACH(other, u->meta.dependencies[UNIT_AFTER], i)
-                if (other->meta.job)
-                        job_add_to_run_queue(other->meta.job);
-        SET_FOREACH(other, u->meta.dependencies[UNIT_BEFORE], i)
-                if (other->meta.job)
-                        job_add_to_run_queue(other->meta.job);
+        SET_FOREACH(other, u->dependencies[UNIT_AFTER], i)
+                if (other->job)
+                        job_add_to_run_queue(other->job);
+        SET_FOREACH(other, u->dependencies[UNIT_BEFORE], i)
+                if (other->job)
+                        job_add_to_run_queue(other->job);
 
-        manager_check_finished(u->meta.manager);
+        manager_check_finished(u->manager);
 
         return recursed;
 }
@@ -644,7 +574,7 @@ int job_start_timer(Job *j) {
         int fd, r;
         assert(j);
 
-        if (j->unit->meta.job_timeout <= 0 ||
+        if (j->unit->job_timeout <= 0 ||
             j->timer_watch.type == WATCH_JOB_TIMER)
                 return 0;
 
@@ -656,7 +586,7 @@ int job_start_timer(Job *j) {
         }
 
         zero(its);
-        timespec_store(&its.it_value, j->unit->meta.job_timeout);
+        timespec_store(&its.it_value, j->unit->job_timeout);
 
         if (timerfd_settime(fd, 0, &its, NULL) < 0) {
                 r = -errno;
@@ -726,7 +656,7 @@ void job_timer_event(Job *j, uint64_t n_elapsed, Watch *w) {
         assert(j);
         assert(w == &j->timer_watch);
 
-        log_warning("Job %s/%s timed out.", j->unit->meta.id, job_type_to_string(j->type));
+        log_warning("Job %s/%s timed out.", j->unit->id, job_type_to_string(j->type));
         job_finish_and_invalidate(j, JOB_TIMEOUT);
 }