chiark / gitweb /
service: remove unneccesary Socket.got_socket_fd
[elogind.git] / src / core / unit.c
index 84c43f721a4869dc288f7fbba11bfc679df37706..31d5f113f7ea2ae7c7ea071cd6fe345c8342695c 100644 (file)
@@ -29,8 +29,8 @@
 #include <unistd.h>
 #include <sys/stat.h>
 
-#include "systemd/sd-id128.h"
-#include "systemd/sd-messages.h"
+#include "sd-id128.h"
+#include "sd-messages.h"
 #include "set.h"
 #include "unit.h"
 #include "macro.h"
@@ -48,6 +48,8 @@
 #include "label.h"
 #include "fileio-label.h"
 #include "bus-errors.h"
+#include "dbus.h"
+#include "execute.h"
 
 const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX] = {
         [UNIT_SERVICE] = &service_vtable,
@@ -85,6 +87,7 @@ Unit *unit_new(Manager *m, size_t size) {
         u->deserialized_job = _JOB_TYPE_INVALID;
         u->default_dependencies = true;
         u->unit_file_state = _UNIT_FILE_STATE_INVALID;
+        u->on_failure_job_mode = JOB_REPLACE;
 
         return u;
 }
@@ -326,7 +329,7 @@ void unit_add_to_dbus_queue(Unit *u) {
                 return;
 
         /* Shortcut things if nobody cares */
-        if (!bus_has_subscriber(u->manager)) {
+        if (set_isempty(u->manager->subscribed)) {
                 u->sent_dbus_new_signal = true;
                 return;
         }
@@ -715,6 +718,8 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
                 timestamp4[FORMAT_TIMESTAMP_MAX],
                 timespan[FORMAT_TIMESPAN_MAX];
         Unit *following;
+        _cleanup_set_free_ Set *following_set = NULL;
+        int r;
 
         assert(u);
         assert(u->type >= 0);
@@ -740,7 +745,8 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
                 "%s\tSlice: %s\n"
                 "%s\tCGroup: %s\n"
                 "%s\tCGroup realized: %s\n"
-                "%s\tCGroup mask: 0x%x\n",
+                "%s\tCGroup mask: 0x%x\n"
+                "%s\tCGroup members mask: 0x%x\n",
                 prefix, u->id,
                 prefix, unit_description(u),
                 prefix, strna(u->instance),
@@ -756,7 +762,8 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
                 prefix, strna(unit_slice_name(u)),
                 prefix, strna(u->cgroup_path),
                 prefix, yes_no(u->cgroup_realized),
-                prefix, u->cgroup_mask);
+                prefix, u->cgroup_mask,
+                prefix, u->cgroup_members_mask);
 
         SET_FOREACH(t, u->names, i)
                 fprintf(f, "%s\tName: %s\n", prefix, t);
@@ -764,9 +771,18 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
         STRV_FOREACH(j, u->documentation)
                 fprintf(f, "%s\tDocumentation: %s\n", prefix, *j);
 
-        if ((following = unit_following(u)))
+        following = unit_following(u);
+        if (following)
                 fprintf(f, "%s\tFollowing: %s\n", prefix, following->id);
 
+        r = unit_following_set(u, &following_set);
+        if (r >= 0) {
+                Unit *other;
+
+                SET_FOREACH(other, following_set, i)
+                        fprintf(f, "%s\tFollowing Set Member: %s\n", prefix, other->id);
+        }
+
         if (u->fragment_path)
                 fprintf(f, "%s\tFragment Path: %s\n", prefix, u->fragment_path);
 
@@ -812,14 +828,14 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
                         "%s\tRefuseManualStart: %s\n"
                         "%s\tRefuseManualStop: %s\n"
                         "%s\tDefaultDependencies: %s\n"
-                        "%s\tOnFailureIsolate: %s\n"
+                        "%s\tOnFailureJobMode: %s\n"
                         "%s\tIgnoreOnIsolate: %s\n"
                         "%s\tIgnoreOnSnapshot: %s\n",
                         prefix, yes_no(u->stop_when_unneeded),
                         prefix, yes_no(u->refuse_manual_start),
                         prefix, yes_no(u->refuse_manual_stop),
                         prefix, yes_no(u->default_dependencies),
-                        prefix, yes_no(u->on_failure_isolate),
+                        prefix, job_mode_to_string(u->on_failure_job_mode),
                         prefix, yes_no(u->ignore_on_isolate),
                         prefix, yes_no(u->ignore_on_snapshot));
 
