core: rework logic to drop duplicate and non-existing items from search path
Move this into a function of its own, so that we can run it after we ran the generators, so that it takes into account removed generator dirs.
This commit is contained in:
parent
cd64fd5613
commit
a145334304
|
@ -1120,6 +1120,7 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
lookup_paths_reduce(&m->lookup_paths);
|
||||
manager_build_unit_path_cache(m);
|
||||
|
||||
/* If we will deserialize make sure that during enumeration
|
||||
|
@ -2540,6 +2541,7 @@ int manager_reload(Manager *m) {
|
|||
if (q < 0 && r >= 0)
|
||||
r = q;
|
||||
|
||||
lookup_paths_reduce(&m->lookup_paths);
|
||||
manager_build_unit_path_cache(m);
|
||||
|
||||
/* First, enumerate what we can from all config files */
|
||||
|
|
|
@ -412,6 +412,22 @@ static int patch_root_prefix(char **p, const char *root_dir) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int patch_root_prefix_strv(char **l, const char *root_dir) {
|
||||
char **i;
|
||||
int r;
|
||||
|
||||
if (!root_dir)
|
||||
return 0;
|
||||
|
||||
STRV_FOREACH(i, l) {
|
||||
r = patch_root_prefix(i, root_dir);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lookup_paths_init(
|
||||
LookupPaths *p,
|
||||
UnitFileScope scope,
|
||||
|
@ -579,23 +595,11 @@ int lookup_paths_init(
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!path_strv_resolve_uniq(l, root))
|
||||
r = patch_root_prefix_strv(l, root);
|
||||
if (r < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
if (strv_isempty(l)) {
|
||||
log_debug("Ignoring unit files.");
|
||||
l = strv_free(l);
|
||||
} else {
|
||||
_cleanup_free_ char *t;
|
||||
|
||||
t = strv_join(l, "\n\t");
|
||||
if (!t)
|
||||
return -ENOMEM;
|
||||
|
||||
log_debug("Looking for unit files in (higher priority first):\n\t%s", t);
|
||||
}
|
||||
|
||||
p->search_path = l;
|
||||
p->search_path = strv_uniq(l);
|
||||
l = NULL;
|
||||
|
||||
p->persistent_config = persistent_config;
|
||||
|
@ -634,6 +638,79 @@ void lookup_paths_free(LookupPaths *p) {
|
|||
p->root_dir = mfree(p->root_dir);
|
||||
}
|
||||
|
||||
int lookup_paths_reduce(LookupPaths *p) {
|
||||
_cleanup_free_ struct stat *stats = NULL;
|
||||
size_t n_stats = 0, allocated = 0;
|
||||
unsigned c = 0;
|
||||
int r;
|
||||
|
||||
assert(p);
|
||||
|
||||
/* Drop duplicates and non-existing directories from the search path. We figure out whether two directories are
|
||||
* the same by comparing their device and inode numbers. Note one special tweak: when we have a root path set,
|
||||
* we do not follow symlinks when retrieving them, because the kernel wouldn't take the root prefix into
|
||||
* account when following symlinks. When we have no root path set this restriction does not apply however. */
|
||||
|
||||
if (!p->search_path)
|
||||
return 0;
|
||||
|
||||
while (p->search_path[c]) {
|
||||
struct stat st;
|
||||
unsigned k;
|
||||
|
||||
if (p->root_dir)
|
||||
r = lstat(p->search_path[c], &st);
|
||||
else
|
||||
r = stat(p->search_path[c], &st);
|
||||
if (r < 0) {
|
||||
if (errno == ENOENT)
|
||||
goto remove_item;
|
||||
|
||||
/* If something we don't grok happened, let's better leave it in. */
|
||||
log_debug_errno(errno, "Failed to stat %s: %m", p->search_path[c]);
|
||||
c++;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (k = 0; k < n_stats; k++) {
|
||||
if (stats[k].st_dev == st.st_dev &&
|
||||
stats[k].st_ino == st.st_ino)
|
||||
break;
|
||||
}
|
||||
|
||||
if (k < n_stats) /* Is there already an entry with the same device/inode? */
|
||||
goto remove_item;
|
||||
|
||||
if (!GREEDY_REALLOC(stats, allocated, n_stats+1))
|
||||
return -ENOMEM;
|
||||
|
||||
stats[n_stats++] = st;
|
||||
c++;
|
||||
continue;
|
||||
|
||||
remove_item:
|
||||
free(p->search_path[c]);
|
||||
memmove(p->search_path + c,
|
||||
p->search_path + c + 1,
|
||||
(strv_length(p->search_path + c + 1) + 1) * sizeof(char*));
|
||||
}
|
||||
|
||||
if (strv_isempty(p->search_path)) {
|
||||
log_debug("Ignoring unit files.");
|
||||
p->search_path = strv_free(p->search_path);
|
||||
} else {
|
||||
_cleanup_free_ char *t;
|
||||
|
||||
t = strv_join(p->search_path, "\n\t");
|
||||
if (!t)
|
||||
return -ENOMEM;
|
||||
|
||||
log_debug("Looking for unit files in (higher priority first):\n\t%s", t);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lookup_paths_mkdir_generator(LookupPaths *p) {
|
||||
int r, q;
|
||||
|
||||
|
|
|
@ -52,6 +52,8 @@ char **generator_paths(UnitFileScope scope);
|
|||
|
||||
int lookup_paths_init(LookupPaths *p, UnitFileScope scope, const char *root_dir);
|
||||
|
||||
int lookup_paths_reduce(LookupPaths *p);
|
||||
|
||||
int lookup_paths_mkdir_generator(LookupPaths *p);
|
||||
void lookup_paths_trim_generator(LookupPaths *p);
|
||||
|
||||
|
|
|
@ -36,8 +36,8 @@ static void test_paths(UnitFileScope scope) {
|
|||
assert_se(mkdtemp(template));
|
||||
|
||||
assert_se(unsetenv("SYSTEMD_UNIT_PATH") == 0);
|
||||
assert_se(lookup_paths_init(&lp_without_env, scope, NULL) == 0);
|
||||
|
||||
assert_se(lookup_paths_init(&lp_without_env, scope, NULL) >= 0);
|
||||
assert_se(lookup_paths_reduce(&lp_without_env) >= 0);
|
||||
assert_se(!strv_isempty(lp_without_env.search_path));
|
||||
|
||||
systemd_unit_path = strjoina(template, "/systemd-unit-path");
|
||||
|
@ -45,6 +45,8 @@ static void test_paths(UnitFileScope scope) {
|
|||
assert_se(lookup_paths_init(&lp_with_env, scope, NULL) == 0);
|
||||
assert_se(strv_length(lp_with_env.search_path) == 1);
|
||||
assert_se(streq(lp_with_env.search_path[0], systemd_unit_path));
|
||||
assert_se(lookup_paths_reduce(&lp_with_env) >= 0);
|
||||
assert_se(strv_length(lp_with_env.search_path) == 0);
|
||||
|
||||
assert_se(rm_rf(template, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue