+ if (name->meta.load_state != NAME_STUB)
+ return 0;
+
+ if ((r = verify_type(name)) < 0)
+ return r;
+
+ if (NAME_VTABLE(name)->init)
+ if ((r = NAME_VTABLE(name)->init(name)) < 0)
+ goto fail;
+
+ if ((r = name_sanitize(name)) < 0)
+ goto fail;
+
+ if ((r = name_link_names(name, false)) < 0)
+ goto fail;
+
+ name->meta.load_state = NAME_LOADED;
+ return 0;
+
+fail:
+ name->meta.load_state = NAME_FAILED;
+ return r;
+}
+
+/* Errors:
+ * -EBADR: This name type does not support starting.
+ * -EALREADY: Name is already started.
+ * -EAGAIN: An operation is already in progress. Retry later.
+ */
+int name_start(Name *n) {
+ NameActiveState state;
+
+ assert(n);
+
+ if (!NAME_VTABLE(n)->start)
+ return -EBADR;
+
+ state = name_active_state(n);
+ if (NAME_IS_ACTIVE_OR_RELOADING(state))
+ return -EALREADY;
+
+ /* We don't suppress calls to ->start() here when we are
+ * already starting, to allow this request to be used as a
+ * "hurry up" call, for example when the name is in some "auto
+ * restart" state where it waits for a holdoff timer to elapse
+ * before it will start again. */
+
+ return NAME_VTABLE(n)->start(n);
+}
+
+bool name_type_can_start(NameType t) {
+ assert(t >= 0 && t < _NAME_TYPE_MAX);
+
+ return !!name_vtable[t]->start;
+}
+
+/* Errors:
+ * -EBADR: This name type does not support stopping.
+ * -EALREADY: Name is already stopped.
+ * -EAGAIN: An operation is already in progress. Retry later.
+ */
+int name_stop(Name *n) {
+ NameActiveState state;
+
+ assert(n);
+
+ if (!NAME_VTABLE(n)->stop)
+ return -EBADR;
+
+ state = name_active_state(n);
+ if (state == NAME_INACTIVE)
+ return -EALREADY;
+
+ if (state == NAME_DEACTIVATING)
+ return 0;
+
+ return NAME_VTABLE(n)->stop(n);
+}
+
+/* Errors:
+ * -EBADR: This name type does not support reloading.
+ * -ENOEXEC: Name is not started.
+ * -EAGAIN: An operation is already in progress. Retry later.
+ */
+int name_reload(Name *n) {
+ NameActiveState state;
+
+ 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);
+