@@ -1024,15 +1040,17 @@ int unit_load(Unit *u) {
                                 goto fail;
                 }
 
+                unit_update_member_masks(u);
+
                 r = unit_add_mount_links(u);
                 if (r < 0)
                         goto fail;
 
-                if (u->on_failure_isolate &&
+                if (u->on_failure_job_mode == JOB_ISOLATE &&
                     set_size(u->dependencies[UNIT_ON_FAILURE]) > 1) {
 
                         log_error_unit(u->id,
-                                       "More than one OnFailure= dependencies specified for %s but OnFailureIsolate= enabled. Refusing.", u->id);
+                                       "More than one OnFailure= dependencies specified for %s but OnFailureJobMode=isolate set. Refusing.", u->id);
 
                         r = -EINVAL;
                         goto fail;
@@ -1438,7 +1456,7 @@ void unit_start_on_failure(Unit *u) {
         SET_FOREACH(other, u->dependencies[UNIT_ON_FAILURE], i) {
                 int r;
 
-                r = manager_add_job(u->manager, JOB_START, other, u->on_failure_isolate ? JOB_ISOLATE : JOB_REPLACE, true, NULL, NULL);
+                r = manager_add_job(u->manager, JOB_START, other, u->on_failure_job_mode, true, NULL, NULL);
                 if (r < 0)
                         log_error_unit(u->id, "Failed to enqueue OnFailure= job: %s", strerror(-r));
         }
@@ -1490,6 +1508,9 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
         if (UNIT_IS_INACTIVE_OR_FAILED(ns))
                 unit_destroy_cgroup(u);
 
+        /* Note that this doesn't apply to RemainAfterExit services exiting
+         * sucessfully, since there's no change of state in that case. Which is
+         * why it is handled in service_set_state() */
         if (UNIT_IS_INACTIVE_OR_FAILED(os) != UNIT_IS_INACTIVE_OR_FAILED(ns)) {
                 ExecContext *ec = unit_get_exec_context(u);
                 if (ec && exec_context_may_touch_console(ec)) {
@@ -1655,46 +1676,6 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
         unit_add_to_gc_queue(u);
 }
 
-int unit_watch_fd(Unit *u, int fd, uint32_t events, Watch *w) {
-        struct epoll_event ev = {
-                .data.ptr = w,
-                .events = events,
-        };
-
-        assert(u);
-        assert(fd >= 0);
-        assert(w);
-        assert(w->type == WATCH_INVALID || (w->type == WATCH_FD && w->fd == fd && w->data.unit == u));
-
-        if (epoll_ctl(u->manager->epoll_fd,
-                      w->type == WATCH_INVALID ? EPOLL_CTL_ADD : EPOLL_CTL_MOD,
-                      fd,
-                      &ev) < 0)
-                return -errno;
-
-        w->fd = fd;
-        w->type = WATCH_FD;
-        w->data.unit = u;
-
-        return 0;
-}
-
-void unit_unwatch_fd(Unit *u, Watch *w) {
-        assert(u);
-        assert(w);
-
-        if (w->type == WATCH_INVALID)
-                return;
-
-        assert(w->type == WATCH_FD);
-        assert(w->data.unit == u);
-        assert_se(epoll_ctl(u->manager->epoll_fd, EPOLL_CTL_DEL, w->fd, NULL) >= 0);
-
-        w->fd = -1;
-        w->type = WATCH_INVALID;
-        w->data.unit = NULL;
-}
-
 int unit_watch_pid(Unit *u, pid_t pid) {
         assert(u);
         assert(pid >= 1);
@@ -1712,90 +1693,6 @@ void unit_unwatch_pid(Unit *u, pid_t pid) {
         hashmap_remove_value(u->manager->watch_pids, LONG_TO_PTR(pid), u);
 }
 
-int unit_watch_timer(Unit *u, clockid_t clock_id, bool relative, usec_t usec, Watch *w) {
-        struct itimerspec its = {};
-        int flags, fd;
-        bool ours;
-
-        assert(u);
-        assert(w);
-        assert(w->type == WATCH_INVALID || (w->type == WATCH_UNIT_TIMER && w->data.unit == u));
-
-        /* This will try to reuse the old timer if there is one */
-
-        if (w->type == WATCH_UNIT_TIMER) {
-                assert(w->data.unit == u);
-                assert(w->fd >= 0);
-
-                ours = false;
-                fd = w->fd;
-        } else if (w->type == WATCH_INVALID) {
-
-                ours = true;
-                fd = timerfd_create(clock_id, TFD_NONBLOCK|TFD_CLOEXEC);
-                if (fd < 0)
-                        return -errno;
-        } else
-                assert_not_reached("Invalid watch type");
-
-        if (usec <= 0) {
-                /* Set absolute time in the past, but not 0, since we
-                 * don't want to disarm the timer */
-                its.it_value.tv_sec = 0;
-                its.it_value.tv_nsec = 1;
-
-                flags = TFD_TIMER_ABSTIME;
-        } else {
-                timespec_store(&its.it_value, usec);
-                flags = relative ? 0 : TFD_TIMER_ABSTIME;
-        }
-
-        /* This will also flush the elapse counter */
-        if (timerfd_settime(fd, flags, &its, NULL) < 0)
-                goto fail;
-
-        if (w->type == WATCH_INVALID) {
-                struct epoll_event ev = {
-                        .data.ptr = w,
-                        .events = EPOLLIN,
-                };
-
-                if (epoll_ctl(u->manager->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0)
-                        goto fail;
-        }
-
-        w->type = WATCH_UNIT_TIMER;
-        w->fd = fd;
-        w->data.unit = u;
-
-        return 0;
-
-fail:
-        if (ours)
-                close_nointr_nofail(fd);
-
-        return -errno;
-}
-
-void unit_unwatch_timer(Unit *u, Watch *w) {
-        assert(u);
-        assert(w);
-
-        if (w->type == WATCH_INVALID)
-                return;
-
-        assert(w->type == WATCH_UNIT_TIMER);
-        assert(w->data.unit == u);
-        assert(w->fd >= 0);
-
-        assert_se(epoll_ctl(u->manager->epoll_fd, EPOLL_CTL_DEL, w->fd, NULL) >= 0);
-        close_nointr_nofail(w->fd);
-
-        w->fd = -1;
-        w->type = WATCH_INVALID;
-        w->data.unit = NULL;
-}
-
 bool unit_job_is_applicable(Unit *u, JobType j) {
         assert(u);
         assert(j >= 0 && j < _JOB_TYPE_MAX);
@@ -1849,6 +1746,7 @@ int unit_add_dependency(Unit *u, UnitDependency d, Unit *other, bool add_referen
                 [UNIT_TRIGGERED_BY] = UNIT_TRIGGERS,
                 [UNIT_PROPAGATES_RELOAD_TO] = UNIT_RELOAD_PROPAGATED_FROM,
                 [UNIT_RELOAD_PROPAGATED_FROM] = UNIT_PROPAGATES_RELOAD_TO,
+                [UNIT_JOINS_NAMESPACE_OF] = UNIT_JOINS_NAMESPACE_OF,
         };
         int r, q = 0, v = 0, w = 0;
 
@@ -1864,34 +1762,47 @@ int unit_add_dependency(Unit *u, UnitDependency d, Unit *other, bool add_referen
         if (u == other)
                 return 0;
 
-        if ((r = set_ensure_allocated(&u->dependencies[d], trivial_hash_func, trivial_compare_func)) < 0)
+        r = set_ensure_allocated(&u->dependencies[d], trivial_hash_func, trivial_compare_func);
+        if (r < 0)
                 return r;
 
-        if (inverse_table[d] != _UNIT_DEPENDENCY_INVALID)
-                if ((r = set_ensure_allocated(&other->dependencies[inverse_table[d]], trivial_hash_func, trivial_compare_func)) < 0)
+        if (inverse_table[d] != _UNIT_DEPENDENCY_INVALID) {
+                r = set_ensure_allocated(&other->dependencies[inverse_table[d]], trivial_hash_func, trivial_compare_func);
+                if (r < 0)
+                        return r;
+        }
+
+        if (add_reference) {
+                r = set_ensure_allocated(&u->dependencies[UNIT_REFERENCES], trivial_hash_func, trivial_compare_func);
+                if (r < 0)
                         return r;
 
-        if (add_reference)
-                if ((r = set_ensure_allocated(&u->dependencies[UNIT_REFERENCES], trivial_hash_func, trivial_compare_func)) < 0 ||
-                    (r = set_ensure_allocated(&other->dependencies[UNIT_REFERENCED_BY], trivial_hash_func, trivial_compare_func)) < 0)
+                r = set_ensure_allocated(&other->dependencies[UNIT_REFERENCED_BY], trivial_hash_func, trivial_compare_func);
+                if (r < 0)
                         return r;
+        }
 
-        if ((q = set_put(u->dependencies[d], other)) < 0)
+        q = set_put(u->dependencies[d], other);
+        if (q < 0)
                 return q;
 
-        if (inverse_table[d] != _UNIT_DEPENDENCY_INVALID)
-                if ((v = set_put(other->dependencies[inverse_table[d]], u)) < 0) {
+        if (inverse_table[d] != _UNIT_DEPENDENCY_INVALID && inverse_table[d] != d) {
+                v = set_put(other->dependencies[inverse_table[d]], u);
+                if (v < 0) {
                         r = v;
                         goto fail;
                 }
+        }
 
         if (add_reference) {
-                if ((w = set_put(u->dependencies[UNIT_REFERENCES], other)) < 0) {
+                w = set_put(u->dependencies[UNIT_REFERENCES], other);
+                if (w < 0) {
                         r = w;
                         goto fail;
                 }
 
-                if ((r = set_put(other->dependencies[UNIT_REFERENCED_BY], u)) < 0)
+                r = set_put(other->dependencies[UNIT_REFERENCED_BY], u);
+                if (r < 0)
                         goto fail;
         }
 
@@ -2186,6 +2097,7 @@ bool unit_can_serialize(Unit *u) {
 }
 
 int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
+        ExecRuntime *rt;
         int r;
 
         assert(u);
@@ -2199,17 +2111,11 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
         if (r < 0)
                 return r;
 
-
-        if (serialize_jobs) {
-                if (u->job) {
-                        fprintf(f, "job\n");
-                        job_serialize(u->job, f, fds);
-                }
-
-                if (u->nop_job) {
-                        fprintf(f, "job\n");
-                        job_serialize(u->nop_job, f, fds);
-                }
+        rt = unit_get_exec_runtime(u);
+        if (rt) {
+                r = exec_runtime_serialize(rt, u, f, fds);
+                if (r < 0)
+                        return r;
         }
 
         dual_timestamp_serialize(f, "inactive-exit-timestamp", &u->inactive_exit_timestamp);
@@ -2226,6 +2132,18 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
         if (u->cgroup_path)
                 unit_serialize_item(u, f, "cgroup", u->cgroup_path);
 
+        if (serialize_jobs) {
+                if (u->job) {
+                        fprintf(f, "job\n");
+                        job_serialize(u->job, f, fds);
+                }
+
+                if (u->nop_job) {
+                        fprintf(f, "job\n");
+                        job_serialize(u->nop_job, f, fds);
+                }
+        }
+
         /* End marker */
         fputc('\n', f);
         return 0;
@@ -2259,6 +2177,8 @@ void unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value) {
 }
 
 int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
+        size_t offset;
+        ExecRuntime **rt = NULL;
         int r;
 
         assert(u);
@@ -2268,6 +2188,10 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
         if (!unit_can_serialize(u))
                 return 0;
 
+        offset = UNIT_VTABLE(u)->exec_runtime_offset;
+        if (offset > 0)
+                rt = (ExecRuntime**) ((uint8_t*) u + offset);
+
         for (;;) {
                 char line[LINE_MAX], *l, *v;
                 size_t k;
@@ -2380,6 +2304,14 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
                         continue;
                 }
 
+                if (rt) {
+                        r = exec_runtime_deserialize_item(rt, u, l, v, fds);
+                        if (r < 0)
+                                return r;
+                        if (r > 0)
+                                continue;
+                }
+
                 r = UNIT_VTABLE(u)->deserialize_item(u, l, v, fds);
                 if (r < 0)
                         return r;
@@ -2569,7 +2501,7 @@ bool unit_active_or_pending(Unit *u) {
         return false;
 }
 
-int unit_kill(Unit *u, KillWho w, int signo, DBusError *error) {
+int unit_kill(Unit *u, KillWho w, int signo, sd_bus_error *error) {
         assert(u);
         assert(w >= 0 && w < _KILL_WHO_MAX);
         assert(signo > 0);
@@ -2615,23 +2547,23 @@ int unit_kill_common(
                 int signo,
                 pid_t main_pid,
                 pid_t control_pid,
-                DBusError *error) {
+                sd_bus_error *error) {
 
         int r = 0;
 
         if (who == KILL_MAIN && main_pid <= 0) {
                 if (main_pid < 0)
-                        dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "%s units have no main processes", unit_type_to_string(u->type));
+                        sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_PROCESS, "%s units have no main processes", unit_type_to_string(u->type));
                 else
-                        dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "No main process to kill");
+                        sd_bus_error_set_const(error, BUS_ERROR_NO_SUCH_PROCESS, "No main process to kill");
                 return -ESRCH;
         }
 
         if (who == KILL_CONTROL && control_pid <= 0) {
                 if (control_pid < 0)
-                        dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "%s units have no control processes", unit_type_to_string(u->type));
+                        sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_PROCESS, "%s units have no control processes", unit_type_to_string(u->type));
                 else
-                        dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "No control process to kill");
+                        sd_bus_error_set_const(error, BUS_ERROR_NO_SUCH_PROCESS, "No control process to kill");
                 return -ESRCH;
         }
 
@@ -2743,6 +2675,17 @@ ExecContext *unit_get_exec_context(Unit *u) {
         return (ExecContext*) ((uint8_t*) u + offset);
 }
 
+KillContext *unit_get_kill_context(Unit *u) {
+        size_t offset;
+        assert(u);
+
+        offset = UNIT_VTABLE(u)->kill_context_offset;
+        if (offset <= 0)
+                return NULL;
+
+        return (KillContext*) ((uint8_t*) u + offset);
+}
+
 CGroupContext *unit_get_cgroup_context(Unit *u) {
         size_t offset;
 
@@ -2753,6 +2696,16 @@ CGroupContext *unit_get_cgroup_context(Unit *u) {
         return (CGroupContext*) ((uint8_t*) u + offset);
 }
 
+ExecRuntime *unit_get_exec_runtime(Unit *u) {
+        size_t offset;
+
+        offset = UNIT_VTABLE(u)->exec_runtime_offset;
+        if (offset <= 0)
+                return NULL;
+
+        return *(ExecRuntime**) ((uint8_t*) u + offset);
+}
+
 static int drop_in_file(Unit *u, UnitSetPropertiesMode mode, const char *name, char **_p, char **_q) {
         _cleanup_free_ char *b = NULL;
         char *p, *q;
@@ -3103,6 +3056,33 @@ int unit_require_mounts_for(Unit *u, const char *path) {
         return 0;
 }
 
+int unit_setup_exec_runtime(Unit *u) {
+        ExecRuntime **rt;
+        size_t offset;
+        Iterator i;
+        Unit *other;
+
+        offset = UNIT_VTABLE(u)->exec_runtime_offset;
+        assert(offset > 0);
+
+        /* Check if ther already is an ExecRuntime for this unit? */
+        rt = (ExecRuntime**) ((uint8_t*) u + offset);
+        if (*rt)
+                return 0;
+
+        /* Try to get it from somebody else */
+        SET_FOREACH(other, u->dependencies[UNIT_JOINS_NAMESPACE_OF], i) {
+
+                *rt = unit_get_exec_runtime(other);
+                if (*rt) {
+                        exec_runtime_ref(*rt);
+                        return 0;
+                }
+        }
+
+        return exec_runtime_make(rt, unit_get_exec_context(u), u->id);
+}
+
 static const char* const unit_active_state_table[_UNIT_ACTIVE_STATE_MAX] = {
         [UNIT_ACTIVE] = "active",
         [UNIT_RELOADING] = "reloading",
@@ -3138,6 +3118,7 @@ static const char* const unit_dependency_table[_UNIT_DEPENDENCY_MAX] = {
         [UNIT_RELOAD_PROPAGATED_FROM] = "ReloadPropagatedFrom",
         [UNIT_REFERENCES] = "References",
         [UNIT_REFERENCED_BY] = "ReferencedBy",
+        [UNIT_JOINS_NAMESPACE_OF] = "JoinsNamespaceOf",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(unit_dependency, UnitDependency);