a->expire_event_source = sd_event_source_unref(a->expire_event_source);
}
-static int automount_add_mount_links(Automount *a) {
+static int automount_add_trigger_dependencies(Automount *a) {
+ Unit *x;
+ int r;
+
+ assert(a);
+
+ r = unit_load_related_unit(UNIT(a), ".mount", &x);
+ if (r < 0)
+ return r;
+
+ return unit_add_two_dependencies(UNIT(a), UNIT_BEFORE, UNIT_TRIGGERS, x, true, UNIT_DEPENDENCY_IMPLICIT);
+}
+
+static int automount_add_mount_dependencies(Automount *a) {
_cleanup_free_ char *parent = NULL;
assert(a);
if (!parent)
return -ENOMEM;
- return unit_require_mounts_for(UNIT(a), parent);
+ return unit_require_mounts_for(UNIT(a), parent, UNIT_DEPENDENCY_IMPLICIT);
}
static int automount_add_default_dependencies(Automount *a) {
if (!MANAGER_IS_SYSTEM(UNIT(a)->manager))
return 0;
- r = unit_add_two_dependencies_by_name(UNIT(a), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true);
+ r = unit_add_two_dependencies_by_name(UNIT(a), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
return r;
if (u->load_state == UNIT_LOADED) {
- Unit *x;
-
r = automount_set_where(a);
if (r < 0)
return r;
- r = unit_load_related_unit(u, ".mount", &x);
- if (r < 0)
- return r;
-
- r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, x, true);
+ r = automount_add_trigger_dependencies(a);
if (r < 0)
return r;
- r = automount_add_mount_links(a);
+ r = automount_add_mount_dependencies(a);
if (r < 0)
return r;
u->cgroup_members_mask = 0;
if (u->type == UNIT_SLICE) {
+ void *v;
Unit *member;
Iterator i;
- SET_FOREACH(member, u->dependencies[UNIT_BEFORE], i) {
+ HASHMAP_FOREACH_KEY(v, member, u->dependencies[UNIT_BEFORE], i) {
if (member == u)
continue;
while ((slice = UNIT_DEREF(u->slice))) {
Iterator i;
Unit *m;
+ void *v;
- SET_FOREACH(m, slice->dependencies[UNIT_BEFORE], i) {
+ HASHMAP_FOREACH_KEY(v, m, u->dependencies[UNIT_BEFORE], i) {
if (m == u)
continue;
if (u->type == UNIT_SLICE) {
Unit *member;
Iterator i;
+ void *v;
- SET_FOREACH(member, u->dependencies[UNIT_BEFORE], i) {
+ HASHMAP_FOREACH_KEY(v, member, u->dependencies[UNIT_BEFORE], i) {
if (member == u)
continue;
void *userdata,
sd_bus_error *error) {
- Set *s = *(Set**) userdata;
+ Hashmap *h = *(Hashmap**) userdata;
Iterator j;
Unit *u;
+ void *v;
int r;
assert(bus);
if (r < 0)
return r;
- SET_FOREACH(u, s, j) {
+ HASHMAP_FOREACH_KEY(v, u, h, j) {
r = sd_bus_message_append(reply, "s", u->id);
if (r < 0)
return r;
if (mode != UNIT_CHECK) {
_cleanup_free_ char *label = NULL;
- r = unit_add_dependency_by_name(u, d, other, NULL, true);
+ r = unit_add_dependency_by_name(u, d, other, NULL, true, UNIT_DEPENDENCY_FILE);
if (r < 0)
return r;
if (r < 0)
return log_unit_error_errno(u, r, "Failed to mangle unit name \"%s\": %m", word);
- r = unit_add_dependency_by_name(u, UNIT_WANTS, k, NULL, true);
+ r = unit_add_dependency_by_name(u, UNIT_WANTS, k, NULL, true, UNIT_DEPENDENCY_UDEV);
if (r < 0)
return log_unit_error_errno(u, r, "Failed to add wants dependency: %m");
}
static int device_upgrade_mount_deps(Unit *u) {
Unit *other;
Iterator i;
+ void *v;
int r;
- SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY], i) {
+ /* Let's upgrade Requires= to BindsTo= on us. (Used when SYSTEMD_MOUNT_DEVICE_BOUND is set) */
+
+ HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_REQUIRED_BY], i) {
if (other->type != UNIT_MOUNT)
continue;
- r = unit_add_dependency(other, UNIT_BINDS_TO, u, true);
+ r = unit_add_dependency(other, UNIT_BINDS_TO, u, true, UNIT_DEPENDENCY_UDEV);
if (r < 0)
return r;
}
(void) device_add_udev_wants(u, dev);
}
- /* So the user wants the mount units to be bound to the device but a
- * mount unit might has been seen by systemd before the device appears
- * on its radar. In this case the device unit is partially initialized
- * and includes the deps on the mount unit but at that time the "bind
- * mounts" flag wasn't not present. Fix this up now. */
+ /* So the user wants the mount units to be bound to the device but a mount unit might has been seen by systemd
+ * before the device appears on its radar. In this case the device unit is partially initialized and includes
+ * the deps on the mount unit but at that time the "bind mounts" flag wasn't not present. Fix this up now. */
if (dev && device_is_bound_by_mounts(u, dev))
device_upgrade_mount_deps(u);
static bool job_is_runnable(Job *j) {
Iterator i;
Unit *other;
+ void *v;
assert(j);
assert(j->installed);
return true;
if (IN_SET(j->type, JOB_START, JOB_VERIFY_ACTIVE, JOB_RELOAD)) {
-
/* Immediate result is that the job is or might be
* started. In this case let's wait for the
* dependencies, regardless whether they are
* starting or stopping something. */
- SET_FOREACH(other, j->unit->dependencies[UNIT_AFTER], i)
+ HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_AFTER], i)
if (other->job)
return false;
}
/* Also, if something else is being stopped and we should
* change state after it, then let's wait. */
- SET_FOREACH(other, j->unit->dependencies[UNIT_BEFORE], i)
+ HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_BEFORE], i)
if (other->job &&
IN_SET(other->job->type, JOB_STOP, JOB_RESTART))
return false;
static void job_fail_dependencies(Unit *u, UnitDependency d) {
Unit *other;
Iterator i;
+ void *v;
assert(u);
- SET_FOREACH(other, u->dependencies[d], i) {
+ HASHMAP_FOREACH_KEY(v, other, u->dependencies[d], i) {
Job *j = other->job;
if (!j)
Unit *other;
JobType t;
Iterator i;
+ void *v;
assert(j);
assert(j->installed);
finish:
/* Try to start the next jobs that can be started */
- SET_FOREACH(other, u->dependencies[UNIT_AFTER], i)
+ HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_AFTER], i)
if (other->job) {
job_add_to_run_queue(other->job);
job_add_to_gc_queue(other->job);
}
- SET_FOREACH(other, u->dependencies[UNIT_BEFORE], i)
+ HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_BEFORE], i)
if (other->job) {
job_add_to_run_queue(other->job);
job_add_to_gc_queue(other->job);
bool job_check_gc(Job *j) {
Unit *other;
Iterator i;
+ void *v;
assert(j);
/* If a job is ordered after ours, and is to be started, then it needs to wait for us, regardless if we stop or
* start, hence let's not GC in that case. */
- SET_FOREACH(other, j->unit->dependencies[UNIT_BEFORE], i) {
+ HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_BEFORE], i) {
if (!other->job)
continue;
/* If we are going down, but something else is ordered After= us, then it needs to wait for us */
if (IN_SET(j->type, JOB_STOP, JOB_RESTART))
- SET_FOREACH(other, j->unit->dependencies[UNIT_AFTER], i) {
+ HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_AFTER], i) {
if (!other->job)
continue;
size_t n = 0, n_allocated = 0;
Unit *other = NULL;
Iterator i;
+ void *v;
/* Returns a list of all pending jobs that need to finish before this job may be started. */
if (IN_SET(j->type, JOB_START, JOB_VERIFY_ACTIVE, JOB_RELOAD)) {
- SET_FOREACH(other, j->unit->dependencies[UNIT_AFTER], i) {
+ HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_AFTER], i) {
if (!other->job)
continue;
}
}
- SET_FOREACH(other, j->unit->dependencies[UNIT_BEFORE], i) {
+ HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_BEFORE], i) {
if (!other->job)
continue;
_cleanup_free_ Job** list = NULL;
size_t n = 0, n_allocated = 0;
Unit *other = NULL;
+ void *v;
Iterator i;
assert(j);
/* Returns a list of all pending jobs that are waiting for this job to finish. */
- SET_FOREACH(other, j->unit->dependencies[UNIT_BEFORE], i) {
+ HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_BEFORE], i) {
if (!other->job)
continue;
if (IN_SET(j->type, JOB_STOP, JOB_RESTART)) {
- SET_FOREACH(other, j->unit->dependencies[UNIT_AFTER], i) {
+ HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_AFTER], i) {
if (!other->job)
continue;
log_unit_warning(u, "%s dependency dropin %s target %s has different name",
unit_dependency_to_string(dependency), *p, target);
- r = unit_add_dependency_by_name(u, dependency, entry, *p, true);
+ r = unit_add_dependency_by_name(u, dependency, entry, *p, true, UNIT_DEPENDENCY_FILE);
if (r < 0)
log_unit_error_errno(u, r, "cannot add %s dependency on %s, ignoring: %m",
unit_dependency_to_string(dependency), entry);
continue;
}
- r = unit_add_dependency_by_name(u, d, k, NULL, true);
+ r = unit_add_dependency_by_name(u, d, k, NULL, true, UNIT_DEPENDENCY_FILE);
if (r < 0)
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
}
assert(rvalue);
assert(data);
- if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
+ if (!hashmap_isempty(u->dependencies[UNIT_TRIGGERS])) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Multiple units to trigger specified, ignoring: %s", rvalue);
return 0;
}
return 0;
}
- r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p, NULL, true);
+ r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p, NULL, true, UNIT_DEPENDENCY_FILE);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add trigger on %s, ignoring: %m", p);
return 0;
continue;
}
- r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
+ r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true, UNIT_DEPENDENCY_FILE);
if (r < 0)
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
- r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
+ r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true, UNIT_DEPENDENCY_FILE);
if (r < 0)
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
}
continue;
}
- r = unit_require_mounts_for(u, resolved);
+ r = unit_require_mounts_for(u, resolved, UNIT_DEPENDENCY_FILE);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add required mount \"%s\", ignoring: %m", resolved);
continue;
};
static void unit_gc_mark_good(Unit *u, unsigned gc_marker) {
- Iterator i;
Unit *other;
+ Iterator i;
+ void *v;
u->gc_marker = gc_marker + GC_OFFSET_GOOD;
/* Recursively mark referenced units as GOOD as well */
- SET_FOREACH(other, u->dependencies[UNIT_REFERENCES], i)
+ HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_REFERENCES], i)
if (other->gc_marker == gc_marker + GC_OFFSET_UNSURE)
unit_gc_mark_good(other, gc_marker);
}
static void unit_gc_sweep(Unit *u, unsigned gc_marker) {
- Iterator i;
Unit *other;
bool is_bad;
+ Iterator i;
+ void *v;
assert(u);
is_bad = true;
- SET_FOREACH(other, u->dependencies[UNIT_REFERENCED_BY], i) {
+ HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_REFERENCED_BY], i) {
unit_gc_sweep(other, gc_marker);
if (other->gc_marker == gc_marker + GC_OFFSET_GOOD)
return get_mount_parameters_fragment(m);
}
-static int mount_add_mount_links(Mount *m) {
- _cleanup_free_ char *parent = NULL;
+static int mount_add_mount_dependencies(Mount *m) {
const char *fstype;
MountParameters *pm;
Unit *other;
assert(m);
if (!path_equal(m->where, "/")) {
- /* Adds in links to other mount points that might lie further
- * up in the hierarchy */
+ _cleanup_free_ char *parent = NULL;
+
+ /* Adds in links to other mount points that might lie further up in the hierarchy */
parent = dirname_malloc(m->where);
if (!parent)
return -ENOMEM;
- r = unit_require_mounts_for(UNIT(m), parent);
+ r = unit_require_mounts_for(UNIT(m), parent, UNIT_DEPENDENCY_IMPLICIT);
if (r < 0)
return r;
}
- /* Adds in links to other mount points that might be needed
- * for the source path (if this is a bind mount or a loop mount) to be
- * available. */
+ /* Adds in dependencies to other mount points that might be needed for the source path (if this is a bind mount
+ * or a loop mount) to be available. */
pm = get_mount_parameters_fragment(m);
if (pm && pm->what &&
path_is_absolute(pm->what) &&
(mount_is_bind(pm) || mount_is_loop(pm) || !mount_is_network(pm))) {
- r = unit_require_mounts_for(UNIT(m), pm->what);
+ r = unit_require_mounts_for(UNIT(m), pm->what, UNIT_DEPENDENCY_FILE);
if (r < 0)
return r;
}
- /* Adds in links to other units that use this path or paths
- * further down in the hierarchy */
+ /* Adds in dependencies to other units that use this path or paths further down in the hierarchy */
s = manager_get_units_requiring_mounts_for(UNIT(m)->manager, m->where);
SET_FOREACH(other, s, i) {
if (other == UNIT(m))
continue;
- r = unit_add_dependency(other, UNIT_AFTER, UNIT(m), true);
+ r = unit_add_dependency(other, UNIT_AFTER, UNIT(m), true, UNIT_DEPENDENCY_PATH);
if (r < 0)
return r;
if (UNIT(m)->fragment_path) {
/* If we have fragment configuration, then make this dependency required */
- r = unit_add_dependency(other, UNIT_REQUIRES, UNIT(m), true);
+ r = unit_add_dependency(other, UNIT_REQUIRES, UNIT(m), true, UNIT_DEPENDENCY_PATH);
if (r < 0)
return r;
}
/* If this is a tmpfs mount then we have to unmount it before we try to deactivate swaps */
fstype = mount_get_fstype(m);
if (streq(fstype, "tmpfs")) {
- r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, SPECIAL_SWAP_TARGET, NULL, true);
+ r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, SPECIAL_SWAP_TARGET, NULL, true, UNIT_DEPENDENCY_IMPLICIT);
if (r < 0)
return r;
}
return 0;
}
-static int mount_add_device_links(Mount *m) {
- MountParameters *p;
+static int mount_add_device_dependencies(Mount *m) {
bool device_wants_mount = false;
+ UnitDependencyMask mask;
+ MountParameters *p;
UnitDependency dep;
int r;
* automatically stopped when the device disappears suddenly. */
dep = mount_is_bound_to_device(m) ? UNIT_BINDS_TO : UNIT_REQUIRES;
- r = unit_add_node_link(UNIT(m), p->what, device_wants_mount, dep);
+ mask = m->from_fragment ? UNIT_DEPENDENCY_FILE : UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT;
+
+ r = unit_add_node_dependency(UNIT(m), p->what, device_wants_mount, dep, mask);
if (r < 0)
return r;
return 0;
}
-static int mount_add_quota_links(Mount *m) {
- int r;
+static int mount_add_quota_dependencies(Mount *m) {
+ UnitDependencyMask mask;
MountParameters *p;
+ int r;
assert(m);
if (!needs_quota(p))
return 0;
- r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_WANTS, SPECIAL_QUOTACHECK_SERVICE, NULL, true);
+ mask = m->from_fragment ? UNIT_DEPENDENCY_FILE : UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT;
+
+ r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_WANTS, SPECIAL_QUOTACHECK_SERVICE, NULL, true, mask);
if (r < 0)
return r;
- r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_WANTS, SPECIAL_QUOTAON_SERVICE, NULL, true);
+ r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_WANTS, SPECIAL_QUOTAON_SERVICE, NULL, true, mask);
if (r < 0)
return r;
}
static int mount_add_default_dependencies(Mount *m) {
+ UnitDependencyMask mask;
+ int r;
MountParameters *p;
const char *after;
- int r;
assert(m);
if (!p)
return 0;
+ mask = m->from_fragment ? UNIT_DEPENDENCY_FILE : UNIT_DEPENDENCY_MOUNTINFO_DEFAULT;
+
if (mount_is_network(p)) {
/* We order ourselves after network.target. This is
* primarily useful at shutdown: services that take
* network.target, so that they are shut down only
* after this mount unit is stopped. */
- r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, SPECIAL_NETWORK_TARGET, NULL, true);
+ r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, SPECIAL_NETWORK_TARGET, NULL, true, mask);
if (r < 0)
return r;
* whose purpose it is to delay this until the network
* is "up". */
- r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_WANTS, UNIT_AFTER, SPECIAL_NETWORK_ONLINE_TARGET, NULL, true);
+ r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_WANTS, UNIT_AFTER, SPECIAL_NETWORK_ONLINE_TARGET, NULL, true, mask);
if (r < 0)
return r;
} else
after = SPECIAL_LOCAL_FS_PRE_TARGET;
- r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after, NULL, true);
+ r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after, NULL, true, mask);
if (r < 0)
return r;
- r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true);
+ r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true, mask);
if (r < 0)
return r;
return r;
}
- r = mount_add_device_links(m);
+ r = mount_add_device_dependencies(m);
if (r < 0)
return r;
- r = mount_add_mount_links(m);
+ r = mount_add_mount_dependencies(m);
if (r < 0)
return r;
- r = mount_add_quota_links(m);
+ r = mount_add_quota_dependencies(m);
if (r < 0)
return r;
int r;
target = mount_is_network(p) ? SPECIAL_REMOTE_FS_TARGET : SPECIAL_LOCAL_FS_TARGET;
- r = unit_add_dependency_by_name(u, UNIT_BEFORE, target, NULL, true);
+ r = unit_add_dependency_by_name(u, UNIT_BEFORE, target, NULL, true, UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT);
if (r < 0)
return r;
- r = unit_add_dependency_by_name(u, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true);
+ r = unit_add_dependency_by_name(u, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true, UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT);
if (r < 0)
return r;
}
* in the dependency "Set*" objects who created a
* dependency), we can only add deps, never lose them,
* until the next full daemon-reload. */
- unit_add_dependency_by_name(u, UNIT_BEFORE, SPECIAL_REMOTE_FS_TARGET, NULL, true);
+ unit_add_dependency_by_name(u, UNIT_BEFORE, SPECIAL_REMOTE_FS_TARGET, NULL, true, UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT);
load_extras = true;
}
path_free_specs(p);
}
-static int path_add_mount_links(Path *p) {
+static int path_add_mount_dependencies(Path *p) {
PathSpec *s;
int r;
assert(p);
LIST_FOREACH(spec, s, p->specs) {
- r = unit_require_mounts_for(UNIT(p), s->path);
+ r = unit_require_mounts_for(UNIT(p), s->path, UNIT_DEPENDENCY_FILE);
if (r < 0)
return r;
}
if (!UNIT(p)->default_dependencies)
return 0;
- r = unit_add_dependency_by_name(UNIT(p), UNIT_BEFORE, SPECIAL_PATHS_TARGET, NULL, true);
+ r = unit_add_dependency_by_name(UNIT(p), UNIT_BEFORE, SPECIAL_PATHS_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
if (MANAGER_IS_SYSTEM(UNIT(p)->manager)) {
- r = unit_add_two_dependencies_by_name(UNIT(p), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
+ r = unit_add_two_dependencies_by_name(UNIT(p), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
}
- return unit_add_two_dependencies_by_name(UNIT(p), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
+ return unit_add_two_dependencies_by_name(UNIT(p), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
+}
+
+static int path_add_trigger_dependencies(Path *p) {
+ Unit *x;
+ int r;
+
+ assert(p);
+
+ if (!hashmap_isempty(UNIT(p)->dependencies[UNIT_TRIGGERS]))
+ return 0;
+
+ r = unit_load_related_unit(UNIT(p), ".service", &x);
+ if (r < 0)
+ return r;
+
+ return unit_add_two_dependencies(UNIT(p), UNIT_BEFORE, UNIT_TRIGGERS, x, true, UNIT_DEPENDENCY_IMPLICIT);
}
static int path_load(Unit *u) {
if (u->load_state == UNIT_LOADED) {
- if (set_isempty(u->dependencies[UNIT_TRIGGERS])) {
- Unit *x;
-
- r = unit_load_related_unit(u, ".service", &x);
- if (r < 0)
- return r;
-
- r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, x, true);
- if (r < 0)
- return r;
- }
+ r = path_add_trigger_dependencies(p);
+ if (r < 0)
+ return r;
- r = path_add_mount_links(p);
+ r = path_add_mount_dependencies(p);
if (r < 0)
return r;
r = unit_add_two_dependencies_by_name(
UNIT(s),
UNIT_BEFORE, UNIT_CONFLICTS,
- SPECIAL_SHUTDOWN_TARGET, NULL, true);
+ SPECIAL_SHUTDOWN_TARGET, NULL, true,
+ UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
* require it, so that we fail if we can't acquire
* it. */
- r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
+ r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
} else {
/* In the --user instance there's no sysinit.target,
* in that case require basic.target instead. */
- r = unit_add_dependency_by_name(UNIT(s), UNIT_REQUIRES, SPECIAL_BASIC_TARGET, NULL, true);
+ r = unit_add_dependency_by_name(UNIT(s), UNIT_REQUIRES, SPECIAL_BASIC_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
}
/* Second, if the rest of the base system is in the same
* transaction, order us after it, but do not pull it in or
* even require it. */
- r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_BASIC_TARGET, NULL, true);
+ r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_BASIC_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
/* Third, add us in for normal shutdown. */
- return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
+ return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
}
static void service_fix_output(Service *s) {
if (!s->bus_name)
return 0;
- r = unit_add_dependency_by_name(UNIT(s), UNIT_REQUIRES, SPECIAL_DBUS_SOCKET, NULL, true);
+ r = unit_add_dependency_by_name(UNIT(s), UNIT_REQUIRES, SPECIAL_DBUS_SOCKET, NULL, true, UNIT_DEPENDENCY_FILE);
if (r < 0)
return log_unit_error_errno(UNIT(s), r, "Failed to add dependency on " SPECIAL_DBUS_SOCKET ": %m");
/* We always want to be ordered against dbus.socket if both are in the transaction. */
- r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_DBUS_SOCKET, NULL, true);
+ r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_DBUS_SOCKET, NULL, true, UNIT_DEPENDENCY_FILE);
if (r < 0)
return log_unit_error_errno(UNIT(s), r, "Failed to add dependency on " SPECIAL_DBUS_SOCKET ": %m");
rn_socket_fds = 1;
} else {
Iterator i;
+ void *v;
Unit *u;
/* Pass all our configured sockets for singleton services */
- SET_FOREACH(u, UNIT(s)->dependencies[UNIT_TRIGGERED_BY], i) {
+ HASHMAP_FOREACH_KEY(v, u, UNIT(s)->dependencies[UNIT_TRIGGERED_BY], i) {
_cleanup_free_ int *cfds = NULL;
Socket *sock;
int cn_fds;
return r;
}
- r = unit_add_two_dependencies(UNIT(sock), UNIT_BEFORE, UNIT_TRIGGERS, UNIT(s), false);
+ r = unit_add_two_dependencies(UNIT(sock), UNIT_BEFORE, UNIT_TRIGGERS, UNIT(s), false, UNIT_DEPENDENCY_IMPLICIT);
if (r < 0)
return r;
r = unit_add_two_dependencies_by_name(
UNIT(s),
UNIT_BEFORE, UNIT_CONFLICTS,
- SPECIAL_SHUTDOWN_TARGET, NULL, true);
+ SPECIAL_SHUTDOWN_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
unit_ref_set(&s->service, u);
- return unit_add_two_dependencies(UNIT(s), UNIT_BEFORE, UNIT_TRIGGERS, u, false);
+ return unit_add_two_dependencies(UNIT(s), UNIT_BEFORE, UNIT_TRIGGERS, u, false, UNIT_DEPENDENCY_IMPLICIT);
}
static bool have_non_accept_socket(Socket *s) {
return false;
}
-static int socket_add_mount_links(Socket *s) {
+static int socket_add_mount_dependencies(Socket *s) {
SocketPort *p;
int r;
if (!path)
continue;
- r = unit_require_mounts_for(UNIT(s), path);
+ r = unit_require_mounts_for(UNIT(s), path, UNIT_DEPENDENCY_FILE);
if (r < 0)
return r;
}
return 0;
}
-static int socket_add_device_link(Socket *s) {
+static int socket_add_device_dependencies(Socket *s) {
char *t;
assert(s);
return 0;
t = strjoina("/sys/subsystem/net/devices/", s->bind_to_device);
- return unit_add_node_link(UNIT(s), t, false, UNIT_BINDS_TO);
+ return unit_add_node_dependency(UNIT(s), t, false, UNIT_BINDS_TO, UNIT_DEPENDENCY_FILE);
}
static int socket_add_default_dependencies(Socket *s) {
if (!UNIT(s)->default_dependencies)
return 0;
- r = unit_add_dependency_by_name(UNIT(s), UNIT_BEFORE, SPECIAL_SOCKETS_TARGET, NULL, true);
+ r = unit_add_dependency_by_name(UNIT(s), UNIT_BEFORE, SPECIAL_SOCKETS_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
if (MANAGER_IS_SYSTEM(UNIT(s)->manager)) {
- r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
+ r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
}
- return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
+ return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
}
_pure_ static bool socket_has_exec(Socket *s) {
unit_ref_set(&s->service, x);
}
- r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, UNIT_DEREF(s->service), true);
+ r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, UNIT_DEREF(s->service), true, UNIT_DEPENDENCY_IMPLICIT);
if (r < 0)
return r;
}
- r = socket_add_mount_links(s);
+ r = socket_add_mount_dependencies(s);
if (r < 0)
return r;
- r = socket_add_device_link(s);
+ r = socket_add_device_dependencies(s);
if (r < 0)
return r;
}
if (cfd < 0) {
- Iterator i;
- Unit *other;
bool pending = false;
+ Unit *other;
+ Iterator i;
+ void *v;
/* If there's already a start pending don't bother to
* do anything */
- SET_FOREACH(other, UNIT(s)->dependencies[UNIT_TRIGGERS], i)
+ HASHMAP_FOREACH_KEY(v, other, UNIT(s)->dependencies[UNIT_TRIGGERS], i)
if (unit_active_or_pending(other)) {
pending = true;
break;
return 0;
}
-static int swap_add_device_links(Swap *s) {
+static int swap_add_device_dependencies(Swap *s) {
assert(s);
if (!s->what)
return 0;
if (is_device_path(s->what))
- return unit_add_node_link(UNIT(s), s->what, MANAGER_IS_SYSTEM(UNIT(s)->manager), UNIT_BINDS_TO);
+ return unit_add_node_dependency(UNIT(s), s->what, MANAGER_IS_SYSTEM(UNIT(s)->manager), UNIT_BINDS_TO, UNIT_DEPENDENCY_FILE);
else
/* File based swap devices need to be ordered after
* systemd-remount-fs.service, since they might need a
* writable file system. */
- return unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_REMOUNT_FS_SERVICE, NULL, true);
+ return unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_REMOUNT_FS_SERVICE, NULL, true, UNIT_DEPENDENCY_FILE);
}
static int swap_add_default_dependencies(Swap *s) {
/* swap units generated for the swap dev links are missing the
* ordering dep against the swap target. */
- r = unit_add_dependency_by_name(UNIT(s), UNIT_BEFORE, SPECIAL_SWAP_TARGET, NULL, true);
+ r = unit_add_dependency_by_name(UNIT(s), UNIT_BEFORE, SPECIAL_SWAP_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
- return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true);
+ return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
}
static int swap_verify(Swap *s) {
return r;
}
- r = unit_require_mounts_for(UNIT(s), s->what);
+ r = unit_require_mounts_for(UNIT(s), s->what, UNIT_DEPENDENCY_IMPLICIT);
if (r < 0)
return r;
- r = swap_add_device_links(s);
+ r = swap_add_device_dependencies(s);
if (r < 0)
return r;
UNIT_PART_OF
};
- Iterator i;
- Unit *other;
int r;
unsigned k;
if (!UNIT(t)->default_dependencies)
return 0;
- /* Imply ordering for requirement dependencies on target
- * units. Note that when the user created a contradicting
- * ordering manually we won't add anything in here to make
- * sure we don't create a loop. */
+ /* Imply ordering for requirement dependencies on target units. Note that when the user created a contradicting
+ * ordering manually we won't add anything in here to make sure we don't create a loop. */
- for (k = 0; k < ELEMENTSOF(deps); k++)
- SET_FOREACH(other, UNIT(t)->dependencies[deps[k]], i) {
+ for (k = 0; k < ELEMENTSOF(deps); k++) {
+ Unit *other;
+ Iterator i;
+ void *v;
+
+ HASHMAP_FOREACH_KEY(v, other, UNIT(t)->dependencies[deps[k]], i) {
r = unit_add_default_target_dependency(other, UNIT(t));
if (r < 0)
return r;
}
+ }
if (unit_has_name(UNIT(t), SPECIAL_SHUTDOWN_TARGET))
return 0;
/* Make sure targets are unloaded on shutdown */
- return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
+ return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
}
static int target_load(Unit *u) {
if (!UNIT(t)->default_dependencies)
return 0;
- r = unit_add_dependency_by_name(UNIT(t), UNIT_BEFORE, SPECIAL_TIMERS_TARGET, NULL, true);
+ r = unit_add_dependency_by_name(UNIT(t), UNIT_BEFORE, SPECIAL_TIMERS_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
if (MANAGER_IS_SYSTEM(UNIT(t)->manager)) {
- r = unit_add_two_dependencies_by_name(UNIT(t), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
+ r = unit_add_two_dependencies_by_name(UNIT(t), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
LIST_FOREACH(value, v, t->values) {
if (v->base == TIMER_CALENDAR) {
- r = unit_add_dependency_by_name(UNIT(t), UNIT_AFTER, SPECIAL_TIME_SYNC_TARGET, NULL, true);
+ r = unit_add_dependency_by_name(UNIT(t), UNIT_AFTER, SPECIAL_TIME_SYNC_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
break;
}
}
- return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
+ return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
+}
+
+static int timer_add_trigger_dependencies(Timer *t) {
+ Unit *x;
+ int r;
+
+ assert(t);
+
+ if (!hashmap_isempty(UNIT(t)->dependencies[UNIT_TRIGGERS]))
+ return 0;
+
+ r = unit_load_related_unit(UNIT(t), ".service", &x);
+ if (r < 0)
+ return r;
+
+ return unit_add_two_dependencies(UNIT(t), UNIT_BEFORE, UNIT_TRIGGERS, x, true, UNIT_DEPENDENCY_IMPLICIT);
}
static int timer_setup_persistent(Timer *t) {
if (MANAGER_IS_SYSTEM(UNIT(t)->manager)) {
- r = unit_require_mounts_for(UNIT(t), "/var/lib/systemd/timers");
+ r = unit_require_mounts_for(UNIT(t), "/var/lib/systemd/timers", UNIT_DEPENDENCY_FILE);
if (r < 0)
return r;
if (u->load_state == UNIT_LOADED) {
- if (set_isempty(u->dependencies[UNIT_TRIGGERS])) {
- Unit *x;
-
- r = unit_load_related_unit(u, ".service", &x);
- if (r < 0)
- return r;
-
- r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, x, true);
- if (r < 0)
- return r;
- }
+ r = timer_add_trigger_dependencies(t);
+ if (r < 0)
+ return r;
r = timer_setup_persistent(t);
if (r < 0)
static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsigned generation, sd_bus_error *e) {
Iterator i;
Unit *u;
+ void *v;
int r;
assert(tr);
/* We assume that the dependencies are bidirectional, and
* hence can ignore UNIT_AFTER */
- SET_FOREACH(u, j->unit->dependencies[UNIT_BEFORE], i) {
+ HASHMAP_FOREACH_KEY(v, u, j->unit->dependencies[UNIT_BEFORE], i) {
Job *o;
/* Is there a job for this unit? */
void transaction_add_propagate_reload_jobs(Transaction *tr, Unit *unit, Job *by, bool ignore_order, sd_bus_error *e) {
Iterator i;
- Unit *dep;
JobType nt;
+ Unit *dep;
+ void *v;
int r;
assert(tr);
assert(unit);
- SET_FOREACH(dep, unit->dependencies[UNIT_PROPAGATES_RELOAD_TO], i) {
+ HASHMAP_FOREACH_KEY(v, dep, unit->dependencies[UNIT_PROPAGATES_RELOAD_TO], i) {
nt = job_type_collapse(JOB_TRY_RELOAD, dep);
if (nt == JOB_NOP)
continue;
bool ignore_requirements,
bool ignore_order,
sd_bus_error *e) {
- Job *ret;
+
+ bool is_new;
Iterator i;
Unit *dep;
+ Job *ret;
+ void *v;
int r;
- bool is_new;
assert(tr);
assert(type < _JOB_TYPE_MAX);
/* Finally, recursively add in all dependencies. */
if (IN_SET(type, JOB_START, JOB_RESTART)) {
- SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES], i) {
+ HASHMAP_FOREACH_KEY(v, dep, ret->unit->dependencies[UNIT_REQUIRES], i) {
r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, false, false, ignore_order, e);
if (r < 0) {
if (r != -EBADR) /* job type not applicable */
}
}
- SET_FOREACH(dep, ret->unit->dependencies[UNIT_BINDS_TO], i) {
+ HASHMAP_FOREACH_KEY(v, dep, ret->unit->dependencies[UNIT_BINDS_TO], i) {
r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, false, false, ignore_order, e);
if (r < 0) {
if (r != -EBADR) /* job type not applicable */
}
}
- SET_FOREACH(dep, ret->unit->dependencies[UNIT_WANTS], i) {
+ HASHMAP_FOREACH_KEY(v, dep, ret->unit->dependencies[UNIT_WANTS], i) {
r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, false, false, false, ignore_order, e);
if (r < 0) {
/* unit masked, job type not applicable and unit not found are not considered as errors. */
}
}
- SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE], i) {
+ HASHMAP_FOREACH_KEY(v, dep, ret->unit->dependencies[UNIT_REQUISITE], i) {
r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, true, false, false, ignore_order, e);
if (r < 0) {
if (r != -EBADR) /* job type not applicable */
}
}
- SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTS], i) {
+ HASHMAP_FOREACH_KEY(v, dep, ret->unit->dependencies[UNIT_CONFLICTS], i) {
r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, true, true, false, ignore_order, e);
if (r < 0) {
if (r != -EBADR) /* job type not applicable */
}
}
- SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTED_BY], i) {
+ HASHMAP_FOREACH_KEY(v, dep, ret->unit->dependencies[UNIT_CONFLICTED_BY], i) {
r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, false, false, false, ignore_order, e);
if (r < 0) {
log_unit_warning(dep,
ptype = type == JOB_RESTART ? JOB_TRY_RESTART : type;
for (j = 0; j < ELEMENTSOF(propagate_deps); j++)
- SET_FOREACH(dep, ret->unit->dependencies[propagate_deps[j]], i) {
+ HASHMAP_FOREACH_KEY(v, dep, ret->unit->dependencies[propagate_deps[j]], i) {
JobType nt;
nt = job_type_collapse(ptype, dep);
u->in_dbus_queue = true;
}
-static void bidi_set_free(Unit *u, Set *s) {
- Iterator i;
+static void bidi_set_free(Unit *u, Hashmap *h) {
Unit *other;
+ Iterator i;
+ void *v;
assert(u);
- /* Frees the set and makes sure we are dropped from the
- * inverse pointers */
+ /* Frees the hashmap and makes sure we are dropped from the inverse pointers */
- SET_FOREACH(other, s, i) {
+ HASHMAP_FOREACH_KEY(v, other, h, i) {
UnitDependency d;
for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++)
- set_remove(other->dependencies[d], u);
+ hashmap_remove(other->dependencies[d], u);
unit_add_to_gc_queue(other);
}
- set_free(s);
+ hashmap_free(h);
}
static void unit_remove_transient(Unit *u) {
}
static void unit_free_requires_mounts_for(Unit *u) {
- char **j;
+ assert(u);
- STRV_FOREACH(j, u->requires_mounts_for) {
- char s[strlen(*j) + 1];
+ for (;;) {
+ _cleanup_free_ char *path;
- PATH_FOREACH_PREFIX_MORE(s, *j) {
- char *y;
- Set *x;
+ path = hashmap_steal_first_key(u->requires_mounts_for);
+ if (!path)
+ break;
+ else {
+ char s[strlen(path) + 1];
- x = hashmap_get2(u->manager->units_requiring_mounts_for, s, (void**) &y);
- if (!x)
- continue;
+ PATH_FOREACH_PREFIX_MORE(s, path) {
+ char *y;
+ Set *x;
+
+ x = hashmap_get2(u->manager->units_requiring_mounts_for, s, (void**) &y);
+ if (!x)
+ continue;
- set_remove(x, u);
+ (void) set_remove(x, u);
- if (set_isempty(x)) {
- hashmap_remove(u->manager->units_requiring_mounts_for, y);
- free(y);
- set_free(x);
+ if (set_isempty(x)) {
+ (void) hashmap_remove(u->manager->units_requiring_mounts_for, y);
+ free(y);
+ set_free(x);
+ }
}
}
}
- u->requires_mounts_for = strv_free(u->requires_mounts_for);
+ u->requires_mounts_for = hashmap_free(u->requires_mounts_for);
}
static void unit_done(Unit *u) {
return UNIT_VTABLE(u)->sub_state_to_string(u);
}
-static int complete_move(Set **s, Set **other) {
- int r;
+static int set_complete_move(Set **s, Set **other) {
+ assert(s);
+ assert(other);
+
+ if (!other)
+ return 0;
+
+ if (*s)
+ return set_move(*s, *other);
+ else {
+ *s = *other;
+ *other = NULL;
+ }
+ return 0;
+}
+
+static int hashmap_complete_move(Hashmap **s, Hashmap **other) {
assert(s);
assert(other);
if (!*other)
return 0;
- if (*s) {
- r = set_move(*s, *other);
- if (r < 0)
- return r;
- } else {
+ if (*s)
+ return hashmap_move(*s, *other);
+ else {
*s = *other;
*other = NULL;
}
assert(u);
assert(other);
- r = complete_move(&u->names, &other->names);
+ r = set_complete_move(&u->names, &other->names);
if (r < 0)
return r;
return 0;
/* merge_dependencies() will skip a u-on-u dependency */
- n_reserve = set_size(other->dependencies[d]) - !!set_get(other->dependencies[d], u);
+ n_reserve = hashmap_size(other->dependencies[d]) - !!hashmap_get(other->dependencies[d], u);
- return set_reserve(u->dependencies[d], n_reserve);
+ return hashmap_reserve(u->dependencies[d], n_reserve);
}
static void merge_dependencies(Unit *u, Unit *other, const char *other_id, UnitDependency d) {
Iterator i;
Unit *back;
+ void *v;
int r;
+ /* Merges all dependencies of type 'd' of the unit 'other' into the deps of the unit 'u' */
+
assert(u);
assert(other);
assert(d < _UNIT_DEPENDENCY_MAX);
- /* Fix backwards pointers */
- SET_FOREACH(back, other->dependencies[d], i) {
+ /* Fix backwards pointers. Let's iterate through all dependendent units of the other unit. */
+ HASHMAP_FOREACH_KEY(v, back, other->dependencies[d], i) {
UnitDependency k;
+ /* Let's now iterate through the dependencies of that dependencies of the other units, looking for
+ * pointers back, and let's fix them up, to instead point to 'u'. */
+
for (k = 0; k < _UNIT_DEPENDENCY_MAX; k++) {
- /* Do not add dependencies between u and itself */
if (back == u) {
- if (set_remove(back->dependencies[k], other))
+ /* Do not add dependencies between u and itself. */
+ if (hashmap_remove(back->dependencies[k], other))
maybe_warn_about_dependency(u, other_id, k);
} else {
- r = set_remove_and_put(back->dependencies[k], other, u);
- if (r == -EEXIST)
- set_remove(back->dependencies[k], other);
- else
- assert(r >= 0 || r == -ENOENT);
+ UnitDependencyInfo di_u, di_other, di_merged;
+
+ /* Let's drop this dependency between "back" and "other", and let's create it between
+ * "back" and "u" instead. Let's merge the bit masks of the dependency we are moving,
+ * and any such dependency which might already exist */
+
+ di_other.data = hashmap_get(back->dependencies[k], other);
+ if (!di_other.data)
+ continue; /* dependency isn't set, let's try the next one */
+
+ di_u.data = hashmap_get(back->dependencies[k], u);
+
+ di_merged = (UnitDependencyInfo) {
+ .origin_mask = di_u.origin_mask | di_other.origin_mask,
+ .destination_mask = di_u.destination_mask | di_other.destination_mask,
+ };
+
+ r = hashmap_remove_and_replace(back->dependencies[k], other, u, di_merged.data);
+ if (r < 0)
+ log_warning_errno(r, "Failed to remove/replace: back=%s other=%s u=%s: %m", back->id, other_id, u->id);
+ assert(r >= 0);
+
+ /* assert_se(hashmap_remove_and_replace(back->dependencies[k], other, u, di_merged.data) >= 0); */
}
}
+
}
/* Also do not move dependencies on u to itself */
- back = set_remove(other->dependencies[d], u);
+ back = hashmap_remove(other->dependencies[d], u);
if (back)
maybe_warn_about_dependency(u, other_id, d);
/* The move cannot fail. The caller must have performed a reservation. */
- assert_se(complete_move(&u->dependencies[d], &other->dependencies[d]) == 0);
+ assert_se(hashmap_complete_move(&u->dependencies[d], &other->dependencies[d]) == 0);
- other->dependencies[d] = set_free(other->dependencies[d]);
+ other->dependencies[d] = hashmap_free(other->dependencies[d]);
}
int unit_merge(Unit *u, Unit *other) {
assert(c);
if (c->working_directory) {
- r = unit_require_mounts_for(u, c->working_directory);
+ r = unit_require_mounts_for(u, c->working_directory, UNIT_DEPENDENCY_FILE);
if (r < 0)
return r;
}
if (c->root_directory) {
- r = unit_require_mounts_for(u, c->root_directory);
+ r = unit_require_mounts_for(u, c->root_directory, UNIT_DEPENDENCY_FILE);
if (r < 0)
return r;
}
if (c->root_image) {
- r = unit_require_mounts_for(u, c->root_image);
+ r = unit_require_mounts_for(u, c->root_image, UNIT_DEPENDENCY_FILE);
if (r < 0)
return r;
}
if (!p)
return -ENOMEM;
- r = unit_require_mounts_for(u, p);
+ r = unit_require_mounts_for(u, p, UNIT_DEPENDENCY_FILE);
if (r < 0)
return r;
}
const char *p;
FOREACH_STRING(p, "/tmp", "/var/tmp") {
- r = unit_require_mounts_for(u, p);
+ r = unit_require_mounts_for(u, p, UNIT_DEPENDENCY_FILE);
if (r < 0)
return r;
}
- r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_TMPFILES_SETUP_SERVICE, NULL, true);
+ r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_TMPFILES_SETUP_SERVICE, NULL, true, UNIT_DEPENDENCY_FILE);
if (r < 0)
return r;
}
/* If syslog or kernel logging is requested, make sure our own
* logging daemon is run first. */
- r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_JOURNALD_SOCKET, NULL, true);
+ r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_JOURNALD_SOCKET, NULL, true, UNIT_DEPENDENCY_FILE);
if (r < 0)
return r;
return strna(u->id);
}
+static void print_unit_dependency_mask(FILE *f, const char *kind, UnitDependencyMask mask, bool *space) {
+ const struct {
+ UnitDependencyMask mask;
+ const char *name;
+ } table[] = {
+ { UNIT_DEPENDENCY_FILE, "file" },
+ { UNIT_DEPENDENCY_IMPLICIT, "implicit" },
+ { UNIT_DEPENDENCY_DEFAULT, "default" },
+ { UNIT_DEPENDENCY_UDEV, "udev" },
+ { UNIT_DEPENDENCY_PATH, "path" },
+ { UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT, "mountinfo-implicit" },
+ { UNIT_DEPENDENCY_MOUNTINFO_DEFAULT, "mountinfo-default" },
+ { UNIT_DEPENDENCY_PROC_SWAP, "proc-swap" },
+ };
+ size_t i;
+
+ assert(f);
+ assert(kind);
+ assert(space);
+
+ for (i = 0; i < ELEMENTSOF(table); i++) {
+
+ if (mask == 0)
+ break;
+
+ if ((mask & table[i].mask) == table[i].mask) {
+ if (*space)
+ fputc(' ', f);
+ else
+ *space = true;
+
+ fputs(kind, f);
+ fputs("-", f);
+ fputs(table[i].name, f);
+
+ mask &= ~table[i].mask;
+ }
+ }
+
+ assert(mask == 0);
+}
+
void unit_dump(Unit *u, FILE *f, const char *prefix) {
char *t, **j;
UnitDependency d;
prefix, yes_no(u->assert_result));
for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++) {
+ UnitDependencyInfo di;
Unit *other;
- SET_FOREACH(other, u->dependencies[d], i)
- fprintf(f, "%s\t%s: %s\n", prefix, unit_dependency_to_string(d), other->id);
+ HASHMAP_FOREACH_KEY(di.data, other, u->dependencies[d], i) {
+ bool space = false;
+
+ fprintf(f, "%s\t%s: %s (", prefix, unit_dependency_to_string(d), other->id);
+
+ print_unit_dependency_mask(f, "origin", di.origin_mask, &space);
+ print_unit_dependency_mask(f, "destination", di.destination_mask, &space);
+
+ fputs(")\n", f);
+ }
}
- if (!strv_isempty(u->requires_mounts_for)) {
- fprintf(f,
- "%s\tRequiresMountsFor:", prefix);
+ if (!hashmap_isempty(u->requires_mounts_for)) {
+ UnitDependencyInfo di;
+ const char *path;
+
+ HASHMAP_FOREACH_KEY(di.data, path, u->requires_mounts_for, i) {
+ bool space = false;
- STRV_FOREACH(j, u->requires_mounts_for)
- fprintf(f, " %s", *j);
+ fprintf(f, "%s\tRequiresMountsFor: %s (", prefix, path);
- fputs("\n", f);
+ print_unit_dependency_mask(f, "origin", di.origin_mask, &space);
+ print_unit_dependency_mask(f, "destination", di.destination_mask, &space);
+
+ fputs(")\n", f);
+ }
}
if (u->load_state == UNIT_LOADED) {
return 0;
/* Don't create loops */
- if (set_get(target->dependencies[UNIT_BEFORE], u))
+ if (hashmap_get(target->dependencies[UNIT_BEFORE], u))
return 0;
- return unit_add_dependency(target, UNIT_AFTER, u, true);
+ return unit_add_dependency(target, UNIT_AFTER, u, true, UNIT_DEPENDENCY_DEFAULT);
}
static int unit_add_target_dependencies(Unit *u) {
UNIT_BOUND_BY
};
- Unit *target;
- Iterator i;
unsigned k;
int r = 0;
assert(u);
- for (k = 0; k < ELEMENTSOF(deps); k++)
- SET_FOREACH(target, u->dependencies[deps[k]], i) {
+ for (k = 0; k < ELEMENTSOF(deps); k++) {
+ Unit *target;
+ Iterator i;
+ void *v;
+
+ HASHMAP_FOREACH_KEY(v, target, u->dependencies[deps[k]], i) {
r = unit_add_default_target_dependency(u, target);
if (r < 0)
return r;
}
+ }
return r;
}
static int unit_add_slice_dependencies(Unit *u) {
+ UnitDependencyMask mask;
assert(u);
if (!UNIT_HAS_CGROUP_CONTEXT(u))
return 0;
+ /* Slice units are implicitly ordered against their parent slices (as this relationship is encoded in the
+ name), while all other units are ordered based on configuration (as in their case Slice= configures the
+ relationship). */
+ mask = u->type == UNIT_SLICE ? UNIT_DEPENDENCY_IMPLICIT : UNIT_DEPENDENCY_FILE;
+
if (UNIT_ISSET(u->slice))
- return unit_add_two_dependencies(u, UNIT_AFTER, UNIT_REQUIRES, UNIT_DEREF(u->slice), true);
+ return unit_add_two_dependencies(u, UNIT_AFTER, UNIT_REQUIRES, UNIT_DEREF(u->slice), true, mask);
if (unit_has_name(u, SPECIAL_ROOT_SLICE))
return 0;
- return unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_REQUIRES, SPECIAL_ROOT_SLICE, NULL, true);
+ return unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_REQUIRES, SPECIAL_ROOT_SLICE, NULL, true, mask);
}
static int unit_add_mount_dependencies(Unit *u) {
- char **i;
+ UnitDependencyInfo di;
+ const char *path;
+ Iterator i;
int r;
assert(u);
- STRV_FOREACH(i, u->requires_mounts_for) {
- char prefix[strlen(*i) + 1];
+ HASHMAP_FOREACH_KEY(di.data, path, u->requires_mounts_for, i) {
+ char prefix[strlen(path) + 1];
- PATH_FOREACH_PREFIX_MORE(prefix, *i) {
+ PATH_FOREACH_PREFIX_MORE(prefix, path) {
_cleanup_free_ char *p = NULL;
Unit *m;
if (m->load_state != UNIT_LOADED)
continue;
- r = unit_add_dependency(u, UNIT_AFTER, m, true);
+ r = unit_add_dependency(u, UNIT_AFTER, m, true, di.origin_mask);
if (r < 0)
return r;
if (m->fragment_path) {
- r = unit_add_dependency(u, UNIT_REQUIRES, m, true);
+ r = unit_add_dependency(u, UNIT_REQUIRES, m, true, di.origin_mask);
if (r < 0)
return r;
}
if (r < 0)
goto fail;
- if (u->on_failure_job_mode == JOB_ISOLATE && set_size(u->dependencies[UNIT_ON_FAILURE]) > 1) {
+ if (u->on_failure_job_mode == JOB_ISOLATE && hashmap_size(u->dependencies[UNIT_ON_FAILURE]) > 1) {
log_unit_error(u, "More than one OnFailure= dependencies specified but OnFailureJobMode=isolate set. Refusing.");
r = -EINVAL;
goto fail;
static bool unit_verify_deps(Unit *u) {
Unit *other;
Iterator j;
+ void *v;
assert(u);
* processing, but do not have any effect afterwards. We don't check BindsTo= dependencies that are not used in
* conjunction with After= as for them any such check would make things entirely racy. */
- SET_FOREACH(other, u->dependencies[UNIT_BINDS_TO], j) {
+ HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_BINDS_TO], j) {
- if (!set_contains(u->dependencies[UNIT_AFTER], other))
+ if (!hashmap_contains(u->dependencies[UNIT_AFTER], other))
continue;
if (!UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(other))) {
if (UNIT_VTABLE(u)->can_reload)
return UNIT_VTABLE(u)->can_reload(u);
- if (!set_isempty(u->dependencies[UNIT_PROPAGATES_RELOAD_TO]))
+ if (!hashmap_isempty(u->dependencies[UNIT_PROPAGATES_RELOAD_TO]))
return true;
return UNIT_VTABLE(u)->reload;
UNIT_BOUND_BY,
};
- Unit *other;
- Iterator i;
unsigned j;
int r;
if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u)))
return;
- for (j = 0; j < ELEMENTSOF(needed_dependencies); j++)
- SET_FOREACH(other, u->dependencies[needed_dependencies[j]], i)
+ for (j = 0; j < ELEMENTSOF(needed_dependencies); j++) {
+ Unit *other;
+ Iterator i;
+ void *v;
+
+ HASHMAP_FOREACH_KEY(v, other, u->dependencies[needed_dependencies[j]], i)
if (unit_active_or_pending(other))
return;
+ }
/* If stopping a unit fails continuously we might enter a stop
* loop here, hence stop acting on the service being
bool stop = false;
Unit *other;
Iterator i;
+ void *v;
int r;
assert(u);
if (unit_active_state(u) != UNIT_ACTIVE)
return;
- SET_FOREACH(other, u->dependencies[UNIT_BINDS_TO], i) {
+ HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_BINDS_TO], i) {
if (other->job)
continue;
static void retroactively_start_dependencies(Unit *u) {
Iterator i;
Unit *other;
+ void *v;
assert(u);
assert(UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u)));
- SET_FOREACH(other, u->dependencies[UNIT_REQUIRES], i)
- if (!set_get(u->dependencies[UNIT_AFTER], other) &&
+ HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_REQUIRES], i)
+ if (!hashmap_get(u->dependencies[UNIT_AFTER], other) &&
!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, NULL, NULL);
- SET_FOREACH(other, u->dependencies[UNIT_BINDS_TO], i)
- if (!set_get(u->dependencies[UNIT_AFTER], other) &&
+ HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_BINDS_TO], i)
+ if (!hashmap_get(u->dependencies[UNIT_AFTER], other) &&
!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, NULL, NULL);
- SET_FOREACH(other, u->dependencies[UNIT_WANTS], i)
- if (!set_get(u->dependencies[UNIT_AFTER], other) &&
+ HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_WANTS], i)
+ if (!hashmap_get(u->dependencies[UNIT_AFTER], other) &&
!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
manager_add_job(u->manager, JOB_START, other, JOB_FAIL, NULL, NULL);
- SET_FOREACH(other, u->dependencies[UNIT_CONFLICTS], i)
+ HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_CONFLICTS], i)
if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, NULL, NULL);
- SET_FOREACH(other, u->dependencies[UNIT_CONFLICTED_BY], i)
+ HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_CONFLICTED_BY], i)
if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, NULL, NULL);
}
static void retroactively_stop_dependencies(Unit *u) {
- Iterator i;
Unit *other;
+ Iterator i;
+ void *v;
assert(u);
assert(UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(u)));
/* Pull down units which are bound to us recursively if enabled */
- SET_FOREACH(other, u->dependencies[UNIT_BOUND_BY], i)
+ HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_BOUND_BY], i)
if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, NULL, NULL);
}
static void check_unneeded_dependencies(Unit *u) {
- Iterator i;
Unit *other;
+ Iterator i;
+ void *v;
assert(u);
assert(UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(u)));
/* Garbage collect services that might not be needed anymore, if enabled */
- SET_FOREACH(other, u->dependencies[UNIT_REQUIRES], i)
+ HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_REQUIRES], i)
if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
unit_check_unneeded(other);
- SET_FOREACH(other, u->dependencies[UNIT_WANTS], i)
+ HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_WANTS], i)
if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
unit_check_unneeded(other);
- SET_FOREACH(other, u->dependencies[UNIT_REQUISITE], i)
+ HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_REQUISITE], i)
if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
unit_check_unneeded(other);
- SET_FOREACH(other, u->dependencies[UNIT_BINDS_TO], i)
+ HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_BINDS_TO], i)
if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
unit_check_unneeded(other);
}
void unit_start_on_failure(Unit *u) {
Unit *other;
Iterator i;
+ void *v;
assert(u);
- if (set_size(u->dependencies[UNIT_ON_FAILURE]) <= 0)
+ if (hashmap_size(u->dependencies[UNIT_ON_FAILURE]) <= 0)
return;
log_unit_info(u, "Triggering OnFailure= dependencies.");
- SET_FOREACH(other, u->dependencies[UNIT_ON_FAILURE], i) {
+ HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_ON_FAILURE], i) {
int r;
r = manager_add_job(u->manager, JOB_START, other, u->on_failure_job_mode, NULL, NULL);
void unit_trigger_notify(Unit *u) {
Unit *other;
Iterator i;
+ void *v;
assert(u);
- SET_FOREACH(other, u->dependencies[UNIT_TRIGGERED_BY], i)
+ HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_TRIGGERED_BY], i)
if (UNIT_VTABLE(other)->trigger_notify)
UNIT_VTABLE(other)->trigger_notify(other, u);
}
log_unit_warning(u, "Dependency %s=%s dropped, merged into %s", unit_dependency_to_string(dependency), strna(other), u->id);
}
-int unit_add_dependency(Unit *u, UnitDependency d, Unit *other, bool add_reference) {
+static int unit_add_dependency_hashmap(
+ Hashmap **h,
+ Unit *other,
+ UnitDependencyMask origin_mask,
+ UnitDependencyMask destination_mask) {
+
+ UnitDependencyInfo info;
+ int r;
+
+ assert(h);
+ assert(other);
+ assert(origin_mask < _UNIT_DEPENDENCY_MASK_FULL);
+ assert(destination_mask < _UNIT_DEPENDENCY_MASK_FULL);
+ assert(origin_mask > 0 || destination_mask > 0);
+
+ r = hashmap_ensure_allocated(h, NULL);
+ if (r < 0)
+ return r;
+
+ assert_cc(sizeof(void*) == sizeof(info));
+
+ info.data = hashmap_get(*h, other);
+ if (info.data) {
+ /* Entry already exists. Add in our mask. */
+
+ if ((info.origin_mask & origin_mask) == info.origin_mask &&
+ (info.destination_mask & destination_mask) == info.destination_mask)
+ return 0; /* NOP */
+
+ info.origin_mask |= origin_mask;
+ info.destination_mask |= destination_mask;
+
+ r = hashmap_update(*h, other, info.data);
+ } else {
+ info = (UnitDependencyInfo) {
+ .origin_mask = origin_mask,
+ .destination_mask = destination_mask,
+ };
+
+ r = hashmap_put(*h, other, info.data);
+ }
+ if (r < 0)
+ return r;
+
+ return 1;
+}
+
+int unit_add_dependency(
+ Unit *u,
+ UnitDependency d,
+ Unit *other,
+ bool add_reference,
+ UnitDependencyMask mask) {
static const UnitDependency inverse_table[_UNIT_DEPENDENCY_MAX] = {
[UNIT_REQUIRES] = UNIT_REQUIRED_BY,
[UNIT_RELOAD_PROPAGATED_FROM] = UNIT_PROPAGATES_RELOAD_TO,
[UNIT_JOINS_NAMESPACE_OF] = UNIT_JOINS_NAMESPACE_OF,
};
- int r, q = 0, v = 0, w = 0;
- Unit *orig_u = u, *orig_other = other;
+ Unit *original_u = u, *original_other = other;
+ int r;
assert(u);
assert(d >= 0 && d < _UNIT_DEPENDENCY_MAX);
/* We won't allow dependencies on ourselves. We will not
* consider them an error however. */
if (u == other) {
- maybe_warn_about_dependency(orig_u, orig_other->id, d);
+ maybe_warn_about_dependency(original_u, original_other->id, d);
return 0;
}
- if (d == UNIT_BEFORE && other->type == UNIT_DEVICE) {
+ if ((d == UNIT_BEFORE && other->type == UNIT_DEVICE) ||
+ (d == UNIT_AFTER && u->type == UNIT_DEVICE)) {
log_unit_warning(u, "Dependency Before=%s ignored (.device units cannot be delayed)", other->id);
return 0;
}
- r = set_ensure_allocated(&u->dependencies[d], NULL);
+ r = unit_add_dependency_hashmap(u->dependencies + d, other, mask, 0);
if (r < 0)
return r;
- if (inverse_table[d] != _UNIT_DEPENDENCY_INVALID) {
- r = set_ensure_allocated(&other->dependencies[inverse_table[d]], NULL);
+ if (inverse_table[d] != _UNIT_DEPENDENCY_INVALID && inverse_table[d] != d) {
+ r = unit_add_dependency_hashmap(other->dependencies + inverse_table[d], u, 0, mask);
if (r < 0)
return r;
}
if (add_reference) {
- r = set_ensure_allocated(&u->dependencies[UNIT_REFERENCES], NULL);
+ r = unit_add_dependency_hashmap(u->dependencies + UNIT_REFERENCES, other, mask, 0);
if (r < 0)
return r;
- r = set_ensure_allocated(&other->dependencies[UNIT_REFERENCED_BY], NULL);
+ r = unit_add_dependency_hashmap(other->dependencies + UNIT_REFERENCED_BY, u, 0, mask);
if (r < 0)
return r;
}
- q = set_put(u->dependencies[d], other);
- if (q < 0)
- return q;
-
- 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) {
- w = set_put(u->dependencies[UNIT_REFERENCES], other);
- if (w < 0) {
- r = w;
- goto fail;
- }
-
- r = set_put(other->dependencies[UNIT_REFERENCED_BY], u);
- if (r < 0)
- goto fail;
- }
-
unit_add_to_dbus_queue(u);
return 0;
-
-fail:
- if (q > 0)
- set_remove(u->dependencies[d], other);
-
- if (v > 0)
- set_remove(other->dependencies[inverse_table[d]], u);
-
- if (w > 0)
- set_remove(u->dependencies[UNIT_REFERENCES], other);
-
- return r;
}
-int unit_add_two_dependencies(Unit *u, UnitDependency d, UnitDependency e, Unit *other, bool add_reference) {
+int unit_add_two_dependencies(Unit *u, UnitDependency d, UnitDependency e, Unit *other, bool add_reference, UnitDependencyMask mask) {
int r;
assert(u);
- r = unit_add_dependency(u, d, other, add_reference);
+ r = unit_add_dependency(u, d, other, add_reference, mask);
if (r < 0)
return r;
- return unit_add_dependency(u, e, other, add_reference);
+ return unit_add_dependency(u, e, other, add_reference, mask);
}
static int resolve_template(Unit *u, const char *name, const char*path, char **buf, const char **ret) {
return 0;
}
-int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, const char *path, bool add_reference) {
+int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, const char *path, bool add_reference, UnitDependencyMask mask) {
_cleanup_free_ char *buf = NULL;
Unit *other;
int r;
if (r < 0)
return r;
- return unit_add_dependency(u, d, other, add_reference);
+ return unit_add_dependency(u, d, other, add_reference, mask);
}
-int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference) {
+int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference, UnitDependencyMask mask) {
_cleanup_free_ char *buf = NULL;
Unit *other;
int r;
if (r < 0)
return r;
- return unit_add_two_dependencies(u, d, e, other, add_reference);
+ return unit_add_two_dependencies(u, d, e, other, add_reference, mask);
}
int set_unit_path(const char *p) {
}
-int unit_add_node_link(Unit *u, const char *what, bool wants, UnitDependency dep) {
+int unit_add_node_dependency(Unit *u, const char *what, bool wants, UnitDependency dep, UnitDependencyMask mask) {
Unit *device;
_cleanup_free_ char *e = NULL;
int r;
r = unit_add_two_dependencies(u, UNIT_AFTER,
MANAGER_IS_SYSTEM(u->manager) ? dep : UNIT_WANTS,
- device, true);
+ device, true, mask);
if (r < 0)
return r;
if (wants) {
- r = unit_add_dependency(device, UNIT_WANTS, u, false);
+ r = unit_add_dependency(device, UNIT_WANTS, u, false, mask);
if (r < 0)
return r;
}
return wait_for_exit;
}
-int unit_require_mounts_for(Unit *u, const char *path) {
+int unit_require_mounts_for(Unit *u, const char *path, UnitDependencyMask mask) {
char prefix[strlen(path) + 1], *p;
+ UnitDependencyInfo di;
int r;
assert(u);
assert(path);
- /* Registers a unit for requiring a certain path and all its
- * prefixes. We keep a simple array of these paths in the
- * unit, since its usually short. However, we build a prefix
- * table for all possible prefixes so that new appearing mount
- * units can easily determine which units to make themselves a
- * dependency of. */
+ /* Registers a unit for requiring a certain path and all its prefixes. We keep a hashtable of these paths in
+ * the unit (from the path to the UnitDependencyInfo structure indicating how to the dependency came to
+ * be). However, we build a prefix table for all possible prefixes so that new appearing mount units can easily
+ * determine which units to make themselves a dependency of. */
if (!path_is_absolute(path))
return -EINVAL;
+ r = hashmap_ensure_allocated(&u->requires_mounts_for, &string_hash_ops);
+ if (r < 0)
+ return r;
+
p = strdup(path);
if (!p)
return -ENOMEM;
return -EPERM;
}
- if (strv_contains(u->requires_mounts_for, p)) {
+ if (hashmap_contains(u->requires_mounts_for, p)) {
free(p);
return 0;
}
- r = strv_consume(&u->requires_mounts_for, p);
- if (r < 0)
+ di = (UnitDependencyInfo) {
+ .origin_mask = mask
+ };
+
+ r = hashmap_put(u->requires_mounts_for, p, di.data);
+ if (r < 0) {
+ free(p);
return r;
+ }
PATH_FOREACH_PREFIX_MORE(prefix, p) {
Set *x;
int unit_setup_exec_runtime(Unit *u) {
ExecRuntime **rt;
size_t offset;
- Iterator i;
Unit *other;
+ Iterator i;
+ void *v;
offset = UNIT_VTABLE(u)->exec_runtime_offset;
assert(offset > 0);
return 0;
/* Try to get it from somebody else */
- SET_FOREACH(other, u->dependencies[UNIT_JOINS_NAMESPACE_OF], i) {
+ HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_JOINS_NAMESPACE_OF], i) {
*rt = unit_get_exec_runtime(other);
if (*rt) {
return IN_SET(t, UNIT_INACTIVE, UNIT_FAILED);
}
+/* Stores the 'reason' a dependency was created as a bit mask, i.e. due to which configuration source it came to be. We
+ * use this so that we can selectively flush out parts of dependencies again. Note that the same dependency might be
+ * created as a result of multiple "reasons", hence the bitmask. */
+typedef enum UnitDependencyMask {
+ /* Configured directly by the unit file, .wants/.requries symlink or drop-in, or as an immediate result of a
+ * non-dependency option configured that way. */
+ UNIT_DEPENDENCY_FILE = 1 << 0,
+
+ /* As unconditional implicit dependency (not affected by unit configuration — except by the unit name and
+ * type) */
+ UNIT_DEPENDENCY_IMPLICIT = 1 << 1,
+
+ /* A dependency effected by DefaultDependencies=yes. Note that dependencies marked this way are conceptually
+ * just a subset of UNIT_DEPENDENCY_FILE, as DefaultDependencies= is itself a unit file setting that can only
+ * be set in unit files. We make this two separate bits only to help debugging how dependencies came to be. */
+ UNIT_DEPENDENCY_DEFAULT = 1 << 2,
+
+ /* A dependency created from udev rules */
+ UNIT_DEPENDENCY_UDEV = 1 << 3,
+
+ /* A dependency created because of some unit's RequiresMountsFor= setting */
+ UNIT_DEPENDENCY_PATH = 1 << 4,
+
+ /* A dependency created because of data read from /proc/self/mountinfo and no other configuration source */
+ UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT = 1 << 5,
+
+ /* A dependency created because of data read from /proc/self/mountinfo, but conditionalized by
+ * DefaultDependencies= and thus also involving configuration from UNIT_DEPENDENCY_FILE sources */
+ UNIT_DEPENDENCY_MOUNTINFO_DEFAULT = 1 << 6,
+
+ /* A dependency created because of data read from /proc/swaps and no other configuration source */
+ UNIT_DEPENDENCY_PROC_SWAP = 1 << 7,
+
+ _UNIT_DEPENDENCY_MASK_FULL = (1 << 8) - 1,
+} UnitDependencyMask;
+
+/* The Unit's dependencies[] hashmaps use this structure as value. It has the same size as a void pointer, and thus can
+ * be stored directly as hashmap value, without any indirection. Note that this stores two masks, as both the origin
+ * and the destination of a dependency might have created it. */
+typedef union UnitDependencyInfo {
+ void *data;
+ struct {
+ UnitDependencyMask origin_mask:16;
+ UnitDependencyMask destination_mask:16;
+ } _packed_;
+} UnitDependencyInfo;
+
#include "job.h"
struct UnitRef {
char *instance;
Set *names;
- Set *dependencies[_UNIT_DEPENDENCY_MAX];
- char **requires_mounts_for;
+ /* For each dependency type we maintain a Hashmap whose key is the Unit* object, and the value encodes why the
+ * dependency exists, using the UnitDependencyInfo type */
+ Hashmap *dependencies[_UNIT_DEPENDENCY_MAX];
+
+ /* Similar, for RequiresMountsFor= path dependencies. The key is the path, the value the UnitDependencyInfo type */
+ Hashmap *requires_mounts_for;
char *description;
char **documentation;
#define UNIT_HAS_CGROUP_CONTEXT(u) (UNIT_VTABLE(u)->cgroup_context_offset > 0)
#define UNIT_HAS_KILL_CONTEXT(u) (UNIT_VTABLE(u)->kill_context_offset > 0)
-#define UNIT_TRIGGER(u) ((Unit*) set_first((u)->dependencies[UNIT_TRIGGERS]))
+#define UNIT_TRIGGER(u) ((Unit*) hashmap_first_key((u)->dependencies[UNIT_TRIGGERS]))
DEFINE_CAST(SERVICE, Service);
DEFINE_CAST(SOCKET, Socket);
int unit_new_for_name(Manager *m, size_t size, const char *name, Unit **ret);
int unit_add_name(Unit *u, const char *name);
-int unit_add_dependency(Unit *u, UnitDependency d, Unit *other, bool add_reference);
-int unit_add_two_dependencies(Unit *u, UnitDependency d, UnitDependency e, Unit *other, bool add_reference);
+int unit_add_dependency(Unit *u, UnitDependency d, Unit *other, bool add_reference, UnitDependencyMask mask);
+int unit_add_two_dependencies(Unit *u, UnitDependency d, UnitDependency e, Unit *other, bool add_reference, UnitDependencyMask mask);
-int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, const char *filename, bool add_reference);
-int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference);
+int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, const char *filename, bool add_reference, UnitDependencyMask mask);
+int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference, UnitDependencyMask mask);
int unit_add_exec_dependencies(Unit *u, ExecContext *c);
int unit_serialize_item_fd(Unit *u, FILE *f, FDSet *fds, const char *key, int fd);
void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *value, ...) _printf_(4,5);
-int unit_add_node_link(Unit *u, const char *what, bool wants, UnitDependency d);
+int unit_add_node_dependency(Unit *u, const char *what, bool wants, UnitDependency d, UnitDependencyMask mask);
int unit_coldplug(Unit *u);
int unit_make_transient(Unit *u);
-int unit_require_mounts_for(Unit *u, const char *path);
+int unit_require_mounts_for(Unit *u, const char *path, UnitDependencyMask mask);
bool unit_type_supported(UnitType t);