diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/dbus-job.c | 52 | ||||
| -rw-r--r-- | src/core/dbus-job.h | 1 | ||||
| -rw-r--r-- | src/core/dbus-manager.c | 22 | ||||
| -rw-r--r-- | src/core/job.c | 127 | ||||
| -rw-r--r-- | src/core/job.h | 3 | ||||
| -rw-r--r-- | src/core/org.freedesktop.systemd1.conf | 16 | 
6 files changed, 221 insertions, 0 deletions
| diff --git a/src/core/dbus-job.c b/src/core/dbus-job.c index 7888c163f1..087a08dc0d 100644 --- a/src/core/dbus-job.c +++ b/src/core/dbus-job.c @@ -80,9 +80,61 @@ int bus_job_method_cancel(sd_bus_message *message, void *userdata, sd_bus_error          return sd_bus_reply_method_return(message, NULL);  } +int bus_job_method_get_waiting_jobs(sd_bus_message *message, void *userdata, sd_bus_error *error) { +        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; +        _cleanup_free_ Job **list = NULL; +        Job *j = userdata; +        int r, i, n; + +        if (strstr(sd_bus_message_get_member(message), "After")) +                n = job_get_after(j, &list); +        else +                n = job_get_before(j, &list); +        if (n < 0) +                return n; + +        r = sd_bus_message_new_method_return(message, &reply); +        if (r < 0) +                return r; + +        r = sd_bus_message_open_container(reply, 'a', "(usssoo)"); +        if (r < 0) +                return r; + +        for (i = 0; i < n; i ++) { +                _cleanup_free_ char *unit_path = NULL, *job_path = NULL; + +                job_path = job_dbus_path(list[i]); +                if (!job_path) +                        return -ENOMEM; + +                unit_path = unit_dbus_path(list[i]->unit); +                if (!unit_path) +                        return -ENOMEM; + +                r = sd_bus_message_append(reply, "(usssoo)", +                                          list[i]->id, +                                          list[i]->unit->id, +                                          job_type_to_string(list[i]->type), +                                          job_state_to_string(list[i]->state), +                                          job_path, +                                          unit_path); +                if (r < 0) +                        return r; +        } + +        r = sd_bus_message_close_container(reply); +        if (r < 0) +                return r; + +        return sd_bus_send(NULL, reply, NULL); +} +  const sd_bus_vtable bus_job_vtable[] = {          SD_BUS_VTABLE_START(0),          SD_BUS_METHOD("Cancel", NULL, NULL, bus_job_method_cancel, SD_BUS_VTABLE_UNPRIVILEGED), +        SD_BUS_METHOD("GetAfter", NULL, "a(usssoo)", bus_job_method_get_waiting_jobs, SD_BUS_VTABLE_UNPRIVILEGED), +        SD_BUS_METHOD("GetBefore", NULL, "a(usssoo)", bus_job_method_get_waiting_jobs, SD_BUS_VTABLE_UNPRIVILEGED),          SD_BUS_PROPERTY("Id", "u", NULL, offsetof(Job, id), SD_BUS_VTABLE_PROPERTY_CONST),          SD_BUS_PROPERTY("Unit", "(so)", property_get_unit, 0, SD_BUS_VTABLE_PROPERTY_CONST),          SD_BUS_PROPERTY("JobType", "s", property_get_type, offsetof(Job, type), SD_BUS_VTABLE_PROPERTY_CONST), diff --git a/src/core/dbus-job.h b/src/core/dbus-job.h index f9148895be..a4366a0720 100644 --- a/src/core/dbus-job.h +++ b/src/core/dbus-job.h @@ -26,6 +26,7 @@  extern const sd_bus_vtable bus_job_vtable[];  int bus_job_method_cancel(sd_bus_message *message, void *job, sd_bus_error *error); +int bus_job_method_get_waiting_jobs(sd_bus_message *message, void *userdata, sd_bus_error *error);  void bus_job_send_change_signal(Job *j);  void bus_job_send_removed_signal(Job *j); diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index 5a7922a249..9af49dd1bc 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -2285,6 +2285,26 @@ static int method_get_unit_file_links(sd_bus_message *message, void *userdata, s          return sd_bus_send(NULL, reply, NULL);  } +static int method_get_job_waiting(sd_bus_message *message, void *userdata, sd_bus_error *error) { +        Manager *m = userdata; +        uint32_t id; +        Job *j; +        int r; + +        assert(message); +        assert(m); + +        r = sd_bus_message_read(message, "u", &id); +        if (r < 0) +                return r; + +        j = manager_get_job(m, id); +        if (!j) +                return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id); + +        return bus_job_method_get_waiting_jobs(message, j, error); +} +  const sd_bus_vtable bus_manager_vtable[] = {          SD_BUS_VTABLE_START(0), @@ -2390,6 +2410,8 @@ const sd_bus_vtable bus_manager_vtable[] = {          SD_BUS_METHOD("StartTransientUnit", "ssa(sv)a(sa(sv))", "o", method_start_transient_unit, SD_BUS_VTABLE_UNPRIVILEGED),          SD_BUS_METHOD("GetUnitProcesses", "s", "a(sus)", method_get_unit_processes, SD_BUS_VTABLE_UNPRIVILEGED),          SD_BUS_METHOD("GetJob", "u", "o", method_get_job, SD_BUS_VTABLE_UNPRIVILEGED), +        SD_BUS_METHOD("GetJobAfter", "u", "a(usssoo)", method_get_job_waiting, SD_BUS_VTABLE_UNPRIVILEGED), +        SD_BUS_METHOD("GetJobBefore", "u", "a(usssoo)", method_get_job_waiting, SD_BUS_VTABLE_UNPRIVILEGED),          SD_BUS_METHOD("CancelJob", "u", NULL, method_cancel_job, SD_BUS_VTABLE_UNPRIVILEGED),          SD_BUS_METHOD("ClearJobs", NULL, NULL, method_clear_jobs, SD_BUS_VTABLE_UNPRIVILEGED),          SD_BUS_METHOD("ResetFailed", NULL, NULL, method_reset_failed, SD_BUS_VTABLE_UNPRIVILEGED), diff --git a/src/core/job.c b/src/core/job.c index d6e71d68ef..2ba4c78096 100644 --- a/src/core/job.c +++ b/src/core/job.c @@ -1306,6 +1306,133 @@ void job_add_to_gc_queue(Job *j) {          j->in_gc_queue = true;  } +static int job_compare(const void *a, const void *b) { +        Job *x = *(Job**) a, *y = *(Job**) b; + +        if (x->id < y->id) +                return -1; +        if (x->id > y->id) +                return 1; + +        return 0; +} + +static size_t sort_job_list(Job **list, size_t n) { +        Job *previous = NULL; +        size_t a, b; + +        /* Order by numeric IDs */ +        qsort_safe(list, n, sizeof(Job*), job_compare); + +        /* Filter out duplicates */ +        for (a = 0, b = 0; a < n; a++) { + +                if (previous == list[a]) +                        continue; + +                previous = list[b++] = list[a]; +        } + +        return b; +} + +int job_get_before(Job *j, Job*** ret) { +        _cleanup_free_ Job** list = NULL; +        size_t n = 0, n_allocated = 0; +        Unit *other = NULL; +        Iterator i; + +        /* Returns a list of all pending jobs that need to finish before this job may be started. */ + +        assert(j); +        assert(ret); + +        if (j->ignore_order) { +                *ret = NULL; +                return 0; +        } + +        if (IN_SET(j->type, JOB_START, JOB_VERIFY_ACTIVE, JOB_RELOAD)) { + +                SET_FOREACH(other, j->unit->dependencies[UNIT_AFTER], i) { +                        if (!other->job) +                                continue; + +                        if (!GREEDY_REALLOC(list, n_allocated, n+1)) +                                return -ENOMEM; +                        list[n++] = other->job; +                } +        } + +        SET_FOREACH(other, j->unit->dependencies[UNIT_BEFORE], i) { +                if (!other->job) +                        continue; + +                if (!IN_SET(other->job->type, JOB_STOP, JOB_RESTART)) +                        continue; + +                if (!GREEDY_REALLOC(list, n_allocated, n+1)) +                        return -ENOMEM; +                list[n++] = other->job; +        } + +        n = sort_job_list(list, n); + +        *ret = list; +        list = NULL; + +        return (int) n; +} + +int job_get_after(Job *j, Job*** ret) { +        _cleanup_free_ Job** list = NULL; +        size_t n = 0, n_allocated = 0; +        Unit *other = NULL; +        Iterator i; + +        assert(j); +        assert(ret); + +        /* Returns a list of all pending jobs that are waiting for this job to finish. */ + +        SET_FOREACH(other, j->unit->dependencies[UNIT_BEFORE], i) { +                if (!other->job) +                        continue; + +                if (other->job->ignore_order) +                        continue; + +                if (!IN_SET(other->job->type, JOB_START, JOB_VERIFY_ACTIVE, JOB_RELOAD)) +                        continue; + +                if (!GREEDY_REALLOC(list, n_allocated, n+1)) +                        return -ENOMEM; +                list[n++] = other->job; +        } + +        if (IN_SET(j->type, JOB_STOP, JOB_RESTART)) { + +                SET_FOREACH(other, j->unit->dependencies[UNIT_AFTER], i) { +                        if (!other->job) +                                continue; + +                        if (other->job->ignore_order) +                                continue; + +                        if (!GREEDY_REALLOC(list, n_allocated, n+1)) +                                return -ENOMEM; +                        list[n++] = other->job; +                } +        } + +        n = sort_job_list(list, n); + +        *ret = list; +        list = NULL; + +        return (int) n; +} +  static const char* const job_state_table[_JOB_STATE_MAX] = {          [JOB_WAITING] = "waiting",          [JOB_RUNNING] = "running", diff --git a/src/core/job.h b/src/core/job.h index 6fdec9f226..bea743f462 100644 --- a/src/core/job.h +++ b/src/core/job.h @@ -234,6 +234,9 @@ int job_get_timeout(Job *j, usec_t *timeout) _pure_;  bool job_check_gc(Job *j);  void job_add_to_gc_queue(Job *j); +int job_get_before(Job *j, Job*** ret); +int job_get_after(Job *j, Job*** ret); +  const char* job_type_to_string(JobType t) _const_;  JobType job_type_from_string(const char *s) _pure_; diff --git a/src/core/org.freedesktop.systemd1.conf b/src/core/org.freedesktop.systemd1.conf index a61677e645..e824a2233c 100644 --- a/src/core/org.freedesktop.systemd1.conf +++ b/src/core/org.freedesktop.systemd1.conf @@ -66,6 +66,14 @@                  <allow send_destination="org.freedesktop.systemd1"                         send_interface="org.freedesktop.systemd1.Manager" +                       send_member="GetJobAfter"/> + +                <allow send_destination="org.freedesktop.systemd1" +                       send_interface="org.freedesktop.systemd1.Manager" +                       send_member="GetJobBefore"/> + +                <allow send_destination="org.freedesktop.systemd1" +                       send_interface="org.freedesktop.systemd1.Manager"                         send_member="ListUnits"/>                  <allow send_destination="org.freedesktop.systemd1" @@ -250,6 +258,14 @@                         send_interface="org.freedesktop.systemd1.Job"                         send_member="Cancel"/> +                <allow send_destination="org.freedesktop.systemd1" +                       send_interface="org.freedesktop.systemd1.Job" +                       send_member="GetAfter"/> + +                <allow send_destination="org.freedesktop.systemd1" +                       send_interface="org.freedesktop.systemd1.Job" +                       send_member="GetBefore"/> +                  <allow receive_sender="org.freedesktop.systemd1"/>          </policy> | 
