+}
+
+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;
+
+ if (epoll_ctl(n->meta.manager->epoll_fd, EPOLL_CTL_ADD, fd, &ev) >= 0)
+ return 0;
+
+ if (errno == EEXIST)
+ if (epoll_ctl(n->meta.manager->epoll_fd, EPOLL_CTL_MOD, fd, &ev) >= 0)
+ return 0;
+
+ return -errno;
+}
+
+void name_unwatch_fd(Name *n, int fd) {
+ assert(n);
+ assert(fd >= 0);
+
+ assert_se(epoll_ctl(n->meta.manager->epoll_fd, EPOLL_CTL_DEL, fd, NULL) >= 0 || errno == ENOENT);
+}
+
+int name_watch_pid(Name *n, pid_t pid) {
+ assert(n);
+ assert(pid >= 1);
+
+ return hashmap_put(n->meta.manager->watch_pids, UINT32_TO_PTR(pid), n);
+}
+
+void name_unwatch_pid(Name *n, pid_t pid) {
+ assert(n);
+ assert(pid >= 1);
+
+ hashmap_remove(n->meta.manager->watch_pids, UINT32_TO_PTR(pid));
+}
+
+int name_watch_timer(Name *n, usec_t delay, int *id) {
+ struct epoll_event ev;
+ int fd;
+ struct itimerspec its;
+ int flags;
+ bool ours;
+
+ assert(n);
+ assert(id);
+
+ /* This will try to reuse the old timer if there is one */
+
+ if (*id >= 0) {
+ ours = false;
+ fd = *id;
+
+ } else {
+ ours = true;
+
+ if ((fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC)) < 0)
+ return -errno;
+ }
+
+ zero(its);
+
+ if (delay <= 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, delay);
+ flags = 0;
+ }
+
+ /* This will also flush the elapse counter */
+ if (timerfd_settime(fd, flags, &its, NULL) < 0)
+ goto fail;
+
+ zero(ev);
+ ev.data.fd = fd;
+ ev.data.ptr = n;
+ ev.data.u32 = MANAGER_TIMER;
+ ev.events = POLLIN;
+
+ if (epoll_ctl(n->meta.manager->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0)
+ goto fail;
+
+ *id = fd;
+ return 0;
+
+fail:
+ if (ours)
+ assert_se(close_nointr(fd) == 0);
+
+ return -errno;
+}
+
+void name_unwatch_timer(Name *n, int *id) {
+ assert(n);
+ assert(id);
+
+ if (*id >= 0) {
+ assert_se(epoll_ctl(n->meta.manager->epoll_fd, EPOLL_CTL_DEL, *id, NULL) >= 0);
+ assert_se(close_nointr(*id) == 0);
+
+ *id = -1;
+ }
+}
+
+char *name_change_suffix(const char *t, const char *suffix) {
+ char *e, *n;
+ size_t a, b;
+
+ assert(t);
+ assert(name_is_valid(t));
+ assert(suffix);
+
+ assert_se(e = strrchr(t, '.'));
+ a = e - t;
+ b = strlen(suffix);
+
+ if (!(n = new(char, a + b + 1)))
+ return NULL;
+
+ memcpy(n, t, a);
+ memcpy(n+a, suffix, b+1);
+
+ return n;
+}
+
+bool name_job_is_applicable(Name *n, JobType j) {
+ assert(n);
+ assert(j >= 0 && j < _JOB_TYPE_MAX);
+
+ switch (j) {
+ case JOB_VERIFY_ACTIVE:
+ case JOB_START:
+ return true;
+
+ case JOB_STOP:
+ case JOB_RESTART:
+ case JOB_TRY_RESTART:
+ return name_can_start(n);
+
+ case JOB_RELOAD:
+ return name_can_reload(n);
+
+ case JOB_RELOAD_OR_START:
+ return name_can_reload(n) && name_can_start(n);
+
+ default:
+ assert_not_reached("Invalid job type");
+ }
+}
+
+int name_add_dependency(Name *n, NameDependency d, Name *other) {
+
+ static const NameDependency inverse_table[_NAME_DEPENDENCY_MAX] = {
+ [NAME_REQUIRES] = NAME_REQUIRED_BY,
+ [NAME_SOFT_REQUIRES] = NAME_SOFT_REQUIRED_BY,
+ [NAME_WANTS] = NAME_WANTED_BY,
+ [NAME_REQUISITE] = NAME_REQUIRED_BY,
+ [NAME_SOFT_REQUISITE] = NAME_SOFT_REQUIRED_BY,
+ [NAME_REQUIRED_BY] = _NAME_DEPENDENCY_INVALID,
+ [NAME_SOFT_REQUIRED_BY] = _NAME_DEPENDENCY_INVALID,
+ [NAME_WANTED_BY] = _NAME_DEPENDENCY_INVALID,
+ [NAME_CONFLICTS] = NAME_CONFLICTS,
+ [NAME_BEFORE] = NAME_AFTER,
+ [NAME_AFTER] = NAME_BEFORE
+ };
+ int r;
+
+ assert(n);
+ assert(d >= 0 && d < _NAME_DEPENDENCY_MAX);
+ assert(inverse_table[d] != _NAME_DEPENDENCY_INVALID);
+ assert(other);
+
+ if (n == other)
+ return 0;
+
+ if ((r = set_ensure_allocated(&n->meta.dependencies[d], trivial_hash_func, trivial_compare_func)) < 0)
+ return r;
+
+ if ((r = set_ensure_allocated(&other->meta.dependencies[inverse_table[d]], trivial_hash_func, trivial_compare_func)) < 0)
+ return r;
+
+ if ((r = set_put(n->meta.dependencies[d], other)) < 0)
+ return r;
+
+ if ((r = set_put(other->meta.dependencies[inverse_table[d]], n)) < 0) {
+ set_remove(n->meta.dependencies[d], other);
+ return r;
+ }