diff --git a/TODO b/TODO index 3154fbd165..37a57130dd 100644 --- a/TODO +++ b/TODO @@ -16,8 +16,6 @@ Bugfixes: Cannot add dependency job for unit display-manager.service, ignoring: Unit display-manager.service failed to load: No such file or directory. See system logs and 'systemctl status display-manager.service' for details. -* systemctl --root=container/ set-default ... is totally borked. - * sd_bus_unref() is broken regarding self-references and "pseudo thread-safety". See the comment in sd_bus_unref() for more.. diff --git a/src/core/manager.c b/src/core/manager.c index 5772f402b1..1e3e1273ad 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -968,6 +968,7 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { r = lookup_paths_init( &m->lookup_paths, m->running_as, true, + NULL, m->generator_unit_path, m->generator_unit_path_early, m->generator_unit_path_late); @@ -2374,6 +2375,7 @@ int manager_reload(Manager *m) { q = lookup_paths_init( &m->lookup_paths, m->running_as, true, + NULL, m->generator_unit_path, m->generator_unit_path_early, m->generator_unit_path_late); diff --git a/src/shared/install.c b/src/shared/install.c index 2822e61880..487d0f660d 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -47,7 +47,9 @@ typedef struct { #define _cleanup_install_context_done_ _cleanup_(install_context_done) -static int lookup_paths_init_from_scope(LookupPaths *paths, UnitFileScope scope) { +static int lookup_paths_init_from_scope(LookupPaths *paths, + UnitFileScope scope, + const char *root_dir) { assert(paths); assert(scope >= 0); assert(scope < _UNIT_FILE_SCOPE_MAX); @@ -57,6 +59,7 @@ static int lookup_paths_init_from_scope(LookupPaths *paths, UnitFileScope scope) return lookup_paths_init(paths, scope == UNIT_FILE_SYSTEM ? SYSTEMD_SYSTEM : SYSTEMD_USER, scope == UNIT_FILE_USER, + root_dir, NULL, NULL, NULL); } @@ -701,7 +704,7 @@ int unit_file_link( assert(scope >= 0); assert(scope < _UNIT_FILE_SCOPE_MAX); - r = lookup_paths_init_from_scope(&paths, scope); + r = lookup_paths_init_from_scope(&paths, scope, root_dir); if (r < 0) return r; @@ -1473,7 +1476,7 @@ int unit_file_enable( assert(scope >= 0); assert(scope < _UNIT_FILE_SCOPE_MAX); - r = lookup_paths_init_from_scope(&paths, scope); + r = lookup_paths_init_from_scope(&paths, scope, root_dir); if (r < 0) return r; @@ -1513,7 +1516,7 @@ int unit_file_disable( assert(scope >= 0); assert(scope < _UNIT_FILE_SCOPE_MAX); - r = lookup_paths_init_from_scope(&paths, scope); + r = lookup_paths_init_from_scope(&paths, scope, root_dir); if (r < 0) return r; @@ -1577,7 +1580,7 @@ int unit_file_set_default( if (unit_name_to_type(file) != UNIT_TARGET) return -EINVAL; - r = lookup_paths_init_from_scope(&paths, scope); + r = lookup_paths_init_from_scope(&paths, scope, root_dir); if (r < 0) return r; @@ -1617,7 +1620,7 @@ int unit_file_get_default( assert(scope < _UNIT_FILE_SCOPE_MAX); assert(name); - r = lookup_paths_init_from_scope(&paths, scope); + r = lookup_paths_init_from_scope(&paths, scope, root_dir); if (r < 0) return r; @@ -1675,12 +1678,13 @@ UnitFileState unit_file_get_state( if (!unit_name_is_valid(name, TEMPLATE_VALID)) return -EINVAL; - r = lookup_paths_init_from_scope(&paths, scope); + r = lookup_paths_init_from_scope(&paths, scope, root_dir); if (r < 0) return r; STRV_FOREACH(i, paths.unit_path) { struct stat st; + char *partial; free(path); path = NULL; @@ -1689,10 +1693,14 @@ UnitFileState unit_file_get_state( asprintf(&path, "%s/%s/%s", root_dir, *i, name); else asprintf(&path, "%s/%s", *i, name); - if (!path) return -ENOMEM; + if (root_dir) + partial = path + strlen(root_dir) + 1; + else + partial = path; + /* * Search for a unit file in our default paths, to * be sure, that there are no broken symlinks. @@ -1724,7 +1732,7 @@ UnitFileState unit_file_get_state( else if (r > 0) return state; - r = unit_file_can_install(&paths, root_dir, path, true); + r = unit_file_can_install(&paths, root_dir, partial, true); if (r < 0 && errno != ENOENT) return r; else if (r > 0) @@ -1832,7 +1840,7 @@ int unit_file_preset( assert(scope >= 0); assert(scope < _UNIT_FILE_SCOPE_MAX); - r = lookup_paths_init_from_scope(&paths, scope); + r = lookup_paths_init_from_scope(&paths, scope, root_dir); if (r < 0) return r; @@ -1902,7 +1910,7 @@ int unit_file_get_list( if (root_dir && scope != UNIT_FILE_SYSTEM) return -EINVAL; - r = lookup_paths_init_from_scope(&paths, scope); + r = lookup_paths_init_from_scope(&paths, scope, root_dir); if (r < 0) return r; diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c index 63af43cdbb..c6b4ba1e22 100644 --- a/src/shared/path-lookup.c +++ b/src/shared/path-lookup.c @@ -198,6 +198,7 @@ int lookup_paths_init( LookupPaths *p, SystemdRunningAs running_as, bool personal, + const char *root_dir, const char *generator, const char *generator_early, const char *generator_late) { @@ -275,11 +276,9 @@ int lookup_paths_init( } } - if (!path_strv_canonicalize_absolute(p->unit_path, NULL)) + if (!path_strv_canonicalize_absolute_uniq(p->unit_path, root_dir)) return -ENOMEM; - strv_uniq(p->unit_path); - if (!strv_isempty(p->unit_path)) { _cleanup_free_ char *t = strv_join(p->unit_path, "\n\t"); if (!t) @@ -331,15 +330,12 @@ int lookup_paths_init( return -ENOMEM; } - if (!path_strv_canonicalize_absolute(p->sysvinit_path, NULL)) + if (!path_strv_canonicalize_absolute_uniq(p->sysvinit_path, root_dir)) return -ENOMEM; - if (!path_strv_canonicalize_absolute(p->sysvrcnd_path, NULL)) + if (!path_strv_canonicalize_absolute_uniq(p->sysvrcnd_path, root_dir)) return -ENOMEM; - strv_uniq(p->sysvinit_path); - strv_uniq(p->sysvrcnd_path); - if (!strv_isempty(p->sysvinit_path)) { _cleanup_free_ char *t = strv_join(p->sysvinit_path, "\n\t"); if (!t) diff --git a/src/shared/path-lookup.h b/src/shared/path-lookup.h index a3ef824a86..847a52f20a 100644 --- a/src/shared/path-lookup.h +++ b/src/shared/path-lookup.h @@ -43,5 +43,11 @@ SystemdRunningAs systemd_running_as_from_string(const char *s) _pure_; int user_config_home(char **config_home); -int lookup_paths_init(LookupPaths *p, SystemdRunningAs running_as, bool personal, const char *generator, const char *generator_early, const char *generator_late); +int lookup_paths_init(LookupPaths *p, + SystemdRunningAs running_as, + bool personal, + const char *root_dir, + const char *generator, + const char *generator_early, + const char *generator_late); void lookup_paths_free(LookupPaths *p); diff --git a/src/shared/path-util.c b/src/shared/path-util.c index 69fcb1660a..8bf9a3cf96 100644 --- a/src/shared/path-util.c +++ b/src/shared/path-util.c @@ -167,36 +167,63 @@ char **path_strv_canonicalize_absolute(char **l, const char *prefix) { STRV_FOREACH(s, l) { char *t, *u; + _cleanup_free_ char *orig = NULL; - if (!path_is_absolute(*s)) + if (!path_is_absolute(*s)) { + free(*s); continue; + } if (prefix) { - t = strappend(prefix, *s); - free(*s); - *s = NULL; - + orig = *s; + t = strappend(prefix, orig); if (!t) { enomem = true; continue; } - } else { + } else t = *s; - *s = NULL; - } errno = 0; u = canonicalize_file_name(t); if (!u) { - if (errno == ENOENT) - u = t; - else { + if (errno == ENOENT) { + if (prefix) { + u = orig; + orig = NULL; + free(t); + } else + u = t; + } else { free(t); if (errno == ENOMEM || errno == 0) enomem = true; continue; } + } else if (prefix) { + char *x; + + free(t); + x = path_startswith(u, prefix); + if (x) { + /* restore the slash if it was lost */ + if (!startswith(x, "/")) + *(--x) = '/'; + + t = strdup(x); + free(u); + if (!t) { + enomem = true; + continue; + } + u = t; + } else { + /* canonicalized path goes outside of + * prefix, keep the original path instead */ + u = orig; + orig = NULL; + } } else free(t); diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 91d8032945..a60a301988 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -5002,7 +5002,7 @@ static int enable_sysv_units(const char *verb, char **args) { /* Processes all SysV units, and reshuffles the array so that * afterwards only the native units remain */ - r = lookup_paths_init(&paths, SYSTEMD_SYSTEM, false, NULL, NULL, NULL); + r = lookup_paths_init(&paths, SYSTEMD_SYSTEM, false, arg_root, NULL, NULL, NULL); if (r < 0) return r;