+ assert(n);
+
+ if (!name_can_reload(n))
+ return -EBADR;
+
+ state = name_active_state(n);
+ if (name_active_state(n) == NAME_ACTIVE_RELOADING)
+ return -EALREADY;
+
+ if (name_active_state(n) != NAME_ACTIVE)
+ return -ENOEXEC;
+
+ return NAME_VTABLE(n)->reload(n);
+}
+
+bool name_type_can_reload(NameType t) {
+ assert(t >= 0 && t < _NAME_TYPE_MAX);
+
+ return !!name_vtable[t]->reload;
+}
+
+bool name_can_reload(Name *n) {
+ assert(n);
+
+ if (!name_type_can_reload(n->meta.type))
+ return false;
+
+ if (!NAME_VTABLE(n)->can_reload)
+ return true;
+
+ return NAME_VTABLE(n)->can_reload(n);
+}
+
+static void retroactively_start_dependencies(Name *n) {
+ Iterator i;
+ Name *other;
+
+ assert(n);
+ assert(NAME_IS_ACTIVE_OR_ACTIVATING(name_active_state(n)));
+
+ SET_FOREACH(other, n->meta.dependencies[NAME_REQUIRES], i)
+ if (!NAME_IS_ACTIVE_OR_ACTIVATING(name_active_state(other)))
+ manager_add_job(n->meta.manager, JOB_START, other, JOB_REPLACE, true, NULL);
+
+ SET_FOREACH(other, n->meta.dependencies[NAME_SOFT_REQUIRES], i)
+ if (!NAME_IS_ACTIVE_OR_ACTIVATING(name_active_state(other)))
+ manager_add_job(n->meta.manager, JOB_START, other, JOB_FAIL, false, NULL);
+
+ SET_FOREACH(other, n->meta.dependencies[NAME_REQUISITE], i)
+ if (!NAME_IS_ACTIVE_OR_ACTIVATING(name_active_state(other)))
+ manager_add_job(n->meta.manager, JOB_START, other, JOB_REPLACE, true, NULL);
+
+ SET_FOREACH(other, n->meta.dependencies[NAME_WANTS], i)
+ if (!NAME_IS_ACTIVE_OR_ACTIVATING(name_active_state(other)))
+ manager_add_job(n->meta.manager, JOB_START, other, JOB_FAIL, false, NULL);
+
+ SET_FOREACH(other, n->meta.dependencies[NAME_CONFLICTS], i)
+ if (!NAME_IS_ACTIVE_OR_ACTIVATING(name_active_state(other)))
+ manager_add_job(n->meta.manager, JOB_STOP, other, JOB_REPLACE, true, NULL);
+}
+
+static void retroactively_stop_dependencies(Name *n) {
+ Iterator i;
+ Name *other;
+
+ assert(n);
+ assert(NAME_IS_INACTIVE_OR_DEACTIVATING(name_active_state(n)));
+
+ SET_FOREACH(other, n->meta.dependencies[NAME_REQUIRED_BY], i)
+ if (!NAME_IS_INACTIVE_OR_DEACTIVATING(name_active_state(other)))
+ manager_add_job(n->meta.manager, JOB_STOP, other, JOB_REPLACE, true, NULL);
+}
+
+void name_notify(Name *n, NameActiveState os, NameActiveState ns) {
+ assert(n);
+ assert(os < _NAME_ACTIVE_STATE_MAX);
+ assert(ns < _NAME_ACTIVE_STATE_MAX);
+ assert(!(os == NAME_ACTIVE && ns == NAME_ACTIVATING));
+ assert(!(os == NAME_INACTIVE && ns == NAME_DEACTIVATING));
+
+ if (os == ns)
+ return;
+
+ if (!NAME_IS_ACTIVE_OR_RELOADING(os) && NAME_IS_ACTIVE_OR_RELOADING(ns))
+ n->meta.active_enter_timestamp = now(CLOCK_REALTIME);
+ else if (NAME_IS_ACTIVE_OR_RELOADING(os) && !NAME_IS_ACTIVE_OR_RELOADING(ns))
+ n->meta.active_exit_timestamp = now(CLOCK_REALTIME);
+
+ if (n->meta.job) {
+
+ if (n->meta.job->state == JOB_WAITING)
+
+ /* So we reached a different state for this
+ * job. Let's see if we can run it now if it
+ * failed previously due to EAGAIN. */
+ job_schedule_run(n->meta.job);
+
+ else {
+ assert(n->meta.job->state == JOB_RUNNING);
+
+ /* Let's check of this state change
+ * constitutes a finished job, or maybe
+ * cotradicts a running job and hence needs to
+ * invalidate jobs. */
+
+ switch (n->meta.job->type) {
+
+ case JOB_START:
+ case JOB_VERIFY_ACTIVE:
+
+ if (NAME_IS_ACTIVE_OR_RELOADING(ns)) {
+ job_finish_and_invalidate(n->meta.job, true);
+ return;
+ } else if (ns == NAME_ACTIVATING)
+ return;
+ else
+ job_finish_and_invalidate(n->meta.job, false);
+
+ break;
+
+ case JOB_RELOAD:
+ case JOB_RELOAD_OR_START:
+
+ if (ns == NAME_ACTIVE) {
+ job_finish_and_invalidate(n->meta.job, true);
+ return;
+ } else if (ns == NAME_ACTIVATING || ns == NAME_ACTIVE_RELOADING)
+ return;
+ else
+ job_finish_and_invalidate(n->meta.job, false);
+
+ break;
+
+ case JOB_STOP:
+ case JOB_RESTART:
+ case JOB_TRY_RESTART:
+
+ if (ns == NAME_INACTIVE) {
+ job_finish_and_invalidate(n->meta.job, true);
+ return;
+ } else if (ns == NAME_DEACTIVATING)
+ return;
+ else
+ job_finish_and_invalidate(n->meta.job, false);
+
+ break;
+
+ default:
+ assert_not_reached("Job type unknown");
+ }
+ }
+ }
+
+ /* If this state change happened without being requested by a
+ * job, then let's retroactively start or stop dependencies */
+
+ if (NAME_IS_INACTIVE_OR_DEACTIVATING(os) && NAME_IS_ACTIVE_OR_ACTIVATING(ns))
+ retroactively_start_dependencies(n);
+ else if (NAME_IS_ACTIVE_OR_ACTIVATING(os) && NAME_IS_INACTIVE_OR_DEACTIVATING(ns))
+ retroactively_stop_dependencies(n);
+}
+
+int name_watch_fd(Name *n, int fd, uint32_t events) {
+ struct epoll_event ev;
+
+ assert(n);
+ assert(fd >= 0);
+
+ zero(ev);
+ ev.data.fd = fd;
+ ev.data.ptr = n;
+ ev.data.u32 = MANAGER_FD;
+ ev.events = events;