From 9825181143530af7003fc50567b814dbbee39046 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Wed, 2 Mar 2022 16:53:54 +0100 Subject: [PATCH 01/43] basic/unit-file: split out the subroutine for symlink verification The old logs used __func__, but this doesn't make sense now, because the low-level function will be used in other places. So those are adjusted to be more generic. --- src/basic/unit-file.c | 163 +++++++++++++++++++++++++----------------- 1 file changed, 98 insertions(+), 65 deletions(-) diff --git a/src/basic/unit-file.c b/src/basic/unit-file.c index d44b886440..aeddf8401f 100644 --- a/src/basic/unit-file.c +++ b/src/basic/unit-file.c @@ -259,6 +259,83 @@ static int directory_name_is_valid(const char *name) { return false; } +static int unit_file_resolve_symlink( + const char *root_dir, + char **search_path, + const char *dir, + int dirfd, + const char *filename, + char **ret_destination) { + + _cleanup_free_ char *target = NULL, *simplified = NULL, *dst = NULL; + int r; + + assert(dir); + assert(dirfd >= 0); + assert(filename); + assert(ret_destination); + + r = readlinkat_malloc(dirfd, filename, &target); + if (r < 0) + return log_warning_errno(r, "Failed to read symlink %s%s%s: %m", + dir, dir ? "/" : "", filename); + + bool is_abs = path_is_absolute(target); + if (root_dir || !is_abs) { + char *target_abs = path_join(is_abs ? root_dir : dir, target); + if (!target_abs) + return log_oom(); + + free_and_replace(target, target_abs); + } + + /* Get rid of "." and ".." components in target path */ + r = chase_symlinks(target, root_dir, CHASE_NOFOLLOW | CHASE_NONEXISTENT, &simplified, NULL); + if (r < 0) + return log_warning_errno(r, "Failed to resolve symlink %s/%s pointing to %s: %m", + dir, filename, target); + + /* Check if the symlink goes outside of our search path. + * If yes, it's a linked unit file or mask, and we don't care about the target name. + * Let's just store the link source directly. + * If not, let's verify that it's a good symlink. */ + const char *tail = path_startswith_strv(simplified, search_path); + if (!tail) { + log_debug("Linked unit file: %s/%s → %s", dir, filename, simplified); + + dst = path_join(dir, filename); + if (!dst) + return log_oom(); + + } else { + r = path_extract_filename(simplified, &dst); + if (r < 0) + return r; + + bool self_alias = streq(dst, filename); + + if (is_path(tail)) + log_full(self_alias ? LOG_DEBUG : LOG_WARNING, + "Suspicious symlink %s/%s→%s, treating as alias.", + dir, filename, simplified); + + r = unit_validate_alias_symlink_and_warn(filename, simplified); + if (r < 0) + return r; + + if (self_alias) + /* A self-alias that has no effect */ + return log_debug_errno(SYNTHETIC_ERRNO(ELOOP), + "Unit file self-alias: %s/%s → %s, ignoring.", + dir, filename, dst); + + log_debug("Unit file alias: %s/%s → %s", dir, filename, dst); + } + + *ret_destination = TAKE_PTR(dst); + return 0; +} + int unit_file_build_name_map( const LookupPaths *lp, uint64_t *cache_timestamp_hash, @@ -308,10 +385,9 @@ int unit_file_build_name_map( FOREACH_DIRENT_ALL(de, d, log_warning_errno(errno, "Failed to read \"%s\", ignoring: %m", *dir)) { _unused_ _cleanup_free_ char *_filename_free = NULL; - _cleanup_free_ char *simplified = NULL; - bool symlink_to_dir = false; - const char *dst = NULL; char *filename; + _cleanup_free_ char *dst = NULL; + bool symlink_to_dir = false; /* We only care about valid units and dirs with certain suffixes, let's ignore the * rest. */ @@ -395,77 +471,34 @@ int unit_file_build_name_map( /* We don't explicitly check for alias loops here. unit_ids_map_get() which * limits the number of hops should be used to access the map. */ - _cleanup_free_ char *target = NULL; - - r = readlinkat_malloc(dirfd(d), de->d_name, &target); - if (r < 0) { - log_warning_errno(r, "Failed to read symlink %s/%s, ignoring: %m", - *dir, de->d_name); + r = unit_file_resolve_symlink(lp->root_dir, lp->search_path, + *dir, dirfd(d), de->d_name, + &dst); + if (r == -ENOMEM) + return r; + if (r < 0) /* we ignore other errors here */ continue; - } - - const bool is_abs = path_is_absolute(target); - if (lp->root_dir || !is_abs) { - char *target_abs = path_join(is_abs ? lp->root_dir : *dir, target); - if (!target_abs) - return log_oom(); - - free_and_replace(target, target_abs); - } - - /* Get rid of "." and ".." components in target path */ - r = chase_symlinks(target, lp->root_dir, CHASE_NOFOLLOW | CHASE_NONEXISTENT, &simplified, NULL); - if (r < 0) { - log_warning_errno(r, "Failed to resolve symlink %s pointing to %s, ignoring: %m", - filename, target); - continue; - } - - /* Check if the symlink goes outside of our search path. - * If yes, it's a linked unit file or mask, and we don't care about the target name. - * Let's just store the link source directly. - * If not, let's verify that it's a good symlink. */ - char *tail = path_startswith_strv(simplified, lp->search_path); - if (!tail) { - log_debug("%s: linked unit file: %s → %s", - __func__, filename, simplified); - - dst = filename; - } else { - - bool self_alias; - - dst = basename(simplified); - self_alias = streq(dst, de->d_name); - - if (is_path(tail)) - log_full(self_alias ? LOG_DEBUG : LOG_WARNING, - "Suspicious symlink %s→%s, treating as alias.", - filename, simplified); - - r = unit_validate_alias_symlink_and_warn(filename, simplified); - if (r < 0) - continue; - - if (self_alias) { - /* A self-alias that has no effect */ - log_debug("%s: self-alias: %s/%s → %s, ignoring.", - __func__, *dir, de->d_name, dst); - continue; - } - - log_debug("%s: alias: %s/%s → %s", __func__, *dir, de->d_name, dst); - } } else { - dst = filename; + dst = TAKE_PTR(_filename_free); /* Grab the copy we made previously, if available. */ + if (!dst) { + dst = strdup(filename); + if (!dst) + return log_oom(); + } + log_debug("%s: normal unit file: %s", __func__, dst); } - r = hashmap_put_strdup(&ids, de->d_name, dst); + _cleanup_free_ char *key = strdup(de->d_name); + if (!key) + return log_oom(); + + r = hashmap_ensure_put(&ids, &string_hash_ops_free_free, key, dst); if (r < 0) return log_warning_errno(r, "Failed to add entry to hashmap (%s→%s): %m", de->d_name, dst); + key = dst = NULL; } } From 48542eac39999f58f6c331b4b3cdf2d78bf15979 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Wed, 23 Mar 2022 17:47:33 +0100 Subject: [PATCH 02/43] basic/stat-util: add null_or_empty_path_with_root() --- src/basic/stat-util.c | 15 ++++++++++----- src/basic/stat-util.h | 6 +++++- src/test/test-stat-util.c | 24 ++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 6 deletions(-) diff --git a/src/basic/stat-util.c b/src/basic/stat-util.c index 96364b81ac..b25cabc6b4 100644 --- a/src/basic/stat-util.c +++ b/src/basic/stat-util.c @@ -127,17 +127,22 @@ bool null_or_empty(struct stat *st) { return false; } -int null_or_empty_path(const char *fn) { +int null_or_empty_path_with_root(const char *fn, const char *root) { struct stat st; + int r; assert(fn); - /* If we have the path, let's do an easy text comparison first. */ - if (path_equal(fn, "/dev/null")) + /* A symlink to /dev/null or an empty file? + * When looking under root_dir, we can't expect /dev/ to be mounted, + * so let's see if the path is a (possibly dangling) symlink to /dev/null. */ + + if (path_equal_ptr(path_startswith(fn, root ?: "/"), "dev/null")) return true; - if (stat(fn, &st) < 0) - return -errno; + r = chase_symlinks_and_stat(fn, root, CHASE_PREFIX_ROOT, NULL, &st, NULL); + if (r < 0) + return r; return null_or_empty(&st); } diff --git a/src/basic/stat-util.h b/src/basic/stat-util.h index 77732db05e..37513a43e7 100644 --- a/src/basic/stat-util.h +++ b/src/basic/stat-util.h @@ -31,9 +31,13 @@ static inline int dir_is_populated(const char *path) { } bool null_or_empty(struct stat *st) _pure_; -int null_or_empty_path(const char *fn); +int null_or_empty_path_with_root(const char *fn, const char *root); int null_or_empty_fd(int fd); +static inline int null_or_empty_path(const char *fn) { + return null_or_empty_path_with_root(fn, NULL); +} + int path_is_read_only_fs(const char *path); int files_same(const char *filea, const char *fileb, int flags); diff --git a/src/test/test-stat-util.c b/src/test/test-stat-util.c index 5f744b0288..9975a1848d 100644 --- a/src/test/test-stat-util.c +++ b/src/test/test-stat-util.c @@ -18,6 +18,30 @@ #include "tests.h" #include "tmpfile-util.h" +TEST(null_or_empty_path) { + assert_se(null_or_empty_path("/dev/null") == 1); + assert_se(null_or_empty_path("/dev/tty") == 1); /* We assume that any character device is "empty", bleh. */ + assert_se(null_or_empty_path("../../../../../../../../../../../../../../../../../../../../dev/null") == 1); + assert_se(null_or_empty_path("/proc/self/exe") == 0); + assert_se(null_or_empty_path("/nosuchfileordir") == -ENOENT); +} + +TEST(null_or_empty_path_with_root) { + assert_se(null_or_empty_path_with_root("/dev/null", NULL) == 1); + assert_se(null_or_empty_path_with_root("/dev/null", "/") == 1); + assert_se(null_or_empty_path_with_root("/dev/null", "/.././../") == 1); + assert_se(null_or_empty_path_with_root("/dev/null", "/.././..") == 1); + assert_se(null_or_empty_path_with_root("../../../../../../../../../../../../../../../../../../../../dev/null", NULL) == 1); + assert_se(null_or_empty_path_with_root("../../../../../../../../../../../../../../../../../../../../dev/null", "/") == 1); + assert_se(null_or_empty_path_with_root("/proc/self/exe", NULL) == 0); + assert_se(null_or_empty_path_with_root("/proc/self/exe", "/") == 0); + assert_se(null_or_empty_path_with_root("/nosuchfileordir", NULL) == -ENOENT); + assert_se(null_or_empty_path_with_root("/nosuchfileordir", "/.././../") == -ENOENT); + assert_se(null_or_empty_path_with_root("/nosuchfileordir", "/.././..") == -ENOENT); + assert_se(null_or_empty_path_with_root("/foobar/barbar/dev/null", "/foobar/barbar") == 1); + assert_se(null_or_empty_path_with_root("/foobar/barbar/dev/null", "/foobar/barbar/") == 1); +} + TEST(files_same) { _cleanup_close_ int fd = -1; char name[] = "/tmp/test-files_same.XXXXXX"; From 047d37dc3d376d912275c14d217f7a0dda9a5f0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 4 Mar 2022 18:47:31 +0100 Subject: [PATCH 03/43] shared/install: reuse the standard symlink verification subroutine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We save a few lines, but the important thing is that we don't have two different implementations with slightly different rules used for enablement and loading. Fixes #22000. Tested with: - the report in #22000, it now says: $ SYSTEMD_LOG_LEVEL=debug systemctl --root=/ enable test.service Suspicious symlink /etc/systemd/system/test.service→/etc/systemd/system/myown.d/test.service, treating as alias. unit_file_resolve_symlink: self-alias: /etc/systemd/system/test.service → test.service, ignoring. running_in_chroot(): Permission denied Suspicious symlink /etc/systemd/system/test.service→/etc/systemd/system/myown.d/test.service, treating as alias. unit_file_resolve_symlink: self-alias: /etc/systemd/system/test.service → test.service, ignoring. Failed to enable unit, refusing to operate on linked unit file test.service - a symlink to /dev/null: ... unit_file_resolve_symlink: linked unit file: /etc/systemd/system/test3.service → /dev/null Failed to enable unit, unit /etc/systemd/system/test3.service is masked. - the same from the host: ... unit_file_resolve_symlink: linked unit file: /var/lib/machines/rawhide/etc/systemd/system/test3.service → /var/lib/machines/rawhide/dev/null Failed to enable unit, unit /var/lib/machines/rawhide/etc/systemd/system/test3.service is masked. - through the manager: $ sudo systemctl enable test.service Failed to enable unit: Refusing to operate on alias name or linked unit file: test.service $ sudo systemctl enable test3.service Failed to enable unit: Unit file /etc/systemd/system/test3.service is masked. As seen in the first example, the warning is repeated. This is because we call the lookup logic twice: first for sysv-compat, and then again for real. I think that since this is only for broken setups, and when sysv-compat is enabled, and in an infrequent manual operation, at debug level, this is OK. --- src/basic/unit-file.c | 70 ++++++++++++++++++++++++++++++---------- src/basic/unit-file.h | 10 ++++++ src/shared/install.c | 74 +++++++------------------------------------ 3 files changed, 76 insertions(+), 78 deletions(-) diff --git a/src/basic/unit-file.c b/src/basic/unit-file.c index aeddf8401f..95256a7be9 100644 --- a/src/basic/unit-file.c +++ b/src/basic/unit-file.c @@ -259,27 +259,50 @@ static int directory_name_is_valid(const char *name) { return false; } -static int unit_file_resolve_symlink( +int unit_file_resolve_symlink( const char *root_dir, char **search_path, const char *dir, int dirfd, const char *filename, + bool resolve_destination_target, char **ret_destination) { - _cleanup_free_ char *target = NULL, *simplified = NULL, *dst = NULL; + _cleanup_free_ char *target = NULL, *simplified = NULL, *dst = NULL, *_dir = NULL, *_filename = NULL; int r; - assert(dir); - assert(dirfd >= 0); + /* This can be called with either dir+dirfd valid and filename just a name, + * or !dir && dirfd==AT_FDCWD, and filename being a full path. + * + * If resolve_destination_target is true, an absolute path will be returned. + * If not, an absolute path is returned for linked unit files, and a relative + * path otherwise. */ + assert(filename); assert(ret_destination); + assert(dir || path_is_absolute(filename)); + assert(dirfd >= 0 || dirfd == AT_FDCWD); r = readlinkat_malloc(dirfd, filename, &target); if (r < 0) return log_warning_errno(r, "Failed to read symlink %s%s%s: %m", dir, dir ? "/" : "", filename); + if (!dir) { + r = path_extract_directory(filename, &_dir); + if (r < 0) + return r; + dir = _dir; + + r = path_extract_filename(filename, &_filename); + if (r < 0) + return r; + if (r == O_DIRECTORY) + return log_warning_errno(SYNTHETIC_ERRNO(EISDIR), + "Unexpected path to a directory \"%s\", refusing.", filename); + filename = _filename; + } + bool is_abs = path_is_absolute(target); if (root_dir || !is_abs) { char *target_abs = path_join(is_abs ? root_dir : dir, target); @@ -295,24 +318,36 @@ static int unit_file_resolve_symlink( return log_warning_errno(r, "Failed to resolve symlink %s/%s pointing to %s: %m", dir, filename, target); + assert(path_is_absolute(simplified)); + /* Check if the symlink goes outside of our search path. - * If yes, it's a linked unit file or mask, and we don't care about the target name. - * Let's just store the link source directly. - * If not, let's verify that it's a good symlink. */ + * If yes, it's a linked unit file or mask, and we don't care about the target name + * when loading units, and we return the link *source* (resolve_destination_target == false); + * When this is called for installation purposes, we want the final destination, + * so we return the *target*. + * + * Otherwise, let's verify that it's a good alias. + */ const char *tail = path_startswith_strv(simplified, search_path); if (!tail) { log_debug("Linked unit file: %s/%s → %s", dir, filename, simplified); - dst = path_join(dir, filename); - if (!dst) - return log_oom(); + if (resolve_destination_target) + dst = TAKE_PTR(simplified); + else { + dst = path_join(dir, filename); + if (!dst) + return log_oom(); + } } else { - r = path_extract_filename(simplified, &dst); + _cleanup_free_ char *target_name = NULL; + + r = path_extract_filename(simplified, &target_name); if (r < 0) return r; - bool self_alias = streq(dst, filename); + bool self_alias = streq(target_name, filename); if (is_path(tail)) log_full(self_alias ? LOG_DEBUG : LOG_WARNING, @@ -323,13 +358,15 @@ static int unit_file_resolve_symlink( if (r < 0) return r; - if (self_alias) - /* A self-alias that has no effect */ + if (self_alias && !resolve_destination_target) + /* A self-alias that has no effect when loading, let's just ignore it. */ return log_debug_errno(SYNTHETIC_ERRNO(ELOOP), "Unit file self-alias: %s/%s → %s, ignoring.", - dir, filename, dst); + dir, filename, target_name); - log_debug("Unit file alias: %s/%s → %s", dir, filename, dst); + log_debug("Unit file alias: %s/%s → %s", dir, filename, target_name); + + dst = resolve_destination_target ? TAKE_PTR(simplified) : TAKE_PTR(target_name); } *ret_destination = TAKE_PTR(dst); @@ -473,6 +510,7 @@ int unit_file_build_name_map( r = unit_file_resolve_symlink(lp->root_dir, lp->search_path, *dir, dirfd(d), de->d_name, + /* resolve_destination_target= */ false, &dst); if (r == -ENOMEM) return r; diff --git a/src/basic/unit-file.h b/src/basic/unit-file.h index cc731a9e06..e29e878cfd 100644 --- a/src/basic/unit-file.h +++ b/src/basic/unit-file.h @@ -44,6 +44,16 @@ int unit_symlink_name_compatible(const char *symlink, const char *target, bool i int unit_validate_alias_symlink_and_warn(const char *filename, const char *target); bool lookup_paths_timestamp_hash_same(const LookupPaths *lp, uint64_t timestamp_hash, uint64_t *ret_new); + +int unit_file_resolve_symlink( + const char *root_dir, + char **search_path, + const char *dir, + int dirfd, + const char *filename, + bool resolve_destination_target, + char **ret_destination); + int unit_file_build_name_map( const LookupPaths *lp, uint64_t *cache_timestamp_hash, diff --git a/src/shared/install.c b/src/shared/install.c index 53b5418804..7d579003a0 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -1335,76 +1335,26 @@ static int unit_file_load_or_readlink( const char *path, const LookupPaths *lp, SearchFlags flags) { - - _cleanup_free_ char *resolved = NULL; int r; r = unit_file_load(c, info, path, lp->root_dir, flags); if (r != -ELOOP || (flags & SEARCH_DROPIN)) return r; - r = chase_symlinks(path, lp->root_dir, CHASE_WARN | CHASE_NONEXISTENT, &resolved, NULL); - if (r >= 0 && - lp->root_dir && - path_equal_ptr(path_startswith(resolved, lp->root_dir), "dev/null")) - /* When looking under root_dir, we can't expect /dev/ to be mounted, - * so let's see if the path is a (possibly dangling) symlink to /dev/null. */ + /* This is a symlink, let's read and verify it. */ + r = unit_file_resolve_symlink(lp->root_dir, lp->search_path, + NULL, AT_FDCWD, path, + true, &info->symlink_target); + if (r < 0) + return r; + + r = null_or_empty_path_with_root(info->symlink_target, lp->root_dir); + if (r < 0 && r != -ENOENT) + return log_debug_errno(r, "Failed to stat %s: %m", info->symlink_target); + if (r > 0) info->type = UNIT_FILE_TYPE_MASKED; - - else if (r > 0 && null_or_empty_path(resolved) > 0) - - info->type = UNIT_FILE_TYPE_MASKED; - - else { - _cleanup_free_ char *target = NULL; - const char *bn; - UnitType a, b; - - /* This is a symlink, let's read it. We read the link again, because last time - * we followed the link until resolution, and here we need to do one step. */ - - r = readlink_malloc(path, &target); - if (r < 0) - return r; - - bn = basename(target); - - if (unit_name_is_valid(info->name, UNIT_NAME_PLAIN)) { - - if (!unit_name_is_valid(bn, UNIT_NAME_PLAIN)) - return -EINVAL; - - } else if (unit_name_is_valid(info->name, UNIT_NAME_INSTANCE)) { - - if (!unit_name_is_valid(bn, UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE)) - return -EINVAL; - - } else if (unit_name_is_valid(info->name, UNIT_NAME_TEMPLATE)) { - - if (!unit_name_is_valid(bn, UNIT_NAME_TEMPLATE)) - return -EINVAL; - } else - return -EINVAL; - - /* Enforce that the symlink destination does not - * change the unit file type. */ - - a = unit_name_to_type(info->name); - b = unit_name_to_type(bn); - if (a < 0 || b < 0 || a != b) - return -EINVAL; - - if (path_is_absolute(target)) - /* This is an absolute path, prefix the root so that we always deal with fully qualified paths */ - info->symlink_target = path_join(lp->root_dir, target); - else - /* This is a relative path, take it relative to the dir the symlink is located in. */ - info->symlink_target = file_in_same_dir(path, target); - if (!info->symlink_target) - return -ENOMEM; - + else info->type = UNIT_FILE_TYPE_SYMLINK; - } return 0; } From e75a26d0457d67a3146ff2d90af07db22213da3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Thu, 3 Mar 2022 11:09:25 +0100 Subject: [PATCH 04/43] shared/install: add a bit more quoting When we are printing a valid unit name, quoting isn't necessary, because unit names cannot contain whitespace or other confusing characters. In particular if the unit name is prefixed by " unit " or something else that clearly identifies the string as a unit name, quoting would just add unnecessary noise. But when we're printing paths or invalid names, it's better to add quotes for clarity. --- src/shared/install.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/shared/install.c b/src/shared/install.c index 7d579003a0..e2fcf6cf62 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -338,7 +338,7 @@ void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *chang break; case UNIT_FILE_UNLINK: if (!quiet) - log_info("Removed %s.", changes[i].path); + log_info("Removed \"%s\".", changes[i].path); break; case UNIT_FILE_IS_MASKED: if (!quiet) @@ -361,11 +361,11 @@ void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *chang case -EEXIST: if (changes[i].source) log_error_errno(changes[i].type_or_errno, - "Failed to %s unit, file %s already exists and is a symlink to %s.", + "Failed to %s unit, file \"%s\" already exists and is a symlink to \"%s\".", verb, changes[i].path, changes[i].source); else log_error_errno(changes[i].type_or_errno, - "Failed to %s unit, file %s already exists.", + "Failed to %s unit, file \"%s\" already exists.", verb, changes[i].path); logged = true; break; @@ -391,7 +391,7 @@ void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *chang logged = true; break; case -ELOOP: - log_error_errno(changes[i].type_or_errno, "Failed to %s unit, refusing to operate on linked unit file %s", + log_error_errno(changes[i].type_or_errno, "Failed to %s unit, refusing to operate on linked unit file %s.", verb, changes[i].path); logged = true; break; @@ -403,7 +403,7 @@ void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *chang default: assert(changes[i].type_or_errno < 0); - log_error_errno(changes[i].type_or_errno, "Failed to %s unit, file %s: %m.", + log_error_errno(changes[i].type_or_errno, "Failed to %s unit, file \"%s\": %m", verb, changes[i].path); logged = true; } @@ -838,7 +838,7 @@ static int find_symlinks( d = opendir(path); if (!d) { - log_error_errno(errno, "Failed to open directory '%s' while scanning for symlinks, ignoring: %m", path); + log_error_errno(errno, "Failed to open directory \"%s\" while scanning for symlinks, ignoring: %m", path); continue; } @@ -846,7 +846,7 @@ static int find_symlinks( if (r > 0) return 1; else if (r < 0) - log_debug_errno(r, "Failed to lookup for symlinks in '%s': %m", path); + log_debug_errno(r, "Failed to look up symlinks in \"%s\": %m", path); } /* We didn't find any suitable symlinks in .wants or .requires directories, let's look for linked unit files in this directory. */ @@ -1318,7 +1318,7 @@ static int unit_file_load( 0, info, NULL); if (r < 0) - return log_debug_errno(r, "Failed to parse %s: %m", info->name); + return log_debug_errno(r, "Failed to parse \"%s\": %m", info->name); if ((flags & SEARCH_DROPIN) == 0) info->type = UNIT_FILE_TYPE_REGULAR; @@ -1477,7 +1477,7 @@ static int unit_file_search( STRV_FOREACH(p, files) { r = unit_file_load_or_readlink(c, info, *p, lp, flags | SEARCH_DROPIN); if (r < 0) - return log_debug_errno(r, "Failed to load conf file %s: %m", *p); + return log_debug_errno(r, "Failed to load conf file \"%s\": %m", *p); } return result; @@ -1719,7 +1719,7 @@ int unit_file_verify_alias(const UnitFileInstallInfo *i, const char *dst, char * return log_error_errno(r, "Failed to verify alias validity: %m"); if (r == 0) return log_warning_errno(SYNTHETIC_ERRNO(EXDEV), - "Invalid unit %s symlink %s.", + "Invalid unit \"%s\" symlink \"%s\".", i->name, dst); } else { @@ -1730,7 +1730,7 @@ int unit_file_verify_alias(const UnitFileInstallInfo *i, const char *dst, char * UnitNameFlags type = unit_name_to_instance(i->name, &inst); if (type < 0) - return log_error_errno(type, "Failed to extract instance name from %s: %m", i->name); + return log_error_errno(type, "Failed to extract instance name from \"%s\": %m", i->name); if (type == UNIT_NAME_INSTANCE) { r = unit_name_replace_instance(dst, inst, &dst_updated); From 50c5f5a3d907f819fa139e1853f660ad4fd82c55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Mon, 7 Mar 2022 12:15:42 +0100 Subject: [PATCH 05/43] test: add test for systemctl link & enable This test has overlap with test-install-root, but it tests things at a different level, so I think it's useful to add. It immediately shows various bugs which will be fixed in later patches. --- meson.build | 9 +- test/meson.build | 1 + test/test-systemctl-enable.sh | 523 ++++++++++++++++++++++++++++++++++ 3 files changed, 532 insertions(+), 1 deletion(-) create mode 100644 test/test-systemctl-enable.sh diff --git a/meson.build b/meson.build index 7babab1363..33caaec56c 100644 --- a/meson.build +++ b/meson.build @@ -2446,7 +2446,7 @@ public_programs += executable( install_rpath : rootlibexecdir, install : true) -public_programs += executable( +exe = executable( 'systemctl', systemctl_sources, include_directories : includes, @@ -2460,6 +2460,13 @@ public_programs += executable( install_rpath : rootlibexecdir, install : true, install_dir : rootbindir) +public_programs += exe +if want_tests != 'false' + test('test-systemctl-enable', + test_systemctl_enable_sh, + # https://github.com/mesonbuild/meson/issues/2681 + args : exe.full_path()) +endif if conf.get('ENABLE_PORTABLED') == 1 dbus_programs += executable( diff --git a/test/meson.build b/test/meson.build index 4fe93f6e51..34f78d5c62 100644 --- a/test/meson.build +++ b/test/meson.build @@ -88,6 +88,7 @@ endif test_fstab_generator_sh = find_program('test-fstab-generator.sh') test_network_generator_conversion_sh = find_program('test-network-generator-conversion.sh') +test_systemctl_enable_sh = find_program('test-systemctl-enable.sh') test_systemd_tmpfiles_py = find_program('test-systemd-tmpfiles.py') hwdb_test_sh = find_program('hwdb-test.sh') diff --git a/test/test-systemctl-enable.sh b/test/test-systemctl-enable.sh new file mode 100644 index 0000000000..30ba6532e7 --- /dev/null +++ b/test/test-systemctl-enable.sh @@ -0,0 +1,523 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +set -ex + +# Silence warning from running_in_chroot_or_offline() +export SYSTEMD_IGNORE_CHROOT=1 + +systemctl=${1:-systemctl} + +unset root +cleanup() { + [ -n "$root" ] && rm -rf "$root" +} +trap cleanup exit +root=$(mktemp -d --tmpdir systemctl-test.XXXXXX) + +islink() { + test -h "$1" || return 1 + test "$(readlink "$1")" = "$2" || return 2 +} + +: ------enablement nonexistent-------------------------------- +"$systemctl" --root="$root" enable test1.service && { echo "Expected failure" >&2; exit 1; } + +: ------basic enablement-------------------------------------- +mkdir -p "$root/etc/systemd/system" +cat >"$root/etc/systemd/system/test1.service" <>"$root/etc/systemd/system/test1.service" <"$root/etc/systemd/system/test2.socket" <"$root/etc/systemd/system/test2.service" <&2; exit 1; } +test ! -e "$root/etc/systemd/system/link1.path" + +cat >"$root/link1.path" <&2; exit 1; } +islink "$root/etc/systemd/system/link1.path" "/link1.path" + +: -------link bad suffix-------------------------------------- +cp "$root/link1.path" "$root/subdir/link1.suffix" +"$systemctl" --root="$root" link '/subdir/link1.suffix' && { echo "Expected failure" >&2; exit 1; } +test ! -e "$root/etc/systemd/system/link1.suffix" + +: -------unlink by unit name---------------------------------- +"$systemctl" --root="$root" disable 'link1.path' +test ! -e "$root/etc/systemd/system/link1.path" + +: -------unlink by path--------------------------------------- +"$systemctl" --root="$root" link '/link1.path' +test -h "$root/etc/systemd/system/link1.path" +"$systemctl" --root="$root" disable '/link1.path' +test ! -e "$root/etc/systemd/system/link1.path" + +: -------unlink by wrong path--------------------------------- +"$systemctl" --root="$root" link '/link1.path' +test -h "$root/etc/systemd/system/link1.path" +"$systemctl" --root="$root" disable '/subdir/link1.path' # we only care about the name +test ! -e "$root/etc/systemd/system/link1.path" + + +: -------link and enable-------------------------------------- +"$systemctl" --root="$root" enable '/link1.path' +islink "$root/etc/systemd/system/link1.path" "/link1.path" +islink "$root/etc/systemd/system/paths.target.wants/link1.path" "/link1.path" + +: -------enable already linked same path---------------------- +"$systemctl" --root="$root" enable '/link1.path' +islink "$root/etc/systemd/system/link1.path" "/link1.path" +islink "$root/etc/systemd/system/paths.target.wants/link1.path" "/link1.path" + +: -------enable already linked different path----------------- +# FIXME +# "$systemctl" --root="$root" enable '/subdir/link1.path' && { echo "Expected failure" >&2; exit 1; } +# test -h "$root/etc/systemd/system/link1.path" +# readlink "$root/etc/systemd/system/link1.path" +# test -h "$root/etc/systemd/system/paths.target.wants/link1.path" +# readlink "$root/etc/systemd/system/paths.target.wants/link1.path" + +: -------enable bad suffix------------------------------------ +cp "$root/link1.path" "$root/subdir/link1.suffix" +"$systemctl" --root="$root" enable '/subdir/link1.suffix' && { echo "Expected failure" >&2; exit 1; } +test ! -e "$root/etc/systemd/system/link1.suffix" +test ! -e "$root/etc/systemd/system/paths.target.wants/link1.suffix" + +: -------disable by unit name--------------------------------- +"$systemctl" --root="$root" disable 'link1.path' +test ! -e "$root/etc/systemd/system/link1.path" +test ! -e "$root/etc/systemd/system/paths.target.wants/link1.path" + +: -------disable by path-------------------------------------- +"$systemctl" --root="$root" enable '/link1.path' +test -h "$root/etc/systemd/system/link1.path" +test -h "$root/etc/systemd/system/paths.target.wants/link1.path" +"$systemctl" --root="$root" disable '/link1.path' +test ! -e "$root/etc/systemd/system/link1.path" +test ! -e "$root/etc/systemd/system/paths.target.wants/link1.path" + + +: -------link then enable------------------------------------- +"$systemctl" --root="$root" link '/link1.path' +islink "$root/etc/systemd/system/link1.path" "/link1.path" +test ! -h "$root/etc/systemd/system/paths.target.wants/link1.path" + +"$systemctl" --root="$root" enable 'link1.path' +islink "$root/etc/systemd/system/link1.path" "/link1.path" +islink "$root/etc/systemd/system/paths.target.wants/link1.path" "/link1.path" + +# FIXME +# "$systemctl" --root="$root" reenable 'link1.path' +# islink "$root/etc/systemd/system/link1.path" "/link1.path" +# islink "$root/etc/systemd/system/paths.target.wants/link1.path" "/link1.path" + + +: -------manual link------------------------------------------ +cat >"$root/link3.suffix" <&2; exit 1; } +"$systemctl" --root="$root" enable '/etc/systemd/system/masked.service' && { echo "Expected failure" >&2; exit 1; } + +: -------enable on masked alias------------------------------- +test -h "$root/etc/systemd/system/masked.service" +ln -s "masked.service" "$root/etc/systemd/system/masked-alias.service" +"$systemctl" --root="$root" enable 'masked-alias.service' && { echo "Expected failure" >&2; exit 1; } +"$systemctl" --root="$root" enable '/etc/systemd/system/masked-alias.service' && { echo "Expected failure" >&2; exit 1; } + +: -------issue 22000: link in subdirectory-------------------- +mkdir -p "$root/etc/systemd/system/myown.d" +cat >"$root/etc/systemd/system/link5-also.service" <"$root/etc/systemd/system/myown.d/link5.service" <&2; exit 1; } +test ! -h "$root/etc/systemd/system/services.target.wants/link5.service" +test ! -h "$root/etc/systemd/system/services.target.wants/link5-also.service" + +"$systemctl" --root="$root" enable 'link5-also.service' +test ! -h "$root/etc/systemd/system/services.target.wants/link5.service" +islink "$root/etc/systemd/system/services.target.wants/link5-also.service" "/etc/systemd/system/link5-also.service" + +: -------template enablement---------------------------------- +cat >"$root/etc/systemd/system/templ1@.service" <&2; exit 1; } +test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service" + +"$systemctl" --root="$root" enable 'templ1@one.service' +test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service" +islink "$root/etc/systemd/system/services.target.wants/templ1@one.service" "/etc/systemd/system/templ1@.service" + +"$systemctl" --root="$root" enable 'templ1@two.service' +test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service" +islink "$root/etc/systemd/system/services.target.wants/templ1@one.service" "/etc/systemd/system/templ1@.service" +islink "$root/etc/systemd/system/services.target.wants/templ1@two.service" "/etc/systemd/system/templ1@.service" + +"$systemctl" --root="$root" disable 'templ1@one.service' +test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service" +test ! -h "$root/etc/systemd/system/services.target.wants/templ1@one.service" +islink "$root/etc/systemd/system/services.target.wants/templ1@two.service" "/etc/systemd/system/templ1@.service" + +"$systemctl" --root="$root" disable 'templ1@two.service' +test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service" +test ! -h "$root/etc/systemd/system/services.target.wants/templ1@one.service" +test ! -h "$root/etc/systemd/system/services.target.wants/templ1@two.service" + +: -------template enablement w/ default instance-------------- +cat >>"$root/etc/systemd/system/templ1@.service" <"$root/etc/systemd/system/link4.service" <"$root/etc/systemd/system/link5.service" <"$root/etc/systemd/system/link5@.path" <"$root/etc/systemd/system/multilink.mount" <"$root/etc/systemd/system/some-some-link6@.socket" <&2; exit 1; } + +check_alias z 'z' && { echo "Expected failure because %z is not known" >&2; exit 1; } + +# FIXME: if there's an invalid Alias=, we shouldn't preach about empty [Install] + +exit 0 # yes, this is needed because the last test above fails + +# TODO: repeat the tests above for presets From 367c47c886af7d915e23de8d6aae0a1c135c0350 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Mon, 7 Mar 2022 15:06:57 +0100 Subject: [PATCH 06/43] tests: add helper for creating tempfiles with content I put it in tests because I think we're most likely to use it in tests. If necessary, it can be moved somewhere else later. --- src/shared/tests.c | 19 +++++++++ src/shared/tests.h | 2 + src/test/test-env-file.c | 77 +++++++++---------------------------- src/test/test-socket-util.c | 19 +++------ 4 files changed, 44 insertions(+), 73 deletions(-) diff --git a/src/shared/tests.c b/src/shared/tests.c index a624fd7d10..70fbbb45a5 100644 --- a/src/shared/tests.c +++ b/src/shared/tests.c @@ -25,6 +25,7 @@ #include "cgroup-util.h" #include "env-file.h" #include "env-util.h" +#include "fd-util.h" #include "fs-util.h" #include "log.h" #include "namespace-util.h" @@ -33,6 +34,7 @@ #include "random-util.h" #include "strv.h" #include "tests.h" +#include "tmpfile-util.h" char* setup_fake_runtime_dir(void) { char t[] = "/tmp/fake-xdg-runtime-XXXXXX", *p; @@ -132,6 +134,23 @@ int log_tests_skipped_errno(int r, const char *message) { return EXIT_TEST_SKIP; } +int write_tmpfile(char *pattern, const char *contents) { + _cleanup_close_ int fd = -1; + + assert(pattern); + assert(contents); + + fd = mkostemp_safe(pattern); + if (fd < 0) + return fd; + + ssize_t l = strlen(contents); + errno = 0; + if (write(fd, contents, l) != l) + return errno_or_else(EIO); + return 0; +} + bool have_namespaces(void) { siginfo_t si = {}; pid_t pid; diff --git a/src/shared/tests.h b/src/shared/tests.h index ef6acd368e..ade527590b 100644 --- a/src/shared/tests.h +++ b/src/shared/tests.h @@ -30,6 +30,8 @@ void test_setup_logging(int level); int log_tests_skipped(const char *message); int log_tests_skipped_errno(int r, const char *message); +int write_tmpfile(char *pattern, const char *contents); + bool have_namespaces(void); /* We use the small but non-trivial limit here */ diff --git a/src/test/test-env-file.c b/src/test/test-env-file.c index f97206b4d6..886a8e4bc8 100644 --- a/src/test/test-env-file.c +++ b/src/test/test-env-file.c @@ -55,18 +55,11 @@ TEST(load_env_file_1) { - _cleanup_strv_free_ char **data = NULL; - int r; - _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX"; - _cleanup_close_ int fd; + assert_se(write_tmpfile(name, env_file_1) == 0); - fd = mkostemp_safe(name); - assert_se(fd >= 0); - assert_se(write(fd, env_file_1, strlen(env_file_1)) == strlen(env_file_1)); - - r = load_env_file(NULL, name, &data); - assert_se(r == 0); + _cleanup_strv_free_ char **data = NULL; + assert_se(load_env_file(NULL, name, &data) == 0); assert_se(streq(data[0], "a=a")); assert_se(streq(data[1], "b=bc")); assert_se(streq(data[2], "d=de f")); @@ -77,50 +70,30 @@ TEST(load_env_file_1) { } TEST(load_env_file_2) { - _cleanup_strv_free_ char **data = NULL; - int r; - _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX"; - _cleanup_close_ int fd; + assert_se(write_tmpfile(name, env_file_2) == 0); - fd = mkostemp_safe(name); - assert_se(fd >= 0); - assert_se(write(fd, env_file_2, strlen(env_file_2)) == strlen(env_file_2)); - - r = load_env_file(NULL, name, &data); - assert_se(r == 0); + _cleanup_strv_free_ char **data = NULL; + assert_se(load_env_file(NULL, name, &data) == 0); assert_se(streq(data[0], "a=a")); assert_se(data[1] == NULL); } TEST(load_env_file_3) { - _cleanup_strv_free_ char **data = NULL; - int r; - _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX"; - _cleanup_close_ int fd; + assert_se(write_tmpfile(name, env_file_3) == 0); - fd = mkostemp_safe(name); - assert_se(fd >= 0); - assert_se(write(fd, env_file_3, strlen(env_file_3)) == strlen(env_file_3)); - - r = load_env_file(NULL, name, &data); - assert_se(r == 0); + _cleanup_strv_free_ char **data = NULL; + assert_se(load_env_file(NULL, name, &data) == 0); assert_se(data == NULL); } TEST(load_env_file_4) { - _cleanup_strv_free_ char **data = NULL; _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX"; - _cleanup_close_ int fd; - int r; + assert_se(write_tmpfile(name, env_file_4) == 0); - fd = mkostemp_safe(name); - assert_se(fd >= 0); - assert_se(write(fd, env_file_4, strlen(env_file_4)) == strlen(env_file_4)); - - r = load_env_file(NULL, name, &data); - assert_se(r == 0); + _cleanup_strv_free_ char **data = NULL; + assert_se(load_env_file(NULL, name, &data) == 0); assert_se(streq(data[0], "HWMON_MODULES=coretemp f71882fg")); assert_se(streq(data[1], "MODULE_0=coretemp")); assert_se(streq(data[2], "MODULE_1=f71882fg")); @@ -128,36 +101,22 @@ TEST(load_env_file_4) { } TEST(load_env_file_5) { - _cleanup_strv_free_ char **data = NULL; - int r; - _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX"; - _cleanup_close_ int fd; + assert_se(write_tmpfile(name, env_file_5) == 0); - fd = mkostemp_safe(name); - assert_se(fd >= 0); - assert_se(write(fd, env_file_5, strlen(env_file_5)) == strlen(env_file_5)); - - r = load_env_file(NULL, name, &data); - assert_se(r == 0); + _cleanup_strv_free_ char **data = NULL; + assert_se(load_env_file(NULL, name, &data) == 0); assert_se(streq(data[0], "a=")); assert_se(streq(data[1], "b=")); assert_se(data[2] == NULL); } TEST(load_env_file_6) { - _cleanup_strv_free_ char **data = NULL; - int r; - _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX"; - _cleanup_close_ int fd; + assert_se(write_tmpfile(name, env_file_6) == 0); - fd = mkostemp_safe(name); - assert_se(fd >= 0); - assert_se(write(fd, env_file_6, strlen(env_file_6)) == strlen(env_file_6)); - - r = load_env_file(NULL, name, &data); - assert_se(r == 0); + _cleanup_strv_free_ char **data = NULL; + assert_se(load_env_file(NULL, name, &data) == 0); assert_se(streq(data[0], "a= n t x y '")); assert_se(streq(data[1], "b=$'")); assert_se(streq(data[2], "c= \\n\\t\\$\\`\\\\\n")); diff --git a/src/test/test-socket-util.c b/src/test/test-socket-util.c index 9ee651a5fa..3245516f9a 100644 --- a/src/test/test-socket-util.c +++ b/src/test/test-socket-util.c @@ -228,17 +228,12 @@ TEST(passfd_read) { if (r == 0) { /* Child */ - char tmpfile[] = "/tmp/test-socket-util-passfd-read-XXXXXX"; - _cleanup_close_ int tmpfd = -1; - pair[0] = safe_close(pair[0]); - tmpfd = mkostemp_safe(tmpfile); - assert_se(tmpfd >= 0); - assert_se(write(tmpfd, file_contents, strlen(file_contents)) == (ssize_t) strlen(file_contents)); - tmpfd = safe_close(tmpfd); + char tmpfile[] = "/tmp/test-socket-util-passfd-read-XXXXXX"; + assert_se(write_tmpfile(tmpfile, file_contents) == 0); - tmpfd = open(tmpfile, O_RDONLY); + _cleanup_close_ int tmpfd = open(tmpfile, O_RDONLY); assert_se(tmpfd >= 0); assert_se(unlink(tmpfile) == 0); @@ -277,16 +272,12 @@ TEST(passfd_contents_read) { /* Child */ struct iovec iov = IOVEC_INIT_STRING(wire_contents); char tmpfile[] = "/tmp/test-socket-util-passfd-contents-read-XXXXXX"; - _cleanup_close_ int tmpfd = -1; pair[0] = safe_close(pair[0]); - tmpfd = mkostemp_safe(tmpfile); - assert_se(tmpfd >= 0); - assert_se(write(tmpfd, file_contents, strlen(file_contents)) == (ssize_t) strlen(file_contents)); - tmpfd = safe_close(tmpfd); + assert_se(write_tmpfile(tmpfile, file_contents) == 0); - tmpfd = open(tmpfile, O_RDONLY); + _cleanup_close_ int tmpfd = open(tmpfile, O_RDONLY); assert_se(tmpfd >= 0); assert_se(unlink(tmpfile) == 0); From ecd6c000d3a2e743a0f533d427250714c7593cf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Mon, 28 Mar 2022 11:46:38 +0200 Subject: [PATCH 07/43] man: clarify the descriptions of aliases and linked unit files This just describes the rules that are implemented by the manager, and this pull request does not change any of them. --- man/systemd.unit.xml | 58 ++++++++++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 15 deletions(-) diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml index c0c98a0e88..372f5f8f7c 100644 --- a/man/systemd.unit.xml +++ b/man/systemd.unit.xml @@ -138,7 +138,7 @@ a symlink, so when systemd is asked through D-Bus to load dbus-org.freedesktop.network1.service, it'll load systemd-networkd.service. As another example, default.target — - the default system target started at boot — is commonly symlinked (aliased) to either + the default system target started at boot — is commonly aliased to either multi-user.target or graphical.target to select what is started by default. Alias names may be used in commands like disable, start, stop, status, and similar, and in all @@ -154,8 +154,12 @@ template instance (e.g. alias@inst.service) may be a symlink to different template (e.g. template@inst.service). In that case, just this specific instance is aliased, while other instances of the template (e.g. alias@foo.service, - alias@bar.service) are not aliased. Those rule preserve the requirement that the - instance (if any) is always uniquely defined for a given unit and all its aliases. + alias@bar.service) are not aliased. Those rules preserve the requirement that the + instance (if any) is always uniquely defined for a given unit and all its aliases. The target of alias + symlink must point to a valid unit file location, i.e. the symlink target name must match the symlink + source name as described, and the destination path must be in one of the unit search paths, see UNIT FILE + LOAD PATH section below for more details. Note that the target file may not exist, i.e. the symlink may + be dangling. Unit files may specify aliases through the Alias= directive in the [Install] section. When the unit is enabled, symlinks will be created for those names, and removed when the unit is @@ -175,11 +179,18 @@ exists for Requires= type dependencies as well, the directory suffix is .requires/ in this case. This functionality is useful to hook units into the start-up of other units, without having to modify their unit files. For details about the semantics of - Wants=, see below. The preferred way to create symlinks in the - .wants/ or .requires/ directory of a unit file is by embedding - the dependency in [Install] section of the target unit, and creating the symlink in the file system with - the enable or preset commands of - systemctl1. + Wants= and Requires=, see below. The preferred way to create + symlinks in the .wants/ or .requires/ directories is by + specifying the dependency in [Install] section of the target unit, and creating the symlink in the file + system with the enable or preset commands of + systemctl1. The + target can be a normal unit (either plain or a specific instance of a template unit). In case when the + source unit is a template, the target can also be a template, in which case the instance will be + "propagated" to the target unit to form a valid unit instance. The target of symlinks in + .wants/ or .requires/ must thus point to a valid unit file + location, i.e. the symlink target name must satisfy the described requirements, and the destination path + must be in one of the unit search paths, see UNIT FILE LOAD PATH section below for more details. Note + that the target file may not exist, i.e. the symlink may be dangling. Along with a unit file foo.service, a "drop-in" directory foo.service.d/ may exist. All files with the suffix @@ -501,13 +512,30 @@ systemd-analyze --user unit-paths - Moreover, additional units might be loaded into systemd from - directories not on the unit load path by creating a symlink pointing to a - unit file in the directories. You can use systemctl link - for this operation. See - systemctl1 - for its usage and precaution. - + Moreover, additional units might be loaded into systemd from directories not on the unit load path + by creating a symlink pointing to a unit file in the directories. You can use systemctl + link for this; see + systemctl1. The file + system where the linked unit files are located must be accessible when systemd is started (e.g. anything + underneath /home/ or /var/ is not allowed, unless those + directories are located on the root file system). + + It is important to distinguish "linked unit files" from "unit file aliases": any symlink where the + symlink target is within the unit load path becomes an alias: the source name and + the target file name must satisfy specific constraints listed above in the discussion of aliases, but the + symlink target doesn't have to exist, and in fact the symlink target path is not used, except to check + whether the target is within the unit load path. In constrast, a symlink which goes outside of the unit + load path signifies a linked unit file. The symlink is followed when loading the file, but the + destination name is otherwise unused (and may even not be a valid unit file name). For example, symlinks + /etc/systemd/system/alias1.service → service1.service, + /etc/systemd/system/alias2.service → /usr/lib/systemd/service1.service, + /etc/systemd/system/alias3.service → /etc/systemd/system/service1.service + are all valid aliases and service1.service will have + four names, even if the unit file is located at + /run/systemd/system/service1.service. In contrast, + a symlink /etc/systemd/system/link1.service → ../link1_service_file + means that link1.service is a "linked unit" and the contents of + /etc/systemd/link1_service_file provide its configuration. From df78419d107662dd49892d76a745c294d7031d66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Mon, 7 Mar 2022 18:54:50 +0100 Subject: [PATCH 08/43] basic: add new variable $SYSTEMD_OS_RELEASE to override location of os-release The test for the variable is added in test-systemctl-enable because there we can do it almost for free, and the variable is most likely to be used with 'systemctl enable --root' anyway. --- docs/ENVIRONMENT.md | 5 +++++ src/basic/os-util.c | 16 +++++++++++----- test/test-systemctl-enable.sh | 12 ++++++++++-- 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/docs/ENVIRONMENT.md b/docs/ENVIRONMENT.md index 5477110bcc..0cbe5cfb6b 100644 --- a/docs/ENVIRONMENT.md +++ b/docs/ENVIRONMENT.md @@ -43,6 +43,11 @@ All tools: debugging, in order to test generators and other code against specific kernel command lines. +* `$SYSTEMD_OS_RELEASE` — if set, use this path instead of `/etc/os-release` or + `/usr/lib/os-release`. When operating under some root (e.g. `systemctl + --root=…`), the path is taken relative to the outside root. Only useful for + debugging. + * `$SYSTEMD_FSTAB` — if set, use this path instead of `/etc/fstab`. Only useful for debugging. diff --git a/src/basic/os-util.c b/src/basic/os-util.c index bf86f64348..acfff24319 100644 --- a/src/basic/os-util.c +++ b/src/basic/os-util.c @@ -170,13 +170,19 @@ int open_extension_release(const char *root, const char *extension, char **ret_p } } } else { - FOREACH_STRING(p, "/etc/os-release", "/usr/lib/os-release") { - r = chase_symlinks(p, root, CHASE_PREFIX_ROOT, + const char *var = secure_getenv("SYSTEMD_OS_RELEASE"); + if (var) + r = chase_symlinks(var, root, 0, ret_path ? &q : NULL, ret_fd ? &fd : NULL); - if (r != -ENOENT) - break; - } + else + FOREACH_STRING(path, "/etc/os-release", "/usr/lib/os-release") { + r = chase_symlinks(path, root, CHASE_PREFIX_ROOT, + ret_path ? &q : NULL, + ret_fd ? &fd : NULL); + if (r != -ENOENT) + break; + } } if (r < 0) return r; diff --git a/test/test-systemctl-enable.sh b/test/test-systemctl-enable.sh index 30ba6532e7..769341129c 100644 --- a/test/test-systemctl-enable.sh +++ b/test/test-systemctl-enable.sh @@ -518,6 +518,14 @@ check_alias z 'z' && { echo "Expected failure because %z is not known" >&2; exit # FIXME: if there's an invalid Alias=, we shouldn't preach about empty [Install] -exit 0 # yes, this is needed because the last test above fails - # TODO: repeat the tests above for presets + +: -------SYSTEMD_OS_RELEASE relative to root------------------ +# check that os-release overwriting works as expected with root +test -e "$root/etc/os-release" + +cat >"$root/etc/os-release2" < Date: Mon, 7 Mar 2022 19:22:01 +0100 Subject: [PATCH 09/43] test-os-util: add basic tests for os-release parsing --- src/test/test-os-util.c | 62 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/src/test/test-os-util.c b/src/test/test-os-util.c index eb5466259a..5f82748783 100644 --- a/src/test/test-os-util.c +++ b/src/test/test-os-util.c @@ -2,8 +2,11 @@ #include +#include "fs-util.h" #include "log.h" #include "os-util.h" +#include "string-util.h" +#include "strv.h" #include "tests.h" TEST(path_is_os_tree) { @@ -12,4 +15,63 @@ TEST(path_is_os_tree) { assert_se(path_is_os_tree("/idontexist") == -ENOENT); } +TEST(parse_os_release) { + /* Let's assume that we're running in a valid system, so os-release is available */ + _cleanup_free_ char *id = NULL, *id2 = NULL, *name = NULL, *foobar = NULL; + assert_se(parse_os_release(NULL, "ID", &id) == 1); + log_info("ID: %s", id); + + assert_se(setenv("SYSTEMD_OS_RELEASE", "/dev/null", 1) == 0); + assert_se(parse_os_release(NULL, "ID", &id2) == 0); + log_info("ID: %s", strnull(id2)); + + _cleanup_(unlink_tempfilep) char tmpfile[] = "/tmp/test-os-util.XXXXXX"; + assert_se(write_tmpfile(tmpfile, + "ID=the-id \n" + "NAME=the-name") == 0); + + assert_se(setenv("SYSTEMD_OS_RELEASE", tmpfile, 1) == 0); + assert_se(parse_os_release(NULL, "ID", &id, "NAME", &name) == 2); + log_info("ID: %s NAME: %s", id, name); + assert_se(streq(id, "the-id")); + assert_se(streq(name, "the-name")); + + _cleanup_(unlink_tempfilep) char tmpfile2[] = "/tmp/test-os-util.XXXXXX"; + assert_se(write_tmpfile(tmpfile2, + "ID=\"ignored\" \n" + "ID=\"the-id\" \n" + "NAME='the-name'") == 0); + + assert_se(setenv("SYSTEMD_OS_RELEASE", tmpfile2, 1) == 0); + // FIXME: we return 3, which means that the return value is useless in face of repeats + assert_se(parse_os_release(NULL, "ID", &id, "NAME", &name) == 3); + log_info("ID: %s NAME: %s", id, name); + assert_se(streq(id, "the-id")); + assert_se(streq(name, "the-name")); + + assert_se(parse_os_release(NULL, "FOOBAR", &foobar) == 0); + log_info("FOOBAR: %s", strnull(foobar)); + assert_se(foobar == NULL); + + assert_se(unsetenv("SYSTEMD_OS_RELEASE") == 0); +} + +TEST(load_os_release_pairs) { + _cleanup_(unlink_tempfilep) char tmpfile[] = "/tmp/test-os-util.XXXXXX"; + assert_se(write_tmpfile(tmpfile, + "ID=\"ignored\" \n" + "ID=\"the-id\" \n" + "NAME='the-name'") == 0); + + assert_se(setenv("SYSTEMD_OS_RELEASE", tmpfile, 1) == 0); + + _cleanup_strv_free_ char **pairs = NULL; + assert_se(load_os_release_pairs(NULL, &pairs) == 0); + assert_se(strv_equal(pairs, STRV_MAKE("ID", "ignored", // FIXME + "ID", "the-id", + "NAME", "the-name"))); + + assert_se(unsetenv("SYSTEMD_OS_RELEASE") == 0); +} + DEFINE_TEST_MAIN(LOG_DEBUG); From 25407ad2a785d10b1aadff0c99829ea0cf51082b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Tue, 8 Mar 2022 10:08:05 +0100 Subject: [PATCH 10/43] basic/env-file: make load-env-file deduplicate entries with the same key We generally assume parsing like the shell would do it, so the last value should win when there are repeats. --- src/basic/env-file.c | 31 ++++++++++++++++++++----------- src/test/test-env-file.c | 5 +++++ src/test/test-os-util.c | 3 +-- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/src/basic/env-file.c b/src/basic/env-file.c index 3efd77909c..14925e72e1 100644 --- a/src/basic/env-file.c +++ b/src/basic/env-file.c @@ -414,30 +414,39 @@ static int load_env_file_push_pairs( const char *key, char *value, void *userdata, int *n_pushed) { - char ***m = userdata; + char ***m = ASSERT_PTR(userdata); + bool added = false; int r; r = check_utf8ness_and_warn(filename, line, key, value); if (r < 0) return r; + /* Check if the key is present */ + for (char **t = *m; t && *t; t += 2) + if (streq(t[0], key)) { + if (value) + r = free_and_replace(t[1], value); + else + r = free_and_strdup(t+1, ""); + goto finish; + } + r = strv_extend(m, key); if (r < 0) return -ENOMEM; - if (!value) { - r = strv_extend(m, ""); - if (r < 0) - return -ENOMEM; - } else { + if (value) r = strv_push(m, value); - if (r < 0) - return r; - } + else + r = strv_extend(m, ""); + added = true; + finish: + if (r < 0) + return r; - if (n_pushed) + if (n_pushed && added) (*n_pushed)++; - return 0; } diff --git a/src/test/test-env-file.c b/src/test/test-env-file.c index 886a8e4bc8..461a0f0810 100644 --- a/src/test/test-env-file.c +++ b/src/test/test-env-file.c @@ -9,7 +9,12 @@ #include "tests.h" #include "tmpfile-util.h" +/* In case of repeating keys, later entries win. */ + #define env_file_1 \ + "a=a\n" \ + "a=b\n" \ + "a=b\n" \ "a=a\n" \ "b=b\\\n" \ "c\n" \ diff --git a/src/test/test-os-util.c b/src/test/test-os-util.c index 5f82748783..d6336c53e9 100644 --- a/src/test/test-os-util.c +++ b/src/test/test-os-util.c @@ -67,8 +67,7 @@ TEST(load_os_release_pairs) { _cleanup_strv_free_ char **pairs = NULL; assert_se(load_os_release_pairs(NULL, &pairs) == 0); - assert_se(strv_equal(pairs, STRV_MAKE("ID", "ignored", // FIXME - "ID", "the-id", + assert_se(strv_equal(pairs, STRV_MAKE("ID", "the-id", "NAME", "the-name"))); assert_se(unsetenv("SYSTEMD_OS_RELEASE") == 0); From 3a84a3c9dfde5182398a6d0863a2b2fe90a936b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Tue, 8 Mar 2022 10:10:12 +0100 Subject: [PATCH 11/43] man/os-release: add a note about repeating entries We didn't actually say that keys should not be repeated. At least the examples in docs (both python and shell) would do that, and any simple parser that builds a dictionary would most likely behave the same way. But let's document this expectation, but also say how to deal with malformed files. --- man/os-release.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/man/os-release.xml b/man/os-release.xml index 4acd1a9a57..7e3e9a73a8 100644 --- a/man/os-release.xml +++ b/man/os-release.xml @@ -75,6 +75,10 @@ from earliest boot on, and hence must be located on the root file system. + os-release must not contain repeating keys. Nevertheless, readers should pick + the entries later in the file in case of repeats, similarly to how a shell sourcing the file would. A + reader may warn about repeating entries. + For a longer rationale for os-release please refer to the Announcement of /etc/os-release. From 7962116fc8a2572c5c89904ac50fe99c8101f28f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Tue, 8 Mar 2022 11:38:46 +0100 Subject: [PATCH 12/43] shared/specifier: clarify and add test for missing data In systemd.unit we document that unset fields resolve to "". But we didn't directly test this, so let's do that. Also, we return -ENOENT if the file is missing, which we didn't document or test. --- src/shared/specifier.c | 4 +++- src/test/test-specifier.c | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/shared/specifier.c b/src/shared/specifier.c index a02012407b..df52f8cf81 100644 --- a/src/shared/specifier.c +++ b/src/shared/specifier.c @@ -269,7 +269,9 @@ int specifier_architecture(char specifier, const void *data, const char *root, c } /* Note: fields in /etc/os-release might quite possibly be missing, even if everything is entirely valid - * otherwise. We'll return an empty value or NULL in that case from the functions below. */ + * otherwise. We'll return an empty value or NULL in that case from the functions below. But if the + * os-release file is missing, we'll return -ENOENT. This means that something is seriously wrong with the + * installation. */ int specifier_os_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) { assert(ret); diff --git a/src/test/test-specifier.c b/src/test/test-specifier.c index 231625de95..5ece520e9b 100644 --- a/src/test/test-specifier.c +++ b/src/test/test-specifier.c @@ -138,4 +138,18 @@ TEST(specifiers) { } } +TEST(specifiers_missing_data_ok) { + _cleanup_free_ char *resolved = NULL; + + assert_se(setenv("SYSTEMD_OS_RELEASE", "/dev/null", 1) == 0); + assert_se(specifier_printf("%A-%B-%M-%o-%w-%W", SIZE_MAX, specifier_table, NULL, NULL, &resolved) >= 0); + assert_se(streq(resolved, "-----")); + + assert_se(setenv("SYSTEMD_OS_RELEASE", "/nosuchfileordirectory", 1) == 0); + assert_se(specifier_printf("%A-%B-%M-%o-%w-%W", SIZE_MAX, specifier_table, NULL, NULL, &resolved) == -ENOENT); + assert_se(streq(resolved, "-----")); + + assert_se(unsetenv("SYSTEMD_OS_RELEASE") == 0); +} + DEFINE_TEST_MAIN(LOG_DEBUG); From 6ec4c852c910b1aca649e87ba3143841334f01fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Tue, 8 Mar 2022 12:08:00 +0100 Subject: [PATCH 13/43] shared/specifier: provide proper error messages when specifiers fail to read files ENOENT is easily confused with the file that we're working on not being present, e.g. when the file contains %o or something else that requires os-release to be present. Let's use -EUNATCH instead to reduce that chances of confusion if the context of the error is lost. And once we have pinpointed the reason, let's provide a proper error message: + build/systemctl --root=/tmp/systemctl-test.TO7Mcb enable some-some-link6@.socket /tmp/systemctl-test.TO7Mcb/etc/systemd/system/some-some-link6@.socket: Failed to resolve alias "target@A:%A.socket": Protocol driver not attached Failed to enable unit, cannot resolve specifiers in "target@A:%A.socket". --- src/shared/install.c | 31 +++++++++++++------- src/shared/specifier.c | 33 ++++++++++++--------- src/test/test-specifier.c | 2 +- test/test-systemctl-enable.sh | 55 ++++++++++++++++++++++++++--------- 4 files changed, 82 insertions(+), 39 deletions(-) diff --git a/src/shared/install.c b/src/shared/install.c index e2fcf6cf62..72be477ee9 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -374,6 +374,7 @@ void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *chang verb, changes[i].path); logged = true; break; + case -EADDRNOTAVAIL: log_error_errno(changes[i].type_or_errno, "Failed to %s unit, unit %s is transient or generated.", verb, changes[i].path); @@ -401,6 +402,12 @@ void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *chang logged = true; break; + case -EUNATCH: + log_error_errno(changes[i].type_or_errno, "Failed to %s unit, cannot resolve specifiers in \"%s\".", + verb, changes[i].path); + logged = true; + break; + default: assert(changes[i].type_or_errno < 0); log_error_errno(changes[i].type_or_errno, "Failed to %s unit, file \"%s\": %m", @@ -1151,7 +1158,8 @@ static int config_parse_also( r = install_name_printf(info, word, info->root, &printed); if (r < 0) - return r; + return log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to resolve unit name in Also=\"%s\": %m", word); r = install_info_add(c, printed, NULL, info->root, /* auxiliary= */ true, NULL); if (r < 0) @@ -1198,14 +1206,13 @@ static int config_parse_default_instance( r = install_name_printf(i, rvalue, i->root, &printed); if (r < 0) - return r; + return log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to resolve instance name in DefaultInstance=\"%s\": %m", rvalue); - if (isempty(printed)) { - i->default_instance = mfree(i->default_instance); - return 0; - } + if (isempty(printed)) + printed = mfree(printed); - if (!unit_instance_is_valid(printed)) + if (printed && !unit_instance_is_valid(printed)) return log_syntax(unit, LOG_WARNING, filename, line, SYNTHETIC_ERRNO(EINVAL), "Invalid DefaultInstance= value \"%s\".", printed); @@ -1768,8 +1775,10 @@ static int install_info_symlink_alias( _cleanup_free_ char *alias_path = NULL, *dst = NULL, *dst_updated = NULL; q = install_name_printf(i, *s, i->root, &dst); - if (q < 0) + if (q < 0) { + unit_file_changes_add(changes, n_changes, q, *s, NULL); return q; + } q = unit_file_verify_alias(i, dst, &dst_updated); if (q < 0) @@ -1852,8 +1861,10 @@ static int install_info_symlink_wants( _cleanup_free_ char *path = NULL, *dst = NULL; q = install_name_printf(i, *s, i->root, &dst); - if (q < 0) + if (q < 0) { + unit_file_changes_add(changes, n_changes, q, *s, NULL); return q; + } if (!unit_name_is_valid(dst, valid_dst_type)) { /* Generate a proper error here: EUCLEAN if the name is generally bad, EIDRM if the @@ -3307,7 +3318,7 @@ int unit_file_preset_all( r = preset_prepare_one(scope, &plus, &minus, &lp, de->d_name, &presets, changes, n_changes); if (r < 0 && - !IN_SET(r, -EEXIST, -ERFKILL, -EADDRNOTAVAIL, -EIDRM, -EUCLEAN, -ELOOP, -ENOENT)) + !IN_SET(r, -EEXIST, -ERFKILL, -EADDRNOTAVAIL, -EIDRM, -EUCLEAN, -ELOOP, -ENOENT, -EUNATCH)) /* Ignore generated/transient/missing/invalid units when applying preset, propagate other errors. * Coordinate with unit_file_dump_changes() above. */ return r; diff --git a/src/shared/specifier.c b/src/shared/specifier.c index df52f8cf81..e994884196 100644 --- a/src/shared/specifier.c +++ b/src/shared/specifier.c @@ -162,7 +162,8 @@ int specifier_machine_id(char specifier, const void *data, const char *root, con fd = chase_symlinks_and_open("/etc/machine-id", root, CHASE_PREFIX_ROOT, O_RDONLY|O_CLOEXEC|O_NOCTTY, NULL); if (fd < 0) - return fd; + /* Translate error for missing os-release file to EUNATCH. */ + return fd == -ENOENT ? -EUNATCH : fd; r = id128_read_fd(fd, ID128_PLAIN, &id); } else @@ -270,37 +271,41 @@ int specifier_architecture(char specifier, const void *data, const char *root, c /* Note: fields in /etc/os-release might quite possibly be missing, even if everything is entirely valid * otherwise. We'll return an empty value or NULL in that case from the functions below. But if the - * os-release file is missing, we'll return -ENOENT. This means that something is seriously wrong with the + * os-release file is missing, we'll return -EUNATCH. This means that something is seriously wrong with the * installation. */ -int specifier_os_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) { +static int parse_os_release_specifier(const char *root, const char *id, char **ret) { + int r; + assert(ret); - return parse_os_release(root, "ID", ret); + + /* Translate error for missing os-release file to EUNATCH. */ + r = parse_os_release(root, id, ret); + return r == -ENOENT ? -EUNATCH : r; +} + +int specifier_os_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) { + return parse_os_release_specifier(root, "ID", ret); } int specifier_os_version_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) { - assert(ret); - return parse_os_release(root, "VERSION_ID", ret); + return parse_os_release_specifier(root, "VERSION_ID", ret); } int specifier_os_build_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) { - assert(ret); - return parse_os_release(root, "BUILD_ID", ret); + return parse_os_release_specifier(root, "BUILD_ID", ret); } int specifier_os_variant_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) { - assert(ret); - return parse_os_release(root, "VARIANT_ID", ret); + return parse_os_release_specifier(root, "VARIANT_ID", ret); } int specifier_os_image_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) { - assert(ret); - return parse_os_release(root, "IMAGE_ID", ret); + return parse_os_release_specifier(root, "IMAGE_ID", ret); } int specifier_os_image_version(char specifier, const void *data, const char *root, const void *userdata, char **ret) { - assert(ret); - return parse_os_release(root, "IMAGE_VERSION", ret); + return parse_os_release_specifier(root, "IMAGE_VERSION", ret); } int specifier_group_name(char specifier, const void *data, const char *root, const void *userdata, char **ret) { diff --git a/src/test/test-specifier.c b/src/test/test-specifier.c index 5ece520e9b..bb1c651c2a 100644 --- a/src/test/test-specifier.c +++ b/src/test/test-specifier.c @@ -146,7 +146,7 @@ TEST(specifiers_missing_data_ok) { assert_se(streq(resolved, "-----")); assert_se(setenv("SYSTEMD_OS_RELEASE", "/nosuchfileordirectory", 1) == 0); - assert_se(specifier_printf("%A-%B-%M-%o-%w-%W", SIZE_MAX, specifier_table, NULL, NULL, &resolved) == -ENOENT); + assert_se(specifier_printf("%A-%B-%M-%o-%w-%W", SIZE_MAX, specifier_table, NULL, NULL, &resolved) == -EUNATCH); assert_se(streq(resolved, "-----")); assert_se(unsetenv("SYSTEMD_OS_RELEASE") == 0); diff --git a/test/test-systemctl-enable.sh b/test/test-systemctl-enable.sh index 769341129c..43a2c0a0fb 100644 --- a/test/test-systemctl-enable.sh +++ b/test/test-systemctl-enable.sh @@ -445,13 +445,46 @@ EOF check_alias a "$(uname -m | tr '_' '-')" -# FIXME: when os-release is not found, we fail we a cryptic error -# Alias=target@%A.socket +test ! -e "$root/etc/os-release" +test ! -e "$root/usr/lib/os-release" + +check_alias A '' && { echo "Expected failure" >&2; exit 1; } +check_alias B '' && { echo "Expected failure" >&2; exit 1; } +check_alias M '' && { echo "Expected failure" >&2; exit 1; } +check_alias o '' && { echo "Expected failure" >&2; exit 1; } +check_alias w '' && { echo "Expected failure" >&2; exit 1; } +check_alias W '' && { echo "Expected failure" >&2; exit 1; } + +cat >"$root/etc/os-release" <"$root/etc/os-release" <&2; exit 1; } -# FIXME: Failed to enable: No such file or directory. -# Alias=target@%M.socket +systemd-id128 new >"$root/etc/machine-id" +check_alias m "$(cat "$root/etc/machine-id")" check_alias n 'some-some-link6@.socket' check_alias N 'some-some-link6@' -# FIXME: Failed to enable: No such file or directory. -# Alias=target@%o.socket - check_alias p 'some-some-link6' # FIXME: Failed to enable: Invalid slot. @@ -509,9 +539,6 @@ check_alias v "$(uname -r)" # FIXME: Failed to enable: Invalid slot. # Alias=target@%V.socket -# Alias=target@%w.socket -# Alias=target@%W.socket - check_alias % '%' && { echo "Expected failure because % is not legal in unit name" >&2; exit 1; } check_alias z 'z' && { echo "Expected failure because %z is not known" >&2; exit 1; } From 19b9d5d0d14f2c9b8be8d0a026b0445168808b94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Wed, 9 Mar 2022 16:06:24 +0100 Subject: [PATCH 14/43] shared/install: provide proper error messages when invalid specifiers are used $ build/systemctl --root=/tmp/systemctl-test.KXY8fu enable some-some-link6@.socket Failed to enable unit, invalid specifier in "target@C:%C.socket". --- src/shared/install.c | 11 +++++----- test/test-systemctl-enable.sh | 40 ++++++++++++----------------------- 2 files changed, 20 insertions(+), 31 deletions(-) diff --git a/src/shared/install.c b/src/shared/install.c index 72be477ee9..d05e03fb3b 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -374,12 +374,16 @@ void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *chang verb, changes[i].path); logged = true; break; - case -EADDRNOTAVAIL: log_error_errno(changes[i].type_or_errno, "Failed to %s unit, unit %s is transient or generated.", verb, changes[i].path); logged = true; break; + case -EBADSLT: + log_error_errno(changes[i].type_or_errno, "Failed to %s unit, invalid specifier in \"%s\".", + verb, changes[i].path); + logged = true; + break; case -EIDRM: log_error_errno(changes[i].type_or_errno, "Failed to %s %s, destination unit %s is a non-template unit.", verb, changes[i].source, changes[i].path); @@ -396,18 +400,15 @@ void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *chang verb, changes[i].path); logged = true; break; - case -ENOENT: log_error_errno(changes[i].type_or_errno, "Failed to %s unit, unit %s does not exist.", verb, changes[i].path); logged = true; break; - case -EUNATCH: log_error_errno(changes[i].type_or_errno, "Failed to %s unit, cannot resolve specifiers in \"%s\".", verb, changes[i].path); logged = true; break; - default: assert(changes[i].type_or_errno < 0); log_error_errno(changes[i].type_or_errno, "Failed to %s unit, file \"%s\": %m", @@ -3318,7 +3319,7 @@ int unit_file_preset_all( r = preset_prepare_one(scope, &plus, &minus, &lp, de->d_name, &presets, changes, n_changes); if (r < 0 && - !IN_SET(r, -EEXIST, -ERFKILL, -EADDRNOTAVAIL, -EIDRM, -EUCLEAN, -ELOOP, -ENOENT, -EUNATCH)) + !IN_SET(r, -EEXIST, -ERFKILL, -EADDRNOTAVAIL, -EBADSLT, -EIDRM, -EUCLEAN, -ELOOP, -ENOENT, -EUNATCH)) /* Ignore generated/transient/missing/invalid units when applying preset, propagate other errors. * Coordinate with unit_file_dump_changes() above. */ return r; diff --git a/test/test-systemctl-enable.sh b/test/test-systemctl-enable.sh index 43a2c0a0fb..da1fffe944 100644 --- a/test/test-systemctl-enable.sh +++ b/test/test-systemctl-enable.sh @@ -485,33 +485,31 @@ check_alias W 'right' check_alias b "$(systemd-id128 boot-id)" -# FIXME: Failed to enable: Invalid slot. -# Alias=target@%C.socket -# Alias=target@%E.socket -# Alias=target@%f.socket +# Specifiers not available for [Install] +check_alias C '' && { echo "Expected failure" >&2; exit 1; } +check_alias E '' && { echo "Expected failure" >&2; exit 1; } +check_alias f '' && { echo "Expected failure" >&2; exit 1; } +check_alias h '' && { echo "Expected failure" >&2; exit 1; } +check_alias I '' && { echo "Expected failure" >&2; exit 1; } +check_alias J '' && { echo "Expected failure" >&2; exit 1; } +check_alias L '' && { echo "Expected failure" >&2; exit 1; } +check_alias P '' && { echo "Expected failure" >&2; exit 1; } +check_alias s '' && { echo "Expected failure" >&2; exit 1; } +check_alias S '' && { echo "Expected failure" >&2; exit 1; } +check_alias t '' && { echo "Expected failure" >&2; exit 1; } +check_alias T '' && { echo "Expected failure" >&2; exit 1; } +check_alias V '' && { echo "Expected failure" >&2; exit 1; } # FIXME: we use the calling user instead of root :( check_alias g root || : check_alias G 0 || : -# FIXME: Failed to enable: Invalid slot. -# Alias=target@%h.socket - check_alias i "" -# FIXME: Failed to enable: Invalid slot. -# Alias=target@%I.socket - check_alias j 'link6' -# FIXME: Failed to enable: Invalid slot. -# Alias=target@%J.socket - check_alias l "$(uname -n | sed 's/\..*//')" -# FIXME: Failed to enable: Invalid slot. -# Alias=target@%L.socket - test ! -e "$root/etc/machine-id" check_alias m '' && { echo "Expected failure" >&2; exit 1; } @@ -523,22 +521,12 @@ check_alias N 'some-some-link6@' check_alias p 'some-some-link6' -# FIXME: Failed to enable: Invalid slot. -# Alias=target@%P.socket -# Alias=target@%s.socket -# Alias=target@%S.socket -# Alias=target@%t.socket -# Alias=target@%T.socket - # FIXME: we use the calling user instead of root :( check_alias u root || : check_alias U 0 || : check_alias v "$(uname -r)" -# FIXME: Failed to enable: Invalid slot. -# Alias=target@%V.socket - check_alias % '%' && { echo "Expected failure because % is not legal in unit name" >&2; exit 1; } check_alias z 'z' && { echo "Expected failure because %z is not known" >&2; exit 1; } From 4a84db4c0c2eef6f40da35347c95dfa6b6e3d139 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Wed, 9 Mar 2022 17:51:36 +0100 Subject: [PATCH 15/43] shared/install: move scope into InstallContext MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This makes it easier to pass it around in preparation for future changes. While at it, let's rename InstallContext c → ctx, and InstallInfo i → info. 'c' and 'i' are bad names for variables that are passed through multiple layers of functions calls. It's easier to follow what is happening with a meaningful variable names. --- src/shared/install.c | 386 +++++++++++++++++++++---------------------- 1 file changed, 191 insertions(+), 195 deletions(-) diff --git a/src/shared/install.c b/src/shared/install.c index d05e03fb3b..bff1930828 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -47,6 +47,7 @@ typedef enum SearchFlags { } SearchFlags; typedef struct { + UnitFileScope scope; OrderedHashmap *will_process; OrderedHashmap *have_processed; } InstallContext; @@ -725,7 +726,7 @@ static int find_symlinks_in_directory( DIR *dir, const char *dir_path, const char *root_dir, - const UnitFileInstallInfo *i, + const UnitFileInstallInfo *info, bool match_aliases, bool ignore_same_name, const char *config_path, @@ -762,17 +763,17 @@ static int find_symlinks_in_directory( free_and_replace(dest, x); } - assert(unit_name_is_valid(i->name, UNIT_NAME_ANY)); + assert(unit_name_is_valid(info->name, UNIT_NAME_ANY)); if (!ignore_same_name) /* Check if the symlink itself matches what we are looking for. * * If ignore_same_name is specified, we are in one of the directories which * have lower priority than the unit file, and even if a file or symlink with * this name was found, we should ignore it. */ - found_path = streq(de->d_name, i->name); + found_path = streq(de->d_name, info->name); /* Check if what the symlink points to matches what we are looking for */ - found_dest = streq(basename(dest), i->name); + found_dest = streq(basename(dest), info->name); if (found_path && found_dest) { _cleanup_free_ char *p = NULL, *t = NULL; @@ -780,7 +781,7 @@ static int find_symlinks_in_directory( /* Filter out same name links in the main * config path */ p = path_make_absolute(de->d_name, dir_path); - t = path_make_absolute(i->name, config_path); + t = path_make_absolute(info->name, config_path); if (!p || !t) return -ENOMEM; @@ -795,7 +796,7 @@ static int find_symlinks_in_directory( return 1; /* Check if symlink name is in the set of names used by [Install] */ - q = is_symlink_with_known_name(i, de->d_name); + q = is_symlink_with_known_name(info, de->d_name); if (q < 0) return q; if (q > 0) @@ -865,7 +866,7 @@ static int find_symlinks( static int find_symlinks_in_scope( UnitFileScope scope, const LookupPaths *lp, - const UnitFileInstallInfo *i, + const UnitFileInstallInfo *info, bool match_name, UnitFileState *state) { @@ -875,7 +876,7 @@ static int find_symlinks_in_scope( int r; assert(lp); - assert(i); + assert(info); /* As we iterate over the list of search paths in lp->search_path, we may encounter "same name" * symlinks. The ones which are "below" (i.e. have lower priority) than the unit file itself are @@ -884,7 +885,7 @@ static int find_symlinks_in_scope( STRV_FOREACH(p, lp->search_path) { bool same_name_link = false; - r = find_symlinks(lp->root_dir, i, match_name, ignore_same_name, *p, &same_name_link); + r = find_symlinks(lp->root_dir, info, match_name, ignore_same_name, *p, &same_name_link); if (r < 0) return r; if (r > 0) { @@ -924,7 +925,7 @@ static int find_symlinks_in_scope( /* Check if next iteration will be "below" the unit file (either a regular file * or a symlink), and hence should be ignored */ - if (!ignore_same_name && path_startswith(i->path, *p)) + if (!ignore_same_name && path_startswith(info->path, *p)) ignore_same_name = true; } @@ -937,7 +938,7 @@ static int find_symlinks_in_scope( * outside of runtime and configuration directory, then we consider it statically enabled. Note we do that only * for instance, not for regular names, as those are merely aliases, while instances explicitly instantiate * something, and hence are a much stronger concept. */ - if (enabled_at_all && unit_name_is_valid(i->name, UNIT_NAME_INSTANCE)) { + if (enabled_at_all && unit_name_is_valid(info->name, UNIT_NAME_INSTANCE)) { *state = UNIT_FILE_STATIC; return 1; } @@ -957,7 +958,6 @@ static int find_symlinks_in_scope( } static void install_info_free(UnitFileInstallInfo *i) { - if (!i) return; @@ -973,21 +973,21 @@ static void install_info_free(UnitFileInstallInfo *i) { free(i); } -static void install_context_done(InstallContext *c) { - assert(c); +static void install_context_done(InstallContext *ctx) { + assert(ctx); - c->will_process = ordered_hashmap_free_with_destructor(c->will_process, install_info_free); - c->have_processed = ordered_hashmap_free_with_destructor(c->have_processed, install_info_free); + ctx->will_process = ordered_hashmap_free_with_destructor(ctx->will_process, install_info_free); + ctx->have_processed = ordered_hashmap_free_with_destructor(ctx->have_processed, install_info_free); } -static UnitFileInstallInfo *install_info_find(InstallContext *c, const char *name) { +static UnitFileInstallInfo *install_info_find(InstallContext *ctx, const char *name) { UnitFileInstallInfo *i; - i = ordered_hashmap_get(c->have_processed, name); + i = ordered_hashmap_get(ctx->have_processed, name); if (i) return i; - return ordered_hashmap_get(c->will_process, name); + return ordered_hashmap_get(ctx->will_process, name); } static int install_info_may_process( @@ -1021,7 +1021,7 @@ static int install_info_may_process( * Returns negative on error, 0 if the unit was already known, 1 otherwise. */ static int install_info_add( - InstallContext *c, + InstallContext *ctx, const char *name, const char *path, const char *root, @@ -1031,7 +1031,7 @@ static int install_info_add( UnitFileInstallInfo *i = NULL; int r; - assert(c); + assert(ctx); if (!name) { /* 'name' and 'path' must not both be null. Check here 'path' using assert_se() to @@ -1044,7 +1044,7 @@ static int install_info_add( if (!unit_name_is_valid(name, UNIT_NAME_ANY)) return -EINVAL; - i = install_info_find(c, name); + i = install_info_find(ctx, name); if (i) { i->auxiliary = i->auxiliary && auxiliary; @@ -1084,7 +1084,7 @@ static int install_info_add( } } - r = ordered_hashmap_ensure_put(&c->will_process, &string_hash_ops, i->name, i); + r = ordered_hashmap_ensure_put(&ctx->will_process, &string_hash_ops, i->name, i); if (r < 0) goto fail; @@ -1139,8 +1139,8 @@ static int config_parse_also( void *data, void *userdata) { - UnitFileInstallInfo *info = userdata; - InstallContext *c = data; + UnitFileInstallInfo *info = ASSERT_PTR(userdata); + InstallContext *ctx = ASSERT_PTR(data); int r; assert(unit); @@ -1162,7 +1162,7 @@ static int config_parse_also( return log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit name in Also=\"%s\": %m", word); - r = install_info_add(c, printed, NULL, info->root, /* auxiliary= */ true, NULL); + r = install_info_add(ctx, printed, NULL, info->root, /* auxiliary= */ true, NULL); if (r < 0) return r; @@ -1188,7 +1188,7 @@ static int config_parse_default_instance( void *data, void *userdata) { - UnitFileInstallInfo *i = data; + UnitFileInstallInfo *info = ASSERT_PTR(userdata); _cleanup_free_ char *printed = NULL; int r; @@ -1205,7 +1205,7 @@ static int config_parse_default_instance( return log_syntax(unit, LOG_WARNING, filename, line, 0, "DefaultInstance= only makes sense for template units, ignoring."); - r = install_name_printf(i, rvalue, i->root, &printed); + r = install_name_printf(info, rvalue, info->root, &printed); if (r < 0) return log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve instance name in DefaultInstance=\"%s\": %m", rvalue); @@ -1217,11 +1217,11 @@ static int config_parse_default_instance( return log_syntax(unit, LOG_WARNING, filename, line, SYNTHETIC_ERRNO(EINVAL), "Invalid DefaultInstance= value \"%s\".", printed); - return free_and_replace(i->default_instance, printed); + return free_and_replace(info->default_instance, printed); } static int unit_file_load( - InstallContext *c, + InstallContext *ctx, UnitFileInstallInfo *info, const char *path, const char *root_dir, @@ -1232,7 +1232,7 @@ static int unit_file_load( { "Install", "WantedBy", config_parse_strv, 0, &info->wanted_by }, { "Install", "RequiredBy", config_parse_strv, 0, &info->required_by }, { "Install", "DefaultInstance", config_parse_default_instance, 0, info }, - { "Install", "Also", config_parse_also, 0, c }, + { "Install", "Also", config_parse_also, 0, ctx }, {} }; @@ -1305,8 +1305,8 @@ static int unit_file_load( if (!f) return -errno; - /* c is only needed if we actually load the file (it's referenced from items[] btw, in case you wonder.) */ - assert(c); + /* ctx is only needed if we actually load the file (it's referenced from items[] btw, in case you wonder.) */ + assert(ctx); r = config_parse(info->name, path, f, "Install\0" @@ -1338,14 +1338,14 @@ static int unit_file_load( } static int unit_file_load_or_readlink( - InstallContext *c, + InstallContext *ctx, UnitFileInstallInfo *info, const char *path, const LookupPaths *lp, SearchFlags flags) { int r; - r = unit_file_load(c, info, path, lp->root_dir, flags); + r = unit_file_load(ctx, info, path, lp->root_dir, flags); if (r != -ELOOP || (flags & SEARCH_DROPIN)) return r; @@ -1368,7 +1368,7 @@ static int unit_file_load_or_readlink( } static int unit_file_search( - InstallContext *c, + InstallContext *ctx, UnitFileInstallInfo *info, const LookupPaths *lp, SearchFlags flags) { @@ -1387,7 +1387,7 @@ static int unit_file_search( return 0; if (info->path) - return unit_file_load_or_readlink(c, info, info->path, lp, flags); + return unit_file_load_or_readlink(ctx, info, info->path, lp, flags); assert(info->name); @@ -1404,7 +1404,7 @@ static int unit_file_search( if (!path) return -ENOMEM; - r = unit_file_load_or_readlink(c, info, path, lp, flags); + r = unit_file_load_or_readlink(ctx, info, path, lp, flags); if (r >= 0) { info->path = TAKE_PTR(path); result = r; @@ -1427,7 +1427,7 @@ static int unit_file_search( if (!path) return -ENOMEM; - r = unit_file_load_or_readlink(c, info, path, lp, flags); + r = unit_file_load_or_readlink(ctx, info, path, lp, flags); if (r >= 0) { info->path = TAKE_PTR(path); result = r; @@ -1483,7 +1483,7 @@ static int unit_file_search( return log_debug_errno(r, "Failed to get list of conf files: %m"); STRV_FOREACH(p, files) { - r = unit_file_load_or_readlink(c, info, *p, lp, flags | SEARCH_DROPIN); + r = unit_file_load_or_readlink(ctx, info, *p, lp, flags | SEARCH_DROPIN); if (r < 0) return log_debug_errno(r, "Failed to load conf file \"%s\": %m", *p); } @@ -1492,29 +1492,29 @@ static int unit_file_search( } static int install_info_follow( - InstallContext *c, - UnitFileInstallInfo *i, + InstallContext *ctx, + UnitFileInstallInfo *info, const LookupPaths *lp, SearchFlags flags, bool ignore_different_name) { - assert(c); - assert(i); + assert(ctx); + assert(info); - if (i->type != UNIT_FILE_TYPE_SYMLINK) + if (info->type != UNIT_FILE_TYPE_SYMLINK) return -EINVAL; - if (!i->symlink_target) + if (!info->symlink_target) return -EINVAL; /* If the basename doesn't match, the caller should add a complete new entry for this. */ - if (!ignore_different_name && !streq(basename(i->symlink_target), i->name)) + if (!ignore_different_name && !streq(basename(info->symlink_target), info->name)) return -EXDEV; - free_and_replace(i->path, i->symlink_target); - i->type = _UNIT_FILE_TYPE_INVALID; + free_and_replace(info->path, info->symlink_target); + info->type = _UNIT_FILE_TYPE_INVALID; - return unit_file_load_or_readlink(c, i, i->path, lp, flags); + return unit_file_load_or_readlink(ctx, info, info->path, lp, flags); } /** @@ -1522,8 +1522,7 @@ static int install_info_follow( * target, maybe more than once. Propagate the instance name if present. */ static int install_info_traverse( - UnitFileScope scope, - InstallContext *c, + InstallContext *ctx, const LookupPaths *lp, UnitFileInstallInfo *start, SearchFlags flags, @@ -1535,9 +1534,9 @@ static int install_info_traverse( assert(lp); assert(start); - assert(c); + assert(ctx); - r = unit_file_search(c, start, lp, flags); + r = unit_file_search(ctx, start, lp, flags); if (r < 0) return r; @@ -1556,7 +1555,7 @@ static int install_info_traverse( return -ELOOP; } - r = install_info_follow(c, i, lp, flags, false); + r = install_info_follow(ctx, i, lp, flags, false); if (r == -EXDEV) { _cleanup_free_ char *buffer = NULL; const char *bn; @@ -1583,7 +1582,7 @@ static int install_info_traverse( /* We filled in the instance, and the target stayed the same? If so, * then let's honour the link as it is. */ - r = install_info_follow(c, i, lp, flags, true); + r = install_info_follow(ctx, i, lp, flags, true); if (r < 0) return r; @@ -1593,12 +1592,12 @@ static int install_info_traverse( bn = buffer; } - r = install_info_add(c, bn, NULL, lp->root_dir, /* auxiliary= */ false, &i); + r = install_info_add(ctx, bn, NULL, lp->root_dir, /* auxiliary= */ false, &i); if (r < 0) return r; /* Try again, with the new target we found. */ - r = unit_file_search(c, i, lp, flags); + r = unit_file_search(ctx, i, lp, flags); if (r == -ENOENT) /* Translate error code to highlight this specific case */ return -ENOLINK; @@ -1619,12 +1618,12 @@ static int install_info_traverse( * or the name (otherwise). root_dir is prepended to the path. */ static int install_info_add_auto( - InstallContext *c, + InstallContext *ctx, const LookupPaths *lp, const char *name_or_path, UnitFileInstallInfo **ret) { - assert(c); + assert(ctx); assert(name_or_path); if (path_is_absolute(name_or_path)) { @@ -1632,14 +1631,13 @@ static int install_info_add_auto( pp = prefix_roota(lp->root_dir, name_or_path); - return install_info_add(c, NULL, pp, lp->root_dir, /* auxiliary= */ false, ret); + return install_info_add(ctx, NULL, pp, lp->root_dir, /* auxiliary= */ false, ret); } else - return install_info_add(c, name_or_path, NULL, lp->root_dir, /* auxiliary= */ false, ret); + return install_info_add(ctx, name_or_path, NULL, lp->root_dir, /* auxiliary= */ false, ret); } static int install_info_discover( - UnitFileScope scope, - InstallContext *c, + InstallContext *ctx, const LookupPaths *lp, const char *name, SearchFlags flags, @@ -1647,16 +1645,16 @@ static int install_info_discover( UnitFileChange **changes, size_t *n_changes) { - UnitFileInstallInfo *i; + UnitFileInstallInfo *info; int r; - assert(c); + assert(ctx); assert(lp); assert(name); - r = install_info_add_auto(c, lp, name, &i); + r = install_info_add_auto(ctx, lp, name, &info); if (r >= 0) - r = install_info_traverse(scope, c, lp, i, flags, ret); + r = install_info_traverse(ctx, lp, info, flags, ret); if (r < 0) unit_file_changes_add(changes, n_changes, r, name, NULL); @@ -1664,25 +1662,24 @@ static int install_info_discover( } static int install_info_discover_and_check( - UnitFileScope scope, - InstallContext *c, - const LookupPaths *lp, - const char *name, - SearchFlags flags, - UnitFileInstallInfo **ret, - UnitFileChange **changes, - size_t *n_changes) { + InstallContext *ctx, + const LookupPaths *lp, + const char *name, + SearchFlags flags, + UnitFileInstallInfo **ret, + UnitFileChange **changes, + size_t *n_changes) { int r; - r = install_info_discover(scope, c, lp, name, flags, ret, changes, n_changes); + r = install_info_discover(ctx, lp, name, flags, ret, changes, n_changes); if (r < 0) return r; return install_info_may_process(ret ? *ret : NULL, lp, changes, n_changes); } -int unit_file_verify_alias(const UnitFileInstallInfo *i, const char *dst, char **ret_dst) { +int unit_file_verify_alias(const UnitFileInstallInfo *info, const char *dst, char **ret_dst) { _cleanup_free_ char *dst_updated = NULL; int r; @@ -1722,13 +1719,13 @@ int unit_file_verify_alias(const UnitFileInstallInfo *i, const char *dst, char * const bool instance_propagation = type == UNIT_NAME_TEMPLATE; /* That's the name we want to use for verification. */ - r = unit_symlink_name_compatible(path_alias, i->name, instance_propagation); + r = unit_symlink_name_compatible(path_alias, info->name, instance_propagation); if (r < 0) return log_error_errno(r, "Failed to verify alias validity: %m"); if (r == 0) return log_warning_errno(SYNTHETIC_ERRNO(EXDEV), "Invalid unit \"%s\" symlink \"%s\".", - i->name, dst); + info->name, dst); } else { /* If the symlink target has an instance set and the symlink source doesn't, we "propagate @@ -1736,9 +1733,9 @@ int unit_file_verify_alias(const UnitFileInstallInfo *i, const char *dst, char * if (unit_name_is_valid(dst, UNIT_NAME_TEMPLATE)) { _cleanup_free_ char *inst = NULL; - UnitNameFlags type = unit_name_to_instance(i->name, &inst); + UnitNameFlags type = unit_name_to_instance(info->name, &inst); if (type < 0) - return log_error_errno(type, "Failed to extract instance name from \"%s\": %m", i->name); + return log_error_errno(type, "Failed to extract instance name from \"%s\": %m", info->name); if (type == UNIT_NAME_INSTANCE) { r = unit_name_replace_instance(dst, inst, &dst_updated); @@ -1748,10 +1745,9 @@ int unit_file_verify_alias(const UnitFileInstallInfo *i, const char *dst, char * } } - r = unit_validate_alias_symlink_and_warn(dst_updated ?: dst, i->name); + r = unit_validate_alias_symlink_and_warn(dst_updated ?: dst, info->name); if (r < 0) return r; - } *ret_dst = TAKE_PTR(dst_updated); @@ -1759,7 +1755,8 @@ int unit_file_verify_alias(const UnitFileInstallInfo *i, const char *dst, char * } static int install_info_symlink_alias( - UnitFileInstallInfo *i, + UnitFileScope scope, + UnitFileInstallInfo *info, const LookupPaths *lp, const char *config_path, bool force, @@ -1768,20 +1765,20 @@ static int install_info_symlink_alias( int r = 0, q; - assert(i); + assert(info); assert(lp); assert(config_path); - STRV_FOREACH(s, i->aliases) { + STRV_FOREACH(s, info->aliases) { _cleanup_free_ char *alias_path = NULL, *dst = NULL, *dst_updated = NULL; - q = install_name_printf(i, *s, i->root, &dst); + q = install_name_printf(info, *s, info->root, &dst); if (q < 0) { unit_file_changes_add(changes, n_changes, q, *s, NULL); return q; } - q = unit_file_verify_alias(i, dst, &dst_updated); + q = unit_file_verify_alias(info, dst, &dst_updated); if (q < 0) continue; @@ -1789,7 +1786,7 @@ static int install_info_symlink_alias( if (!alias_path) return -ENOMEM; - q = create_symlink(lp, i->path, alias_path, force, changes, n_changes); + q = create_symlink(lp, info->path, alias_path, force, changes, n_changes); if (r == 0) r = q; } @@ -1800,7 +1797,7 @@ static int install_info_symlink_alias( static int install_info_symlink_wants( UnitFileScope scope, UnitFileFlags file_flags, - UnitFileInstallInfo *i, + UnitFileInstallInfo *info, const LookupPaths *lp, const char *config_path, char **list, @@ -1813,18 +1810,18 @@ static int install_info_symlink_wants( const char *n; int r = 0, q; - assert(i); + assert(info); assert(lp); assert(config_path); if (strv_isempty(list)) return 0; - if (unit_name_is_valid(i->name, UNIT_NAME_PLAIN | UNIT_NAME_INSTANCE)) + if (unit_name_is_valid(info->name, UNIT_NAME_PLAIN | UNIT_NAME_INSTANCE)) /* Not a template unit. Use the name directly. */ - n = i->name; + n = info->name; - else if (i->default_instance) { + else if (info->default_instance) { UnitFileInstallInfo instance = { .type = _UNIT_FILE_TYPE_INVALID, }; @@ -1832,7 +1829,7 @@ static int install_info_symlink_wants( /* If this is a template, and we have a default instance, use it. */ - r = unit_name_replace_instance(i->name, i->default_instance, &buf); + r = unit_name_replace_instance(info->name, info->default_instance, &buf); if (r < 0) return r; @@ -1855,13 +1852,13 @@ static int install_info_symlink_wants( * the instance from that unit. Cannot be used with non-instance units. */ valid_dst_type = UNIT_NAME_INSTANCE | UNIT_NAME_TEMPLATE; - n = i->name; + n = info->name; } STRV_FOREACH(s, list) { _cleanup_free_ char *path = NULL, *dst = NULL; - q = install_name_printf(i, *s, i->root, &dst); + q = install_name_printf(info, *s, info->root, &dst); if (q < 0) { unit_file_changes_add(changes, n_changes, q, *s, NULL); return q; @@ -1893,19 +1890,19 @@ static int install_info_symlink_wants( if (!path) return -ENOMEM; - q = create_symlink(lp, i->path, path, true, changes, n_changes); + q = create_symlink(lp, info->path, path, true, changes, n_changes); if (r == 0) r = q; if (unit_file_exists(scope, lp, dst) == 0) - unit_file_changes_add(changes, n_changes, UNIT_FILE_DESTINATION_NOT_PRESENT, dst, i->path); + unit_file_changes_add(changes, n_changes, UNIT_FILE_DESTINATION_NOT_PRESENT, dst, info->path); } return r; } static int install_info_symlink_link( - UnitFileInstallInfo *i, + UnitFileInstallInfo *info, const LookupPaths *lp, const char *config_path, bool force, @@ -1915,28 +1912,28 @@ static int install_info_symlink_link( _cleanup_free_ char *path = NULL; int r; - assert(i); + assert(info); assert(lp); assert(config_path); - assert(i->path); + assert(info->path); - r = in_search_path(lp, i->path); + r = in_search_path(lp, info->path); if (r < 0) return r; if (r > 0) return 0; - path = path_join(config_path, i->name); + path = path_join(config_path, info->name); if (!path) return -ENOMEM; - return create_symlink(lp, i->path, path, force, changes, n_changes); + return create_symlink(lp, info->path, path, force, changes, n_changes); } static int install_info_apply( UnitFileScope scope, UnitFileFlags file_flags, - UnitFileInstallInfo *i, + UnitFileInstallInfo *info, const LookupPaths *lp, const char *config_path, UnitFileChange **changes, @@ -1944,26 +1941,26 @@ static int install_info_apply( int r, q; - assert(i); + assert(info); assert(lp); assert(config_path); - if (i->type != UNIT_FILE_TYPE_REGULAR) + if (info->type != UNIT_FILE_TYPE_REGULAR) return 0; bool force = file_flags & UNIT_FILE_FORCE; - r = install_info_symlink_alias(i, lp, config_path, force, changes, n_changes); + r = install_info_symlink_alias(scope, info, lp, config_path, force, changes, n_changes); - q = install_info_symlink_wants(scope, file_flags, i, lp, config_path, i->wanted_by, ".wants/", changes, n_changes); + q = install_info_symlink_wants(scope, file_flags, info, lp, config_path, info->wanted_by, ".wants/", changes, n_changes); if (r == 0) r = q; - q = install_info_symlink_wants(scope, file_flags, i, lp, config_path, i->required_by, ".requires/", changes, n_changes); + q = install_info_symlink_wants(scope, file_flags, info, lp, config_path, info->required_by, ".requires/", changes, n_changes); if (r == 0) r = q; - q = install_info_symlink_link(i, lp, config_path, force, changes, n_changes); + q = install_info_symlink_link(info, lp, config_path, force, changes, n_changes); /* Do not count links to the unit file towards the "carries_install_info" count */ if (r == 0 && q < 0) r = q; @@ -1972,10 +1969,9 @@ static int install_info_apply( } static int install_context_apply( - UnitFileScope scope, - UnitFileFlags file_flags, - InstallContext *c, + InstallContext *ctx, const LookupPaths *lp, + UnitFileFlags file_flags, const char *config_path, SearchFlags flags, UnitFileChange **changes, @@ -1984,26 +1980,26 @@ static int install_context_apply( UnitFileInstallInfo *i; int r; - assert(c); + assert(ctx); assert(lp); assert(config_path); - if (ordered_hashmap_isempty(c->will_process)) + if (ordered_hashmap_isempty(ctx->will_process)) return 0; - r = ordered_hashmap_ensure_allocated(&c->have_processed, &string_hash_ops); + r = ordered_hashmap_ensure_allocated(&ctx->have_processed, &string_hash_ops); if (r < 0) return r; r = 0; - while ((i = ordered_hashmap_first(c->will_process))) { + while ((i = ordered_hashmap_first(ctx->will_process))) { int q; - q = ordered_hashmap_move_one(c->have_processed, c->will_process, i->name); + q = ordered_hashmap_move_one(ctx->have_processed, ctx->will_process, i->name); if (q < 0) return q; - q = install_info_traverse(scope, c, lp, i, flags, NULL); + q = install_info_traverse(ctx, lp, i, flags, NULL); if (q < 0) { if (i->auxiliary) { q = unit_file_changes_add(changes, n_changes, UNIT_FILE_AUXILIARY_FAILED, NULL, i->name); @@ -2030,7 +2026,7 @@ static int install_context_apply( if (i->type != UNIT_FILE_TYPE_REGULAR) continue; - q = install_info_apply(scope, file_flags, i, lp, config_path, changes, n_changes); + q = install_info_apply(ctx->scope, file_flags, i, lp, config_path, changes, n_changes); if (r >= 0) { if (q < 0) r = q; @@ -2043,8 +2039,7 @@ static int install_context_apply( } static int install_context_mark_for_removal( - UnitFileScope scope, - InstallContext *c, + InstallContext *ctx, const LookupPaths *lp, Set **remove_symlinks_to, const char *config_path, @@ -2054,26 +2049,26 @@ static int install_context_mark_for_removal( UnitFileInstallInfo *i; int r; - assert(c); + assert(ctx); assert(lp); assert(config_path); /* Marks all items for removal */ - if (ordered_hashmap_isempty(c->will_process)) + if (ordered_hashmap_isempty(ctx->will_process)) return 0; - r = ordered_hashmap_ensure_allocated(&c->have_processed, &string_hash_ops); + r = ordered_hashmap_ensure_allocated(&ctx->have_processed, &string_hash_ops); if (r < 0) return r; - while ((i = ordered_hashmap_first(c->will_process))) { + while ((i = ordered_hashmap_first(ctx->will_process))) { - r = ordered_hashmap_move_one(c->have_processed, c->will_process, i->name); + r = ordered_hashmap_move_one(ctx->have_processed, ctx->will_process, i->name); if (r < 0) return r; - r = install_info_traverse(scope, c, lp, i, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, NULL); + r = install_info_traverse(ctx, lp, i, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, NULL); if (r == -ENOLINK) { log_debug_errno(r, "Name %s leads to a dangling symlink, removing name.", i->name); unit_file_changes_add(changes, n_changes, UNIT_FILE_IS_DANGLING, i->path ?: i->name, NULL); @@ -2505,8 +2500,8 @@ int unit_file_add_dependency( size_t *n_changes) { _cleanup_(lookup_paths_free) LookupPaths lp = {}; - _cleanup_(install_context_done) InstallContext c = {}; - UnitFileInstallInfo *i, *target_info; + _cleanup_(install_context_done) InstallContext ctx = { .scope = scope }; + UnitFileInstallInfo *info, *target_info; const char *config_path; int r; @@ -2528,7 +2523,7 @@ int unit_file_add_dependency( if (!config_path) return -ENXIO; - r = install_info_discover_and_check(scope, &c, &lp, target, SEARCH_FOLLOW_CONFIG_SYMLINKS, + r = install_info_discover_and_check(&ctx, &lp, target, SEARCH_FOLLOW_CONFIG_SYMLINKS, &target_info, changes, n_changes); if (r < 0) return r; @@ -2538,21 +2533,21 @@ int unit_file_add_dependency( STRV_FOREACH(f, files) { char ***l; - r = install_info_discover_and_check(scope, &c, &lp, *f, SEARCH_FOLLOW_CONFIG_SYMLINKS, - &i, changes, n_changes); + r = install_info_discover_and_check(&ctx, &lp, *f, SEARCH_FOLLOW_CONFIG_SYMLINKS, + &info, changes, n_changes); if (r < 0) return r; - assert(i->type == UNIT_FILE_TYPE_REGULAR); + assert(info->type == UNIT_FILE_TYPE_REGULAR); /* We didn't actually load anything from the unit * file, but instead just add in our new symlink to * create. */ if (dep == UNIT_WANTS) - l = &i->wanted_by; + l = &info->wanted_by; else - l = &i->required_by; + l = &info->required_by; strv_free(*l); *l = strv_new(target_info->name); @@ -2560,7 +2555,7 @@ int unit_file_add_dependency( return -ENOMEM; } - return install_context_apply(scope, file_flags, &c, &lp, config_path, + return install_context_apply(&ctx, &lp, file_flags, config_path, SEARCH_FOLLOW_CONFIG_SYMLINKS, changes, n_changes); } @@ -2573,9 +2568,9 @@ int unit_file_enable( size_t *n_changes) { _cleanup_(lookup_paths_free) LookupPaths lp = {}; - _cleanup_(install_context_done) InstallContext c = {}; + _cleanup_(install_context_done) InstallContext ctx = { .scope = scope }; const char *config_path; - UnitFileInstallInfo *i; + UnitFileInstallInfo *info; int r; assert(scope >= 0); @@ -2590,12 +2585,12 @@ int unit_file_enable( return -ENXIO; STRV_FOREACH(f, files) { - r = install_info_discover_and_check(scope, &c, &lp, *f, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, - &i, changes, n_changes); + r = install_info_discover_and_check(&ctx, &lp, *f, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, + &info, changes, n_changes); if (r < 0) return r; - assert(i->type == UNIT_FILE_TYPE_REGULAR); + assert(info->type == UNIT_FILE_TYPE_REGULAR); } /* This will return the number of symlink rules that were @@ -2603,7 +2598,8 @@ int unit_file_enable( is useful to determine whether the passed files had any installation data at all. */ - return install_context_apply(scope, file_flags, &c, &lp, config_path, SEARCH_LOAD, changes, n_changes); + return install_context_apply(&ctx, &lp, file_flags, config_path, + SEARCH_LOAD, changes, n_changes); } int unit_file_disable( @@ -2615,7 +2611,7 @@ int unit_file_disable( size_t *n_changes) { _cleanup_(lookup_paths_free) LookupPaths lp = {}; - _cleanup_(install_context_done) InstallContext c = {}; + _cleanup_(install_context_done) InstallContext ctx = { .scope = scope }; _cleanup_set_free_free_ Set *remove_symlinks_to = NULL; const char *config_path; int r; @@ -2635,12 +2631,12 @@ int unit_file_disable( if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) return -EINVAL; - r = install_info_add(&c, *i, NULL, lp.root_dir, /* auxiliary= */ false, NULL); + r = install_info_add(&ctx, *i, NULL, lp.root_dir, /* auxiliary= */ false, NULL); if (r < 0) return r; } - r = install_context_mark_for_removal(scope, &c, &lp, &remove_symlinks_to, config_path, changes, n_changes); + r = install_context_mark_for_removal(&ctx, &lp, &remove_symlinks_to, config_path, changes, n_changes); if (r < 0) return r; @@ -2683,8 +2679,8 @@ int unit_file_set_default( size_t *n_changes) { _cleanup_(lookup_paths_free) LookupPaths lp = {}; - _cleanup_(install_context_done) InstallContext c = {}; - UnitFileInstallInfo *i; + _cleanup_(install_context_done) InstallContext ctx = { .scope = scope }; + UnitFileInstallInfo *info; const char *new_path; int r; @@ -2701,12 +2697,12 @@ int unit_file_set_default( if (r < 0) return r; - r = install_info_discover_and_check(scope, &c, &lp, name, 0, &i, changes, n_changes); + r = install_info_discover_and_check(&ctx, &lp, name, 0, &info, changes, n_changes); if (r < 0) return r; new_path = strjoina(lp.persistent_config, "/" SPECIAL_DEFAULT_TARGET); - return create_symlink(&lp, i->path, new_path, flags & UNIT_FILE_FORCE, changes, n_changes); + return create_symlink(&lp, info->path, new_path, flags & UNIT_FILE_FORCE, changes, n_changes); } int unit_file_get_default( @@ -2715,8 +2711,8 @@ int unit_file_get_default( char **name) { _cleanup_(lookup_paths_free) LookupPaths lp = {}; - _cleanup_(install_context_done) InstallContext c = {}; - UnitFileInstallInfo *i; + _cleanup_(install_context_done) InstallContext ctx = { .scope = scope }; + UnitFileInstallInfo *info; char *n; int r; @@ -2728,15 +2724,15 @@ int unit_file_get_default( if (r < 0) return r; - r = install_info_discover(scope, &c, &lp, SPECIAL_DEFAULT_TARGET, SEARCH_FOLLOW_CONFIG_SYMLINKS, - &i, NULL, NULL); + r = install_info_discover(&ctx, &lp, SPECIAL_DEFAULT_TARGET, SEARCH_FOLLOW_CONFIG_SYMLINKS, + &info, NULL, NULL); if (r < 0) return r; - r = install_info_may_process(i, &lp, NULL, 0); + r = install_info_may_process(info, &lp, NULL, 0); if (r < 0) return r; - n = strdup(i->name); + n = strdup(info->name); if (!n) return -ENOMEM; @@ -2750,8 +2746,8 @@ int unit_file_lookup_state( const char *name, UnitFileState *ret) { - _cleanup_(install_context_done) InstallContext c = {}; - UnitFileInstallInfo *i; + _cleanup_(install_context_done) InstallContext ctx = { .scope = scope }; + UnitFileInstallInfo *info; UnitFileState state; int r; @@ -2761,23 +2757,23 @@ int unit_file_lookup_state( if (!unit_name_is_valid(name, UNIT_NAME_ANY)) return -EINVAL; - r = install_info_discover(scope, &c, lp, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, - &i, NULL, NULL); + r = install_info_discover(&ctx, lp, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, + &info, NULL, NULL); if (r < 0) return log_debug_errno(r, "Failed to discover unit %s: %m", name); - assert(IN_SET(i->type, UNIT_FILE_TYPE_REGULAR, UNIT_FILE_TYPE_MASKED)); - log_debug("Found unit %s at %s (%s)", name, strna(i->path), - i->type == UNIT_FILE_TYPE_REGULAR ? "regular file" : "mask"); + assert(IN_SET(info->type, UNIT_FILE_TYPE_REGULAR, UNIT_FILE_TYPE_MASKED)); + log_debug("Found unit %s at %s (%s)", name, strna(info->path), + info->type == UNIT_FILE_TYPE_REGULAR ? "regular file" : "mask"); /* Shortcut things, if the caller just wants to know if this unit exists. */ if (!ret) return 0; - switch (i->type) { + switch (info->type) { case UNIT_FILE_TYPE_MASKED: - r = path_is_runtime(lp, i->path, true); + r = path_is_runtime(lp, info->path, true); if (r < 0) return r; @@ -2786,12 +2782,12 @@ int unit_file_lookup_state( case UNIT_FILE_TYPE_REGULAR: /* Check if the name we were querying is actually an alias */ - if (!streq(name, basename(i->path)) && !unit_name_is_valid(i->name, UNIT_NAME_INSTANCE)) { + if (!streq(name, basename(info->path)) && !unit_name_is_valid(info->name, UNIT_NAME_INSTANCE)) { state = UNIT_FILE_ALIAS; break; } - r = path_is_generator(lp, i->path); + r = path_is_generator(lp, info->path); if (r < 0) return r; if (r > 0) { @@ -2799,7 +2795,7 @@ int unit_file_lookup_state( break; } - r = path_is_transient(lp, i->path); + r = path_is_transient(lp, info->path); if (r < 0) return r; if (r > 0) { @@ -2810,7 +2806,7 @@ int unit_file_lookup_state( /* Check if any of the Alias= symlinks have been created. * We ignore other aliases, and only check those that would * be created by systemctl enable for this unit. */ - r = find_symlinks_in_scope(scope, lp, i, true, &state); + r = find_symlinks_in_scope(scope, lp, info, true, &state); if (r < 0) return r; if (r > 0) @@ -2818,15 +2814,15 @@ int unit_file_lookup_state( /* Check if the file is known under other names. If it is, * it might be in use. Report that as UNIT_FILE_INDIRECT. */ - r = find_symlinks_in_scope(scope, lp, i, false, &state); + r = find_symlinks_in_scope(scope, lp, info, false, &state); if (r < 0) return r; if (r > 0) state = UNIT_FILE_INDIRECT; else { - if (unit_file_install_info_has_rules(i)) + if (unit_file_install_info_has_rules(info)) state = UNIT_FILE_DISABLED; - else if (unit_file_install_info_has_also(i)) + else if (unit_file_install_info_has_also(info)) state = UNIT_FILE_INDIRECT; else state = UNIT_FILE_STATIC; @@ -2863,7 +2859,7 @@ int unit_file_get_state( } int unit_file_exists(UnitFileScope scope, const LookupPaths *lp, const char *name) { - _cleanup_(install_context_done) InstallContext c = {}; + _cleanup_(install_context_done) InstallContext c = { .scope = scope }; int r; assert(lp); @@ -2872,7 +2868,7 @@ int unit_file_exists(UnitFileScope scope, const LookupPaths *lp, const char *nam if (!unit_name_is_valid(name, UNIT_NAME_ANY)) return -EINVAL; - r = install_info_discover(scope, &c, lp, name, 0, NULL, NULL, NULL); + r = install_info_discover(&c, lp, name, 0, NULL, NULL, NULL); if (r == -ENOENT) return 0; if (r < 0) @@ -3128,7 +3124,6 @@ int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char } static int execute_preset( - UnitFileScope scope, UnitFileFlags file_flags, InstallContext *plus, InstallContext *minus, @@ -3149,7 +3144,7 @@ static int execute_preset( if (mode != UNIT_FILE_PRESET_ENABLE_ONLY) { _cleanup_set_free_free_ Set *remove_symlinks_to = NULL; - r = install_context_mark_for_removal(scope, minus, lp, &remove_symlinks_to, config_path, changes, n_changes); + r = install_context_mark_for_removal(minus, lp, &remove_symlinks_to, config_path, changes, n_changes); if (r < 0) return r; @@ -3161,9 +3156,10 @@ static int execute_preset( int q; /* Returns number of symlinks that where supposed to be installed. */ - q = install_context_apply(scope, + q = install_context_apply(plus, lp, file_flags | UNIT_FILE_IGNORE_AUXILIARY_FAILURE, - plus, lp, config_path, SEARCH_LOAD, changes, n_changes); + config_path, + SEARCH_LOAD, changes, n_changes); if (r >= 0) { if (q < 0) r = q; @@ -3185,20 +3181,20 @@ static int preset_prepare_one( UnitFileChange **changes, size_t *n_changes) { - _cleanup_(install_context_done) InstallContext tmp = {}; + _cleanup_(install_context_done) InstallContext tmp = { .scope = scope }; _cleanup_strv_free_ char **instance_name_list = NULL; - UnitFileInstallInfo *i; + UnitFileInstallInfo *info; int r; if (install_info_find(plus, name) || install_info_find(minus, name)) return 0; - r = install_info_discover(scope, &tmp, lp, name, SEARCH_FOLLOW_CONFIG_SYMLINKS, - &i, changes, n_changes); + r = install_info_discover(&tmp, lp, name, SEARCH_FOLLOW_CONFIG_SYMLINKS, + &info, changes, n_changes); if (r < 0) return r; - if (!streq(name, i->name)) { - log_debug("Skipping %s because it is an alias for %s.", name, i->name); + if (!streq(name, info->name)) { + log_debug("Skipping %s because it is an alias for %s.", name, info->name); return 0; } @@ -3209,21 +3205,21 @@ static int preset_prepare_one( if (r > 0) { if (instance_name_list) STRV_FOREACH(s, instance_name_list) { - r = install_info_discover_and_check(scope, plus, lp, *s, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, - &i, changes, n_changes); + r = install_info_discover_and_check(plus, lp, *s, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, + &info, changes, n_changes); if (r < 0) return r; } else { - r = install_info_discover_and_check(scope, plus, lp, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, - &i, changes, n_changes); + r = install_info_discover_and_check(plus, lp, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, + &info, changes, n_changes); if (r < 0) return r; } } else - r = install_info_discover(scope, minus, lp, name, SEARCH_FOLLOW_CONFIG_SYMLINKS, - &i, changes, n_changes); + r = install_info_discover(minus, lp, name, SEARCH_FOLLOW_CONFIG_SYMLINKS, + &info, changes, n_changes); return r; } @@ -3265,7 +3261,7 @@ int unit_file_preset( return r; } - return execute_preset(scope, file_flags, &plus, &minus, &lp, config_path, files, mode, changes, n_changes); + return execute_preset(file_flags, &plus, &minus, &lp, config_path, files, mode, changes, n_changes); } int unit_file_preset_all( @@ -3326,7 +3322,7 @@ int unit_file_preset_all( } } - return execute_preset(scope, file_flags, &plus, &minus, &lp, config_path, NULL, mode, changes, n_changes); + return execute_preset(file_flags, &plus, &minus, &lp, config_path, NULL, mode, changes, n_changes); } static UnitFileList* unit_file_list_free_one(UnitFileList *f) { From 172e9cc3ee3dcca288d04c744984a9a3b2a0d008 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Wed, 9 Mar 2022 22:29:19 +0100 Subject: [PATCH 16/43] shared/specifier: fix %u/%U/%g/%G when called as unprivileged user MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We would resolve those specifiers to the calling user/group. This is mostly OK when done in the manager, because the manager generally operates as root in system mode, and a non-root in user mode. It would still be wrong if called with --test though. But in systemctl, this would be generally wrong, since we can call 'systemctl --system' as a normal user, either for testing or even for actual operation with '--root=…'. When operating in --global mode, %u/%U/%g/%G should return an error. The information whether we're operating in system mode, user mode, or global mode is passed as the data pointer to specifier_group_name(), specifier_user_name(), specifier_group_id(), specifier_user_id(). We can't use userdata, because it's already used for other things. --- src/core/unit-printf.c | 4 +- src/shared/install-printf.c | 9 +++- src/shared/install-printf.h | 7 ++- src/shared/install.c | 9 ++-- src/shared/specifier.c | 44 ++++++++++++++--- src/shared/specifier.h | 10 ++-- src/test/test-load-fragment.c | 91 ++++++++++++++++++++--------------- src/test/test-specifier.c | 3 +- src/tmpfiles/tmpfiles.c | 53 ++++++++++---------- test/test-systemctl-enable.sh | 11 ++--- test/test-systemd-tmpfiles.py | 8 +-- 11 files changed, 150 insertions(+), 99 deletions(-) diff --git a/src/core/unit-printf.c b/src/core/unit-printf.c index 4a86a3c0d6..0cdfcd6efd 100644 --- a/src/core/unit-printf.c +++ b/src/core/unit-printf.c @@ -183,7 +183,7 @@ int unit_name_printf(const Unit *u, const char* format, char **ret) { COMMON_SYSTEM_SPECIFIERS, - COMMON_CREDS_SPECIFIERS, + COMMON_CREDS_SPECIFIERS(u->manager->unit_file_scope), {} }; @@ -253,7 +253,7 @@ int unit_full_printf_full(const Unit *u, const char *format, size_t max_length, COMMON_SYSTEM_SPECIFIERS, - COMMON_CREDS_SPECIFIERS, + COMMON_CREDS_SPECIFIERS(u->manager->unit_file_scope), COMMON_TMP_SPECIFIERS, {} diff --git a/src/shared/install-printf.c b/src/shared/install-printf.c index 9c121cbaf7..571c4818e2 100644 --- a/src/shared/install-printf.c +++ b/src/shared/install-printf.c @@ -97,7 +97,12 @@ static int specifier_last_component(char specifier, const void *data, const char return 0; } -int install_name_printf(const UnitFileInstallInfo *i, const char *format, const char *root, char **ret) { +int install_name_printf( + UnitFileScope scope, + const UnitFileInstallInfo *i, + const char *format, + const char *root, + char **ret) { /* This is similar to unit_name_printf() */ const Specifier table[] = { @@ -109,7 +114,7 @@ int install_name_printf(const UnitFileInstallInfo *i, const char *format, const COMMON_SYSTEM_SPECIFIERS, - COMMON_CREDS_SPECIFIERS, + COMMON_CREDS_SPECIFIERS(scope), {} }; diff --git a/src/shared/install-printf.h b/src/shared/install-printf.h index 5ca9406797..d2cccdf66d 100644 --- a/src/shared/install-printf.h +++ b/src/shared/install-printf.h @@ -4,4 +4,9 @@ #include "install.h" #include "unit-name.h" -int install_name_printf(const UnitFileInstallInfo *i, const char *format, const char *root, char **ret); +int install_name_printf( + UnitFileScope scope, + const UnitFileInstallInfo *i, + const char *format, + const char *root, + char **ret); diff --git a/src/shared/install.c b/src/shared/install.c index bff1930828..4f43f190d6 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -1157,7 +1157,7 @@ static int config_parse_also( if (r == 0) break; - r = install_name_printf(info, word, info->root, &printed); + r = install_name_printf(ctx->scope, info, word, info->root, &printed); if (r < 0) return log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit name in Also=\"%s\": %m", word); @@ -1188,6 +1188,7 @@ static int config_parse_default_instance( void *data, void *userdata) { + InstallContext *ctx = ASSERT_PTR(data); UnitFileInstallInfo *info = ASSERT_PTR(userdata); _cleanup_free_ char *printed = NULL; int r; @@ -1205,7 +1206,7 @@ static int config_parse_default_instance( return log_syntax(unit, LOG_WARNING, filename, line, 0, "DefaultInstance= only makes sense for template units, ignoring."); - r = install_name_printf(info, rvalue, info->root, &printed); + r = install_name_printf(ctx->scope, info, rvalue, info->root, &printed); if (r < 0) return log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve instance name in DefaultInstance=\"%s\": %m", rvalue); @@ -1772,7 +1773,7 @@ static int install_info_symlink_alias( STRV_FOREACH(s, info->aliases) { _cleanup_free_ char *alias_path = NULL, *dst = NULL, *dst_updated = NULL; - q = install_name_printf(info, *s, info->root, &dst); + q = install_name_printf(scope, info, *s, info->root, &dst); if (q < 0) { unit_file_changes_add(changes, n_changes, q, *s, NULL); return q; @@ -1858,7 +1859,7 @@ static int install_info_symlink_wants( STRV_FOREACH(s, list) { _cleanup_free_ char *path = NULL, *dst = NULL; - q = install_name_printf(info, *s, info->root, &dst); + q = install_name_printf(scope, info, *s, info->root, &dst); if (q < 0) { unit_file_changes_add(changes, n_changes, q, *s, NULL); return q; diff --git a/src/shared/specifier.c b/src/shared/specifier.c index e994884196..777881b325 100644 --- a/src/shared/specifier.c +++ b/src/shared/specifier.c @@ -22,6 +22,7 @@ #include "specifier.h" #include "string-util.h" #include "strv.h" +#include "unit-file.h" #include "user-util.h" /* @@ -309,11 +310,15 @@ int specifier_os_image_version(char specifier, const void *data, const char *roo } int specifier_group_name(char specifier, const void *data, const char *root, const void *userdata, char **ret) { + UnitFileScope scope = PTR_TO_INT(data); char *t; assert(ret); - t = gid_to_name(getgid()); + if (scope == UNIT_FILE_GLOBAL) + return -EINVAL; + + t = gid_to_name(scope == UNIT_FILE_USER ? getgid() : 0); if (!t) return -ENOMEM; @@ -322,27 +327,42 @@ int specifier_group_name(char specifier, const void *data, const char *root, con } int specifier_group_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) { + UnitFileScope scope = PTR_TO_INT(data); + gid_t gid; + assert(ret); - if (asprintf(ret, UID_FMT, getgid()) < 0) + if (scope == UNIT_FILE_GLOBAL) + return -EINVAL; + + gid = scope == UNIT_FILE_USER ? getgid() : 0; + + if (asprintf(ret, UID_FMT, gid) < 0) return -ENOMEM; return 0; } int specifier_user_name(char specifier, const void *data, const char *root, const void *userdata, char **ret) { + UnitFileScope scope = PTR_TO_INT(data); + uid_t uid; char *t; assert(ret); - /* If we are UID 0 (root), this will not result in NSS, otherwise it might. This is good, as we want to be able - * to run this in PID 1, where our user ID is 0, but where NSS lookups are not allowed. + if (scope == UNIT_FILE_GLOBAL) + return -EINVAL; - * We don't use getusername_malloc() here, because we don't want to look at $USER, to remain consistent with - * specifer_user_id() below. + uid = scope == UNIT_FILE_USER ? getuid() : 0; + + /* If we are UID 0 (root), this will not result in NSS, otherwise it might. This is good, as we want + * to be able to run this in PID 1, where our user ID is 0, but where NSS lookups are not allowed. + + * We don't use getusername_malloc() here, because we don't want to look at $USER, to remain + * consistent with specifer_user_id() below. */ - t = uid_to_name(getuid()); + t = uid_to_name(uid); if (!t) return -ENOMEM; @@ -351,9 +371,17 @@ int specifier_user_name(char specifier, const void *data, const char *root, cons } int specifier_user_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) { + UnitFileScope scope = PTR_TO_INT(data); + uid_t uid; + assert(ret); - if (asprintf(ret, UID_FMT, getuid()) < 0) + if (scope == UNIT_FILE_GLOBAL) + return -EINVAL; + + uid = scope == UNIT_FILE_USER ? getuid() : 0; + + if (asprintf(ret, UID_FMT, uid) < 0) return -ENOMEM; return 0; diff --git a/src/shared/specifier.h b/src/shared/specifier.h index 2f2553cfdc..78b10f8467 100644 --- a/src/shared/specifier.h +++ b/src/shared/specifier.h @@ -84,11 +84,11 @@ int specifier_var_tmp_dir(char specifier, const void *data, const char *root, co { 'w', specifier_os_version_id, NULL }, \ { 'W', specifier_os_variant_id, NULL } -#define COMMON_CREDS_SPECIFIERS \ - { 'g', specifier_group_name, NULL }, \ - { 'G', specifier_group_id, NULL }, \ - { 'u', specifier_user_name, NULL }, \ - { 'U', specifier_user_id, NULL } +#define COMMON_CREDS_SPECIFIERS(scope) \ + { 'g', specifier_group_name, INT_TO_PTR(scope) }, \ + { 'G', specifier_group_id, INT_TO_PTR(scope) }, \ + { 'u', specifier_user_name, INT_TO_PTR(scope) }, \ + { 'U', specifier_user_id, INT_TO_PTR(scope) } #define COMMON_TMP_SPECIFIERS \ { 'T', specifier_tmp_dir, NULL }, \ diff --git a/src/test/test-load-fragment.c b/src/test/test-load-fragment.c index 52f6096eee..40cd7ea7e6 100644 --- a/src/test/test-load-fragment.c +++ b/src/test/test-load-fragment.c @@ -510,59 +510,74 @@ TEST(install_printf, .sd_booted = true) { assert_se(user = uid_to_name(getuid())); assert_se(asprintf(&uid, UID_FMT, getuid()) >= 0); -#define expect(src, pattern, result) \ +#define expect(scope, src, pattern, result) \ do { \ - _cleanup_free_ char *t = NULL; \ - _cleanup_free_ char \ - *d1 = strdup(i.name), \ - *d2 = strdup(i.path); \ - assert_se(install_name_printf(&src, pattern, NULL, &t) >= 0 || !result); \ + _cleanup_free_ char *t = NULL, \ + *d1 = ASSERT_PTR(strdup(i.name)), \ + *d2 = ASSERT_PTR(strdup(i.path)); \ + int r = install_name_printf(scope, &src, pattern, NULL, &t); \ + assert_se(result ? r >= 0 : r < 0); \ memzero(i.name, strlen(i.name)); \ memzero(i.path, strlen(i.path)); \ - assert_se(d1 && d2); \ if (result) { \ printf("%s\n", t); \ assert_se(streq(t, result)); \ - } else assert_se(t == NULL); \ + } else \ + assert_se(!t); \ strcpy(i.name, d1); \ strcpy(i.path, d2); \ } while (false) - expect(i, "%n", "name.service"); - expect(i, "%N", "name"); - expect(i, "%p", "name"); - expect(i, "%i", ""); - expect(i, "%j", "name"); - expect(i, "%g", group); - expect(i, "%G", gid); - expect(i, "%u", user); - expect(i, "%U", uid); + expect(UNIT_FILE_SYSTEM, i, "%n", "name.service"); + expect(UNIT_FILE_SYSTEM, i, "%N", "name"); + expect(UNIT_FILE_SYSTEM, i, "%p", "name"); + expect(UNIT_FILE_SYSTEM, i, "%i", ""); + expect(UNIT_FILE_SYSTEM, i, "%j", "name"); + expect(UNIT_FILE_SYSTEM, i, "%g", "root"); + expect(UNIT_FILE_SYSTEM, i, "%G", "0"); + expect(UNIT_FILE_SYSTEM, i, "%u", "root"); + expect(UNIT_FILE_SYSTEM, i, "%U", "0"); - expect(i, "%m", mid); - expect(i, "%b", bid); - expect(i, "%H", host); + expect(UNIT_FILE_SYSTEM, i, "%m", mid); + expect(UNIT_FILE_SYSTEM, i, "%b", bid); + expect(UNIT_FILE_SYSTEM, i, "%H", host); - expect(i2, "%g", group); - expect(i2, "%G", gid); - expect(i2, "%u", user); - expect(i2, "%U", uid); + expect(UNIT_FILE_SYSTEM, i2, "%g", "root"); + expect(UNIT_FILE_SYSTEM, i2, "%G", "0"); + expect(UNIT_FILE_SYSTEM, i2, "%u", "root"); + expect(UNIT_FILE_SYSTEM, i2, "%U", "0"); - expect(i3, "%n", "name@inst.service"); - expect(i3, "%N", "name@inst"); - expect(i3, "%p", "name"); - expect(i3, "%g", group); - expect(i3, "%G", gid); - expect(i3, "%u", user); - expect(i3, "%U", uid); + expect(UNIT_FILE_USER, i2, "%g", group); + expect(UNIT_FILE_USER, i2, "%G", gid); + expect(UNIT_FILE_USER, i2, "%u", user); + expect(UNIT_FILE_USER, i2, "%U", uid); - expect(i3, "%m", mid); - expect(i3, "%b", bid); - expect(i3, "%H", host); + /* gcc-12.0.1-0.9.fc36.x86_64 insist that streq(…, NULL) is called, + * even though the call is inside of a conditional where the pointer is checked. :( */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnonnull" + expect(UNIT_FILE_GLOBAL, i2, "%g", NULL); + expect(UNIT_FILE_GLOBAL, i2, "%G", NULL); + expect(UNIT_FILE_GLOBAL, i2, "%u", NULL); + expect(UNIT_FILE_GLOBAL, i2, "%U", NULL); +#pragma GCC diagnostic pop - expect(i4, "%g", group); - expect(i4, "%G", gid); - expect(i4, "%u", user); - expect(i4, "%U", uid); + expect(UNIT_FILE_SYSTEM, i3, "%n", "name@inst.service"); + expect(UNIT_FILE_SYSTEM, i3, "%N", "name@inst"); + expect(UNIT_FILE_SYSTEM, i3, "%p", "name"); + expect(UNIT_FILE_USER, i3, "%g", group); + expect(UNIT_FILE_USER, i3, "%G", gid); + expect(UNIT_FILE_USER, i3, "%u", user); + expect(UNIT_FILE_USER, i3, "%U", uid); + + expect(UNIT_FILE_SYSTEM, i3, "%m", mid); + expect(UNIT_FILE_SYSTEM, i3, "%b", bid); + expect(UNIT_FILE_SYSTEM, i3, "%H", host); + + expect(UNIT_FILE_USER, i4, "%g", group); + expect(UNIT_FILE_USER, i4, "%G", gid); + expect(UNIT_FILE_USER, i4, "%u", user); + expect(UNIT_FILE_USER, i4, "%U", uid); } static uint64_t make_cap(int cap) { diff --git a/src/test/test-specifier.c b/src/test/test-specifier.c index bb1c651c2a..947a32acf7 100644 --- a/src/test/test-specifier.c +++ b/src/test/test-specifier.c @@ -8,6 +8,7 @@ #include "string-util.h" #include "strv.h" #include "tests.h" +#include "unit-file.h" static void test_specifier_escape_one(const char *a, const char *b) { _cleanup_free_ char *x = NULL; @@ -46,7 +47,7 @@ TEST(specifier_escape_strv) { static const Specifier specifier_table[] = { COMMON_SYSTEM_SPECIFIERS, - COMMON_CREDS_SPECIFIERS, + COMMON_CREDS_SPECIFIERS(UNIT_FILE_USER), { 'h', specifier_user_home, NULL }, COMMON_TMP_SPECIFIERS, diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index f0190f9b4c..17b9c6ab9a 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -204,31 +204,6 @@ STATIC_DESTRUCTOR_REGISTER(arg_image, freep); static int specifier_machine_id_safe(char specifier, const void *data, const char *root, const void *userdata, char **ret); static int specifier_directory(char specifier, const void *data, const char *root, const void *userdata, char **ret); -static const Specifier specifier_table[] = { - { 'a', specifier_architecture, NULL }, - { 'b', specifier_boot_id, NULL }, - { 'B', specifier_os_build_id, NULL }, - { 'H', specifier_host_name, NULL }, - { 'l', specifier_short_host_name, NULL }, - { 'm', specifier_machine_id_safe, NULL }, - { 'o', specifier_os_id, NULL }, - { 'v', specifier_kernel_release, NULL }, - { 'w', specifier_os_version_id, NULL }, - { 'W', specifier_os_variant_id, NULL }, - - { 'h', specifier_user_home, NULL }, - - { 'C', specifier_directory, UINT_TO_PTR(DIRECTORY_CACHE) }, - { 'L', specifier_directory, UINT_TO_PTR(DIRECTORY_LOGS) }, - { 'S', specifier_directory, UINT_TO_PTR(DIRECTORY_STATE) }, - { 't', specifier_directory, UINT_TO_PTR(DIRECTORY_RUNTIME) }, - - COMMON_CREDS_SPECIFIERS, - - COMMON_TMP_SPECIFIERS, - {} -}; - static int specifier_machine_id_safe(char specifier, const void *data, const char *root, const void *userdata, char **ret) { int r; @@ -2737,7 +2712,7 @@ static bool should_include_path(const char *path) { return false; } -static int specifier_expansion_from_arg(Item *i) { +static int specifier_expansion_from_arg(const Specifier *specifier_table, Item *i) { int r; assert(i); @@ -2944,6 +2919,30 @@ static int parse_line( assert(line >= 1); assert(buffer); + const Specifier specifier_table[] = { + { 'a', specifier_architecture, NULL }, + { 'b', specifier_boot_id, NULL }, + { 'B', specifier_os_build_id, NULL }, + { 'H', specifier_host_name, NULL }, + { 'l', specifier_short_host_name, NULL }, + { 'm', specifier_machine_id_safe, NULL }, + { 'o', specifier_os_id, NULL }, + { 'v', specifier_kernel_release, NULL }, + { 'w', specifier_os_version_id, NULL }, + { 'W', specifier_os_variant_id, NULL }, + + { 'h', specifier_user_home, NULL }, + + { 'C', specifier_directory, UINT_TO_PTR(DIRECTORY_CACHE) }, + { 'L', specifier_directory, UINT_TO_PTR(DIRECTORY_LOGS) }, + { 'S', specifier_directory, UINT_TO_PTR(DIRECTORY_STATE) }, + { 't', specifier_directory, UINT_TO_PTR(DIRECTORY_RUNTIME) }, + + COMMON_CREDS_SPECIFIERS(arg_user ? UNIT_FILE_USER : UNIT_FILE_SYSTEM), + COMMON_TMP_SPECIFIERS, + {} + }; + r = extract_many_words( &buffer, NULL, @@ -3148,7 +3147,7 @@ static int parse_line( if (!should_include_path(i.path)) return 0; - r = specifier_expansion_from_arg(&i); + r = specifier_expansion_from_arg(specifier_table, &i); if (r == -ENXIO) return log_unresolvable_specifier(fname, line); if (r < 0) { diff --git a/test/test-systemctl-enable.sh b/test/test-systemctl-enable.sh index da1fffe944..8ac1342b91 100644 --- a/test/test-systemctl-enable.sh +++ b/test/test-systemctl-enable.sh @@ -500,9 +500,10 @@ check_alias t '' && { echo "Expected failure" >&2; exit 1; } check_alias T '' && { echo "Expected failure" >&2; exit 1; } check_alias V '' && { echo "Expected failure" >&2; exit 1; } -# FIXME: we use the calling user instead of root :( -check_alias g root || : -check_alias G 0 || : +check_alias g root +check_alias G 0 +check_alias u root +check_alias U 0 check_alias i "" @@ -521,10 +522,6 @@ check_alias N 'some-some-link6@' check_alias p 'some-some-link6' -# FIXME: we use the calling user instead of root :( -check_alias u root || : -check_alias U 0 || : - check_alias v "$(uname -r)" check_alias % '%' && { echo "Expected failure because % is not legal in unit name" >&2; exit 1; } diff --git a/test/test-systemd-tmpfiles.py b/test/test-systemd-tmpfiles.py index 3376029463..ba42b3fa37 100755 --- a/test/test-systemd-tmpfiles.py +++ b/test/test-systemd-tmpfiles.py @@ -98,13 +98,13 @@ def test_valid_specifiers(*, user): test_content('f {} - - - - %b', '{}'.format(id128.get_boot().hex), user=user) test_content('f {} - - - - %H', '{}'.format(socket.gethostname()), user=user) test_content('f {} - - - - %v', '{}'.format(os.uname().release), user=user) - test_content('f {} - - - - %U', '{}'.format(os.getuid()), user=user) - test_content('f {} - - - - %G', '{}'.format(os.getgid()), user=user) + test_content('f {} - - - - %U', '{}'.format(os.getuid() if user else 0), user=user) + test_content('f {} - - - - %G', '{}'.format(os.getgid() if user else 0), user=user) - puser = pwd.getpwuid(os.getuid()) + puser = pwd.getpwuid(os.getuid() if user else 0) test_content('f {} - - - - %u', '{}'.format(puser.pw_name), user=user) - pgroup = grp.getgrgid(os.getgid()) + pgroup = grp.getgrgid(os.getgid() if user else 0) test_content('f {} - - - - %g', '{}'.format(pgroup.gr_name), user=user) # Note that %h is the only specifier in which we look the environment, From 32450f5348c03262f3257af328b6547cbfba5859 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Thu, 10 Mar 2022 09:19:37 +0100 Subject: [PATCH 17/43] shared/install: simplify unit_file_dump_changes() No functional change. --- src/shared/install.c | 63 +++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 36 deletions(-) diff --git a/src/shared/install.c b/src/shared/install.c index 4f43f190d6..2ac3845a35 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -320,7 +320,7 @@ void unit_file_changes_free(UnitFileChange *changes, size_t n_changes) { } void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *changes, size_t n_changes, bool quiet) { - bool logged = false; + int err = 0; assert(changes || n_changes == 0); /* If verb is not specified, errors are not allowed! */ @@ -361,64 +361,55 @@ void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *chang break; case -EEXIST: if (changes[i].source) - log_error_errno(changes[i].type_or_errno, - "Failed to %s unit, file \"%s\" already exists and is a symlink to \"%s\".", - verb, changes[i].path, changes[i].source); + err = log_error_errno(changes[i].type_or_errno, + "Failed to %s unit, file \"%s\" already exists and is a symlink to \"%s\".", + verb, changes[i].path, changes[i].source); else - log_error_errno(changes[i].type_or_errno, - "Failed to %s unit, file \"%s\" already exists.", - verb, changes[i].path); - logged = true; + err = log_error_errno(changes[i].type_or_errno, + "Failed to %s unit, file \"%s\" already exists.", + verb, changes[i].path); break; case -ERFKILL: - log_error_errno(changes[i].type_or_errno, "Failed to %s unit, unit %s is masked.", - verb, changes[i].path); - logged = true; + err = log_error_errno(changes[i].type_or_errno, "Failed to %s unit, unit %s is masked.", + verb, changes[i].path); break; case -EADDRNOTAVAIL: - log_error_errno(changes[i].type_or_errno, "Failed to %s unit, unit %s is transient or generated.", - verb, changes[i].path); - logged = true; + err = log_error_errno(changes[i].type_or_errno, "Failed to %s unit, unit %s is transient or generated.", + verb, changes[i].path); break; case -EBADSLT: - log_error_errno(changes[i].type_or_errno, "Failed to %s unit, invalid specifier in \"%s\".", - verb, changes[i].path); - logged = true; + err = log_error_errno(changes[i].type_or_errno, "Failed to %s unit, invalid specifier in \"%s\".", + verb, changes[i].path); break; case -EIDRM: - log_error_errno(changes[i].type_or_errno, "Failed to %s %s, destination unit %s is a non-template unit.", - verb, changes[i].source, changes[i].path); - logged = true; + err = log_error_errno(changes[i].type_or_errno, "Failed to %s %s, destination unit %s is a non-template unit.", + verb, changes[i].source, changes[i].path); break; case -EUCLEAN: - log_error_errno(changes[i].type_or_errno, - "Failed to %s unit, \"%s\" is not a valid unit name.", - verb, changes[i].path); - logged = true; + err = log_error_errno(changes[i].type_or_errno, + "Failed to %s unit, \"%s\" is not a valid unit name.", + verb, changes[i].path); break; case -ELOOP: - log_error_errno(changes[i].type_or_errno, "Failed to %s unit, refusing to operate on linked unit file %s.", - verb, changes[i].path); - logged = true; + err = log_error_errno(changes[i].type_or_errno, "Failed to %s unit, refusing to operate on linked unit file %s.", + verb, changes[i].path); break; case -ENOENT: - log_error_errno(changes[i].type_or_errno, "Failed to %s unit, unit %s does not exist.", verb, changes[i].path); - logged = true; + err = log_error_errno(changes[i].type_or_errno, "Failed to %s unit, unit %s does not exist.", + verb, changes[i].path); break; case -EUNATCH: - log_error_errno(changes[i].type_or_errno, "Failed to %s unit, cannot resolve specifiers in \"%s\".", - verb, changes[i].path); - logged = true; + err = log_error_errno(changes[i].type_or_errno, "Failed to %s unit, cannot resolve specifiers in \"%s\".", + verb, changes[i].path); break; default: assert(changes[i].type_or_errno < 0); - log_error_errno(changes[i].type_or_errno, "Failed to %s unit, file \"%s\": %m", - verb, changes[i].path); - logged = true; + err = log_error_errno(changes[i].type_or_errno, "Failed to %s unit, file \"%s\": %m", + verb, changes[i].path); } } - if (r < 0 && !logged) + if (r < 0 && err >= 0) log_error_errno(r, "Failed to %s: %m.", verb); } From cbfdbffb618f1d75e668c59887a27c7a60950546 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Thu, 10 Mar 2022 11:03:41 +0100 Subject: [PATCH 18/43] shared/install: propagate errors about invalid aliases and such too If an invalid arg appears in [Install] Alias=, WantedBy=, RequiredBy=, we'd warn in the logs, but not propagate this information to the caller, and in particular not over dbus. But if we call "systemctl enable" on a unit, and the config if invalid, this information is quite important. --- src/basic/unit-file.c | 44 +++++++++++++------------- src/basic/unit-file.h | 2 +- src/shared/install.c | 61 ++++++++++++++++++++++++++---------- src/shared/install.h | 7 ++++- src/test/test-install-root.c | 2 +- src/test/test-unit-file.c | 28 ++++++++--------- 6 files changed, 88 insertions(+), 56 deletions(-) diff --git a/src/basic/unit-file.c b/src/basic/unit-file.c index 95256a7be9..0e9a556268 100644 --- a/src/basic/unit-file.c +++ b/src/basic/unit-file.c @@ -69,7 +69,7 @@ int unit_symlink_name_compatible(const char *symlink, const char *target, bool i return 0; } -int unit_validate_alias_symlink_and_warn(const char *filename, const char *target) { +int unit_validate_alias_symlink_or_warn(int log_level, const char *filename, const char *target) { const char *src, *dst; _cleanup_free_ char *src_instance = NULL, *dst_instance = NULL; UnitType src_unit_type, dst_unit_type; @@ -92,51 +92,51 @@ int unit_validate_alias_symlink_and_warn(const char *filename, const char *targe src_name_type = unit_name_to_instance(src, &src_instance); if (src_name_type < 0) - return log_notice_errno(src_name_type, - "%s: not a valid unit name \"%s\": %m", filename, src); + return log_full_errno(log_level, src_name_type, + "%s: not a valid unit name \"%s\": %m", filename, src); src_unit_type = unit_name_to_type(src); assert(src_unit_type >= 0); /* unit_name_to_instance() checked the suffix already */ if (!unit_type_may_alias(src_unit_type)) - return log_notice_errno(SYNTHETIC_ERRNO(EINVAL), - "%s: symlinks are not allowed for units of this type, rejecting.", - filename); + return log_full_errno(log_level, SYNTHETIC_ERRNO(EINVAL), + "%s: symlinks are not allowed for units of this type, rejecting.", + filename); if (src_name_type != UNIT_NAME_PLAIN && !unit_type_may_template(src_unit_type)) - return log_notice_errno(SYNTHETIC_ERRNO(EINVAL), - "%s: templates not allowed for %s units, rejecting.", - filename, unit_type_to_string(src_unit_type)); + return log_full_errno(log_level, SYNTHETIC_ERRNO(EINVAL), + "%s: templates not allowed for %s units, rejecting.", + filename, unit_type_to_string(src_unit_type)); /* dst checks */ dst_name_type = unit_name_to_instance(dst, &dst_instance); if (dst_name_type < 0) - return log_notice_errno(dst_name_type == -EINVAL ? SYNTHETIC_ERRNO(EXDEV) : dst_name_type, - "%s points to \"%s\" which is not a valid unit name: %m", - filename, dst); + return log_full_errno(log_level, dst_name_type == -EINVAL ? SYNTHETIC_ERRNO(EXDEV) : dst_name_type, + "%s points to \"%s\" which is not a valid unit name: %m", + filename, dst); if (!(dst_name_type == src_name_type || (src_name_type == UNIT_NAME_INSTANCE && dst_name_type == UNIT_NAME_TEMPLATE))) - return log_notice_errno(SYNTHETIC_ERRNO(EXDEV), - "%s: symlink target name type \"%s\" does not match source, rejecting.", - filename, dst); + return log_full_errno(log_level, SYNTHETIC_ERRNO(EXDEV), + "%s: symlink target name type \"%s\" does not match source, rejecting.", + filename, dst); if (dst_name_type == UNIT_NAME_INSTANCE) { assert(src_instance); assert(dst_instance); if (!streq(src_instance, dst_instance)) - return log_notice_errno(SYNTHETIC_ERRNO(EXDEV), - "%s: unit symlink target \"%s\" instance name doesn't match, rejecting.", - filename, dst); + return log_full_errno(log_level, SYNTHETIC_ERRNO(EXDEV), + "%s: unit symlink target \"%s\" instance name doesn't match, rejecting.", + filename, dst); } dst_unit_type = unit_name_to_type(dst); if (dst_unit_type != src_unit_type) - return log_notice_errno(SYNTHETIC_ERRNO(EXDEV), - "%s: symlink target \"%s\" has incompatible suffix, rejecting.", - filename, dst); + return log_full_errno(log_level, SYNTHETIC_ERRNO(EXDEV), + "%s: symlink target \"%s\" has incompatible suffix, rejecting.", + filename, dst); return 0; } @@ -354,7 +354,7 @@ int unit_file_resolve_symlink( "Suspicious symlink %s/%s→%s, treating as alias.", dir, filename, simplified); - r = unit_validate_alias_symlink_and_warn(filename, simplified); + r = unit_validate_alias_symlink_or_warn(LOG_NOTICE, filename, simplified); if (r < 0) return r; diff --git a/src/basic/unit-file.h b/src/basic/unit-file.h index e29e878cfd..b7c03e9c2c 100644 --- a/src/basic/unit-file.h +++ b/src/basic/unit-file.h @@ -41,7 +41,7 @@ bool unit_type_may_alias(UnitType type) _const_; bool unit_type_may_template(UnitType type) _const_; int unit_symlink_name_compatible(const char *symlink, const char *target, bool instance_propagation); -int unit_validate_alias_symlink_and_warn(const char *filename, const char *target); +int unit_validate_alias_symlink_or_warn(int log_level, const char *filename, const char *target); bool lookup_paths_timestamp_hash_same(const LookupPaths *lp, uint64_t timestamp_hash, uint64_t *ret_new); diff --git a/src/shared/install.c b/src/shared/install.c index 2ac3845a35..332c146710 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -394,6 +394,14 @@ void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *chang err = log_error_errno(changes[i].type_or_errno, "Failed to %s unit, refusing to operate on linked unit file %s.", verb, changes[i].path); break; + case -EXDEV: + if (changes[i].source) + err = log_error_errno(changes[i].type_or_errno, "Failed to %s unit, cannot alias %s as %s.", + verb, changes[i].source, changes[i].path); + else + err = log_error_errno(changes[i].type_or_errno, "Failed to %s unit, invalid unit reference \"%s\".", + verb, changes[i].path); + break; case -ENOENT: err = log_error_errno(changes[i].type_or_errno, "Failed to %s unit, unit %s does not exist.", verb, changes[i].path); @@ -1671,7 +1679,13 @@ static int install_info_discover_and_check( return install_info_may_process(ret ? *ret : NULL, lp, changes, n_changes); } -int unit_file_verify_alias(const UnitFileInstallInfo *info, const char *dst, char **ret_dst) { +int unit_file_verify_alias( + const UnitFileInstallInfo *info, + const char *dst, + char **ret_dst, + UnitFileChange **changes, + size_t *n_changes) { + _cleanup_free_ char *dst_updated = NULL; int r; @@ -1698,15 +1712,19 @@ int unit_file_verify_alias(const UnitFileInstallInfo *info, const char *dst, cha p = endswith(dir, ".wants"); if (!p) p = endswith(dir, ".requires"); - if (!p) - return log_warning_errno(SYNTHETIC_ERRNO(EXDEV), - "Invalid path \"%s\" in alias.", dir); + if (!p) { + unit_file_changes_add(changes, n_changes, -EXDEV, dst, NULL); + return log_debug_errno(SYNTHETIC_ERRNO(EXDEV), "Invalid path \"%s\" in alias.", dir); + } + *p = '\0'; /* dir should now be a unit name */ UnitNameFlags type = unit_name_classify(dir); - if (type < 0) - return log_warning_errno(SYNTHETIC_ERRNO(EXDEV), - "Invalid unit name component \"%s\" in alias.", dir); + if (type < 0) { + unit_file_changes_add(changes, n_changes, -EXDEV, dst, NULL); + return log_debug_errno(SYNTHETIC_ERRNO(EXDEV), + "Invalid unit name component \"%s\" in alias.", dir); + } const bool instance_propagation = type == UNIT_NAME_TEMPLATE; @@ -1714,10 +1732,12 @@ int unit_file_verify_alias(const UnitFileInstallInfo *info, const char *dst, cha r = unit_symlink_name_compatible(path_alias, info->name, instance_propagation); if (r < 0) return log_error_errno(r, "Failed to verify alias validity: %m"); - if (r == 0) - return log_warning_errno(SYNTHETIC_ERRNO(EXDEV), - "Invalid unit \"%s\" symlink \"%s\".", - info->name, dst); + if (r == 0) { + unit_file_changes_add(changes, n_changes, -EXDEV, dst, info->name); + return log_debug_errno(SYNTHETIC_ERRNO(EXDEV), + "Invalid unit \"%s\" symlink \"%s\".", + info->name, dst); + } } else { /* If the symlink target has an instance set and the symlink source doesn't, we "propagate @@ -1726,8 +1746,10 @@ int unit_file_verify_alias(const UnitFileInstallInfo *info, const char *dst, cha _cleanup_free_ char *inst = NULL; UnitNameFlags type = unit_name_to_instance(info->name, &inst); - if (type < 0) - return log_error_errno(type, "Failed to extract instance name from \"%s\": %m", info->name); + if (type < 0) { + unit_file_changes_add(changes, n_changes, -EUCLEAN, info->name, NULL); + return log_debug_errno(type, "Failed to extract instance name from \"%s\": %m", info->name); + } if (type == UNIT_NAME_INSTANCE) { r = unit_name_replace_instance(dst, inst, &dst_updated); @@ -1737,9 +1759,14 @@ int unit_file_verify_alias(const UnitFileInstallInfo *info, const char *dst, cha } } - r = unit_validate_alias_symlink_and_warn(dst_updated ?: dst, info->name); - if (r < 0) + r = unit_validate_alias_symlink_or_warn(LOG_DEBUG, dst_updated ?: dst, info->name); + if (r < 0) { + unit_file_changes_add(changes, n_changes, + r == -EINVAL ? -EXDEV : r, + dst_updated ?: dst, + info->name); return r; + } } *ret_dst = TAKE_PTR(dst_updated); @@ -1770,7 +1797,7 @@ static int install_info_symlink_alias( return q; } - q = unit_file_verify_alias(info, dst, &dst_updated); + q = unit_file_verify_alias(info, dst, &dst_updated, changes, n_changes); if (q < 0) continue; @@ -3307,7 +3334,7 @@ int unit_file_preset_all( r = preset_prepare_one(scope, &plus, &minus, &lp, de->d_name, &presets, changes, n_changes); if (r < 0 && - !IN_SET(r, -EEXIST, -ERFKILL, -EADDRNOTAVAIL, -EBADSLT, -EIDRM, -EUCLEAN, -ELOOP, -ENOENT, -EUNATCH)) + !IN_SET(r, -EEXIST, -ERFKILL, -EADDRNOTAVAIL, -EBADSLT, -EIDRM, -EUCLEAN, -ELOOP, -ENOENT, -EUNATCH, -EXDEV)) /* Ignore generated/transient/missing/invalid units when applying preset, propagate other errors. * Coordinate with unit_file_dump_changes() above. */ return r; diff --git a/src/shared/install.h b/src/shared/install.h index cdc5435035..d21e2aaa45 100644 --- a/src/shared/install.h +++ b/src/shared/install.h @@ -193,7 +193,12 @@ int unit_file_changes_add(UnitFileChange **changes, size_t *n_changes, int type, void unit_file_changes_free(UnitFileChange *changes, size_t n_changes); void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *changes, size_t n_changes, bool quiet); -int unit_file_verify_alias(const UnitFileInstallInfo *i, const char *dst, char **ret_dst); +int unit_file_verify_alias( + const UnitFileInstallInfo *info, + const char *dst, + char **ret_dst, + UnitFileChange **changes, + size_t *n_changes); typedef struct UnitFilePresetRule UnitFilePresetRule; diff --git a/src/test/test-install-root.c b/src/test/test-install-root.c index f718689c3a..4f66c12655 100644 --- a/src/test/test-install-root.c +++ b/src/test/test-install-root.c @@ -1091,7 +1091,7 @@ static void verify_one( if (i != last_info) log_info("-- %s --", (last_info = i)->name); - r = unit_file_verify_alias(i, alias, &alias2); + r = unit_file_verify_alias(i, alias, &alias2, NULL, NULL); log_info_errno(r, "alias %s ← %s: %d/%m (expected %d)%s%s%s", i->name, alias, r, expected, alias2 ? " [" : "", strempty(alias2), diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c index 9b05a191e6..261bd7412f 100644 --- a/src/test/test-unit-file.c +++ b/src/test/test-unit-file.c @@ -8,20 +8,20 @@ #include "unit-file.h" TEST(unit_validate_alias_symlink_and_warn) { - assert_se(unit_validate_alias_symlink_and_warn("/path/a.service", "/other/b.service") == 0); - assert_se(unit_validate_alias_symlink_and_warn("/path/a.service", "/other/b.socket") == -EXDEV); - assert_se(unit_validate_alias_symlink_and_warn("/path/a.service", "/other/b.foobar") == -EXDEV); - assert_se(unit_validate_alias_symlink_and_warn("/path/a@.service", "/other/b@.service") == 0); - assert_se(unit_validate_alias_symlink_and_warn("/path/a@.service", "/other/b@.socket") == -EXDEV); - assert_se(unit_validate_alias_symlink_and_warn("/path/a@XXX.service", "/other/b@YYY.service") == -EXDEV); - assert_se(unit_validate_alias_symlink_and_warn("/path/a@XXX.service", "/other/b@YYY.socket") == -EXDEV); - assert_se(unit_validate_alias_symlink_and_warn("/path/a@.service", "/other/b@YYY.service") == -EXDEV); - assert_se(unit_validate_alias_symlink_and_warn("/path/a@XXX.service", "/other/b@XXX.service") == 0); - assert_se(unit_validate_alias_symlink_and_warn("/path/a@XXX.service", "/other/b@.service") == 0); - assert_se(unit_validate_alias_symlink_and_warn("/path/a@.service", "/other/b.service") == -EXDEV); - assert_se(unit_validate_alias_symlink_and_warn("/path/a.service", "/other/b@.service") == -EXDEV); - assert_se(unit_validate_alias_symlink_and_warn("/path/a@.slice", "/other/b.slice") == -EINVAL); - assert_se(unit_validate_alias_symlink_and_warn("/path/a.slice", "/other/b.slice") == -EINVAL); + assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a.service", "/other/b.service") == 0); + assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a.service", "/other/b.socket") == -EXDEV); + assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a.service", "/other/b.foobar") == -EXDEV); + assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a@.service", "/other/b@.service") == 0); + assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a@.service", "/other/b@.socket") == -EXDEV); + assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a@XXX.service", "/other/b@YYY.service") == -EXDEV); + assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a@XXX.service", "/other/b@YYY.socket") == -EXDEV); + assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a@.service", "/other/b@YYY.service") == -EXDEV); + assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a@XXX.service", "/other/b@XXX.service") == 0); + assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a@XXX.service", "/other/b@.service") == 0); + assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a@.service", "/other/b.service") == -EXDEV); + assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a.service", "/other/b@.service") == -EXDEV); + assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a@.slice", "/other/b.slice") == -EINVAL); + assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a.slice", "/other/b.slice") == -EINVAL); } TEST(unit_file_build_name_map) { From 0d11db59825a9deee0b56fdede0602ef1c37c5c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Thu, 10 Mar 2022 15:47:12 +0100 Subject: [PATCH 19/43] shared/install: return failure when enablement fails, but process as much as possible So far we'd issue a warning (before this series, just in the logs on the server side, and before this commit, on stderr on the caller's side), but return success. It seems that successfull return was introduced by mistake in aa0f357fd833feecbea6c3e9be80b643e433bced (my fault :( ), which was supposed to be a refactoring without a functional change. I think it's better to fail, because if enablement fails, the user will most likely want to diagnose the issue. Note that we still do partial enablement, as far as that is possible. So if e.g. we have [Install] Alias=foo.service foobar, we'll create the symlink 'foo.service', but not 'foobar', since that's not a valid unit name. We'll print info about the action taken, and about 'foobar' being invalid, and return failure. --- src/shared/install.c | 10 +++++---- test/test-systemctl-enable.sh | 39 ++++++++++++++++++----------------- 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/src/shared/install.c b/src/shared/install.c index 332c146710..554c530cc4 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -1794,20 +1794,22 @@ static int install_info_symlink_alias( q = install_name_printf(scope, info, *s, info->root, &dst); if (q < 0) { unit_file_changes_add(changes, n_changes, q, *s, NULL); - return q; + r = r < 0 ? r : q; + continue; } q = unit_file_verify_alias(info, dst, &dst_updated, changes, n_changes); - if (q < 0) + if (q < 0) { + r = r < 0 ? r : q; continue; + } alias_path = path_make_absolute(dst_updated ?: dst, config_path); if (!alias_path) return -ENOMEM; q = create_symlink(lp, info->path, alias_path, force, changes, n_changes); - if (r == 0) - r = q; + r = r < 0 ? r : q; } return r; diff --git a/test/test-systemctl-enable.sh b/test/test-systemctl-enable.sh index 8ac1342b91..32bc6e5ef7 100644 --- a/test/test-systemctl-enable.sh +++ b/test/test-systemctl-enable.sh @@ -56,19 +56,27 @@ test ! -e "$root/etc/systemd/system/default.target.wants/test1.service" test ! -e "$root/etc/systemd/system/special.target.requires/test1.service" : -------aliases---------------------------------------------- -"$systemctl" --root="$root" enable test1 -test -h "$root/etc/systemd/system/default.target.wants/test1.service" -test -h "$root/etc/systemd/system/special.target.requires/test1.service" - cat >>"$root/etc/systemd/system/test1.service" <&2; exit 1; } +test -h "$root/etc/systemd/system/default.target.wants/test1.service" +test -h "$root/etc/systemd/system/special.target.requires/test1.service" +test ! -e "$root/etc/systemd/system/test1-goodalias.service" +test -h "$root/etc/systemd/system/test1-goodalias.service" +test ! -e "$root/etc/systemd/system/test1@badalias.service" +test ! -e "$root/etc/systemd/system/test1-badalias.target" +test ! -e "$root/etc/systemd/system/test1-badalias.socket" +test -h "$root/etc/systemd/system/test1-goodalias2.service" + : -------aliases in reeanble---------------------------------- -"$systemctl" --root="$root" reenable test1 +"$systemctl" --root="$root" reenable test1 && { echo "Expected failure" >&2; exit 1; } test -h "$root/etc/systemd/system/default.target.wants/test1.service" test ! -e "$root/etc/systemd/system/test1-goodalias.service" test -h "$root/etc/systemd/system/test1-goodalias.service" @@ -328,7 +336,7 @@ Alias=link4alias.service Alias=link4alias2.service EOF -"$systemctl" --root="$root" enable 'link4.service' +"$systemctl" --root="$root" enable 'link4.service' && { echo "Expected failure" >&2; exit 1; } test ! -h "$root/etc/systemd/system/link4.service" # this is our file test ! -h "$root/etc/systemd/system/link4@.service" test ! -h "$root/etc/systemd/system/link4@inst.service" @@ -343,18 +351,20 @@ test ! -h "$root/etc/systemd/system/link4alias.service" test ! -h "$root/etc/systemd/system/link4alias2.service" : -------systemctl enable on path to unit file---------------- +cat >"$root/etc/systemd/system/link4.service" <"$root/etc/systemd/system/link5.service" <&2; exit 1; } -# FIXME: if there's an invalid Alias=, we shouldn't preach about empty [Install] - # TODO: repeat the tests above for presets : -------SYSTEMD_OS_RELEASE relative to root------------------ From 99aad9a2b9e2c06023a2043976fd9395332ff097 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Thu, 10 Mar 2022 16:47:51 +0100 Subject: [PATCH 20/43] systemctl: fix silent failure when --root is not found Some calls to lookup_path_init() were not followed by any log emission. E.g.: $ SYSTEMD_LOG_LEVEL=debug systemctl --root=/missing enable unit; echo $? 1 Let's add a helper function and use it in various places. $ SYSTEMD_LOG_LEVEL=debug build/systemctl --root=/missing enable unit; echo $? Failed to initialize unit search paths for root directory /missing: No such file or directory 1 $ SYSTEMCTL_SKIP_SYSV=1 build/systemctl --root=/missing enable unit; echo $? Failed to initialize unit search paths for root directory /missing: No such file or directory Failed to enable: No such file or directory. 1 The repeated error in the second case is not very nice, but this is a niche case and I don't think it's worth the trouble to trying to avoid it. --- src/analyze/analyze-unit-files.c | 4 +- src/analyze/analyze-unit-paths.c | 4 +- src/basic/env-file.c | 85 +++++++++------------------ src/basic/path-lookup.c | 70 ++++++++++++---------- src/basic/path-lookup.h | 3 +- src/core/manager.c | 12 ++-- src/shared/condition.c | 3 +- src/shared/install.c | 2 +- src/systemctl/systemctl-edit.c | 8 +-- src/systemctl/systemctl-enable.c | 2 +- src/systemctl/systemctl-sysv-compat.c | 2 +- src/sysv-generator/sysv-generator.c | 4 +- src/test/test-fileio.c | 3 +- src/test/test-os-util.c | 7 +-- 14 files changed, 96 insertions(+), 113 deletions(-) diff --git a/src/analyze/analyze-unit-files.c b/src/analyze/analyze-unit-files.c index 60fbdcb230..f07ec3e56c 100644 --- a/src/analyze/analyze-unit-files.c +++ b/src/analyze/analyze-unit-files.c @@ -21,9 +21,9 @@ int verb_unit_files(int argc, char *argv[], void *userdata) { char **v; int r; - r = lookup_paths_init(&lp, arg_scope, 0, NULL); + r = lookup_paths_init_or_warn(&lp, arg_scope, 0, NULL); if (r < 0) - return log_error_errno(r, "lookup_paths_init() failed: %m"); + return r; r = unit_file_build_name_map(&lp, NULL, &unit_ids, &unit_names, NULL); if (r < 0) diff --git a/src/analyze/analyze-unit-paths.c b/src/analyze/analyze-unit-paths.c index 32c97b2e52..6fa1527dd6 100644 --- a/src/analyze/analyze-unit-paths.c +++ b/src/analyze/analyze-unit-paths.c @@ -9,9 +9,9 @@ int verb_unit_paths(int argc, char *argv[], void *userdata) { _cleanup_(lookup_paths_free) LookupPaths paths = {}; int r; - r = lookup_paths_init(&paths, arg_scope, 0, NULL); + r = lookup_paths_init_or_warn(&paths, arg_scope, 0, NULL); if (r < 0) - return log_error_errno(r, "lookup_paths_init() failed: %m"); + return r; STRV_FOREACH(p, paths.search_path) puts(*p); diff --git a/src/basic/env-file.c b/src/basic/env-file.c index 14925e72e1..2ab5c7bc0d 100644 --- a/src/basic/env-file.c +++ b/src/basic/env-file.c @@ -16,9 +16,8 @@ static int parse_env_file_internal( FILE *f, const char *fname, int (*push) (const char *filename, unsigned line, - const char *key, char *value, void *userdata, int *n_pushed), - void *userdata, - int *n_pushed) { + const char *key, char *value, void *userdata), + void *userdata) { size_t n_key = 0, n_value = 0, last_value_whitespace = SIZE_MAX, last_key_whitespace = SIZE_MAX; _cleanup_free_ char *contents = NULL, *key = NULL, *value = NULL; @@ -99,7 +98,7 @@ static int parse_env_file_internal( if (last_key_whitespace != SIZE_MAX) key[last_key_whitespace] = 0; - r = push(fname, line, key, value, userdata, n_pushed); + r = push(fname, line, key, value, userdata); if (r < 0) return r; @@ -142,7 +141,7 @@ static int parse_env_file_internal( if (last_key_whitespace != SIZE_MAX) key[last_key_whitespace] = 0; - r = push(fname, line, key, value, userdata, n_pushed); + r = push(fname, line, key, value, userdata); if (r < 0) return r; @@ -261,7 +260,7 @@ static int parse_env_file_internal( if (last_key_whitespace != SIZE_MAX) key[last_key_whitespace] = 0; - r = push(fname, line, key, value, userdata, n_pushed); + r = push(fname, line, key, value, userdata); if (r < 0) return r; @@ -299,8 +298,7 @@ static int check_utf8ness_and_warn( static int parse_env_file_push( const char *filename, unsigned line, const char *key, char *value, - void *userdata, - int *n_pushed) { + void *userdata) { const char *k; va_list aq, *ap = userdata; @@ -322,9 +320,6 @@ static int parse_env_file_push( free(*v); *v = value; - if (n_pushed) - (*n_pushed)++; - return 1; } } @@ -340,16 +335,13 @@ int parse_env_filev( const char *fname, va_list ap) { - int r, n_pushed = 0; + int r; va_list aq; va_copy(aq, ap); - r = parse_env_file_internal(f, fname, parse_env_file_push, &aq, &n_pushed); + r = parse_env_file_internal(f, fname, parse_env_file_push, &aq); va_end(aq); - if (r < 0) - return r; - - return n_pushed; + return r; } int parse_env_file_sentinel( @@ -370,8 +362,7 @@ int parse_env_file_sentinel( static int load_env_file_push( const char *filename, unsigned line, const char *key, char *value, - void *userdata, - int *n_pushed) { + void *userdata) { char ***m = userdata; char *p; int r; @@ -388,34 +379,28 @@ static int load_env_file_push( if (r < 0) return r; - if (n_pushed) - (*n_pushed)++; - free(value); return 0; } int load_env_file(FILE *f, const char *fname, char ***rl) { - char **m = NULL; + _cleanup_strv_free_ char **m = NULL; int r; - r = parse_env_file_internal(f, fname, load_env_file_push, &m, NULL); - if (r < 0) { - strv_free(m); + r = parse_env_file_internal(f, fname, load_env_file_push, &m); + if (r < 0) return r; - } - *rl = m; + *rl = TAKE_PTR(m); return 0; } static int load_env_file_push_pairs( const char *filename, unsigned line, const char *key, char *value, - void *userdata, - int *n_pushed) { + void *userdata) { + char ***m = ASSERT_PTR(userdata); - bool added = false; int r; r = check_utf8ness_and_warn(filename, line, key, value); @@ -426,49 +411,37 @@ static int load_env_file_push_pairs( for (char **t = *m; t && *t; t += 2) if (streq(t[0], key)) { if (value) - r = free_and_replace(t[1], value); + return free_and_replace(t[1], value); else - r = free_and_strdup(t+1, ""); - goto finish; + return free_and_strdup(t+1, ""); } r = strv_extend(m, key); - if (r < 0) - return -ENOMEM; - - if (value) - r = strv_push(m, value); - else - r = strv_extend(m, ""); - added = true; - finish: if (r < 0) return r; - if (n_pushed && added) - (*n_pushed)++; - return 0; + if (value) + return strv_push(m, value); + else + return strv_extend(m, ""); } int load_env_file_pairs(FILE *f, const char *fname, char ***rl) { - char **m = NULL; + _cleanup_strv_free_ char **m = NULL; int r; - r = parse_env_file_internal(f, fname, load_env_file_push_pairs, &m, NULL); - if (r < 0) { - strv_free(m); + r = parse_env_file_internal(f, fname, load_env_file_push_pairs, &m); + if (r < 0) return r; - } - *rl = m; + *rl = TAKE_PTR(m); return 0; } static int merge_env_file_push( const char *filename, unsigned line, const char *key, char *value, - void *userdata, - int *n_pushed) { + void *userdata) { char ***env = userdata; char *expanded_value; @@ -497,7 +470,7 @@ static int merge_env_file_push( log_debug("%s:%u: setting %s=%s", filename, line, key, value); - return load_env_file_push(filename, line, key, value, env, n_pushed); + return load_env_file_push(filename, line, key, value, env); } int merge_env_file( @@ -509,7 +482,7 @@ int merge_env_file( * plus "extended" substitutions, unlike other exported parsing functions. */ - return parse_env_file_internal(f, fname, merge_env_file_push, env, NULL); + return parse_env_file_internal(f, fname, merge_env_file_push, env); } static void write_env_var(FILE *f, const char *v) { diff --git a/src/basic/path-lookup.c b/src/basic/path-lookup.c index 2dd587fd8a..b699756658 100644 --- a/src/basic/path-lookup.c +++ b/src/basic/path-lookup.c @@ -508,7 +508,7 @@ static int get_paths_from_environ(const char *var, char ***paths, bool *append) } int lookup_paths_init( - LookupPaths *p, + LookupPaths *lp, UnitFileScope scope, LookupPathsFlags flags, const char *root_dir) { @@ -526,7 +526,7 @@ int lookup_paths_init( _cleanup_strv_free_ char **paths = NULL; int r; - assert(p); + assert(lp); assert(scope >= 0); assert(scope < _UNIT_FILE_SCOPE_MAX); @@ -716,7 +716,7 @@ int lookup_paths_init( if (r < 0) return -ENOMEM; - *p = (LookupPaths) { + *lp = (LookupPaths) { .search_path = strv_uniq(TAKE_PTR(paths)), .persistent_config = TAKE_PTR(persistent_config), @@ -741,41 +741,51 @@ int lookup_paths_init( return 0; } -void lookup_paths_free(LookupPaths *p) { - if (!p) - return; +int lookup_paths_init_or_warn(LookupPaths *lp, UnitFileScope scope, LookupPathsFlags flags, const char *root_dir) { + int r; - p->search_path = strv_free(p->search_path); - - p->persistent_config = mfree(p->persistent_config); - p->runtime_config = mfree(p->runtime_config); - - p->persistent_attached = mfree(p->persistent_attached); - p->runtime_attached = mfree(p->runtime_attached); - - p->generator = mfree(p->generator); - p->generator_early = mfree(p->generator_early); - p->generator_late = mfree(p->generator_late); - - p->transient = mfree(p->transient); - - p->persistent_control = mfree(p->persistent_control); - p->runtime_control = mfree(p->runtime_control); - - p->root_dir = mfree(p->root_dir); - p->temporary_dir = mfree(p->temporary_dir); + r = lookup_paths_init(lp, scope, flags, root_dir); + if (r < 0) + return log_error_errno(r, "Failed to initialize unit search paths%s%s: %m", + isempty(root_dir) ? "" : " for root directory ", strempty(root_dir)); + return r; } -void lookup_paths_log(LookupPaths *p) { - assert(p); +void lookup_paths_free(LookupPaths *lp) { + if (!lp) + return; - if (strv_isempty(p->search_path)) { + lp->search_path = strv_free(lp->search_path); + + lp->persistent_config = mfree(lp->persistent_config); + lp->runtime_config = mfree(lp->runtime_config); + + lp->persistent_attached = mfree(lp->persistent_attached); + lp->runtime_attached = mfree(lp->runtime_attached); + + lp->generator = mfree(lp->generator); + lp->generator_early = mfree(lp->generator_early); + lp->generator_late = mfree(lp->generator_late); + + lp->transient = mfree(lp->transient); + + lp->persistent_control = mfree(lp->persistent_control); + lp->runtime_control = mfree(lp->runtime_control); + + lp->root_dir = mfree(lp->root_dir); + lp->temporary_dir = mfree(lp->temporary_dir); +} + +void lookup_paths_log(LookupPaths *lp) { + assert(lp); + + if (strv_isempty(lp->search_path)) { log_debug("Ignoring unit files."); - p->search_path = strv_free(p->search_path); + lp->search_path = strv_free(lp->search_path); } else { _cleanup_free_ char *t = NULL; - t = strv_join(p->search_path, "\n\t"); + t = strv_join(lp->search_path, "\n\t"); log_debug("Looking for unit files in (higher priority first):\n\t%s", strna(t)); } } diff --git a/src/basic/path-lookup.h b/src/basic/path-lookup.h index af85dc7b4f..1f0e5ea271 100644 --- a/src/basic/path-lookup.h +++ b/src/basic/path-lookup.h @@ -54,7 +54,8 @@ struct LookupPaths { char *temporary_dir; }; -int lookup_paths_init(LookupPaths *p, UnitFileScope scope, LookupPathsFlags flags, const char *root_dir); +int lookup_paths_init(LookupPaths *lp, UnitFileScope scope, LookupPathsFlags flags, const char *root_dir); +int lookup_paths_init_or_warn(LookupPaths *lp, UnitFileScope scope, LookupPathsFlags flags, const char *root_dir); int xdg_user_dirs(char ***ret_config_dirs, char ***ret_data_dirs); int xdg_user_runtime_dir(char **ret, const char *suffix); diff --git a/src/core/manager.c b/src/core/manager.c index 69717e5ba6..0fbb7d290e 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -1751,11 +1751,11 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds, const char *roo /* If we are running in test mode, we still want to run the generators, * but we should not touch the real generator directories. */ - r = lookup_paths_init(&m->lookup_paths, m->unit_file_scope, - MANAGER_IS_TEST_RUN(m) ? LOOKUP_PATHS_TEMPORARY_GENERATED : 0, - root); + r = lookup_paths_init_or_warn(&m->lookup_paths, m->unit_file_scope, + MANAGER_IS_TEST_RUN(m) ? LOOKUP_PATHS_TEMPORARY_GENERATED : 0, + root); if (r < 0) - return log_error_errno(r, "Failed to initialize path lookup table: %m"); + return r; dual_timestamp_get(m->timestamps + manager_timestamp_initrd_mangle(MANAGER_TIMESTAMP_GENERATORS_START)); r = manager_run_environment_generators(m); @@ -3343,9 +3343,9 @@ int manager_reload(Manager *m) { m->uid_refs = hashmap_free(m->uid_refs); m->gid_refs = hashmap_free(m->gid_refs); - r = lookup_paths_init(&m->lookup_paths, m->unit_file_scope, 0, NULL); + r = lookup_paths_init_or_warn(&m->lookup_paths, m->unit_file_scope, 0, NULL); if (r < 0) - log_warning_errno(r, "Failed to initialize path lookup table, ignoring: %m"); + return r; (void) manager_run_environment_generators(m); (void) manager_run_generators(m); diff --git a/src/shared/condition.c b/src/shared/condition.c index 0a4072c9be..15b22a4006 100644 --- a/src/shared/condition.c +++ b/src/shared/condition.c @@ -785,7 +785,8 @@ static int condition_test_needs_update(Condition *c, char **env) { if (r < 0) { log_debug_errno(r, "Failed to parse timestamp file '%s', using mtime: %m", p); return true; - } else if (r == 0) { + } + if (isempty(timestamp_str)) { log_debug("No data in timestamp file '%s', using mtime.", p); return true; } diff --git a/src/shared/install.c b/src/shared/install.c index 554c530cc4..cfada13442 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -2597,7 +2597,7 @@ int unit_file_enable( assert(scope >= 0); assert(scope < _UNIT_FILE_SCOPE_MAX); - r = lookup_paths_init(&lp, scope, 0, root_dir); + r = lookup_paths_init_or_warn(&lp, scope, 0, root_dir); if (r < 0) return r; diff --git a/src/systemctl/systemctl-edit.c b/src/systemctl/systemctl-edit.c index 6ef6cc54a8..f8f810e1cd 100644 --- a/src/systemctl/systemctl-edit.c +++ b/src/systemctl/systemctl-edit.c @@ -37,9 +37,9 @@ int verb_cat(int argc, char *argv[], void *userdata) { if (arg_transport != BUS_TRANSPORT_LOCAL) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot remotely cat units."); - r = lookup_paths_init(&lp, arg_scope, 0, arg_root); + r = lookup_paths_init_or_warn(&lp, arg_scope, 0, arg_root); if (r < 0) - return log_error_errno(r, "Failed to determine unit paths: %m"); + return r; r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) @@ -507,9 +507,9 @@ int verb_edit(int argc, char *argv[], void *userdata) { if (arg_transport != BUS_TRANSPORT_LOCAL) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot edit units remotely."); - r = lookup_paths_init(&lp, arg_scope, 0, arg_root); + r = lookup_paths_init_or_warn(&lp, arg_scope, 0, arg_root); if (r < 0) - return log_error_errno(r, "Failed to determine unit paths: %m"); + return r; r = mac_selinux_init(); if (r < 0) diff --git a/src/systemctl/systemctl-enable.c b/src/systemctl/systemctl-enable.c index b18c516b26..a1ca837d4d 100644 --- a/src/systemctl/systemctl-enable.c +++ b/src/systemctl/systemctl-enable.c @@ -141,7 +141,7 @@ int verb_enable(int argc, char *argv[], void *userdata) { if (STR_IN_SET(verb, "mask", "unmask")) { _cleanup_(lookup_paths_free) LookupPaths lp = {}; - r = lookup_paths_init(&lp, arg_scope, 0, arg_root); + r = lookup_paths_init_or_warn(&lp, arg_scope, 0, arg_root); if (r < 0) return r; diff --git a/src/systemctl/systemctl-sysv-compat.c b/src/systemctl/systemctl-sysv-compat.c index 017dba2034..c6e8defd1b 100644 --- a/src/systemctl/systemctl-sysv-compat.c +++ b/src/systemctl/systemctl-sysv-compat.c @@ -128,7 +128,7 @@ int enable_sysv_units(const char *verb, char **args) { "is-enabled")) return 0; - r = lookup_paths_init(&paths, arg_scope, LOOKUP_PATHS_EXCLUDE_GENERATED, arg_root); + r = lookup_paths_init_or_warn(&paths, arg_scope, LOOKUP_PATHS_EXCLUDE_GENERATED, arg_root); if (r < 0) return r; diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c index a81df6600b..428509f4ce 100644 --- a/src/sysv-generator/sysv-generator.c +++ b/src/sysv-generator/sysv-generator.c @@ -891,9 +891,9 @@ static int run(const char *dest, const char *dest_early, const char *dest_late) assert_se(arg_dest = dest_late); - r = lookup_paths_init(&lp, UNIT_FILE_SYSTEM, LOOKUP_PATHS_EXCLUDE_GENERATED, NULL); + r = lookup_paths_init_or_warn(&lp, UNIT_FILE_SYSTEM, LOOKUP_PATHS_EXCLUDE_GENERATED, NULL); if (r < 0) - return log_error_errno(r, "Failed to find lookup paths: %m"); + return r; all_services = hashmap_new(&string_hash_ops); if (!all_services) diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c index 3e626dbe93..3e98d94019 100644 --- a/src/test/test-fileio.c +++ b/src/test/test-fileio.c @@ -109,8 +109,7 @@ TEST(parse_env_file) { "eleven", &eleven, "twelve", &twelve, "thirteen", &thirteen); - - assert_se(r >= 0); + assert_se(r == 0); log_info("one=[%s]", strna(one)); log_info("two=[%s]", strna(two)); diff --git a/src/test/test-os-util.c b/src/test/test-os-util.c index d6336c53e9..2cee6470c4 100644 --- a/src/test/test-os-util.c +++ b/src/test/test-os-util.c @@ -18,7 +18,7 @@ TEST(path_is_os_tree) { TEST(parse_os_release) { /* Let's assume that we're running in a valid system, so os-release is available */ _cleanup_free_ char *id = NULL, *id2 = NULL, *name = NULL, *foobar = NULL; - assert_se(parse_os_release(NULL, "ID", &id) == 1); + assert_se(parse_os_release(NULL, "ID", &id) == 0); log_info("ID: %s", id); assert_se(setenv("SYSTEMD_OS_RELEASE", "/dev/null", 1) == 0); @@ -31,7 +31,7 @@ TEST(parse_os_release) { "NAME=the-name") == 0); assert_se(setenv("SYSTEMD_OS_RELEASE", tmpfile, 1) == 0); - assert_se(parse_os_release(NULL, "ID", &id, "NAME", &name) == 2); + assert_se(parse_os_release(NULL, "ID", &id, "NAME", &name) == 0); log_info("ID: %s NAME: %s", id, name); assert_se(streq(id, "the-id")); assert_se(streq(name, "the-name")); @@ -43,8 +43,7 @@ TEST(parse_os_release) { "NAME='the-name'") == 0); assert_se(setenv("SYSTEMD_OS_RELEASE", tmpfile2, 1) == 0); - // FIXME: we return 3, which means that the return value is useless in face of repeats - assert_se(parse_os_release(NULL, "ID", &id, "NAME", &name) == 3); + assert_se(parse_os_release(NULL, "ID", &id, "NAME", &name) == 0); log_info("ID: %s NAME: %s", id, name); assert_se(streq(id, "the-id")); assert_se(streq(name, "the-name")); From f663e6468ff6f667a67fa1a0f9ca5c4962d4c605 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Thu, 10 Mar 2022 20:26:59 +0100 Subject: [PATCH 21/43] shared/install: also check for self-aliases during installation and ignore them We had a check that was done in unit_file_resolve_symlink(). Let's move the check to unit_validate_alias_symlink_or_warn(), which makes it available to the code in install.c. With this, unit_file_resolve_symlink() behaves almost the same. The warning about "suspicious symlink" is done a bit later. I think this should be OK. --- src/basic/unit-file.c | 26 ++++++++++---------------- src/shared/install.c | 9 +++++++++ test/test-systemctl-enable.sh | 6 ++---- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/basic/unit-file.c b/src/basic/unit-file.c index 0e9a556268..6cf66b45cf 100644 --- a/src/basic/unit-file.c +++ b/src/basic/unit-file.c @@ -82,7 +82,8 @@ int unit_validate_alias_symlink_or_warn(int log_level, const char *filename, con * * -EINVAL is returned if the something is wrong with the source filename or the source unit type is * not allowed to symlink, - * -EXDEV if the target filename is not a valid unit name or doesn't match the source. + * -EXDEV if the target filename is not a valid unit name or doesn't match the source, + * -ELOOP for an alias to self. */ src = basename(filename); @@ -111,6 +112,11 @@ int unit_validate_alias_symlink_or_warn(int log_level, const char *filename, con /* dst checks */ + if (streq(src, dst)) + return log_debug_errno(SYNTHETIC_ERRNO(ELOOP), + "%s: unit self-alias: %s → %s, ignoring.", + filename, src, dst); + dst_name_type = unit_name_to_instance(dst, &dst_instance); if (dst_name_type < 0) return log_full_errno(log_level, dst_name_type == -EINVAL ? SYNTHETIC_ERRNO(EXDEV) : dst_name_type, @@ -347,24 +353,12 @@ int unit_file_resolve_symlink( if (r < 0) return r; - bool self_alias = streq(target_name, filename); - - if (is_path(tail)) - log_full(self_alias ? LOG_DEBUG : LOG_WARNING, - "Suspicious symlink %s/%s→%s, treating as alias.", - dir, filename, simplified); - r = unit_validate_alias_symlink_or_warn(LOG_NOTICE, filename, simplified); if (r < 0) return r; - - if (self_alias && !resolve_destination_target) - /* A self-alias that has no effect when loading, let's just ignore it. */ - return log_debug_errno(SYNTHETIC_ERRNO(ELOOP), - "Unit file self-alias: %s/%s → %s, ignoring.", - dir, filename, target_name); - - log_debug("Unit file alias: %s/%s → %s", dir, filename, target_name); + if (is_path(tail)) + log_warning("Suspicious symlink %s/%s→%s, treating as alias.", + dir, filename, simplified); dst = resolve_destination_target ? TAKE_PTR(simplified) : TAKE_PTR(target_name); } diff --git a/src/shared/install.c b/src/shared/install.c index cfada13442..bc15b0e9d2 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -1695,6 +1695,11 @@ int unit_file_verify_alias( * ret_dst is set in cases where "instance propagation" happens, i.e. when the instance part is * inserted into dst. It is not normally set, even on success, so that the caller can easily * distinguish the case where instance propagation occurred. + * + * Returns: + * -EXDEV when the alias doesn't match the unit, + * -EUCLEAN when the name is invalid, + * -ELOOP when the alias it to the unit itself. */ const char *path_alias = strrchr(dst, '/'); @@ -1760,6 +1765,8 @@ int unit_file_verify_alias( } r = unit_validate_alias_symlink_or_warn(LOG_DEBUG, dst_updated ?: dst, info->name); + if (r == -ELOOP) /* -ELOOP means self-alias, which we (quietly) ignore */ + return r; if (r < 0) { unit_file_changes_add(changes, n_changes, r == -EINVAL ? -EXDEV : r, @@ -1799,6 +1806,8 @@ static int install_info_symlink_alias( } q = unit_file_verify_alias(info, dst, &dst_updated, changes, n_changes); + if (q == -ELOOP) + continue; if (q < 0) { r = r < 0 ? r : q; continue; diff --git a/test/test-systemctl-enable.sh b/test/test-systemctl-enable.sh index 32bc6e5ef7..4117436462 100644 --- a/test/test-systemctl-enable.sh +++ b/test/test-systemctl-enable.sh @@ -328,8 +328,7 @@ test ! -h "$root/etc/systemd/system/services.target.wants/templ1@two.service" test ! -e "$root/etc/systemd/system/link4.service" cat >"$root/etc/systemd/system/link4.service" <"$root/etc/systemd/system/link5.service" < Date: Thu, 10 Mar 2022 21:33:25 +0100 Subject: [PATCH 22/43] man: fix invalid description of template handling in WantedBy= We don't need to talk about Alias=. The approach of using Alias= to enable units is still supported, but hasn't been advertised as the way to do thing for many years. Using it as an explanation is just confusing. Also, the description of templated units did not take DefaultInstance= into account. It is updated and extended. --- man/systemd.unit.xml | 51 +++++++++++++++++------------------ test/test-systemctl-enable.sh | 49 +++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 27 deletions(-) diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml index 372f5f8f7c..dd3553aa18 100644 --- a/man/systemd.unit.xml +++ b/man/systemd.unit.xml @@ -1904,34 +1904,31 @@ WantedBy= RequiredBy= - This option may be used more than once, or a - space-separated list of unit names may be given. A symbolic - link is created in the .wants/ or - .requires/ directory of each of the - listed units when this unit is installed by systemctl - enable. This has the effect that a dependency of - type Wants= or Requires= - is added from the listed unit to the current unit. The primary - result is that the current unit will be started when the - listed unit is started. See the description of - Wants= and Requires= in - the [Unit] section for details. + This option may be used more than once, or a space-separated list of unit names may + be given. A symbolic link is created in the .wants/ or + .requires/ directory of each of the listed units when this unit is installed by + systemctl enable. This has the effect of a dependency of type + Wants= or Requires= being added from the listed unit to the + current unit. The primary result is that the current unit will be started when the listed unit is + started, see the description of Wants= and Requires= in the + [Unit] section for details. - WantedBy=foo.service in a service - bar.service is mostly equivalent to - Alias=foo.service.wants/bar.service in the - same file. In case of template units listing non template units, - systemctl enable must be called with an - instance name, and this instance will be added to the - .wants/ or - .requires/ list of the listed unit. E.g. - WantedBy=getty.target in a service - getty@.service will result in - systemctl enable getty@tty2.service - creating a - getty.target.wants/getty@tty2.service - link to getty@.service. - + In case of template units listing non template units, the listing unit must have + DefaultInstance= set, or systemctl enable must be called with + an instance name. The instance (default or specified) will be added to the + .wants/ or .requires/ list of the listed unit. For example, + WantedBy=getty.target in a service getty@.service will result + in systemctl enable getty@tty2.service creating a + getty.target.wants/getty@tty2.service link to + getty@.service. This also applies to listing specific instances of templated + units: this specific instance will gain the dependency. A template unit may also list a template + unit, in which case a generic dependency will be added where each instance of the listing unit will + have a dependency on an instance of the listed template with the same instance value. For example, + WantedBy=container@.target in a service monitor@.service will + result in systemctl enable monitor@.service creating a + container@.target.wants/monitor@.service link to + monitor@.service, which applies to all instances of + container@.target. diff --git a/test/test-systemctl-enable.sh b/test/test-systemctl-enable.sh index 4117436462..3aa61222a8 100644 --- a/test/test-systemctl-enable.sh +++ b/test/test-systemctl-enable.sh @@ -324,6 +324,31 @@ test ! -h "$root/etc/systemd/system/services.target.wants/templ1@333.service" test ! -h "$root/etc/systemd/system/services.target.wants/templ1@one.service" test ! -h "$root/etc/systemd/system/services.target.wants/templ1@two.service" +: -------template enablement for another template------------- +cat >"$root/etc/systemd/system/templ2@.service" <"$root/etc/systemd/system/link4.service" <&2; exit 1; } +: -------specifiers in WantedBy------------------------------- +# We don't need to repeat all the tests. Let's do a basic check that specifier +# expansion is performed. + +cat >"$root/etc/systemd/system/some-some-link7.socket" < Date: Fri, 11 Mar 2022 14:27:46 +0100 Subject: [PATCH 23/43] install: when linking a file, create the link first or abort We'd create aliases and other symlinks first, and only then try to create the main link. Since that can fail, let's do things in opposite order, and abort immediately if we can't link the file itself. --- src/shared/install.c | 12 +++++++----- test/test-systemctl-enable.sh | 9 +++------ 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/shared/install.c b/src/shared/install.c index bc15b0e9d2..5dbc267eb8 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -1980,6 +1980,13 @@ static int install_info_apply( bool force = file_flags & UNIT_FILE_FORCE; + r = install_info_symlink_link(info, lp, config_path, force, changes, n_changes); + /* Do not count links to the unit file towards the "carries_install_info" count */ + if (r < 0) + /* If linking of the file failed, do not try to create other symlinks, + * because they might would pointing to a non-existent or wrong unit. */ + return r; + r = install_info_symlink_alias(scope, info, lp, config_path, force, changes, n_changes); q = install_info_symlink_wants(scope, file_flags, info, lp, config_path, info->wanted_by, ".wants/", changes, n_changes); @@ -1990,11 +1997,6 @@ static int install_info_apply( if (r == 0) r = q; - q = install_info_symlink_link(info, lp, config_path, force, changes, n_changes); - /* Do not count links to the unit file towards the "carries_install_info" count */ - if (r == 0 && q < 0) - r = q; - return r; } diff --git a/test/test-systemctl-enable.sh b/test/test-systemctl-enable.sh index 3aa61222a8..c1fb9626ab 100644 --- a/test/test-systemctl-enable.sh +++ b/test/test-systemctl-enable.sh @@ -173,12 +173,9 @@ islink "$root/etc/systemd/system/link1.path" "/link1.path" islink "$root/etc/systemd/system/paths.target.wants/link1.path" "/link1.path" : -------enable already linked different path----------------- -# FIXME -# "$systemctl" --root="$root" enable '/subdir/link1.path' && { echo "Expected failure" >&2; exit 1; } -# test -h "$root/etc/systemd/system/link1.path" -# readlink "$root/etc/systemd/system/link1.path" -# test -h "$root/etc/systemd/system/paths.target.wants/link1.path" -# readlink "$root/etc/systemd/system/paths.target.wants/link1.path" +"$systemctl" --root="$root" enable '/subdir/link1.path' && { echo "Expected failure" >&2; exit 1; } +islink "$root/etc/systemd/system/link1.path" "/link1.path" +islink "$root/etc/systemd/system/paths.target.wants/link1.path" "/link1.path" : -------enable bad suffix------------------------------------ cp "$root/link1.path" "$root/subdir/link1.suffix" From ec7eaff3c2abf3048f3fba98bfbe08a0c7c898b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Mon, 14 Mar 2022 12:09:31 +0100 Subject: [PATCH 24/43] shared/install: split unit_file_{disable,enable}() so _reenable doesn't do setup twice It was pretty ugly that we were creating LookupPaths twice. --- src/shared/install.c | 125 ++++++++++++++++++++++++++++--------------- 1 file changed, 82 insertions(+), 43 deletions(-) diff --git a/src/shared/install.c b/src/shared/install.c index 5dbc267eb8..4b69e9129a 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -2591,33 +2591,21 @@ int unit_file_add_dependency( SEARCH_FOLLOW_CONFIG_SYMLINKS, changes, n_changes); } -int unit_file_enable( +static int do_unit_file_enable( + const LookupPaths *lp, UnitFileScope scope, - UnitFileFlags file_flags, - const char *root_dir, + UnitFileFlags flags, + const char *config_path, char **files, UnitFileChange **changes, size_t *n_changes) { - _cleanup_(lookup_paths_free) LookupPaths lp = {}; _cleanup_(install_context_done) InstallContext ctx = { .scope = scope }; - const char *config_path; UnitFileInstallInfo *info; int r; - assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); - - r = lookup_paths_init_or_warn(&lp, scope, 0, root_dir); - if (r < 0) - return r; - - config_path = config_path_from_flags(&lp, file_flags); - if (!config_path) - return -ENXIO; - STRV_FOREACH(f, files) { - r = install_info_discover_and_check(&ctx, &lp, *f, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, + r = install_info_discover_and_check(&ctx, lp, *f, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, &info, changes, n_changes); if (r < 0) return r; @@ -2630,10 +2618,65 @@ int unit_file_enable( is useful to determine whether the passed files had any installation data at all. */ - return install_context_apply(&ctx, &lp, file_flags, config_path, + return install_context_apply(&ctx, lp, flags, config_path, SEARCH_LOAD, changes, n_changes); } +int unit_file_enable( + UnitFileScope scope, + UnitFileFlags flags, + const char *root_dir, + char **files, + UnitFileChange **changes, + size_t *n_changes) { + + _cleanup_(lookup_paths_free) LookupPaths lp = {}; + int r; + + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); + + r = lookup_paths_init(&lp, scope, 0, root_dir); + if (r < 0) + return r; + + const char *config_path = config_path_from_flags(&lp, flags); + if (!config_path) + return -ENXIO; + + return do_unit_file_enable(&lp, scope, flags, config_path, files, changes, n_changes); +} + +static int do_unit_file_disable( + const LookupPaths *lp, + UnitFileScope scope, + UnitFileFlags flags, + const char *config_path, + char **files, + UnitFileChange **changes, + size_t *n_changes) { + + _cleanup_(install_context_done) InstallContext ctx = { .scope = scope }; + _cleanup_set_free_free_ Set *remove_symlinks_to = NULL; + int r; + + STRV_FOREACH(i, files) { + if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) + return -EINVAL; + + r = install_info_add(&ctx, *i, NULL, lp->root_dir, /* auxiliary= */ false, NULL); + if (r < 0) + return r; + } + + r = install_context_mark_for_removal(&ctx, lp, &remove_symlinks_to, config_path, changes, n_changes); + if (r < 0) + return r; + + return remove_marked_symlinks(remove_symlinks_to, config_path, lp, flags & UNIT_FILE_DRY_RUN, changes, n_changes); +} + + int unit_file_disable( UnitFileScope scope, UnitFileFlags flags, @@ -2643,9 +2686,6 @@ int unit_file_disable( size_t *n_changes) { _cleanup_(lookup_paths_free) LookupPaths lp = {}; - _cleanup_(install_context_done) InstallContext ctx = { .scope = scope }; - _cleanup_set_free_free_ Set *remove_symlinks_to = NULL; - const char *config_path; int r; assert(scope >= 0); @@ -2655,24 +2695,11 @@ int unit_file_disable( if (r < 0) return r; - config_path = config_path_from_flags(&lp, flags); + const char *config_path = config_path_from_flags(&lp, flags); if (!config_path) return -ENXIO; - STRV_FOREACH(i, files) { - if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) - return -EINVAL; - - r = install_info_add(&ctx, *i, NULL, lp.root_dir, /* auxiliary= */ false, NULL); - if (r < 0) - return r; - } - - r = install_context_mark_for_removal(&ctx, &lp, &remove_symlinks_to, config_path, changes, n_changes); - if (r < 0) - return r; - - return remove_marked_symlinks(remove_symlinks_to, config_path, &lp, flags & UNIT_FILE_DRY_RUN, changes, n_changes); + return do_unit_file_disable(&lp, scope, flags, config_path, files, changes, n_changes); } int unit_file_reenable( @@ -2683,23 +2710,35 @@ int unit_file_reenable( UnitFileChange **changes, size_t *n_changes) { - char **n; - int r; + _cleanup_(lookup_paths_free) LookupPaths lp = {}; size_t l, i; + char **names; + int r; + + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); + + r = lookup_paths_init(&lp, scope, 0, root_dir); + if (r < 0) + return r; + + const char *config_path = config_path_from_flags(&lp, flags); + if (!config_path) + return -ENXIO; /* First, we invoke the disable command with only the basename... */ l = strv_length(files); - n = newa(char*, l+1); + names = newa(char*, l+1); for (i = 0; i < l; i++) - n[i] = basename(files[i]); - n[i] = NULL; + names[i] = basename(files[i]); + names[i] = NULL; - r = unit_file_disable(scope, flags, root_dir, n, changes, n_changes); + r = do_unit_file_disable(&lp, scope, flags, config_path, names, changes, n_changes); if (r < 0) return r; /* But the enable command with the full name */ - return unit_file_enable(scope, flags, root_dir, files, changes, n_changes); + return do_unit_file_enable(&lp, scope, flags, config_path, files, changes, n_changes); } int unit_file_set_default( From 29a7c59abbe594422f1ed7602263420745339a3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Tue, 15 Mar 2022 09:44:39 +0100 Subject: [PATCH 25/43] shared/install: fix reenable on linked unit files --- src/shared/install.c | 73 ++++++++++++++++++++++++++++++----- src/shared/install.h | 2 +- test/test-systemctl-enable.sh | 8 ++-- 3 files changed, 68 insertions(+), 15 deletions(-) diff --git a/src/shared/install.c b/src/shared/install.c index 4b69e9129a..a4c4be16b3 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -2702,17 +2702,74 @@ int unit_file_disable( return do_unit_file_disable(&lp, scope, flags, config_path, files, changes, n_changes); } +static int normalize_linked_files( + UnitFileScope scope, + const LookupPaths *lp, + char **names_or_paths, + char ***ret_names, + char ***ret_files) { + + /* This is similar to normalize_filenames()/normalize_names() in src/systemctl/, + * but operates on real unit names. For each argument we we look up the actual path + * where the unit is found. This way linked units can be reenabled successfully. */ + + _cleanup_free_ char **files = NULL, **names = NULL; + int r; + + STRV_FOREACH(a, names_or_paths) { + _cleanup_(install_context_done) InstallContext ctx = { .scope = scope }; + UnitFileInstallInfo *i = NULL; + _cleanup_free_ char *n = NULL; + + r = path_extract_filename(*a, &n); + if (r < 0) + return r; + if (r == O_DIRECTORY) + return log_debug_errno(SYNTHETIC_ERRNO(EISDIR), + "Unexpected path to a directory \"%s\", refusing.", *a); + + if (!is_path(*a)) { + r = install_info_discover(&ctx, lp, n, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, &i, NULL, NULL); + if (r < 0) + log_debug_errno(r, "Failed to discover unit \"%s\", operating on name: %m", n); + } + + r = strv_consume(&names, TAKE_PTR(n)); + if (r < 0) + return r; + + const char *p = NULL; + if (i && i->path) + /* Use startswith here, because we know that paths are normalized, and + * path_startswith() would give us a relative path, but we need an absolute path + * relative to i->root. + * + * In other words: /var/tmp/instroot.1234/etc/systemd/system/frobnicator.service + * is replaced by /etc/systemd/system/frobnicator.service, which is "absolute" + * in a sense, but only makes sense "relative" to /var/tmp/instroot.1234/. + */ + p = startswith(i->path, i->root); + + r = strv_extend(&files, p ?: *a); + if (r < 0) + return r; + } + + *ret_names = TAKE_PTR(names); + *ret_files = TAKE_PTR(files); + return 0; +} + int unit_file_reenable( UnitFileScope scope, UnitFileFlags flags, const char *root_dir, - char **files, + char **names_or_paths, UnitFileChange **changes, size_t *n_changes) { _cleanup_(lookup_paths_free) LookupPaths lp = {}; - size_t l, i; - char **names; + _cleanup_strv_free_ char **names = NULL, **files = NULL; int r; assert(scope >= 0); @@ -2726,13 +2783,11 @@ int unit_file_reenable( if (!config_path) return -ENXIO; - /* First, we invoke the disable command with only the basename... */ - l = strv_length(files); - names = newa(char*, l+1); - for (i = 0; i < l; i++) - names[i] = basename(files[i]); - names[i] = NULL; + r = normalize_linked_files(scope, &lp, names_or_paths, &names, &files); + if (r < 0) + return r; + /* First, we invoke the disable command with only the basename... */ r = do_unit_file_disable(&lp, scope, flags, config_path, names, changes, n_changes); if (r < 0) return r; diff --git a/src/shared/install.h b/src/shared/install.h index d21e2aaa45..dba6987406 100644 --- a/src/shared/install.h +++ b/src/shared/install.h @@ -111,7 +111,7 @@ int unit_file_reenable( UnitFileScope scope, UnitFileFlags flags, const char *root_dir, - char **files, + char **names_or_paths, UnitFileChange **changes, size_t *n_changes); int unit_file_preset( diff --git a/test/test-systemctl-enable.sh b/test/test-systemctl-enable.sh index c1fb9626ab..0ed08a9da3 100644 --- a/test/test-systemctl-enable.sh +++ b/test/test-systemctl-enable.sh @@ -206,11 +206,9 @@ test ! -h "$root/etc/systemd/system/paths.target.wants/link1.path" islink "$root/etc/systemd/system/link1.path" "/link1.path" islink "$root/etc/systemd/system/paths.target.wants/link1.path" "/link1.path" -# FIXME -# "$systemctl" --root="$root" reenable 'link1.path' -# islink "$root/etc/systemd/system/link1.path" "/link1.path" -# islink "$root/etc/systemd/system/paths.target.wants/link1.path" "/link1.path" - +"$systemctl" --root="$root" reenable 'link1.path' +islink "$root/etc/systemd/system/link1.path" "/link1.path" +islink "$root/etc/systemd/system/paths.target.wants/link1.path" "/link1.path" : -------manual link------------------------------------------ cat >"$root/link3.suffix" < Date: Tue, 15 Mar 2022 10:13:18 +0100 Subject: [PATCH 26/43] test-systemctl-enable: extend the test for repeated WantedBy/RequiredBy I was considering deduplicating the list of target units in WantedBy/RequiredBy. But to do this meaningfully, we'd need to do alias expansion first, i.e. after the initial parsing is done. This seems to be more trouble than it would be worth. Instead, I added tests that we're doing the right thing and creating symlinks as expected. For duplicate links, we create the link, and on the second time we see that the link is already there, so the output is correct. --- test/test-systemctl-enable.sh | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/test/test-systemctl-enable.sh b/test/test-systemctl-enable.sh index 0ed08a9da3..0a0123b9d7 100644 --- a/test/test-systemctl-enable.sh +++ b/test/test-systemctl-enable.sh @@ -285,39 +285,53 @@ test ! -h "$root/etc/systemd/system/services.target.wants/templ1@one.service" test ! -h "$root/etc/systemd/system/services.target.wants/templ1@two.service" : -------template enablement w/ default instance-------------- -cat >>"$root/etc/systemd/system/templ1@.service" <"$root/etc/systemd/system/templ1@.service" <"$root/etc/systemd/system/templ2@.service" < Date: Wed, 2 Mar 2022 16:53:54 +0100 Subject: [PATCH 27/43] shared/install: when we fail to chase a symlink, show some logs When chase_symlinks() fails, we'd get the generic error: Failed to disable: Permission denied. Let's at least add the failure to changes list, so the user gets a slightly better message. Ideally, we'd say where exactly the permission failure occured, but chase_symlinks() is a library level function and I don't think we should add logging there. The output looks like this now: Failed to resolve symlink "/tmp/systemctl-test.1r7Roj/etc/systemd/system/link5alias2.service": Permission denied Failed to resolve symlink "/tmp/systemctl-test.1r7Roj/etc/systemd/system/link5alias.service": Permission denied Failed to disable unit, file /tmp/systemctl-test.1r7Roj/etc/systemd/system/link5alias2.service: Permission denied. Failed to disable unit, file /tmp/systemctl-test.1r7Roj/etc/systemd/system/link5alias.service: Permission denied. --- src/shared/install.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/shared/install.c b/src/shared/install.c index a4c4be16b3..d20372cfd9 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -615,6 +615,9 @@ static int remove_marked_symlinks_fd( if (q == -ENOENT) continue; if (q < 0) { + log_debug_errno(q, "Failed to resolve symlink \"%s\": %m", p); + unit_file_changes_add(changes, n_changes, q, p, NULL); + if (r == 0) r = q; continue; From 40276314afc4fb5c35c6b3da3e6185af6ed3886b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Tue, 15 Mar 2022 16:35:47 +0100 Subject: [PATCH 28/43] shared/install: do not try to resolve symlinks outside of root directory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I linked a file as root, so I had a symlink /root/test.service ← /etc/systemd/system/test.service. To my surpise, when running test-systemctl-enable, it failed with a cryptic EACCES. The previous commit made the logs a bit better. Strace shows that we were trying to follow the symlink without taking --root into account. It seems that this bug was introduced in 66a19d85a533b15ed32f4066ec880b5a8c06babd: before it, we'd do readlink_malloc(), which returned a path relative to root. But we only used that path for checking if the path is in remove_symlinks_to set, which contains relative paths. So if the path was relative, we'd get a false-negative answer, but we didn't go outside of the root. (We need to canonicalize the symlink to get a consistent answer.) But after 66a19 we use chase_symlinks(), without taking root into account which is completely bogus. --- src/shared/install.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/install.c b/src/shared/install.c index d20372cfd9..8bb459dba7 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -611,7 +611,7 @@ static int remove_marked_symlinks_fd( return -ENOMEM; path_simplify(p); - q = chase_symlinks(p, NULL, CHASE_NONEXISTENT, &dest, NULL); + q = chase_symlinks(p, lp->root_dir, CHASE_NONEXISTENT, &dest, NULL); if (q == -ENOENT) continue; if (q < 0) { From 85516075a24fd2f1316575570d7d5f5a37f43dbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Tue, 15 Mar 2022 17:45:34 +0100 Subject: [PATCH 29/43] test-systemctl-enable: enhance the test for unit file linking Current behaviour is wrong, but it cannot be shown in this test, because we don't have a running systemd instance here. --- test/test-systemctl-enable.sh | 39 ++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/test/test-systemctl-enable.sh b/test/test-systemctl-enable.sh index 0a0123b9d7..220ebfdab7 100644 --- a/test/test-systemctl-enable.sh +++ b/test/test-systemctl-enable.sh @@ -401,7 +401,7 @@ test ! -h "$root/etc/systemd/system/link4.service" test ! -h "$root/etc/systemd/system/link4alias.service" test ! -h "$root/etc/systemd/system/link4alias2.service" -: -------issue 661: link and enable on unit file-------------- +: -------issue 661: enable on unit file-------------- test ! -e "$root/etc/systemd/system/link5.service" cat >"$root/etc/systemd/system/link5.service" <"$root/link5copy.service" <"$root/etc/systemd/system/link5@.path" < Date: Wed, 16 Mar 2022 09:28:46 +0100 Subject: [PATCH 30/43] shared/install: skip unnecessary chasing of symlinks in disable We use the symlink source name and destination names to decide whether to remove the symlink. But if the source name is enough to decide to remove the symlink, we'd still look up the destination for no good reason. This is a slow operation, let's skip it. --- src/shared/install.c | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/src/shared/install.c b/src/shared/install.c index 8bb459dba7..ea303d85cf 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -598,8 +598,7 @@ static int remove_marked_symlinks_fd( r = q; } else if (de->d_type == DT_LNK) { - _cleanup_free_ char *p = NULL, *dest = NULL; - const char *rp; + _cleanup_free_ char *p = NULL; bool found; int q; @@ -611,24 +610,32 @@ static int remove_marked_symlinks_fd( return -ENOMEM; path_simplify(p); - q = chase_symlinks(p, lp->root_dir, CHASE_NONEXISTENT, &dest, NULL); - if (q == -ENOENT) - continue; - if (q < 0) { - log_debug_errno(q, "Failed to resolve symlink \"%s\": %m", p); - unit_file_changes_add(changes, n_changes, q, p, NULL); + /* We remove all links pointing to a file or path that is marked, as well as all + * files sharing the same name as a file that is marked. Do path chasing only if + * we don't already know that we want to remove the symlink. */ + found = set_contains(remove_symlinks_to, de->d_name); + + if (!found) { + _cleanup_free_ char *dest = NULL; + + + q = chase_symlinks(p, lp->root_dir, CHASE_NONEXISTENT, &dest, NULL); + if (q == -ENOENT) + continue; + if (q < 0) { + log_debug_errno(q, "Failed to resolve symlink \"%s\": %m", p); + unit_file_changes_add(changes, n_changes, q, p, NULL); + + if (r == 0) + r = q; + continue; + } + + found = set_contains(remove_symlinks_to, dest) || + set_contains(remove_symlinks_to, basename(dest)); - if (r == 0) - r = q; - continue; } - /* We remove all links pointing to a file or path that is marked, as well as all files sharing - * the same name as a file that is marked. */ - - found = set_contains(remove_symlinks_to, dest) || - set_contains(remove_symlinks_to, basename(dest)) || - set_contains(remove_symlinks_to, de->d_name); if (!found) continue; @@ -649,7 +656,7 @@ static int remove_marked_symlinks_fd( /* Now, remember the full path (but with the root prefix removed) of * the symlink we just removed, and remove any symlinks to it, too. */ - rp = skip_root(lp->root_dir, p); + const char *rp = skip_root(lp->root_dir, p); q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: p); if (q < 0) return q; From 9f61c9f79e0f77044b71ef2ba5edde20e15c6ad2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Wed, 16 Mar 2022 09:51:24 +0100 Subject: [PATCH 31/43] =?UTF-8?q?shared/install:=20also=20remove=20symlink?= =?UTF-8?q?s=20like=20.wants/foo@one.service=20=E2=86=92=20../foo@one.serv?= =?UTF-8?q?ice?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So far 'systemctl enable' would create absolute links to the target template name. And we would remove such symlinks just fine. But the user may create symlinks manually in a different form. In particular, symlinks for instanced units *must* have the instance in the source name, and then it is natural to also include it in the target name (.wants/foo@one.service → ../foo@one.service rather than .wants/foo@one.service → ../foo@.service). We would choke on such links, or not remove them at all. A test is added: before: + build-rawhide/systemctl --root=/tmp/systemctl-test.001xda disable templ1@.service Removed "/tmp/systemctl-test.001xda/etc/systemd/system/services.target.wants/templ1@seven.service". Removed "/tmp/systemctl-test.001xda/etc/systemd/system/services.target.wants/templ1@six.service". Removed "/tmp/systemctl-test.001xda/etc/systemd/system/services.target.wants/templ1@five.service". Removed "/tmp/systemctl-test.001xda/etc/systemd/system/services.target.wants/templ1@four.service". Removed "/tmp/systemctl-test.001xda/etc/systemd/system/services.target.wants/templ1@three.service". Failed to disable unit, refusing to operate on linked unit file /tmp/systemctl-test.001xda/etc/systemd/system/services.target.wants/templ1@two.service. Failed to disable unit, refusing to operate on linked unit file /tmp/systemctl-test.001xda/etc/systemd/system/services.target.wants/templ1@two.service. after: + build-rawhide/systemctl --root=/tmp/systemctl-test.QVP0ev disable templ1@.service Removed "/tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@seven.service". Removed "/tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@six.service". Removed "/tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@five.service". Removed "/tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@four.service". Removed "/tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@three.service". Removed "/tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@two.service". Removed "/tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@one.service". + test '!' -h /tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@one.service + test '!' -h /tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@two.service + test '!' -h /tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@three.service + test '!' -h /tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@four.service + test '!' -h /tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@five.service + test '!' -h /tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@six.service + test '!' -h /tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@seven.service --- src/shared/install.c | 16 +++++++++++++--- test/test-systemctl-enable.sh | 20 ++++++++++++++++++++ 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/shared/install.c b/src/shared/install.c index ea303d85cf..3ec3772e01 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -611,13 +611,23 @@ static int remove_marked_symlinks_fd( path_simplify(p); /* We remove all links pointing to a file or path that is marked, as well as all - * files sharing the same name as a file that is marked. Do path chasing only if - * we don't already know that we want to remove the symlink. */ + * files sharing the same name as a file that is marked, and files sharing the same + * name after the instance has been removed. Do path chasing only if we don't already + * know that we want to remove the symlink. */ found = set_contains(remove_symlinks_to, de->d_name); if (!found) { - _cleanup_free_ char *dest = NULL; + _cleanup_free_ char *template = NULL; + q = unit_name_template(de->d_name, &template); + if (q < 0 && q != -EINVAL) + return q; + if (q >= 0) + found = set_contains(remove_symlinks_to, template); + } + + if (!found) { + _cleanup_free_ char *dest = NULL; q = chase_symlinks(p, lp->root_dir, CHASE_NONEXISTENT, &dest, NULL); if (q == -ENOENT) diff --git a/test/test-systemctl-enable.sh b/test/test-systemctl-enable.sh index 220ebfdab7..4462fb386e 100644 --- a/test/test-systemctl-enable.sh +++ b/test/test-systemctl-enable.sh @@ -333,6 +333,26 @@ test ! -h "$root/etc/systemd/system/other@templ1.target.requires/templ1@one.serv test ! -h "$root/etc/systemd/system/services.target.wants/templ1@two.service" test ! -h "$root/etc/systemd/system/other@templ1.target.requires/templ1@two.service" +: -------removal of relative enablement symlinks-------------- +test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service" +ln -s '../templ1@one.service' "$root/etc/systemd/system/services.target.wants/templ1@one.service" +ln -s 'templ1@two.service' "$root/etc/systemd/system/services.target.wants/templ1@two.service" +ln -s '../templ1@.service' "$root/etc/systemd/system/services.target.wants/templ1@three.service" +ln -s 'templ1@.service' "$root/etc/systemd/system/services.target.wants/templ1@four.service" +ln -s '/usr/lib/systemd/system/templ1@.service' "$root/etc/systemd/system/services.target.wants/templ1@five.service" +ln -s '/etc/systemd/system/templ1@.service' "$root/etc/systemd/system/services.target.wants/templ1@six.service" +ln -s '/run/system/templ1@.service' "$root/etc/systemd/system/services.target.wants/templ1@seven.service" + +# this should remove all links +"$systemctl" --root="$root" disable 'templ1@.service' +test ! -h "$root/etc/systemd/system/services.target.wants/templ1@one.service" +test ! -h "$root/etc/systemd/system/services.target.wants/templ1@two.service" +test ! -h "$root/etc/systemd/system/services.target.wants/templ1@three.service" +test ! -h "$root/etc/systemd/system/services.target.wants/templ1@four.service" +test ! -h "$root/etc/systemd/system/services.target.wants/templ1@five.service" +test ! -h "$root/etc/systemd/system/services.target.wants/templ1@six.service" +test ! -h "$root/etc/systemd/system/services.target.wants/templ1@seven.service" + : -------template enablement for another template------------- cat >"$root/etc/systemd/system/templ2@.service" < Date: Wed, 16 Mar 2022 10:17:32 +0100 Subject: [PATCH 32/43] shared/install: create relative symlinks for enablement and aliasing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a fairly noticable change, but I think it needs to be done. So far we'd create an absolute symlink to the target unit file: .wants/foo.service → /usr/lib/systemd/system/foo.service or alias.service → /etc/systemd/system/aliased.service. This works reasonably well, except in one case: where the unit file is linked. When we look at a file link, the name of the physical file isn't used, and we only take the account the symlink source name. (In fact, the destination filename may not even be a well-formed unit name, so we couldn't use it, even if we wanted to.) But this means that if a file is linked, and specifies aliases, we'd create absolute links for those aliases, and systemd would consider each "alias" to be a separate unit. This isn't checked by the tests here, because we don't have a running systemd instance, but it is easy enough to check manually. The most reasonable way to fix this is to create relative links to the unit file: .wants/foo.service → ../foo.service alias.service → aliased.service. I opted to use no prefix for aliases, both normal and 'default.target', and to add "../" for .wants/ and .requires/. Note that the link that is created doesn't necessarily point to the file. E.g. if we're enabling a file under /usr/lib/systemd/system, and create a symlink in /etc/systemd/system, it'll still be "../foo.service", not "../../usr/lib/systemd/system/foo.service". For our unit loading logic this doesn't matter, and figuring out a path that actually leads somewhere would be more work. Since the user is allowed to move the unit file, or add a new unit file in a different location, and we don't actually follow the symlink, I think it's OK to create a dangling symlink. The prefix of "../" is useful to give a hint that the link points to files that are conceptually "one level up" in the directory hierarchy. With the relative symlinks, systemd knows that those are aliases. The tests are adjusted to use the new forms. There were a few tests that weren't really testing something useful: 'test -e x' fails if 'x' is a a dangling symlink. Absolute links in the chroot would be dangling, even though the target existed in the expected path, but become non-dangling when made relative and the test fails. This should be described in NEWS, but I'm not adding that here, because it'd likely result in conflicts. --- src/shared/install.c | 14 ++-- src/test/test-install-root.c | 65 +++++++++-------- test/test-systemctl-enable.sh | 128 ++++++++++++++++------------------ 3 files changed, 105 insertions(+), 102 deletions(-) diff --git a/src/shared/install.c b/src/shared/install.c index 3ec3772e01..bf110b9e56 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -1837,7 +1837,7 @@ static int install_info_symlink_alias( if (!alias_path) return -ENOMEM; - q = create_symlink(lp, info->path, alias_path, force, changes, n_changes); + q = create_symlink(lp, info->name, alias_path, force, changes, n_changes); r = r < 0 ? r : q; } @@ -1906,7 +1906,7 @@ static int install_info_symlink_wants( } STRV_FOREACH(s, list) { - _cleanup_free_ char *path = NULL, *dst = NULL; + _cleanup_free_ char *dst = NULL; q = install_name_printf(scope, info, *s, info->root, &dst); if (q < 0) { @@ -1936,11 +1936,15 @@ static int install_info_symlink_wants( continue; } - path = strjoin(config_path, "/", dst, suffix, n); + _cleanup_free_ char *path = strjoin(config_path, "/", dst, suffix, n); if (!path) return -ENOMEM; - q = create_symlink(lp, info->path, path, true, changes, n_changes); + _cleanup_free_ char *target = strjoin("../", info->name); + if (!target) + return -ENOMEM; + + q = create_symlink(lp, target, path, true, changes, n_changes); if (r == 0) r = q; @@ -2848,7 +2852,7 @@ int unit_file_set_default( return r; new_path = strjoina(lp.persistent_config, "/" SPECIAL_DEFAULT_TARGET); - return create_symlink(&lp, info->path, new_path, flags & UNIT_FILE_FORCE, changes, n_changes); + return create_symlink(&lp, info->name, new_path, flags & UNIT_FILE_FORCE, changes, n_changes); } int unit_file_get_default( diff --git a/src/test/test-install-root.c b/src/test/test-install-root.c index 4f66c12655..dca695d124 100644 --- a/src/test/test-install-root.c +++ b/src/test/test-install-root.c @@ -88,7 +88,7 @@ TEST(basic_mask_and_enable) { assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) == 1); assert_se(n_changes == 1); assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); - assert_se(streq(changes[0].source, "/usr/lib/systemd/system/a.service")); + assert_se(streq(changes[0].source, "../a.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/a.service"); assert_se(streq(changes[0].path, p)); unit_file_changes_free(changes, n_changes); @@ -128,7 +128,7 @@ TEST(basic_mask_and_enable) { assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("d.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); - assert_se(streq(changes[0].source, "/usr/lib/systemd/system/a.service")); + assert_se(streq(changes[0].source, "../a.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/a.service"); assert_se(streq(changes[0].path, p)); unit_file_changes_free(changes, n_changes); @@ -147,7 +147,7 @@ TEST(basic_mask_and_enable) { p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/a.service"); assert_se(streq(changes[0].path, p)); assert_se(changes[1].type_or_errno == UNIT_FILE_SYMLINK); - assert_se(streq(changes[1].source, "/usr/lib/systemd/system/a.service")); + assert_se(streq(changes[1].source, "../a.service")); assert_se(streq(changes[1].path, p)); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; @@ -186,7 +186,7 @@ TEST(basic_mask_and_enable) { assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("f.service"), &changes, &n_changes) == 1); assert_se(n_changes == 2); assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); - assert_se(streq(changes[0].source, "/usr/lib/systemd/system/f.service")); + assert_se(streq(changes[0].source, "../f.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/x.target.wants/f.service"); assert_se(streq(changes[0].path, p)); assert_se(changes[1].type_or_errno == UNIT_FILE_DESTINATION_NOT_PRESENT); @@ -280,7 +280,8 @@ TEST(linked_units) { q = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/linked.service"); for (i = 0 ; i < n_changes; i++) { assert_se(changes[i].type_or_errno == UNIT_FILE_SYMLINK); - assert_se(streq(changes[i].source, "/opt/linked.service")); + assert_se(STR_IN_SET(changes[i].source, + "../linked.service", "/opt/linked.service")); if (p && streq(changes[i].path, p)) p = NULL; @@ -322,7 +323,8 @@ TEST(linked_units) { q = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/linked2.service"); for (i = 0 ; i < n_changes; i++) { assert_se(changes[i].type_or_errno == UNIT_FILE_SYMLINK); - assert_se(streq(changes[i].source, "/opt/linked2.service")); + assert_se(STR_IN_SET(changes[i].source, + "../linked2.service", "/opt/linked2.service")); if (p && streq(changes[i].path, p)) p = NULL; @@ -340,7 +342,7 @@ TEST(linked_units) { assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); assert_se(startswith(changes[0].path, root)); assert_se(endswith(changes[0].path, "linked3.service")); - assert_se(streq(changes[0].source, "/opt/linked3.service")); + assert_se(streq(changes[0].source, "../linked3.service")); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; } @@ -371,7 +373,7 @@ TEST(default) { assert_se(unit_file_set_default(UNIT_FILE_SYSTEM, 0, root, "test-default.target", &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); - assert_se(streq(changes[0].source, "/usr/lib/systemd/system/test-default-real.target")); + assert_se(streq(changes[0].source, "test-default-real.target")); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR "/" SPECIAL_DEFAULT_TARGET); assert_se(streq(changes[0].path, p)); unit_file_changes_free(changes, n_changes); @@ -401,7 +403,7 @@ TEST(add_dependency) { assert_se(unit_file_add_dependency(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("add-dependency-test-service.service"), "add-dependency-test-target.target", UNIT_WANTS, &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); - assert_se(streq(changes[0].source, "/usr/lib/systemd/system/real-add-dependency-test-service.service")); + assert_se(streq(changes[0].source, "../real-add-dependency-test-service.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/real-add-dependency-test-target.target.wants/real-add-dependency-test-service.service"); assert_se(streq(changes[0].path, p)); unit_file_changes_free(changes, n_changes); @@ -442,7 +444,7 @@ TEST(template_enable) { assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template@.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); - assert_se(streq(changes[0].source, "/usr/lib/systemd/system/template@.service")); + assert_se(streq(changes[0].source, "../template@.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/template@def.service"); assert_se(streq(changes[0].path, p)); unit_file_changes_free(changes, n_changes); @@ -473,13 +475,14 @@ TEST(template_enable) { assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template@foo.service"), &changes, &n_changes) >= 0); assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); - assert_se(streq(changes[0].source, "/usr/lib/systemd/system/template@.service")); + assert_se(streq(changes[0].source, "../template@foo.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/template@foo.service"); assert_se(streq(changes[0].path, p)); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_INDIRECT); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0); + assert_se(state == UNIT_FILE_INDIRECT); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_ENABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_ENABLED); @@ -506,7 +509,7 @@ TEST(template_enable) { assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template-symlink@quux.service"), &changes, &n_changes) >= 0); assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); - assert_se(streq(changes[0].source, "/usr/lib/systemd/system/template@.service")); + assert_se(streq(changes[0].source, "../template@quux.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/template@quux.service"); assert_se(streq(changes[0].path, p)); unit_file_changes_free(changes, n_changes); @@ -552,7 +555,7 @@ TEST(indirect) { assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("indirectc.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); - assert_se(streq(changes[0].source, "/usr/lib/systemd/system/indirectb.service")); + assert_se(streq(changes[0].source, "../indirectb.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/indirectb.service"); assert_se(streq(changes[0].path, p)); unit_file_changes_free(changes, n_changes); @@ -604,7 +607,7 @@ TEST(preset_and_list) { assert_se(unit_file_preset(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("preset-yes.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); - assert_se(streq(changes[0].source, "/usr/lib/systemd/system/preset-yes.service")); + assert_se(streq(changes[0].source, "../preset-yes.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/preset-yes.service"); assert_se(streq(changes[0].path, p)); unit_file_changes_free(changes, n_changes); @@ -641,7 +644,7 @@ TEST(preset_and_list) { for (i = 0; i < n_changes; i++) { if (changes[i].type_or_errno == UNIT_FILE_SYMLINK) { - assert_se(streq(changes[i].source, "/usr/lib/systemd/system/preset-yes.service")); + assert_se(streq(changes[i].source, "../preset-yes.service")); assert_se(streq(changes[i].path, p)); } else assert_se(changes[i].type_or_errno == UNIT_FILE_UNLINK); @@ -757,7 +760,7 @@ TEST(preset_order) { assert_se(unit_file_preset(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("prefix-1.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); - assert_se(streq(changes[0].source, "/usr/lib/systemd/system/prefix-1.service")); + assert_se(streq(changes[0].source, "../prefix-1.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/prefix-1.service"); assert_se(streq(changes[0].path, p)); unit_file_changes_free(changes, n_changes); @@ -866,8 +869,8 @@ TEST(with_dropin) { assert_se(n_changes == 2); assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); assert_se(changes[1].type_or_errno == UNIT_FILE_SYMLINK); - assert_se(streq(changes[0].source, "/usr/lib/systemd/system/with-dropin-1.service")); - assert_se(streq(changes[1].source, "/usr/lib/systemd/system/with-dropin-1.service")); + assert_se(streq(changes[0].source, "../with-dropin-1.service")); + assert_se(streq(changes[1].source, "../with-dropin-1.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/with-dropin-1.service"); assert_se(streq(changes[0].path, p)); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/graphical.target.wants/with-dropin-1.service"); @@ -880,8 +883,8 @@ TEST(with_dropin) { assert_se(n_changes == 2); assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); assert_se(changes[1].type_or_errno == UNIT_FILE_SYMLINK); - assert_se(streq(changes[0].source, SYSTEM_CONFIG_UNIT_DIR"/with-dropin-2.service")); - assert_se(streq(changes[1].source, SYSTEM_CONFIG_UNIT_DIR"/with-dropin-2.service")); + assert_se(streq(changes[0].source, "../with-dropin-2.service")); + assert_se(streq(changes[1].source, "../with-dropin-2.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/with-dropin-2.service"); assert_se(streq(changes[0].path, p)); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/graphical.target.wants/with-dropin-2.service"); @@ -894,8 +897,8 @@ TEST(with_dropin) { assert_se(n_changes == 2); assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); assert_se(changes[1].type_or_errno == UNIT_FILE_SYMLINK); - assert_se(streq(changes[0].source, "/usr/lib/systemd/system/with-dropin-3.service")); - assert_se(streq(changes[1].source, "/usr/lib/systemd/system/with-dropin-3.service")); + assert_se(streq(changes[0].source, "../with-dropin-3.service")); + assert_se(streq(changes[1].source, "../with-dropin-3.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/with-dropin-3.service"); assert_se(streq(changes[0].path, p)); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/graphical.target.wants/with-dropin-3.service"); @@ -908,8 +911,8 @@ TEST(with_dropin) { assert_se(n_changes == 2); assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); assert_se(changes[1].type_or_errno == UNIT_FILE_SYMLINK); - assert_se(streq(changes[0].source, "/usr/lib/systemd/system/with-dropin-4a.service")); - assert_se(streq(changes[1].source, "/usr/lib/systemd/system/with-dropin-4b.service")); + assert_se(streq(changes[0].source, "../with-dropin-4a.service")); + assert_se(streq(changes[1].source, "../with-dropin-4b.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/with-dropin-4a.service"); assert_se(streq(changes[0].path, p)); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/with-dropin-4b.service"); @@ -975,8 +978,8 @@ TEST(with_dropin_template) { assert_se(n_changes == 2); assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); assert_se(changes[1].type_or_errno == UNIT_FILE_SYMLINK); - assert_se(streq(changes[0].source, "/usr/lib/systemd/system/with-dropin-1@.service")); - assert_se(streq(changes[1].source, "/usr/lib/systemd/system/with-dropin-1@.service")); + assert_se(streq(changes[0].source, "../with-dropin-1@instance-1.service")); + assert_se(streq(changes[1].source, "../with-dropin-1@instance-1.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/with-dropin-1@instance-1.service"); assert_se(streq(changes[0].path, p)); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/graphical.target.wants/with-dropin-1@instance-1.service"); @@ -988,8 +991,8 @@ TEST(with_dropin_template) { assert_se(n_changes == 2); assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); assert_se(changes[1].type_or_errno == UNIT_FILE_SYMLINK); - assert_se(streq(changes[0].source, "/usr/lib/systemd/system/with-dropin-2@.service")); - assert_se(streq(changes[1].source, "/usr/lib/systemd/system/with-dropin-2@.service")); + assert_se(streq(changes[0].source, "../with-dropin-2@instance-1.service")); + assert_se(streq(changes[1].source, "../with-dropin-2@instance-1.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/with-dropin-2@instance-1.service"); assert_se(streq(changes[0].path, p)); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/graphical.target.wants/with-dropin-2@instance-1.service"); @@ -1000,7 +1003,7 @@ TEST(with_dropin_template) { assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("with-dropin-2@instance-2.service"), &changes, &n_changes) == 1); assert_se(n_changes == 1); assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); - assert_se(streq(changes[0].source, "/usr/lib/systemd/system/with-dropin-2@.service")); + assert_se(streq(changes[0].source, "../with-dropin-2@instance-2.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/with-dropin-2@instance-2.service"); assert_se(streq(changes[0].path, p)); unit_file_changes_free(changes, n_changes); @@ -1009,7 +1012,7 @@ TEST(with_dropin_template) { assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("with-dropin-3@.service"), &changes, &n_changes) == 1); assert_se(n_changes == 1); assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); - assert_se(streq(changes[0].source, "/usr/lib/systemd/system/with-dropin-3@.service")); + assert_se(streq(changes[0].source, "../with-dropin-3@.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/with-dropin-3@instance-2.service"); assert_se(streq(changes[0].path, p)); unit_file_changes_free(changes, n_changes); diff --git a/test/test-systemctl-enable.sh b/test/test-systemctl-enable.sh index 4462fb386e..9463433c5b 100644 --- a/test/test-systemctl-enable.sh +++ b/test/test-systemctl-enable.sh @@ -68,27 +68,27 @@ EOF "$systemctl" --root="$root" enable test1 && { echo "Expected failure" >&2; exit 1; } test -h "$root/etc/systemd/system/default.target.wants/test1.service" test -h "$root/etc/systemd/system/special.target.requires/test1.service" -test ! -e "$root/etc/systemd/system/test1-goodalias.service" +test -e "$root/etc/systemd/system/test1-goodalias.service" test -h "$root/etc/systemd/system/test1-goodalias.service" -test ! -e "$root/etc/systemd/system/test1@badalias.service" -test ! -e "$root/etc/systemd/system/test1-badalias.target" -test ! -e "$root/etc/systemd/system/test1-badalias.socket" +test ! -h "$root/etc/systemd/system/test1@badalias.service" +test ! -h "$root/etc/systemd/system/test1-badalias.target" +test ! -h "$root/etc/systemd/system/test1-badalias.socket" +test -e "$root/etc/systemd/system/test1-goodalias2.service" test -h "$root/etc/systemd/system/test1-goodalias2.service" : -------aliases in reeanble---------------------------------- "$systemctl" --root="$root" reenable test1 && { echo "Expected failure" >&2; exit 1; } -test -h "$root/etc/systemd/system/default.target.wants/test1.service" -test ! -e "$root/etc/systemd/system/test1-goodalias.service" -test -h "$root/etc/systemd/system/test1-goodalias.service" +islink "$root/etc/systemd/system/default.target.wants/test1.service" "../test1.service" +islink "$root/etc/systemd/system/test1-goodalias.service" "test1.service" -test ! -e "$root/etc/systemd/system/test1@badalias.service" -test ! -e "$root/etc/systemd/system/test1-badalias.target" -test ! -e "$root/etc/systemd/system/test1-badalias.socket" +test ! -h "$root/etc/systemd/system/test1@badalias.service" +test ! -h "$root/etc/systemd/system/test1-badalias.target" +test ! -h "$root/etc/systemd/system/test1-badalias.socket" "$systemctl" --root="$root" disable test1 -test ! -e "$root/etc/systemd/system/default.target.wants/test1.service" -test ! -e "$root/etc/systemd/system/special.target.requires/test1.service" -test ! -e "$root/etc/systemd/system/test1-goodalias.service" +test ! -h "$root/etc/systemd/system/default.target.wants/test1.service" +test ! -h "$root/etc/systemd/system/special.target.requires/test1.service" +test ! -h "$root/etc/systemd/system/test1-goodalias.service" : -------also units------------------------------------------- cat >"$root/etc/systemd/system/test2.socket" <&2; exit 1; } islink "$root/etc/systemd/system/link1.path" "/link1.path" -islink "$root/etc/systemd/system/paths.target.wants/link1.path" "/link1.path" +islink "$root/etc/systemd/system/paths.target.wants/link1.path" "../link1.path" : -------enable bad suffix------------------------------------ cp "$root/link1.path" "$root/subdir/link1.suffix" @@ -204,11 +204,11 @@ test ! -h "$root/etc/systemd/system/paths.target.wants/link1.path" "$systemctl" --root="$root" enable 'link1.path' islink "$root/etc/systemd/system/link1.path" "/link1.path" -islink "$root/etc/systemd/system/paths.target.wants/link1.path" "/link1.path" +islink "$root/etc/systemd/system/paths.target.wants/link1.path" "../link1.path" "$systemctl" --root="$root" reenable 'link1.path' islink "$root/etc/systemd/system/link1.path" "/link1.path" -islink "$root/etc/systemd/system/paths.target.wants/link1.path" "/link1.path" +islink "$root/etc/systemd/system/paths.target.wants/link1.path" "../link1.path" : -------manual link------------------------------------------ cat >"$root/link3.suffix" <"$root/etc/systemd/system/templ1@.service" < Date: Wed, 16 Mar 2022 17:37:58 +0100 Subject: [PATCH 33/43] shared/install: when looking for symlinks in .wants/.requires, ignore symlink target MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We'd say that file is enabled indirectly if we had a symlink like: foo@.service ← bar.target.wants/foo@one.service but not when we had foo@one.service ← bar.target.wants/foo@one.service The effect of both link types is the same. In fact we don't care about the symlink target. (We'll warn if it is mismatched, but we honour it anyway.) So let's use the original match logic only for aliases. For .wants/.requires we instead look for a matching source name, or a source name that matches after stripping of instance. --- src/shared/install.c | 93 ++++++++++++++++++++++++++++---------------- 1 file changed, 60 insertions(+), 33 deletions(-) diff --git a/src/shared/install.c b/src/shared/install.c index bf110b9e56..91e38c57cc 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -746,7 +746,8 @@ static int find_symlinks_in_directory( const char *dir_path, const char *root_dir, const UnitFileInstallInfo *info, - bool match_aliases, + bool ignore_destination, + bool match_name, bool ignore_same_name, const char *config_path, bool *same_name_link) { @@ -754,51 +755,67 @@ static int find_symlinks_in_directory( int r = 0; FOREACH_DIRENT(de, dir, return -errno) { - _cleanup_free_ char *dest = NULL; - bool found_path = false, found_dest, b = false; + bool found_path = false, found_dest = false, b = false; int q; if (de->d_type != DT_LNK) continue; - /* Acquire symlink destination */ - q = readlinkat_malloc(dirfd(dir), de->d_name, &dest); - if (q == -ENOENT) - continue; - if (q < 0) { - if (r == 0) - r = q; - continue; - } + if (!ignore_destination) { + _cleanup_free_ char *dest = NULL; - /* Make absolute */ - if (!path_is_absolute(dest)) { - char *x; + /* Acquire symlink destination */ + q = readlinkat_malloc(dirfd(dir), de->d_name, &dest); + if (q == -ENOENT) + continue; + if (q < 0) { + if (r == 0) + r = q; + continue; + } - x = path_join(dir_path, dest); - if (!x) - return -ENOMEM; + /* Make absolute */ + if (!path_is_absolute(dest)) { + char *x; - free_and_replace(dest, x); + x = path_join(dir_path, dest); + if (!x) + return -ENOMEM; + + free_and_replace(dest, x); + } + + /* Check if what the symlink points to matches what we are looking for */ + found_dest = streq(basename(dest), info->name); } assert(unit_name_is_valid(info->name, UNIT_NAME_ANY)); - if (!ignore_same_name) - /* Check if the symlink itself matches what we are looking for. - * - * If ignore_same_name is specified, we are in one of the directories which - * have lower priority than the unit file, and even if a file or symlink with - * this name was found, we should ignore it. */ - found_path = streq(de->d_name, info->name); - /* Check if what the symlink points to matches what we are looking for */ - found_dest = streq(basename(dest), info->name); + /* Check if the symlink itself matches what we are looking for. + * + * If ignore_destination is specified, we only look at the source name. + * + * If ignore_same_name is specified, we are in one of the directories which + * have lower priority than the unit file, and even if a file or symlink with + * this name was found, we should ignore it. */ + + if (ignore_destination || !ignore_same_name) + found_path = streq(de->d_name, info->name); + + if (!found_path && ignore_destination) { + _cleanup_free_ char *template = NULL; + + q = unit_name_template(de->d_name, &template); + if (q < 0 && q != -EINVAL) + return q; + if (q >= 0) + found_dest = streq(template, info->name); + } if (found_path && found_dest) { _cleanup_free_ char *p = NULL, *t = NULL; - /* Filter out same name links in the main - * config path */ + /* Filter out same name links in the main config path */ p = path_make_absolute(de->d_name, dir_path); t = path_make_absolute(info->name, config_path); @@ -811,7 +828,7 @@ static int find_symlinks_in_directory( if (b) *same_name_link = true; else if (found_path || found_dest) { - if (!match_aliases) + if (!match_name) return 1; /* Check if symlink name is in the set of names used by [Install] */ @@ -870,7 +887,12 @@ static int find_symlinks( continue; } - r = find_symlinks_in_directory(d, path, root_dir, i, match_name, ignore_same_name, config_path, same_name_link); + r = find_symlinks_in_directory(d, path, root_dir, i, + /* ignore_destination= */ true, + /* match_name= */ match_name, + /* ignore_same_name= */ ignore_same_name, + config_path, + same_name_link); if (r > 0) return 1; else if (r < 0) @@ -879,7 +901,12 @@ static int find_symlinks( /* We didn't find any suitable symlinks in .wants or .requires directories, let's look for linked unit files in this directory. */ rewinddir(config_dir); - return find_symlinks_in_directory(config_dir, config_path, root_dir, i, match_name, ignore_same_name, config_path, same_name_link); + return find_symlinks_in_directory(config_dir, config_path, root_dir, i, + /* ignore_destination= */ false, + /* match_name= */ match_name, + /* ignore_same_name= */ ignore_same_name, + config_path, + same_name_link); } static int find_symlinks_in_scope( From 38e8a6c7fdffd3389cb3596139b1309579193946 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Thu, 17 Mar 2022 10:16:30 +0100 Subject: [PATCH 34/43] shared/install: stop passing duplicate root argument to install_name_printf() All callers were just passing info + info->root, we can simplify this. --- src/shared/install-printf.c | 7 +++---- src/shared/install-printf.h | 3 +-- src/shared/install.c | 8 ++++---- src/test/test-load-fragment.c | 2 +- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/shared/install-printf.c b/src/shared/install-printf.c index 571c4818e2..4c0eb3ce61 100644 --- a/src/shared/install-printf.c +++ b/src/shared/install-printf.c @@ -99,9 +99,8 @@ static int specifier_last_component(char specifier, const void *data, const char int install_name_printf( UnitFileScope scope, - const UnitFileInstallInfo *i, + const UnitFileInstallInfo *info, const char *format, - const char *root, char **ret) { /* This is similar to unit_name_printf() */ @@ -118,9 +117,9 @@ int install_name_printf( {} }; - assert(i); + assert(info); assert(format); assert(ret); - return specifier_printf(format, UNIT_NAME_MAX, table, root, i, ret); + return specifier_printf(format, UNIT_NAME_MAX, table, info->root, info, ret); } diff --git a/src/shared/install-printf.h b/src/shared/install-printf.h index d2cccdf66d..60d3a9fc55 100644 --- a/src/shared/install-printf.h +++ b/src/shared/install-printf.h @@ -6,7 +6,6 @@ int install_name_printf( UnitFileScope scope, - const UnitFileInstallInfo *i, + const UnitFileInstallInfo *info, const char *format, - const char *root, char **ret); diff --git a/src/shared/install.c b/src/shared/install.c index 91e38c57cc..d5e1979280 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -1203,7 +1203,7 @@ static int config_parse_also( if (r == 0) break; - r = install_name_printf(ctx->scope, info, word, info->root, &printed); + r = install_name_printf(ctx->scope, info, word, &printed); if (r < 0) return log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit name in Also=\"%s\": %m", word); @@ -1252,7 +1252,7 @@ static int config_parse_default_instance( return log_syntax(unit, LOG_WARNING, filename, line, 0, "DefaultInstance= only makes sense for template units, ignoring."); - r = install_name_printf(ctx->scope, info, rvalue, info->root, &printed); + r = install_name_printf(ctx->scope, info, rvalue, &printed); if (r < 0) return log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve instance name in DefaultInstance=\"%s\": %m", rvalue); @@ -1845,7 +1845,7 @@ static int install_info_symlink_alias( STRV_FOREACH(s, info->aliases) { _cleanup_free_ char *alias_path = NULL, *dst = NULL, *dst_updated = NULL; - q = install_name_printf(scope, info, *s, info->root, &dst); + q = install_name_printf(scope, info, *s, &dst); if (q < 0) { unit_file_changes_add(changes, n_changes, q, *s, NULL); r = r < 0 ? r : q; @@ -1935,7 +1935,7 @@ static int install_info_symlink_wants( STRV_FOREACH(s, list) { _cleanup_free_ char *dst = NULL; - q = install_name_printf(scope, info, *s, info->root, &dst); + q = install_name_printf(scope, info, *s, &dst); if (q < 0) { unit_file_changes_add(changes, n_changes, q, *s, NULL); return q; diff --git a/src/test/test-load-fragment.c b/src/test/test-load-fragment.c index 40cd7ea7e6..52341e5199 100644 --- a/src/test/test-load-fragment.c +++ b/src/test/test-load-fragment.c @@ -515,7 +515,7 @@ TEST(install_printf, .sd_booted = true) { _cleanup_free_ char *t = NULL, \ *d1 = ASSERT_PTR(strdup(i.name)), \ *d2 = ASSERT_PTR(strdup(i.path)); \ - int r = install_name_printf(scope, &src, pattern, NULL, &t); \ + int r = install_name_printf(scope, &src, pattern, &t); \ assert_se(result ? r >= 0 : r < 0); \ memzero(i.name, strlen(i.name)); \ memzero(i.path, strlen(i.path)); \ From bd177c62158df97785af0d360c4fc9c266311d88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Thu, 17 Mar 2022 11:46:03 +0100 Subject: [PATCH 35/43] basic/unit-file: reverse negative conditional Having the reverse condition first makes changes that I want to do later awkward, so reverse it as a separate step first. --- src/basic/unit-file.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/basic/unit-file.c b/src/basic/unit-file.c index 6cf66b45cf..2474648ceb 100644 --- a/src/basic/unit-file.c +++ b/src/basic/unit-file.c @@ -326,27 +326,16 @@ int unit_file_resolve_symlink( assert(path_is_absolute(simplified)); - /* Check if the symlink goes outside of our search path. - * If yes, it's a linked unit file or mask, and we don't care about the target name + /* Check if the symlink remain inside of of our search path. + * If yes, it is an alias. Verify that it is valid. + * + * If no, then this is a linked unit file or mask, and we don't care about the target name * when loading units, and we return the link *source* (resolve_destination_target == false); * When this is called for installation purposes, we want the final destination, * so we return the *target*. - * - * Otherwise, let's verify that it's a good alias. */ const char *tail = path_startswith_strv(simplified, search_path); - if (!tail) { - log_debug("Linked unit file: %s/%s → %s", dir, filename, simplified); - - if (resolve_destination_target) - dst = TAKE_PTR(simplified); - else { - dst = path_join(dir, filename); - if (!dst) - return log_oom(); - } - - } else { + if (tail) { /* An alias */ _cleanup_free_ char *target_name = NULL; r = path_extract_filename(simplified, &target_name); @@ -361,6 +350,17 @@ int unit_file_resolve_symlink( dir, filename, simplified); dst = resolve_destination_target ? TAKE_PTR(simplified) : TAKE_PTR(target_name); + + } else { + log_debug("Linked unit file: %s/%s → %s", dir, filename, simplified); + + if (resolve_destination_target) + dst = TAKE_PTR(simplified); + else { + dst = path_join(dir, filename); + if (!dst) + return log_oom(); + } } *ret_destination = TAKE_PTR(dst); From 48ed75adabef3427767038fa155e55b3b0d48f35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Thu, 17 Mar 2022 15:50:16 +0100 Subject: [PATCH 36/43] shared/install: split UNIT_FILE_SYMLINK into two states The two states are distinguished, but are treated everywhere identically, so there is no difference in behaviour except for slighlty different log output. --- src/basic/unit-file.c | 6 ++++-- src/shared/install.c | 14 +++++++++----- src/shared/install.h | 3 ++- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/basic/unit-file.c b/src/basic/unit-file.c index 2474648ceb..7c1ae515e1 100644 --- a/src/basic/unit-file.c +++ b/src/basic/unit-file.c @@ -282,7 +282,9 @@ int unit_file_resolve_symlink( * * If resolve_destination_target is true, an absolute path will be returned. * If not, an absolute path is returned for linked unit files, and a relative - * path otherwise. */ + * path otherwise. + * + * Returns an error, false if this is an alias, true if it's a linked unit file. */ assert(filename); assert(ret_destination); @@ -364,7 +366,7 @@ int unit_file_resolve_symlink( } *ret_destination = TAKE_PTR(dst); - return 0; + return !tail; /* true if linked unit file */ } int unit_file_build_name_map( diff --git a/src/shared/install.c b/src/shared/install.c index d5e1979280..6aacdcf967 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -93,8 +93,9 @@ void unit_file_presets_freep(UnitFilePresets *p) { static const char *const unit_file_type_table[_UNIT_FILE_TYPE_MAX] = { [UNIT_FILE_TYPE_REGULAR] = "regular", - [UNIT_FILE_TYPE_SYMLINK] = "symlink", - [UNIT_FILE_TYPE_MASKED] = "masked", + [UNIT_FILE_TYPE_LINKED] = "linked", + [UNIT_FILE_TYPE_ALIAS] = "alias", + [UNIT_FILE_TYPE_MASKED] = "masked", }; DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(unit_file_type, UnitFileType); @@ -1402,14 +1403,17 @@ static int unit_file_load_or_readlink( true, &info->symlink_target); if (r < 0) return r; + bool outside_search_path = r > 0; r = null_or_empty_path_with_root(info->symlink_target, lp->root_dir); if (r < 0 && r != -ENOENT) return log_debug_errno(r, "Failed to stat %s: %m", info->symlink_target); if (r > 0) info->type = UNIT_FILE_TYPE_MASKED; + else if (outside_search_path) + info->type = UNIT_FILE_TYPE_LINKED; else - info->type = UNIT_FILE_TYPE_SYMLINK; + info->type = UNIT_FILE_TYPE_ALIAS; return 0; } @@ -1548,7 +1552,7 @@ static int install_info_follow( assert(ctx); assert(info); - if (info->type != UNIT_FILE_TYPE_SYMLINK) + if (!IN_SET(info->type, UNIT_FILE_TYPE_ALIAS, UNIT_FILE_TYPE_LINKED)) return -EINVAL; if (!info->symlink_target) return -EINVAL; @@ -1588,7 +1592,7 @@ static int install_info_traverse( return r; i = start; - while (i->type == UNIT_FILE_TYPE_SYMLINK) { + while (IN_SET(i->type, UNIT_FILE_TYPE_ALIAS, UNIT_FILE_TYPE_LINKED)) { /* Follow the symlink */ if (++k > UNIT_FILE_FOLLOW_SYMLINK_MAX) diff --git a/src/shared/install.h b/src/shared/install.h index dba6987406..95427537f2 100644 --- a/src/shared/install.h +++ b/src/shared/install.h @@ -70,7 +70,8 @@ struct UnitFileList { enum UnitFileType { UNIT_FILE_TYPE_REGULAR, - UNIT_FILE_TYPE_SYMLINK, + UNIT_FILE_TYPE_LINKED, + UNIT_FILE_TYPE_ALIAS, UNIT_FILE_TYPE_MASKED, _UNIT_FILE_TYPE_MAX, _UNIT_FILE_TYPE_INVALID = -EINVAL, From 48eadb9d9b66f302cda09cdf6d35fead31aaa968 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Thu, 17 Mar 2022 16:02:10 +0100 Subject: [PATCH 37/43] shared/install: fix handling of a linked unit file When we have a symlink that goes outside of our search path, we should just ignore the target file name. But we were verifying it, and rejecting in the case where a symlink was created manually. --- src/shared/install.c | 4 +++- test/test-systemctl-enable.sh | 12 ++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/shared/install.c b/src/shared/install.c index 6aacdcf967..20707edf58 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -1606,7 +1606,9 @@ static int install_info_traverse( return -ELOOP; } - r = install_info_follow(ctx, i, lp, flags, false); + r = install_info_follow(ctx, i, lp, flags, + /* If linked, don't look at the target name */ + /* ignore_different_name= */ i->type == UNIT_FILE_TYPE_LINKED); if (r == -EXDEV) { _cleanup_free_ char *buffer = NULL; const char *bn; diff --git a/test/test-systemctl-enable.sh b/test/test-systemctl-enable.sh index 9463433c5b..45f3513de3 100644 --- a/test/test-systemctl-enable.sh +++ b/test/test-systemctl-enable.sh @@ -216,12 +216,16 @@ cat >"$root/link3.suffix" < Date: Thu, 24 Mar 2022 11:52:35 +0100 Subject: [PATCH 38/43] test-systemctl-enable: make shellcheck happy Quoting is not necessary in many places, but I think it's nicer to use it consistently. --- test/test-systemctl-enable.sh | 76 +++++++++++++++++------------------ 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/test/test-systemctl-enable.sh b/test/test-systemctl-enable.sh index 45f3513de3..3b30f090a5 100644 --- a/test/test-systemctl-enable.sh +++ b/test/test-systemctl-enable.sh @@ -19,10 +19,10 @@ islink() { test "$(readlink "$1")" = "$2" || return 2 } -: ------enablement nonexistent-------------------------------- +: '------enable nonexistent------------------------------------' "$systemctl" --root="$root" enable test1.service && { echo "Expected failure" >&2; exit 1; } -: ------basic enablement-------------------------------------- +: '------basic enablement--------------------------------------' mkdir -p "$root/etc/systemd/system" cat >"$root/etc/systemd/system/test1.service" <>"$root/etc/systemd/system/test1.service" <&2; exit 1; } islink "$root/etc/systemd/system/default.target.wants/test1.service" "../test1.service" islink "$root/etc/systemd/system/test1-goodalias.service" "test1.service" @@ -90,7 +90,7 @@ test ! -h "$root/etc/systemd/system/default.target.wants/test1.service" test ! -h "$root/etc/systemd/system/special.target.requires/test1.service" test ! -h "$root/etc/systemd/system/test1-goodalias.service" -: -------also units------------------------------------------- +: '-------also units-------------------------------------------' cat >"$root/etc/systemd/system/test2.socket" <&2; exit 1; } @@ -130,65 +130,65 @@ EOF "$systemctl" --root="$root" link '/link1.path' islink "$root/etc/systemd/system/link1.path" "/link1.path" -: -------link already linked same path------------------------ +: '-------link already linked same path------------------------' SYSTEMD_LOG_LEVEL=debug "$systemctl" --root="$root" link '/link1.path' # this passes islink "$root/etc/systemd/system/link1.path" "/link1.path" -: -------link already linked different path------------------- +: '-------link already linked different path-------------------' mkdir "$root/subdir" cp "$root/link1.path" "$root/subdir/" "$systemctl" --root="$root" link '/subdir/link1.path' && { echo "Expected failure" >&2; exit 1; } islink "$root/etc/systemd/system/link1.path" "/link1.path" -: -------link bad suffix-------------------------------------- +: '-------link bad suffix--------------------------------------' cp "$root/link1.path" "$root/subdir/link1.suffix" "$systemctl" --root="$root" link '/subdir/link1.suffix' && { echo "Expected failure" >&2; exit 1; } test ! -e "$root/etc/systemd/system/link1.suffix" -: -------unlink by unit name---------------------------------- +: '-------unlink by unit name----------------------------------' "$systemctl" --root="$root" disable 'link1.path' test ! -e "$root/etc/systemd/system/link1.path" -: -------unlink by path--------------------------------------- +: '-------unlink by path---------------------------------------' "$systemctl" --root="$root" link '/link1.path' test -h "$root/etc/systemd/system/link1.path" "$systemctl" --root="$root" disable '/link1.path' test ! -e "$root/etc/systemd/system/link1.path" -: -------unlink by wrong path--------------------------------- +: '-------unlink by wrong path---------------------------------' "$systemctl" --root="$root" link '/link1.path' test -h "$root/etc/systemd/system/link1.path" "$systemctl" --root="$root" disable '/subdir/link1.path' # we only care about the name test ! -e "$root/etc/systemd/system/link1.path" -: -------link and enable-------------------------------------- +: '-------link and enable--------------------------------------' "$systemctl" --root="$root" enable '/link1.path' islink "$root/etc/systemd/system/link1.path" "/link1.path" islink "$root/etc/systemd/system/paths.target.wants/link1.path" "../link1.path" -: -------enable already linked same path---------------------- +: '-------enable already linked same path----------------------' "$systemctl" --root="$root" enable '/link1.path' islink "$root/etc/systemd/system/link1.path" "/link1.path" islink "$root/etc/systemd/system/paths.target.wants/link1.path" "../link1.path" -: -------enable already linked different path----------------- +: '-------enable already linked different path-----------------' "$systemctl" --root="$root" enable '/subdir/link1.path' && { echo "Expected failure" >&2; exit 1; } islink "$root/etc/systemd/system/link1.path" "/link1.path" islink "$root/etc/systemd/system/paths.target.wants/link1.path" "../link1.path" -: -------enable bad suffix------------------------------------ +: '-------enable bad suffix------------------------------------' cp "$root/link1.path" "$root/subdir/link1.suffix" "$systemctl" --root="$root" enable '/subdir/link1.suffix' && { echo "Expected failure" >&2; exit 1; } test ! -e "$root/etc/systemd/system/link1.suffix" test ! -e "$root/etc/systemd/system/paths.target.wants/link1.suffix" -: -------disable by unit name--------------------------------- +: '-------disable by unit name---------------------------------' "$systemctl" --root="$root" disable 'link1.path' test ! -e "$root/etc/systemd/system/link1.path" test ! -e "$root/etc/systemd/system/paths.target.wants/link1.path" -: -------disable by path-------------------------------------- +: '-------disable by path--------------------------------------' "$systemctl" --root="$root" enable '/link1.path' test -h "$root/etc/systemd/system/link1.path" test -h "$root/etc/systemd/system/paths.target.wants/link1.path" @@ -197,7 +197,7 @@ test ! -e "$root/etc/systemd/system/link1.path" test ! -e "$root/etc/systemd/system/paths.target.wants/link1.path" -: -------link then enable------------------------------------- +: '-------link and enable-------------------------------------' "$systemctl" --root="$root" link '/link1.path' islink "$root/etc/systemd/system/link1.path" "/link1.path" test ! -h "$root/etc/systemd/system/paths.target.wants/link1.path" @@ -210,7 +210,7 @@ islink "$root/etc/systemd/system/paths.target.wants/link1.path" "../link1.path" islink "$root/etc/systemd/system/link1.path" "/link1.path" islink "$root/etc/systemd/system/paths.target.wants/link1.path" "../link1.path" -: -------manual link------------------------------------------ +: '-------manual link------------------------------------------' cat >"$root/link3.suffix" <&2; exit 1; } "$systemctl" --root="$root" enable '/etc/systemd/system/masked.service' && { echo "Expected failure" >&2; exit 1; } -: -------enable on masked alias------------------------------- +: '-------enable on masked alias-------------------------------' test -h "$root/etc/systemd/system/masked.service" ln -s "masked.service" "$root/etc/systemd/system/masked-alias.service" "$systemctl" --root="$root" enable 'masked-alias.service' && { echo "Expected failure" >&2; exit 1; } "$systemctl" --root="$root" enable '/etc/systemd/system/masked-alias.service' && { echo "Expected failure" >&2; exit 1; } -: -------issue 22000: link in subdirectory-------------------- +: '-------issue 22000: link in subdirectory--------------------' mkdir -p "$root/etc/systemd/system/myown.d" cat >"$root/etc/systemd/system/link5-also.service" <"$root/etc/systemd/system/templ1@.service" <"$root/etc/systemd/system/templ1@.service" <"$root/etc/systemd/system/templ2@.service" <"$root/etc/systemd/system/link4.service" <"$root/etc/systemd/system/link4.service" <"$root/etc/systemd/system/link5.service" <"$root/link5copy.service" <"$root/etc/systemd/system/link5@.path" <"$root/etc/systemd/system/multilink.mount" <"$root/etc/systemd/system/some-some-link6@.socket" <&2; exit 1; } -: -------specifiers in WantedBy------------------------------- +: '-------specifiers in WantedBy-------------------------------' # We don't need to repeat all the tests. Let's do a basic check that specifier # expansion is performed. @@ -642,7 +642,7 @@ test ! -h "$root/etc/systemd/system/another-target2@.target.requires/some-some-l # TODO: repeat the tests above for presets -: -------SYSTEMD_OS_RELEASE relative to root------------------ +: '-------SYSTEMD_OS_RELEASE relative to root-------------------' # check that os-release overwriting works as expected with root test -e "$root/etc/os-release" From 3fc53351dc8f37355f5a4ee8f922d3e13a5182c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 25 Mar 2022 15:43:27 +0100 Subject: [PATCH 39/43] shared/install: when creating symlinks, accept different but equivalent symlinks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We would only accept "identical" links, but having e.g. a symlink /usr/lib/systemd/system/foo-alias.service → /usr/lib/systemd/system/foo.service when we're trying to create /usr/lib/systemd/system/foo-alias.service → ./foo.service is OK. This fixes an issue found in ubuntuautopkg package installation, where we'd fail when enabling systemd-resolved.service, because the existing alias was absolute, and (with the recent patches) we were trying to create a relative one. A test is added. (For .wants/.requires symlinks we were already doing OK. A test is also added, to verify.) --- src/shared/install.c | 59 ++++++++++++++++++++++++++--------- test/test-systemctl-enable.sh | 39 +++++++++++++++++++++-- 2 files changed, 81 insertions(+), 17 deletions(-) diff --git a/src/shared/install.c b/src/shared/install.c index 20707edf58..01fd79923b 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -423,21 +423,54 @@ void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *chang } /** - * Checks if two paths or symlinks from wd are the same, when root is the root of the filesystem. - * wc should be the full path in the host file system. + * Checks if two symlink targets (starting from src) are equivalent as far as the unit enablement logic is + * concerned. If the target is in the unit search path, then anything with the same name is equivalent. + * If outside the unit search path, paths must be identical. */ -static bool chroot_symlinks_same(const char *root, const char *wd, const char *a, const char *b) { - assert(path_is_absolute(wd)); +static int chroot_unit_symlinks_equivalent( + const LookupPaths *lp, + const char *src, + const char *target_a, + const char *target_b) { + + assert(lp); + assert(src); + assert(target_a); + assert(target_b); /* This will give incorrect results if the paths are relative and go outside * of the chroot. False negatives are possible. */ - if (!root) - root = "/"; + const char *root = lp->root_dir ?: "/"; + _cleanup_free_ char *dirname = NULL; + int r; - a = strjoina(path_is_absolute(a) ? root : wd, "/", a); - b = strjoina(path_is_absolute(b) ? root : wd, "/", b); - return path_equal_or_files_same(a, b, 0); + if (!path_is_absolute(target_a) || !path_is_absolute(target_b)) { + r = path_extract_directory(src, &dirname); + if (r < 0) + return r; + } + + _cleanup_free_ char *a = path_join(path_is_absolute(target_a) ? root : dirname, target_a); + _cleanup_free_ char *b = path_join(path_is_absolute(target_b) ? root : dirname, target_b); + if (!a || !b) + return log_oom(); + + r = path_equal_or_files_same(a, b, 0); + if (r != 0) + return r; + + _cleanup_free_ char *a_name = NULL, *b_name = NULL; + r = path_extract_filename(a, &a_name); + if (r < 0) + return r; + r = path_extract_filename(b, &b_name); + if (r < 0) + return r; + + return streq(a_name, b_name) && + path_startswith_strv(a, lp->search_path) && + path_startswith_strv(b, lp->search_path); } static int create_symlink( @@ -448,7 +481,7 @@ static int create_symlink( UnitFileChange **changes, size_t *n_changes) { - _cleanup_free_ char *dest = NULL, *dirname = NULL; + _cleanup_free_ char *dest = NULL; const char *rp; int r; @@ -488,11 +521,7 @@ static int create_symlink( return r; } - dirname = dirname_malloc(new_path); - if (!dirname) - return -ENOMEM; - - if (chroot_symlinks_same(lp->root_dir, dirname, dest, old_path)) { + if (chroot_unit_symlinks_equivalent(lp, new_path, dest, old_path)) { log_debug("Symlink %s → %s already exists", new_path, dest); return 1; } diff --git a/test/test-systemctl-enable.sh b/test/test-systemctl-enable.sh index 3b30f090a5..0f66af309a 100644 --- a/test/test-systemctl-enable.sh +++ b/test/test-systemctl-enable.sh @@ -39,8 +39,29 @@ test -h "$root/etc/systemd/system/default.target.wants/test1.service" test -h "$root/etc/systemd/system/special.target.requires/test1.service" "$systemctl" --root="$root" disable test1.service -test ! -e "$root/etc/systemd/system/default.target.wants/test1.service" -test ! -e "$root/etc/systemd/system/special.target.requires/test1.service" +test ! -h "$root/etc/systemd/system/default.target.wants/test1.service" +test ! -h "$root/etc/systemd/system/special.target.requires/test1.service" + +: '------enable when link already exists-----------------------' +# We don't read the symlink target, so it's OK for the symlink to point +# to something else. We should just silently accept this. + +mkdir -p "$root/etc/systemd/system/default.target.wants" +mkdir -p "$root/etc/systemd/system/special.target.requires" +ln -s /usr/lib/systemd/system/test1.service "$root/etc/systemd/system/default.target.wants/test1.service" +ln -s /usr/lib/systemd/system/test1.service "$root/etc/systemd/system/special.target.requires/test1.service" + +"$systemctl" --root="$root" enable test1.service +test -h "$root/etc/systemd/system/default.target.wants/test1.service" +test -h "$root/etc/systemd/system/special.target.requires/test1.service" + +"$systemctl" --root="$root" reenable test1.service +test -h "$root/etc/systemd/system/default.target.wants/test1.service" +test -h "$root/etc/systemd/system/special.target.requires/test1.service" + +"$systemctl" --root="$root" disable test1.service +test ! -h "$root/etc/systemd/system/default.target.wants/test1.service" +test ! -h "$root/etc/systemd/system/special.target.requires/test1.service" : '------suffix guessing---------------------------------------' "$systemctl" --root="$root" enable test1 @@ -90,6 +111,20 @@ test ! -h "$root/etc/systemd/system/default.target.wants/test1.service" test ! -h "$root/etc/systemd/system/special.target.requires/test1.service" test ! -h "$root/etc/systemd/system/test1-goodalias.service" +: '-------aliases when link already exists---------------------' +cat >"$root/etc/systemd/system/test1a.service" <"$root/etc/systemd/system/test2.socket" < Date: Fri, 25 Mar 2022 15:56:16 +0100 Subject: [PATCH 40/43] test-systemctl-enable: use magic syntax to allow inverted tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Inspired by 7910ec3bcde2ee0086b3e49f8aaa2a9f13f58d97. '! true' passes, because it's a conditional expression. But '( ! true )' fails, because '( … )' creates a subshell, i.e. a separate program, and '! true' becomes the return value of that program, and the whole thing apparently is not a conditional expression for the outer shell. This is shorter, so let's just do this. --- test/test-systemctl-enable.sh | 76 ++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 37 deletions(-) diff --git a/test/test-systemctl-enable.sh b/test/test-systemctl-enable.sh index 0f66af309a..ecb433380e 100644 --- a/test/test-systemctl-enable.sh +++ b/test/test-systemctl-enable.sh @@ -20,7 +20,7 @@ islink() { } : '------enable nonexistent------------------------------------' -"$systemctl" --root="$root" enable test1.service && { echo "Expected failure" >&2; exit 1; } +( ! "$systemctl" --root="$root" enable test1.service ) : '------basic enablement--------------------------------------' mkdir -p "$root/etc/systemd/system" @@ -86,7 +86,7 @@ Alias=test1-badalias.socket Alias=test1-goodalias2.service EOF -"$systemctl" --root="$root" enable test1 && { echo "Expected failure" >&2; exit 1; } +( ! "$systemctl" --root="$root" enable test1 ) test -h "$root/etc/systemd/system/default.target.wants/test1.service" test -h "$root/etc/systemd/system/special.target.requires/test1.service" test -e "$root/etc/systemd/system/test1-goodalias.service" @@ -98,7 +98,7 @@ test -e "$root/etc/systemd/system/test1-goodalias2.service" test -h "$root/etc/systemd/system/test1-goodalias2.service" : '-------aliases in reeanble----------------------------------' -"$systemctl" --root="$root" reenable test1 && { echo "Expected failure" >&2; exit 1; } +( ! "$systemctl" --root="$root" reenable test1 ) islink "$root/etc/systemd/system/default.target.wants/test1.service" "../test1.service" islink "$root/etc/systemd/system/test1-goodalias.service" "test1.service" @@ -154,7 +154,7 @@ test ! -e "$root/etc/systemd/system/sockets.target.wants/test2.socket" : '-------link-------------------------------------------------' # File doesn't exist yet test ! -e "$root/link1.path" -"$systemctl" --root="$root" link '/link1.path' && { echo "Expected failure" >&2; exit 1; } +( ! "$systemctl" --root="$root" link '/link1.path' ) test ! -e "$root/etc/systemd/system/link1.path" cat >"$root/link1.path" <&2; exit 1; } +( ! "$systemctl" --root="$root" link '/subdir/link1.path' ) islink "$root/etc/systemd/system/link1.path" "/link1.path" : '-------link bad suffix--------------------------------------' cp "$root/link1.path" "$root/subdir/link1.suffix" -"$systemctl" --root="$root" link '/subdir/link1.suffix' && { echo "Expected failure" >&2; exit 1; } +( ! "$systemctl" --root="$root" link '/subdir/link1.suffix' ) test ! -e "$root/etc/systemd/system/link1.suffix" : '-------unlink by unit name----------------------------------' @@ -208,13 +208,13 @@ islink "$root/etc/systemd/system/link1.path" "/link1.path" islink "$root/etc/systemd/system/paths.target.wants/link1.path" "../link1.path" : '-------enable already linked different path-----------------' -"$systemctl" --root="$root" enable '/subdir/link1.path' && { echo "Expected failure" >&2; exit 1; } +( ! "$systemctl" --root="$root" enable '/subdir/link1.path' ) islink "$root/etc/systemd/system/link1.path" "/link1.path" islink "$root/etc/systemd/system/paths.target.wants/link1.path" "../link1.path" : '-------enable bad suffix------------------------------------' cp "$root/link1.path" "$root/subdir/link1.suffix" -"$systemctl" --root="$root" enable '/subdir/link1.suffix' && { echo "Expected failure" >&2; exit 1; } +( ! "$systemctl" --root="$root" enable '/subdir/link1.suffix' ) test ! -e "$root/etc/systemd/system/link1.suffix" test ! -e "$root/etc/systemd/system/paths.target.wants/link1.suffix" @@ -264,14 +264,14 @@ test ! -h "$root/etc/systemd/system/services.target.wants/link3.service" : '-------enable on masked-------------------------------------' ln -s "/dev/null" "$root/etc/systemd/system/masked.service" -"$systemctl" --root="$root" enable 'masked.service' && { echo "Expected failure" >&2; exit 1; } -"$systemctl" --root="$root" enable '/etc/systemd/system/masked.service' && { echo "Expected failure" >&2; exit 1; } +( ! "$systemctl" --root="$root" enable 'masked.service' ) +( ! "$systemctl" --root="$root" enable '/etc/systemd/system/masked.service' ) : '-------enable on masked alias-------------------------------' test -h "$root/etc/systemd/system/masked.service" ln -s "masked.service" "$root/etc/systemd/system/masked-alias.service" -"$systemctl" --root="$root" enable 'masked-alias.service' && { echo "Expected failure" >&2; exit 1; } -"$systemctl" --root="$root" enable '/etc/systemd/system/masked-alias.service' && { echo "Expected failure" >&2; exit 1; } +( ! "$systemctl" --root="$root" enable 'masked-alias.service' ) +( ! "$systemctl" --root="$root" enable '/etc/systemd/system/masked-alias.service' ) : '-------issue 22000: link in subdirectory--------------------' mkdir -p "$root/etc/systemd/system/myown.d" @@ -286,7 +286,7 @@ WantedBy=services.target Also=link5-also.service EOF -"$systemctl" --root="$root" enable 'link5.service' && { echo "Expected failure" >&2; exit 1; } +( ! "$systemctl" --root="$root" enable 'link5.service' ) test ! -h "$root/etc/systemd/system/services.target.wants/link5.service" test ! -h "$root/etc/systemd/system/services.target.wants/link5-also.service" @@ -301,7 +301,7 @@ WantedBy=services.target EOF # No instance here — this can't succeed. -"$systemctl" --root="$root" enable 'templ1@.service' && { echo "Expected failure" >&2; exit 1; } +( ! "$systemctl" --root="$root" enable 'templ1@.service' ) test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service" "$systemctl" --root="$root" enable 'templ1@one.service' @@ -428,7 +428,7 @@ Alias=link4alias.service Alias=link4alias2.service EOF -"$systemctl" --root="$root" enable 'link4.service' && { echo "Expected failure" >&2; exit 1; } +( ! "$systemctl" --root="$root" enable 'link4.service' ) test ! -h "$root/etc/systemd/system/link4.service" # this is our file test ! -h "$root/etc/systemd/system/link4@.service" test ! -h "$root/etc/systemd/system/link4@inst.service" @@ -571,12 +571,12 @@ check_alias a "$(uname -m | tr '_' '-')" test ! -e "$root/etc/os-release" test ! -e "$root/usr/lib/os-release" -check_alias A '' && { echo "Expected failure" >&2; exit 1; } -check_alias B '' && { echo "Expected failure" >&2; exit 1; } -check_alias M '' && { echo "Expected failure" >&2; exit 1; } -check_alias o '' && { echo "Expected failure" >&2; exit 1; } -check_alias w '' && { echo "Expected failure" >&2; exit 1; } -check_alias W '' && { echo "Expected failure" >&2; exit 1; } +( ! check_alias A '' ) +( ! check_alias B '' ) +( ! check_alias M '' ) +( ! check_alias o '' ) +( ! check_alias w '' ) +( ! check_alias W '' ) cat >"$root/etc/os-release" <&2; exit 1; } -check_alias E '' && { echo "Expected failure" >&2; exit 1; } -check_alias f '' && { echo "Expected failure" >&2; exit 1; } -check_alias h '' && { echo "Expected failure" >&2; exit 1; } -check_alias I '' && { echo "Expected failure" >&2; exit 1; } -check_alias J '' && { echo "Expected failure" >&2; exit 1; } -check_alias L '' && { echo "Expected failure" >&2; exit 1; } -check_alias P '' && { echo "Expected failure" >&2; exit 1; } -check_alias s '' && { echo "Expected failure" >&2; exit 1; } -check_alias S '' && { echo "Expected failure" >&2; exit 1; } -check_alias t '' && { echo "Expected failure" >&2; exit 1; } -check_alias T '' && { echo "Expected failure" >&2; exit 1; } -check_alias V '' && { echo "Expected failure" >&2; exit 1; } +( ! check_alias C '' ) +( ! check_alias E '' ) +( ! check_alias f '' ) +( ! check_alias h '' ) +( ! check_alias I '' ) +( ! check_alias J '' ) +( ! check_alias L '' ) +( ! check_alias P '' ) +( ! check_alias s '' ) +( ! check_alias S '' ) +( ! check_alias t '' ) +( ! check_alias T '' ) +( ! check_alias V '' ) check_alias g root check_alias G 0 @@ -635,7 +635,7 @@ check_alias j 'link6' check_alias l "$(uname -n | sed 's/\..*//')" test ! -e "$root/etc/machine-id" -check_alias m '' && { echo "Expected failure" >&2; exit 1; } +( ! check_alias m '' ) systemd-id128 new >"$root/etc/machine-id" check_alias m "$(cat "$root/etc/machine-id")" @@ -647,9 +647,11 @@ check_alias p 'some-some-link6' check_alias v "$(uname -r)" -check_alias % '%' && { echo "Expected failure because % is not legal in unit name" >&2; exit 1; } +# % is not legal in unit name +( ! check_alias % '%' ) -check_alias z 'z' && { echo "Expected failure because %z is not known" >&2; exit 1; } +# %z is not defined +( ! check_alias z 'z' ) : '-------specifiers in WantedBy-------------------------------' # We don't need to repeat all the tests. Let's do a basic check that specifier From 2a2d002fb0913fe931b4ac903ca425a725aa79c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Mon, 28 Mar 2022 20:03:37 +0200 Subject: [PATCH 41/43] test-systemctl-enable: also use freshly-built systemd-id128 Tests were failing on centos7 because systemd-id128 is not in path. --- meson.build | 21 ++++++++++++--------- test/test-systemctl-enable.sh | 5 +++-- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/meson.build b/meson.build index 33caaec56c..f17a920a81 100644 --- a/meson.build +++ b/meson.build @@ -2446,7 +2446,7 @@ public_programs += executable( install_rpath : rootlibexecdir, install : true) -exe = executable( +systemctl = executable( 'systemctl', systemctl_sources, include_directories : includes, @@ -2460,13 +2460,7 @@ exe = executable( install_rpath : rootlibexecdir, install : true, install_dir : rootbindir) -public_programs += exe -if want_tests != 'false' - test('test-systemctl-enable', - test_systemctl_enable_sh, - # https://github.com/mesonbuild/meson/issues/2681 - args : exe.full_path()) -endif +public_programs += systemctl if conf.get('ENABLE_PORTABLED') == 1 dbus_programs += executable( @@ -3285,13 +3279,22 @@ executable( install : true, install_dir : rootlibexecdir) -public_programs += executable( +systemd_id128 = executable( 'systemd-id128', 'src/id128/id128.c', include_directories : includes, link_with : [libshared], install_rpath : rootlibexecdir, install : true) +public_programs += systemd_id128 + +if want_tests != 'false' + test('test-systemctl-enable', + test_systemctl_enable_sh, + # https://github.com/mesonbuild/meson/issues/2681 + args : [systemctl.full_path(), + systemd_id128.full_path()]) +endif public_programs += executable( 'systemd-path', diff --git a/test/test-systemctl-enable.sh b/test/test-systemctl-enable.sh index ecb433380e..8eb2828e35 100644 --- a/test/test-systemctl-enable.sh +++ b/test/test-systemctl-enable.sh @@ -6,6 +6,7 @@ set -ex export SYSTEMD_IGNORE_CHROOT=1 systemctl=${1:-systemctl} +systemd_id128=${2:-systemd-id128} unset root cleanup() { @@ -606,7 +607,7 @@ check_alias o 'the-id' check_alias w '39a' check_alias W 'right' -check_alias b "$(systemd-id128 boot-id)" +check_alias b "$("$systemd_id128" boot-id)" # Specifiers not available for [Install] ( ! check_alias C '' ) @@ -637,7 +638,7 @@ check_alias l "$(uname -n | sed 's/\..*//')" test ! -e "$root/etc/machine-id" ( ! check_alias m '' ) -systemd-id128 new >"$root/etc/machine-id" +"$systemd_id128" new >"$root/etc/machine-id" check_alias m "$(cat "$root/etc/machine-id")" check_alias n 'some-some-link6@.socket' From 5c29de29b43829ba09967b05ae2f136356c8c0d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Mon, 28 Mar 2022 20:20:09 +0200 Subject: [PATCH 42/43] test-systemctl-enable: disable the test for %a for now --- test/test-systemctl-enable.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/test-systemctl-enable.sh b/test/test-systemctl-enable.sh index 8eb2828e35..ac1bcc1cc7 100644 --- a/test/test-systemctl-enable.sh +++ b/test/test-systemctl-enable.sh @@ -567,7 +567,9 @@ EOF islink "$root/etc/systemd/system/target@$1:$2.socket" "some-some-link6@.socket" || return 2 } -check_alias a "$(uname -m | tr '_' '-')" +# TODO: our architecture names are different than what uname -m returns. +# Add something like 'systemd-detect-virt --print-architecture' and use it here. +check_alias a "$(uname -m | tr '_' '-')" || : test ! -e "$root/etc/os-release" test ! -e "$root/usr/lib/os-release" From b380b6438361e39ad5076bfa58d2021621a957af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Tue, 29 Mar 2022 15:55:59 +0200 Subject: [PATCH 43/43] Rename UnitFileScope to LookupScope As suggested in https://github.com/systemd/systemd/pull/22649/commits/8b3ad3983f5440eef812b34e5ed862ca59fdf7f7#r837345892 The define is generalized and moved to path-lookup.h, where it seems to fit better. This allows a recursive include to be removed and in general makes things simpler. --- src/analyze/analyze-condition.c | 2 +- src/analyze/analyze-plot.c | 6 +- src/analyze/analyze-security.c | 4 +- src/analyze/analyze-time-data.c | 4 +- src/analyze/analyze-verify-util.c | 2 +- src/analyze/analyze-verify-util.h | 2 +- src/analyze/analyze.c | 14 +- src/analyze/analyze.h | 2 +- src/basic/path-lookup.c | 64 ++-- src/basic/path-lookup.h | 21 +- src/basic/unit-file.h | 11 +- src/core/dbus-manager.c | 8 +- src/core/fuzz-unit-file.c | 2 +- src/core/main.c | 2 +- src/core/manager.c | 6 +- src/core/manager.h | 8 +- src/libsystemd/sd-path/sd-path.c | 8 +- src/portable/portable.c | 14 +- src/shared/install-printf.c | 2 +- src/shared/install-printf.h | 2 +- src/shared/install.c | 92 ++--- src/shared/install.h | 35 +- src/shared/specifier.c | 26 +- src/systemctl/systemctl-edit.c | 6 +- src/systemctl/systemctl-is-enabled.c | 2 +- src/systemctl/systemctl-show.c | 2 +- src/systemctl/systemctl-start-special.c | 4 +- src/systemctl/systemctl-start-unit.c | 6 +- src/systemctl/systemctl-sysv-compat.c | 2 +- src/systemctl/systemctl-util.c | 10 +- src/systemctl/systemctl.c | 12 +- src/systemctl/systemctl.h | 2 +- src/sysv-generator/sysv-generator.c | 4 +- src/test/test-bpf-firewall.c | 2 +- src/test/test-bpf-foreign-programs.c | 2 +- src/test/test-bpf-lsm.c | 2 +- src/test/test-cgroup-mask.c | 2 +- src/test/test-cgroup-unit-default.c | 2 +- src/test/test-engine.c | 2 +- src/test/test-execute.c | 10 +- src/test/test-install-root.c | 448 ++++++++++++------------ src/test/test-install.c | 72 ++-- src/test/test-load-fragment.c | 86 ++--- src/test/test-path-lookup.c | 30 +- src/test/test-path.c | 2 +- src/test/test-sched-prio.c | 2 +- src/test/test-socket-bind.c | 2 +- src/test/test-specifier.c | 2 +- src/test/test-unit-file.c | 2 +- src/test/test-unit-name.c | 2 +- src/test/test-unit-serialize.c | 2 +- src/test/test-watch-pid.c | 2 +- src/tmpfiles/tmpfiles.c | 2 +- 53 files changed, 530 insertions(+), 533 deletions(-) diff --git a/src/analyze/analyze-condition.c b/src/analyze/analyze-condition.c index 58986bc406..011066f148 100644 --- a/src/analyze/analyze-condition.c +++ b/src/analyze/analyze-condition.c @@ -74,7 +74,7 @@ static int log_helper(void *userdata, int level, int error, const char *file, in return r; } -static int verify_conditions(char **lines, UnitFileScope scope, const char *unit, const char *root) { +static int verify_conditions(char **lines, LookupScope scope, const char *unit, const char *root) { _cleanup_(manager_freep) Manager *m = NULL; Unit *u; int r, q = 1; diff --git a/src/analyze/analyze-plot.c b/src/analyze/analyze-plot.c index d663a6561c..edfdfba144 100644 --- a/src/analyze/analyze-plot.c +++ b/src/analyze/analyze-plot.c @@ -78,7 +78,7 @@ static int acquire_host_info(sd_bus *bus, HostInfo **hi) { if (!host) return log_oom(); - if (arg_scope != UNIT_FILE_SYSTEM) { + if (arg_scope != LOOKUP_SCOPE_SYSTEM) { r = bus_connect_transport(arg_transport, arg_host, false, &system_bus); if (r < 0) { log_debug_errno(r, "Failed to connect to system bus, ignoring: %m"); @@ -183,7 +183,7 @@ int verb_plot(int argc, char *argv[], void *userdata) { _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; _cleanup_(unit_times_free_arrayp) UnitTimes *times = NULL; _cleanup_free_ char *pretty_times = NULL; - bool use_full_bus = arg_scope == UNIT_FILE_SYSTEM; + bool use_full_bus = arg_scope == LOOKUP_SCOPE_SYSTEM; BootTimes *boot; UnitTimes *u; int n, m = 1, y = 0, r; @@ -201,7 +201,7 @@ int verb_plot(int argc, char *argv[], void *userdata) { if (n < 0) return n; - if (use_full_bus || arg_scope != UNIT_FILE_SYSTEM) { + if (use_full_bus || arg_scope != LOOKUP_SCOPE_SYSTEM) { n = acquire_host_info(bus, &host); if (n < 0) return n; diff --git a/src/analyze/analyze-security.c b/src/analyze/analyze-security.c index 458b681143..aa41751dd1 100644 --- a/src/analyze/analyze-security.c +++ b/src/analyze/analyze-security.c @@ -2646,7 +2646,7 @@ static int offline_security_check(Unit *u, static int offline_security_checks(char **filenames, JsonVariant *policy, - UnitFileScope scope, + LookupScope scope, bool check_man, bool run_generators, unsigned threshold, @@ -2758,7 +2758,7 @@ static int offline_security_checks(char **filenames, static int analyze_security(sd_bus *bus, char **units, JsonVariant *policy, - UnitFileScope scope, + LookupScope scope, bool check_man, bool run_generators, bool offline, diff --git a/src/analyze/analyze-time-data.c b/src/analyze/analyze-time-data.c index a259d47395..aa42d69322 100644 --- a/src/analyze/analyze-time-data.c +++ b/src/analyze/analyze-time-data.c @@ -67,9 +67,9 @@ int acquire_boot_times(sd_bus *bus, BootTimes **ret) { "Please try again later.\n" "Hint: Use 'systemctl%s list-jobs' to see active jobs", times.finish_time, - arg_scope == UNIT_FILE_SYSTEM ? "" : " --user"); + arg_scope == LOOKUP_SCOPE_SYSTEM ? "" : " --user"); - if (arg_scope == UNIT_FILE_SYSTEM && times.security_start_time > 0) { + if (arg_scope == LOOKUP_SCOPE_SYSTEM && times.security_start_time > 0) { /* security_start_time is set when systemd is not running under container environment. */ if (times.initrd_time > 0) times.kernel_done_time = times.initrd_time; diff --git a/src/analyze/analyze-verify-util.c b/src/analyze/analyze-verify-util.c index 7702d83ddc..531144ba57 100644 --- a/src/analyze/analyze-verify-util.c +++ b/src/analyze/analyze-verify-util.c @@ -242,7 +242,7 @@ static void set_destroy_ignore_pointer_max(Set** s) { set_free_free(*s); } -int verify_units(char **filenames, UnitFileScope scope, bool check_man, bool run_generators, RecursiveErrors recursive_errors, const char *root) { +int verify_units(char **filenames, LookupScope scope, bool check_man, bool run_generators, RecursiveErrors recursive_errors, const char *root) { const ManagerTestRunFlags flags = MANAGER_TEST_RUN_MINIMAL | MANAGER_TEST_RUN_ENV_GENERATORS | diff --git a/src/analyze/analyze-verify-util.h b/src/analyze/analyze-verify-util.h index 47b78a8158..385d635e33 100644 --- a/src/analyze/analyze-verify-util.h +++ b/src/analyze/analyze-verify-util.h @@ -17,7 +17,7 @@ typedef enum RecursiveErrors { int verify_generate_path(char **var, char **filenames); int verify_prepare_filename(const char *filename, char **ret); int verify_executable(Unit *u, const ExecCommand *exec, const char *root); -int verify_units(char **filenames, UnitFileScope scope, bool check_man, bool run_generators, RecursiveErrors recursive_errors, const char *root); +int verify_units(char **filenames, LookupScope scope, bool check_man, bool run_generators, RecursiveErrors recursive_errors, const char *root); const char* recursive_errors_to_string(RecursiveErrors i) _const_; RecursiveErrors recursive_errors_from_string(const char *s) _pure_; diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c index 5c64bf6b4c..905ff2c27f 100644 --- a/src/analyze/analyze.c +++ b/src/analyze/analyze.c @@ -89,7 +89,7 @@ usec_t arg_fuzz = 0; PagerFlags arg_pager_flags = 0; BusTransport arg_transport = BUS_TRANSPORT_LOCAL; const char *arg_host = NULL; -UnitFileScope arg_scope = UNIT_FILE_SYSTEM; +LookupScope arg_scope = LOOKUP_SCOPE_SYSTEM; RecursiveErrors arg_recursive_errors = RECURSIVE_ERRORS_YES; bool arg_man = true; bool arg_generators = false; @@ -114,7 +114,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_unit, freep); STATIC_DESTRUCTOR_REGISTER(arg_profile, freep); int acquire_bus(sd_bus **bus, bool *use_full_bus) { - bool user = arg_scope != UNIT_FILE_SYSTEM; + bool user = arg_scope != LOOKUP_SCOPE_SYSTEM; int r; if (use_full_bus && *use_full_bus) { @@ -351,15 +351,15 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_SYSTEM: - arg_scope = UNIT_FILE_SYSTEM; + arg_scope = LOOKUP_SCOPE_SYSTEM; break; case ARG_USER: - arg_scope = UNIT_FILE_USER; + arg_scope = LOOKUP_SCOPE_USER; break; case ARG_GLOBAL: - arg_scope = UNIT_FILE_GLOBAL; + arg_scope = LOOKUP_SCOPE_GLOBAL; break; case ARG_ORDER: @@ -500,12 +500,12 @@ static int parse_argv(int argc, char *argv[]) { return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Option --threshold= is only supported for security right now."); - if (arg_scope == UNIT_FILE_GLOBAL && + if (arg_scope == LOOKUP_SCOPE_GLOBAL && !STR_IN_SET(argv[optind] ?: "time", "dot", "unit-paths", "verify")) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Option --global only makes sense with verbs dot, unit-paths, verify."); - if (streq_ptr(argv[optind], "cat-config") && arg_scope == UNIT_FILE_USER) + if (streq_ptr(argv[optind], "cat-config") && arg_scope == LOOKUP_SCOPE_USER) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Option --user is not supported for cat-config right now."); diff --git a/src/analyze/analyze.h b/src/analyze/analyze.h index 71a682cdc1..da12058c43 100644 --- a/src/analyze/analyze.h +++ b/src/analyze/analyze.h @@ -22,7 +22,7 @@ extern usec_t arg_fuzz; extern PagerFlags arg_pager_flags; extern BusTransport arg_transport; extern const char *arg_host; -extern UnitFileScope arg_scope; +extern LookupScope arg_scope; extern RecursiveErrors arg_recursive_errors; extern bool arg_man; extern bool arg_generators; diff --git a/src/basic/path-lookup.c b/src/basic/path-lookup.c index b699756658..1f4331a8bf 100644 --- a/src/basic/path-lookup.c +++ b/src/basic/path-lookup.c @@ -232,7 +232,7 @@ bool path_is_user_config_dir(const char *path) { } static int acquire_generator_dirs( - UnitFileScope scope, + LookupScope scope, const char *tempdir, char **generator, char **generator_early, @@ -244,17 +244,17 @@ static int acquire_generator_dirs( assert(generator); assert(generator_early); assert(generator_late); - assert(IN_SET(scope, UNIT_FILE_SYSTEM, UNIT_FILE_USER, UNIT_FILE_GLOBAL)); + assert(IN_SET(scope, LOOKUP_SCOPE_SYSTEM, LOOKUP_SCOPE_USER, LOOKUP_SCOPE_GLOBAL)); - if (scope == UNIT_FILE_GLOBAL) + if (scope == LOOKUP_SCOPE_GLOBAL) return -EOPNOTSUPP; if (tempdir) prefix = tempdir; - else if (scope == UNIT_FILE_SYSTEM) + else if (scope == LOOKUP_SCOPE_SYSTEM) prefix = "/run/systemd"; else { - /* UNIT_FILE_USER */ + /* LOOKUP_SCOPE_USER */ const char *e; e = getenv("XDG_RUNTIME_DIR"); @@ -288,21 +288,21 @@ static int acquire_generator_dirs( } static int acquire_transient_dir( - UnitFileScope scope, + LookupScope scope, const char *tempdir, char **ret) { char *transient; assert(ret); - assert(IN_SET(scope, UNIT_FILE_SYSTEM, UNIT_FILE_USER, UNIT_FILE_GLOBAL)); + assert(IN_SET(scope, LOOKUP_SCOPE_SYSTEM, LOOKUP_SCOPE_USER, LOOKUP_SCOPE_GLOBAL)); - if (scope == UNIT_FILE_GLOBAL) + if (scope == LOOKUP_SCOPE_GLOBAL) return -EOPNOTSUPP; if (tempdir) transient = path_join(tempdir, "transient"); - else if (scope == UNIT_FILE_SYSTEM) + else if (scope == LOOKUP_SCOPE_SYSTEM) transient = strdup("/run/systemd/transient"); else return xdg_user_runtime_dir(ret, "/systemd/transient"); @@ -313,7 +313,7 @@ static int acquire_transient_dir( return 0; } -static int acquire_config_dirs(UnitFileScope scope, char **persistent, char **runtime) { +static int acquire_config_dirs(LookupScope scope, char **persistent, char **runtime) { _cleanup_free_ char *a = NULL, *b = NULL; int r; @@ -322,17 +322,17 @@ static int acquire_config_dirs(UnitFileScope scope, char **persistent, char **ru switch (scope) { - case UNIT_FILE_SYSTEM: + case LOOKUP_SCOPE_SYSTEM: a = strdup(SYSTEM_CONFIG_UNIT_DIR); b = strdup("/run/systemd/system"); break; - case UNIT_FILE_GLOBAL: + case LOOKUP_SCOPE_GLOBAL: a = strdup(USER_CONFIG_UNIT_DIR); b = strdup("/run/systemd/user"); break; - case UNIT_FILE_USER: + case LOOKUP_SCOPE_USER: r = xdg_user_config_dir(&a, "/systemd/user"); if (r < 0 && r != -ENXIO) return r; @@ -364,7 +364,7 @@ static int acquire_config_dirs(UnitFileScope scope, char **persistent, char **ru return 0; } -static int acquire_control_dirs(UnitFileScope scope, char **persistent, char **runtime) { +static int acquire_control_dirs(LookupScope scope, char **persistent, char **runtime) { _cleanup_free_ char *a = NULL; int r; @@ -373,7 +373,7 @@ static int acquire_control_dirs(UnitFileScope scope, char **persistent, char **r switch (scope) { - case UNIT_FILE_SYSTEM: { + case LOOKUP_SCOPE_SYSTEM: { _cleanup_free_ char *b = NULL; a = strdup("/etc/systemd/system.control"); @@ -389,7 +389,7 @@ static int acquire_control_dirs(UnitFileScope scope, char **persistent, char **r break; } - case UNIT_FILE_USER: + case LOOKUP_SCOPE_USER: r = xdg_user_config_dir(&a, "/systemd/user.control"); if (r < 0 && r != -ENXIO) return r; @@ -406,7 +406,7 @@ static int acquire_control_dirs(UnitFileScope scope, char **persistent, char **r break; - case UNIT_FILE_GLOBAL: + case LOOKUP_SCOPE_GLOBAL: return -EOPNOTSUPP; default: @@ -419,7 +419,7 @@ static int acquire_control_dirs(UnitFileScope scope, char **persistent, char **r } static int acquire_attached_dirs( - UnitFileScope scope, + LookupScope scope, char **ret_persistent, char **ret_runtime) { @@ -429,7 +429,7 @@ static int acquire_attached_dirs( assert(ret_runtime); /* Portable services are not available to regular users for now. */ - if (scope != UNIT_FILE_SYSTEM) + if (scope != LOOKUP_SCOPE_SYSTEM) return -EOPNOTSUPP; a = strdup("/etc/systemd/system.attached"); @@ -509,7 +509,7 @@ static int get_paths_from_environ(const char *var, char ***paths, bool *append) int lookup_paths_init( LookupPaths *lp, - UnitFileScope scope, + LookupScope scope, LookupPathsFlags flags, const char *root_dir) { @@ -528,14 +528,14 @@ int lookup_paths_init( assert(lp); assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(scope < _LOOKUP_SCOPE_MAX); #if HAVE_SPLIT_USR flags |= LOOKUP_PATHS_SPLIT_USR; #endif if (!empty_or_root(root_dir)) { - if (scope == UNIT_FILE_USER) + if (scope == LOOKUP_SCOPE_USER) return -EINVAL; r = is_dir(root_dir, true); @@ -560,8 +560,8 @@ int lookup_paths_init( if (r < 0) return r; - if (scope == UNIT_FILE_USER) { - r = acquire_config_dirs(UNIT_FILE_GLOBAL, &global_persistent_config, &global_runtime_config); + if (scope == LOOKUP_SCOPE_USER) { + r = acquire_config_dirs(LOOKUP_SCOPE_GLOBAL, &global_persistent_config, &global_runtime_config); if (r < 0) return r; } @@ -606,7 +606,7 @@ int lookup_paths_init( switch (scope) { - case UNIT_FILE_SYSTEM: + case LOOKUP_SCOPE_SYSTEM: add = strv_new( /* If you modify this you also want to modify * systemdsystemunitpath= in systemd.pc.in! */ @@ -629,7 +629,7 @@ int lookup_paths_init( STRV_IFNOTNULL(generator_late)); break; - case UNIT_FILE_GLOBAL: + case LOOKUP_SCOPE_GLOBAL: add = strv_new( /* If you modify this you also want to modify * systemduserunitpath= in systemd.pc.in, and @@ -652,7 +652,7 @@ int lookup_paths_init( STRV_IFNOTNULL(generator_late)); break; - case UNIT_FILE_USER: + case LOOKUP_SCOPE_USER: add = user_dirs(persistent_config, runtime_config, global_persistent_config, global_runtime_config, generator, generator_early, generator_late, @@ -741,7 +741,7 @@ int lookup_paths_init( return 0; } -int lookup_paths_init_or_warn(LookupPaths *lp, UnitFileScope scope, LookupPathsFlags flags, const char *root_dir) { +int lookup_paths_init_or_warn(LookupPaths *lp, LookupScope scope, LookupPathsFlags flags, const char *root_dir) { int r; r = lookup_paths_init(lp, scope, flags, root_dir); @@ -790,7 +790,7 @@ void lookup_paths_log(LookupPaths *lp) { } } -char **generator_binary_paths(UnitFileScope scope) { +char **generator_binary_paths(LookupScope scope) { bool append = false; /* Add items from SYSTEMD_GENERATOR_PATH before normal directories */ _cleanup_strv_free_ char **paths = NULL; int r; @@ -805,15 +805,15 @@ char **generator_binary_paths(UnitFileScope scope) { switch (scope) { - case UNIT_FILE_SYSTEM: + case LOOKUP_SCOPE_SYSTEM: add = strv_new("/run/systemd/system-generators", "/etc/systemd/system-generators", "/usr/local/lib/systemd/system-generators", SYSTEM_GENERATOR_DIR); break; - case UNIT_FILE_GLOBAL: - case UNIT_FILE_USER: + case LOOKUP_SCOPE_GLOBAL: + case LOOKUP_SCOPE_USER: add = strv_new("/run/systemd/user-generators", "/etc/systemd/user-generators", "/usr/local/lib/systemd/user-generators", diff --git a/src/basic/path-lookup.h b/src/basic/path-lookup.h index 1f0e5ea271..aed72defe7 100644 --- a/src/basic/path-lookup.h +++ b/src/basic/path-lookup.h @@ -3,10 +3,7 @@ #include -typedef struct LookupPaths LookupPaths; - #include "def.h" -#include "unit-file.h" #include "macro.h" typedef enum LookupPathsFlags { @@ -15,7 +12,15 @@ typedef enum LookupPathsFlags { LOOKUP_PATHS_SPLIT_USR = 1 << 2, } LookupPathsFlags; -struct LookupPaths { +typedef enum LookupScope { + LOOKUP_SCOPE_SYSTEM, + LOOKUP_SCOPE_GLOBAL, + LOOKUP_SCOPE_USER, + _LOOKUP_SCOPE_MAX, + _LOOKUP_SCOPE_INVALID = -EINVAL, +} LookupScope; + +typedef struct LookupPaths { /* Where we look for unit files. This includes the individual special paths below, but also any vendor * supplied, static unit file paths. */ char **search_path; @@ -52,10 +57,10 @@ struct LookupPaths { /* A temporary directory when running in test mode, to be nuked */ char *temporary_dir; -}; +} LookupPaths; -int lookup_paths_init(LookupPaths *lp, UnitFileScope scope, LookupPathsFlags flags, const char *root_dir); -int lookup_paths_init_or_warn(LookupPaths *lp, UnitFileScope scope, LookupPathsFlags flags, const char *root_dir); +int lookup_paths_init(LookupPaths *lp, LookupScope scope, LookupPathsFlags flags, const char *root_dir); +int lookup_paths_init_or_warn(LookupPaths *lp, LookupScope scope, LookupPathsFlags flags, const char *root_dir); int xdg_user_dirs(char ***ret_config_dirs, char ***ret_data_dirs); int xdg_user_runtime_dir(char **ret, const char *suffix); @@ -68,7 +73,7 @@ bool path_is_user_config_dir(const char *path); void lookup_paths_log(LookupPaths *p); void lookup_paths_free(LookupPaths *p); -char **generator_binary_paths(UnitFileScope scope); +char **generator_binary_paths(LookupScope scope); char **env_generator_binary_paths(bool is_system); #define NETWORK_DIRS ((const char* const*) CONF_PATHS_STRV("systemd/network")) diff --git a/src/basic/unit-file.h b/src/basic/unit-file.h index b7c03e9c2c..1c43861f00 100644 --- a/src/basic/unit-file.h +++ b/src/basic/unit-file.h @@ -4,12 +4,11 @@ #include #include "hashmap.h" +#include "path-lookup.h" #include "time-util.h" #include "unit-name.h" typedef enum UnitFileState UnitFileState; -typedef enum UnitFileScope UnitFileScope; -typedef struct LookupPaths LookupPaths; enum UnitFileState { UNIT_FILE_ENABLED, @@ -29,14 +28,6 @@ enum UnitFileState { _UNIT_FILE_STATE_INVALID = -EINVAL, }; -enum UnitFileScope { - UNIT_FILE_SYSTEM, - UNIT_FILE_GLOBAL, - UNIT_FILE_USER, - _UNIT_FILE_SCOPE_MAX, - _UNIT_FILE_SCOPE_INVALID = -EINVAL, -}; - bool unit_type_may_alias(UnitType type) _const_; bool unit_type_may_template(UnitType type) _const_; diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index c78e9ef2b2..572c59dda4 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -2288,7 +2288,7 @@ fail: static int method_enable_unit_files_generic( sd_bus_message *message, Manager *m, - int (*call)(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char *files[], UnitFileChange **changes, size_t *n_changes), + int (*call)(LookupScope scope, UnitFileFlags flags, const char *root_dir, char *files[], UnitFileChange **changes, size_t *n_changes), bool carries_install_info, sd_bus_error *error) { @@ -2352,7 +2352,7 @@ static int method_link_unit_files(sd_bus_message *message, void *userdata, sd_bu return method_enable_unit_files_generic(message, userdata, unit_file_link, false, error); } -static int unit_file_preset_without_mode(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char **files, UnitFileChange **changes, size_t *n_changes) { +static int unit_file_preset_without_mode(LookupScope scope, UnitFileFlags flags, const char *root_dir, char **files, UnitFileChange **changes, size_t *n_changes) { return unit_file_preset(scope, flags, root_dir, files, UNIT_FILE_PRESET_FULL, changes, n_changes); } @@ -2412,7 +2412,7 @@ static int method_preset_unit_files_with_mode(sd_bus_message *message, void *use static int method_disable_unit_files_generic( sd_bus_message *message, Manager *m, - int (*call)(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char *files[], UnitFileChange **changes, size_t *n_changes), + int (*call)(LookupScope scope, UnitFileFlags flags, const char *root_dir, char *files[], UnitFileChange **changes, size_t *n_changes), sd_bus_error *error) { _cleanup_strv_free_ char **l = NULL; @@ -2638,7 +2638,7 @@ static int method_get_unit_file_links(sd_bus_message *message, void *userdata, s flags = UNIT_FILE_DRY_RUN | (runtime ? UNIT_FILE_RUNTIME : 0); - r = unit_file_disable(UNIT_FILE_SYSTEM, flags, NULL, p, &changes, &n_changes); + r = unit_file_disable(LOOKUP_SCOPE_SYSTEM, flags, NULL, p, &changes, &n_changes); if (r < 0) return log_error_errno(r, "Failed to get file links for %s: %m", name); diff --git a/src/core/fuzz-unit-file.c b/src/core/fuzz-unit-file.c index 780dd3988d..c12e874e2d 100644 --- a/src/core/fuzz-unit-file.c +++ b/src/core/fuzz-unit-file.c @@ -62,7 +62,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { if (!getenv("SYSTEMD_LOG_LEVEL")) log_set_max_level(LOG_CRIT); - assert_se(manager_new(UNIT_FILE_SYSTEM, MANAGER_TEST_RUN_MINIMAL, &m) >= 0); + assert_se(manager_new(LOOKUP_SCOPE_SYSTEM, MANAGER_TEST_RUN_MINIMAL, &m) >= 0); name = strjoina("a.", unit_type_to_string(t)); assert_se(unit_new_for_name(m, unit_vtable[t]->object_size, name, &u) >= 0); diff --git a/src/core/main.c b/src/core/main.c index 289a1ee01f..f39c7b0e37 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -2885,7 +2885,7 @@ int main(int argc, char *argv[]) { if (r < 0) goto finish; - r = manager_new(arg_system ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, + r = manager_new(arg_system ? LOOKUP_SCOPE_SYSTEM : LOOKUP_SCOPE_USER, arg_action == ACTION_TEST ? MANAGER_TEST_FULL : 0, &m); if (r < 0) { diff --git a/src/core/manager.c b/src/core/manager.c index 0fbb7d290e..6d8e454d35 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -775,13 +775,13 @@ static int manager_setup_sigchld_event_source(Manager *m) { return 0; } -int manager_new(UnitFileScope scope, ManagerTestRunFlags test_run_flags, Manager **_m) { +int manager_new(LookupScope scope, ManagerTestRunFlags test_run_flags, Manager **_m) { _cleanup_(manager_freep) Manager *m = NULL; const char *e; int r; assert(_m); - assert(IN_SET(scope, UNIT_FILE_SYSTEM, UNIT_FILE_USER)); + assert(IN_SET(scope, LOOKUP_SCOPE_SYSTEM, LOOKUP_SCOPE_USER)); m = new(Manager, 1); if (!m) @@ -1700,7 +1700,7 @@ static void manager_preset_all(Manager *m) { return; /* If this is the first boot, and we are in the host system, then preset everything */ - r = unit_file_preset_all(UNIT_FILE_SYSTEM, 0, NULL, UNIT_FILE_PRESET_ENABLE_ONLY, NULL, 0); + r = unit_file_preset_all(LOOKUP_SCOPE_SYSTEM, 0, NULL, UNIT_FILE_PRESET_ENABLE_ONLY, NULL, 0); if (r < 0) log_full_errno(r == -EEXIST ? LOG_NOTICE : LOG_WARNING, r, "Failed to populate /etc with preset unit settings, ignoring: %m"); diff --git a/src/core/manager.h b/src/core/manager.h index c989ce9c32..dc6718ada1 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -235,7 +235,7 @@ struct Manager { int user_lookup_fds[2]; sd_event_source *user_lookup_event_source; - UnitFileScope unit_file_scope; + LookupScope unit_file_scope; LookupPaths lookup_paths; Hashmap *unit_id_map; Hashmap *unit_name_map; @@ -463,8 +463,8 @@ static inline usec_t manager_default_timeout_abort_usec(Manager *m) { return m->default_timeout_abort_set ? m->default_timeout_abort_usec : m->default_timeout_stop_usec; } -#define MANAGER_IS_SYSTEM(m) ((m)->unit_file_scope == UNIT_FILE_SYSTEM) -#define MANAGER_IS_USER(m) ((m)->unit_file_scope != UNIT_FILE_SYSTEM) +#define MANAGER_IS_SYSTEM(m) ((m)->unit_file_scope == LOOKUP_SCOPE_SYSTEM) +#define MANAGER_IS_USER(m) ((m)->unit_file_scope != LOOKUP_SCOPE_SYSTEM) #define MANAGER_IS_RELOADING(m) ((m)->n_reloading > 0) @@ -475,7 +475,7 @@ static inline usec_t manager_default_timeout_abort_usec(Manager *m) { #define MANAGER_IS_TEST_RUN(m) ((m)->test_run_flags != 0) -int manager_new(UnitFileScope scope, ManagerTestRunFlags test_run_flags, Manager **m); +int manager_new(LookupScope scope, ManagerTestRunFlags test_run_flags, Manager **m); Manager* manager_free(Manager *m); DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free); diff --git a/src/libsystemd/sd-path/sd-path.c b/src/libsystemd/sd-path/sd-path.c index 8d9cfbc0af..385cfd3006 100644 --- a/src/libsystemd/sd-path/sd-path.c +++ b/src/libsystemd/sd-path/sd-path.c @@ -601,8 +601,8 @@ static int get_search(uint64_t type, char ***list) { case SD_PATH_SYSTEMD_SEARCH_SYSTEM_UNIT: case SD_PATH_SYSTEMD_SEARCH_USER_UNIT: { _cleanup_(lookup_paths_free) LookupPaths lp = {}; - const UnitFileScope scope = type == SD_PATH_SYSTEMD_SEARCH_SYSTEM_UNIT ? - UNIT_FILE_SYSTEM : UNIT_FILE_USER; + const LookupScope scope = type == SD_PATH_SYSTEMD_SEARCH_SYSTEM_UNIT ? + LOOKUP_SCOPE_SYSTEM : LOOKUP_SCOPE_USER; r = lookup_paths_init(&lp, scope, 0, NULL); if (r < 0) @@ -615,8 +615,8 @@ static int get_search(uint64_t type, char ***list) { case SD_PATH_SYSTEMD_SEARCH_SYSTEM_GENERATOR: case SD_PATH_SYSTEMD_SEARCH_USER_GENERATOR: { char **t; - const UnitFileScope scope = type == SD_PATH_SYSTEMD_SEARCH_SYSTEM_GENERATOR ? - UNIT_FILE_SYSTEM : UNIT_FILE_USER; + const LookupScope scope = type == SD_PATH_SYSTEMD_SEARCH_SYSTEM_GENERATOR ? + LOOKUP_SCOPE_SYSTEM : LOOKUP_SCOPE_USER; t = generator_binary_paths(scope); if (!t) diff --git a/src/portable/portable.c b/src/portable/portable.c index 691aad5238..44595b5f82 100644 --- a/src/portable/portable.c +++ b/src/portable/portable.c @@ -231,7 +231,7 @@ static int extract_now( /* Then, send unit file data to the parent (or/and add it to the hashmap). For that we use our usual unit * discovery logic. Note that we force looking inside of /lib/systemd/system/ for units too, as we mightbe * compiled for a split-usr system but the image might be a legacy-usr one. */ - r = lookup_paths_init(&paths, UNIT_FILE_SYSTEM, LOOKUP_PATHS_SPLIT_USR, where); + r = lookup_paths_init(&paths, LOOKUP_SCOPE_SYSTEM, LOOKUP_PATHS_SPLIT_USR, where); if (r < 0) return log_debug_errno(r, "Failed to acquire lookup paths: %m"); @@ -1340,12 +1340,12 @@ int portable_attach( strempty(extensions_joined)); } - r = lookup_paths_init(&paths, UNIT_FILE_SYSTEM, LOOKUP_PATHS_SPLIT_USR, NULL); + r = lookup_paths_init(&paths, LOOKUP_SCOPE_SYSTEM, LOOKUP_PATHS_SPLIT_USR, NULL); if (r < 0) return r; HASHMAP_FOREACH(item, unit_files) { - r = unit_file_exists(UNIT_FILE_SYSTEM, &paths, item->name); + r = unit_file_exists(LOOKUP_SCOPE_SYSTEM, &paths, item->name); if (r < 0) return sd_bus_error_set_errnof(error, r, "Failed to determine whether unit '%s' exists on the host: %m", item->name); if (!FLAGS_SET(flags, PORTABLE_REATTACH) && r > 0) @@ -1527,7 +1527,7 @@ int portable_detach( assert(name_or_path); - r = lookup_paths_init(&paths, UNIT_FILE_SYSTEM, LOOKUP_PATHS_SPLIT_USR, NULL); + r = lookup_paths_init(&paths, LOOKUP_SCOPE_SYSTEM, LOOKUP_PATHS_SPLIT_USR, NULL); if (r < 0) return r; @@ -1561,7 +1561,7 @@ int portable_detach( if (r == 0) continue; - r = unit_file_lookup_state(UNIT_FILE_SYSTEM, &paths, de->d_name, &state); + r = unit_file_lookup_state(LOOKUP_SCOPE_SYSTEM, &paths, de->d_name, &state); if (r < 0) return log_debug_errno(r, "Failed to determine unit file state of '%s': %m", de->d_name); if (!IN_SET(state, UNIT_FILE_STATIC, UNIT_FILE_DISABLED, UNIT_FILE_LINKED, UNIT_FILE_RUNTIME, UNIT_FILE_LINKED_RUNTIME)) @@ -1696,7 +1696,7 @@ static int portable_get_state_internal( assert(name_or_path); assert(ret); - r = lookup_paths_init(&paths, UNIT_FILE_SYSTEM, LOOKUP_PATHS_SPLIT_USR, NULL); + r = lookup_paths_init(&paths, LOOKUP_SCOPE_SYSTEM, LOOKUP_PATHS_SPLIT_USR, NULL); if (r < 0) return r; @@ -1732,7 +1732,7 @@ static int portable_get_state_internal( if (r == 0) continue; - r = unit_file_lookup_state(UNIT_FILE_SYSTEM, &paths, de->d_name, &state); + r = unit_file_lookup_state(LOOKUP_SCOPE_SYSTEM, &paths, de->d_name, &state); if (r < 0) return log_debug_errno(r, "Failed to determine unit file state of '%s': %m", de->d_name); if (!IN_SET(state, UNIT_FILE_STATIC, UNIT_FILE_DISABLED, UNIT_FILE_LINKED, UNIT_FILE_LINKED_RUNTIME)) diff --git a/src/shared/install-printf.c b/src/shared/install-printf.c index 4c0eb3ce61..5436aa483b 100644 --- a/src/shared/install-printf.c +++ b/src/shared/install-printf.c @@ -98,7 +98,7 @@ static int specifier_last_component(char specifier, const void *data, const char } int install_name_printf( - UnitFileScope scope, + LookupScope scope, const UnitFileInstallInfo *info, const char *format, char **ret) { diff --git a/src/shared/install-printf.h b/src/shared/install-printf.h index 60d3a9fc55..6a9ab24e15 100644 --- a/src/shared/install-printf.h +++ b/src/shared/install-printf.h @@ -5,7 +5,7 @@ #include "unit-name.h" int install_name_printf( - UnitFileScope scope, + LookupScope scope, const UnitFileInstallInfo *info, const char *format, char **ret); diff --git a/src/shared/install.c b/src/shared/install.c index 01fd79923b..f807947a3c 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -47,7 +47,7 @@ typedef enum SearchFlags { } SearchFlags; typedef struct { - UnitFileScope scope; + LookupScope scope; OrderedHashmap *will_process; OrderedHashmap *have_processed; } InstallContext; @@ -940,7 +940,7 @@ static int find_symlinks( } static int find_symlinks_in_scope( - UnitFileScope scope, + LookupScope scope, const LookupPaths *lp, const UnitFileInstallInfo *info, bool match_name, @@ -974,7 +974,7 @@ static int find_symlinks_in_scope( } /* look for global enablement of user units */ - if (scope == UNIT_FILE_USER && path_is_user_config_dir(*p)) { + if (scope == LOOKUP_SCOPE_USER && path_is_user_config_dir(*p)) { *state = UNIT_FILE_ENABLED; return 1; } @@ -1863,7 +1863,7 @@ int unit_file_verify_alias( } static int install_info_symlink_alias( - UnitFileScope scope, + LookupScope scope, UnitFileInstallInfo *info, const LookupPaths *lp, const char *config_path, @@ -1907,7 +1907,7 @@ static int install_info_symlink_alias( } static int install_info_symlink_wants( - UnitFileScope scope, + LookupScope scope, UnitFileFlags file_flags, UnitFileInstallInfo *info, const LookupPaths *lp, @@ -2047,7 +2047,7 @@ static int install_info_symlink_link( } static int install_info_apply( - UnitFileScope scope, + LookupScope scope, UnitFileFlags file_flags, UnitFileInstallInfo *info, const LookupPaths *lp, @@ -2220,7 +2220,7 @@ static int install_context_mark_for_removal( } int unit_file_mask( - UnitFileScope scope, + LookupScope scope, UnitFileFlags flags, const char *root_dir, char **files, @@ -2232,7 +2232,7 @@ int unit_file_mask( int r; assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(scope < _LOOKUP_SCOPE_MAX); r = lookup_paths_init(&lp, scope, 0, root_dir); if (r < 0) @@ -2265,7 +2265,7 @@ int unit_file_mask( } int unit_file_unmask( - UnitFileScope scope, + LookupScope scope, UnitFileFlags flags, const char *root_dir, char **files, @@ -2280,7 +2280,7 @@ int unit_file_unmask( int r, q; assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(scope < _LOOKUP_SCOPE_MAX); r = lookup_paths_init(&lp, scope, 0, root_dir); if (r < 0) @@ -2357,7 +2357,7 @@ int unit_file_unmask( } int unit_file_link( - UnitFileScope scope, + LookupScope scope, UnitFileFlags flags, const char *root_dir, char **files, @@ -2371,7 +2371,7 @@ int unit_file_link( int r, q; assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(scope < _LOOKUP_SCOPE_MAX); r = lookup_paths_init(&lp, scope, 0, root_dir); if (r < 0) @@ -2457,7 +2457,7 @@ static int path_shall_revert(const LookupPaths *lp, const char *path) { } int unit_file_revert( - UnitFileScope scope, + LookupScope scope, const char *root_dir, char **files, UnitFileChange **changes, @@ -2608,7 +2608,7 @@ int unit_file_revert( } int unit_file_add_dependency( - UnitFileScope scope, + LookupScope scope, UnitFileFlags file_flags, const char *root_dir, char **files, @@ -2624,7 +2624,7 @@ int unit_file_add_dependency( int r; assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(scope < _LOOKUP_SCOPE_MAX); assert(target); if (!IN_SET(dep, UNIT_WANTS, UNIT_REQUIRES)) @@ -2679,7 +2679,7 @@ int unit_file_add_dependency( static int do_unit_file_enable( const LookupPaths *lp, - UnitFileScope scope, + LookupScope scope, UnitFileFlags flags, const char *config_path, char **files, @@ -2709,7 +2709,7 @@ static int do_unit_file_enable( } int unit_file_enable( - UnitFileScope scope, + LookupScope scope, UnitFileFlags flags, const char *root_dir, char **files, @@ -2720,7 +2720,7 @@ int unit_file_enable( int r; assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(scope < _LOOKUP_SCOPE_MAX); r = lookup_paths_init(&lp, scope, 0, root_dir); if (r < 0) @@ -2735,7 +2735,7 @@ int unit_file_enable( static int do_unit_file_disable( const LookupPaths *lp, - UnitFileScope scope, + LookupScope scope, UnitFileFlags flags, const char *config_path, char **files, @@ -2764,7 +2764,7 @@ static int do_unit_file_disable( int unit_file_disable( - UnitFileScope scope, + LookupScope scope, UnitFileFlags flags, const char *root_dir, char **files, @@ -2775,7 +2775,7 @@ int unit_file_disable( int r; assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(scope < _LOOKUP_SCOPE_MAX); r = lookup_paths_init(&lp, scope, 0, root_dir); if (r < 0) @@ -2789,7 +2789,7 @@ int unit_file_disable( } static int normalize_linked_files( - UnitFileScope scope, + LookupScope scope, const LookupPaths *lp, char **names_or_paths, char ***ret_names, @@ -2847,7 +2847,7 @@ static int normalize_linked_files( } int unit_file_reenable( - UnitFileScope scope, + LookupScope scope, UnitFileFlags flags, const char *root_dir, char **names_or_paths, @@ -2859,7 +2859,7 @@ int unit_file_reenable( int r; assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(scope < _LOOKUP_SCOPE_MAX); r = lookup_paths_init(&lp, scope, 0, root_dir); if (r < 0) @@ -2883,7 +2883,7 @@ int unit_file_reenable( } int unit_file_set_default( - UnitFileScope scope, + LookupScope scope, UnitFileFlags flags, const char *root_dir, const char *name, @@ -2897,7 +2897,7 @@ int unit_file_set_default( int r; assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(scope < _LOOKUP_SCOPE_MAX); assert(name); if (unit_name_to_type(name) != UNIT_TARGET) /* this also validates the name */ @@ -2918,7 +2918,7 @@ int unit_file_set_default( } int unit_file_get_default( - UnitFileScope scope, + LookupScope scope, const char *root_dir, char **name) { @@ -2929,7 +2929,7 @@ int unit_file_get_default( int r; assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(scope < _LOOKUP_SCOPE_MAX); assert(name); r = lookup_paths_init(&lp, scope, 0, root_dir); @@ -2953,7 +2953,7 @@ int unit_file_get_default( } int unit_file_lookup_state( - UnitFileScope scope, + LookupScope scope, const LookupPaths *lp, const char *name, UnitFileState *ret) { @@ -3051,7 +3051,7 @@ int unit_file_lookup_state( } int unit_file_get_state( - UnitFileScope scope, + LookupScope scope, const char *root_dir, const char *name, UnitFileState *ret) { @@ -3060,7 +3060,7 @@ int unit_file_get_state( int r; assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(scope < _LOOKUP_SCOPE_MAX); assert(name); r = lookup_paths_init(&lp, scope, 0, root_dir); @@ -3070,7 +3070,7 @@ int unit_file_get_state( return unit_file_lookup_state(scope, &lp, name, ret); } -int unit_file_exists(UnitFileScope scope, const LookupPaths *lp, const char *name) { +int unit_file_exists(LookupScope scope, const LookupPaths *lp, const char *name) { _cleanup_(install_context_done) InstallContext c = { .scope = scope }; int r; @@ -3122,17 +3122,17 @@ static int split_pattern_into_name_and_instances(const char *pattern, char **out return 0; } -static int presets_find_config(UnitFileScope scope, const char *root_dir, char ***files) { +static int presets_find_config(LookupScope scope, const char *root_dir, char ***files) { static const char* const system_dirs[] = {CONF_PATHS("systemd/system-preset"), NULL}; static const char* const user_dirs[] = {CONF_PATHS_USR("systemd/user-preset"), NULL}; const char* const* dirs; assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(scope < _LOOKUP_SCOPE_MAX); - if (scope == UNIT_FILE_SYSTEM) + if (scope == LOOKUP_SCOPE_SYSTEM) dirs = system_dirs; - else if (IN_SET(scope, UNIT_FILE_GLOBAL, UNIT_FILE_USER)) + else if (IN_SET(scope, LOOKUP_SCOPE_GLOBAL, LOOKUP_SCOPE_USER)) dirs = user_dirs; else assert_not_reached(); @@ -3140,13 +3140,13 @@ static int presets_find_config(UnitFileScope scope, const char *root_dir, char * return conf_files_list_strv(files, ".preset", root_dir, 0, dirs); } -static int read_presets(UnitFileScope scope, const char *root_dir, UnitFilePresets *presets) { +static int read_presets(LookupScope scope, const char *root_dir, UnitFilePresets *presets) { _cleanup_(unit_file_presets_freep) UnitFilePresets ps = {}; _cleanup_strv_free_ char **files = NULL; int r; assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(scope < _LOOKUP_SCOPE_MAX); assert(presets); r = presets_find_config(scope, root_dir, &files); @@ -3320,7 +3320,7 @@ static int query_presets(const char *name, const UnitFilePresets *presets, char } } -int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name, UnitFilePresets *cached) { +int unit_file_query_preset(LookupScope scope, const char *root_dir, const char *name, UnitFilePresets *cached) { _cleanup_(unit_file_presets_freep) UnitFilePresets tmp = {}; int r; @@ -3384,7 +3384,7 @@ static int execute_preset( } static int preset_prepare_one( - UnitFileScope scope, + LookupScope scope, InstallContext *plus, InstallContext *minus, LookupPaths *lp, @@ -3437,7 +3437,7 @@ static int preset_prepare_one( } int unit_file_preset( - UnitFileScope scope, + LookupScope scope, UnitFileFlags file_flags, const char *root_dir, char **files, @@ -3452,7 +3452,7 @@ int unit_file_preset( int r; assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(scope < _LOOKUP_SCOPE_MAX); assert(mode < _UNIT_FILE_PRESET_MAX); r = lookup_paths_init(&lp, scope, 0, root_dir); @@ -3477,7 +3477,7 @@ int unit_file_preset( } int unit_file_preset_all( - UnitFileScope scope, + LookupScope scope, UnitFileFlags file_flags, const char *root_dir, UnitFilePresetMode mode, @@ -3491,7 +3491,7 @@ int unit_file_preset_all( int r; assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(scope < _LOOKUP_SCOPE_MAX); assert(mode < _UNIT_FILE_PRESET_MAX); r = lookup_paths_init(&lp, scope, 0, root_dir); @@ -3552,7 +3552,7 @@ Hashmap* unit_file_list_free(Hashmap *h) { DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList*, unit_file_list_free_one); int unit_file_get_list( - UnitFileScope scope, + LookupScope scope, const char *root_dir, Hashmap *h, char **states, @@ -3562,7 +3562,7 @@ int unit_file_get_list( int r; assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(scope < _LOOKUP_SCOPE_MAX); assert(h); r = lookup_paths_init(&lp, scope, 0, root_dir); diff --git a/src/shared/install.h b/src/shared/install.h index 95427537f2..2ba7e8aea0 100644 --- a/src/shared/install.h +++ b/src/shared/install.h @@ -15,6 +15,7 @@ typedef struct UnitFileInstallInfo UnitFileInstallInfo; #include "macro.h" #include "path-lookup.h" #include "strv.h" +#include "unit-file.h" #include "unit-name.h" enum UnitFilePresetMode { @@ -95,28 +96,28 @@ struct UnitFileInstallInfo { }; int unit_file_enable( - UnitFileScope scope, + LookupScope scope, UnitFileFlags flags, const char *root_dir, char **files, UnitFileChange **changes, size_t *n_changes); int unit_file_disable( - UnitFileScope scope, + LookupScope scope, UnitFileFlags flags, const char *root_dir, char **files, UnitFileChange **changes, size_t *n_changes); int unit_file_reenable( - UnitFileScope scope, + LookupScope scope, UnitFileFlags flags, const char *root_dir, char **names_or_paths, UnitFileChange **changes, size_t *n_changes); int unit_file_preset( - UnitFileScope scope, + LookupScope scope, UnitFileFlags flags, const char *root_dir, char **files, @@ -124,52 +125,52 @@ int unit_file_preset( UnitFileChange **changes, size_t *n_changes); int unit_file_preset_all( - UnitFileScope scope, + LookupScope scope, UnitFileFlags flags, const char *root_dir, UnitFilePresetMode mode, UnitFileChange **changes, size_t *n_changes); int unit_file_mask( - UnitFileScope scope, + LookupScope scope, UnitFileFlags flags, const char *root_dir, char **files, UnitFileChange **changes, size_t *n_changes); int unit_file_unmask( - UnitFileScope scope, + LookupScope scope, UnitFileFlags flags, const char *root_dir, char **files, UnitFileChange **changes, size_t *n_changes); int unit_file_link( - UnitFileScope scope, + LookupScope scope, UnitFileFlags flags, const char *root_dir, char **files, UnitFileChange **changes, size_t *n_changes); int unit_file_revert( - UnitFileScope scope, + LookupScope scope, const char *root_dir, char **files, UnitFileChange **changes, size_t *n_changes); int unit_file_set_default( - UnitFileScope scope, + LookupScope scope, UnitFileFlags flags, const char *root_dir, const char *file, UnitFileChange **changes, size_t *n_changes); int unit_file_get_default( - UnitFileScope scope, + LookupScope scope, const char *root_dir, char **name); int unit_file_add_dependency( - UnitFileScope scope, + LookupScope scope, UnitFileFlags flags, const char *root_dir, char **files, @@ -179,15 +180,15 @@ int unit_file_add_dependency( size_t *n_changes); int unit_file_lookup_state( - UnitFileScope scope, + LookupScope scope, const LookupPaths *paths, const char *name, UnitFileState *ret); -int unit_file_get_state(UnitFileScope scope, const char *root_dir, const char *filename, UnitFileState *ret); -int unit_file_exists(UnitFileScope scope, const LookupPaths *paths, const char *name); +int unit_file_get_state(LookupScope scope, const char *root_dir, const char *filename, UnitFileState *ret); +int unit_file_exists(LookupScope scope, const LookupPaths *paths, const char *name); -int unit_file_get_list(UnitFileScope scope, const char *root_dir, Hashmap *h, char **states, char **patterns); +int unit_file_get_list(LookupScope scope, const char *root_dir, Hashmap *h, char **states, char **patterns); Hashmap* unit_file_list_free(Hashmap *h); int unit_file_changes_add(UnitFileChange **changes, size_t *n_changes, int type, const char *path, const char *source); @@ -210,7 +211,7 @@ typedef struct { } UnitFilePresets; void unit_file_presets_freep(UnitFilePresets *p); -int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name, UnitFilePresets *cached); +int unit_file_query_preset(LookupScope scope, const char *root_dir, const char *name, UnitFilePresets *cached); const char *unit_file_state_to_string(UnitFileState s) _const_; UnitFileState unit_file_state_from_string(const char *s) _pure_; diff --git a/src/shared/specifier.c b/src/shared/specifier.c index 777881b325..16eb8830dc 100644 --- a/src/shared/specifier.c +++ b/src/shared/specifier.c @@ -18,11 +18,11 @@ #include "id128-util.h" #include "macro.h" #include "os-util.h" +#include "path-lookup.h" #include "path-util.h" #include "specifier.h" #include "string-util.h" #include "strv.h" -#include "unit-file.h" #include "user-util.h" /* @@ -310,15 +310,15 @@ int specifier_os_image_version(char specifier, const void *data, const char *roo } int specifier_group_name(char specifier, const void *data, const char *root, const void *userdata, char **ret) { - UnitFileScope scope = PTR_TO_INT(data); + LookupScope scope = PTR_TO_INT(data); char *t; assert(ret); - if (scope == UNIT_FILE_GLOBAL) + if (scope == LOOKUP_SCOPE_GLOBAL) return -EINVAL; - t = gid_to_name(scope == UNIT_FILE_USER ? getgid() : 0); + t = gid_to_name(scope == LOOKUP_SCOPE_USER ? getgid() : 0); if (!t) return -ENOMEM; @@ -327,15 +327,15 @@ int specifier_group_name(char specifier, const void *data, const char *root, con } int specifier_group_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) { - UnitFileScope scope = PTR_TO_INT(data); + LookupScope scope = PTR_TO_INT(data); gid_t gid; assert(ret); - if (scope == UNIT_FILE_GLOBAL) + if (scope == LOOKUP_SCOPE_GLOBAL) return -EINVAL; - gid = scope == UNIT_FILE_USER ? getgid() : 0; + gid = scope == LOOKUP_SCOPE_USER ? getgid() : 0; if (asprintf(ret, UID_FMT, gid) < 0) return -ENOMEM; @@ -344,16 +344,16 @@ int specifier_group_id(char specifier, const void *data, const char *root, const } int specifier_user_name(char specifier, const void *data, const char *root, const void *userdata, char **ret) { - UnitFileScope scope = PTR_TO_INT(data); + LookupScope scope = PTR_TO_INT(data); uid_t uid; char *t; assert(ret); - if (scope == UNIT_FILE_GLOBAL) + if (scope == LOOKUP_SCOPE_GLOBAL) return -EINVAL; - uid = scope == UNIT_FILE_USER ? getuid() : 0; + uid = scope == LOOKUP_SCOPE_USER ? getuid() : 0; /* If we are UID 0 (root), this will not result in NSS, otherwise it might. This is good, as we want * to be able to run this in PID 1, where our user ID is 0, but where NSS lookups are not allowed. @@ -371,15 +371,15 @@ int specifier_user_name(char specifier, const void *data, const char *root, cons } int specifier_user_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) { - UnitFileScope scope = PTR_TO_INT(data); + LookupScope scope = PTR_TO_INT(data); uid_t uid; assert(ret); - if (scope == UNIT_FILE_GLOBAL) + if (scope == LOOKUP_SCOPE_GLOBAL) return -EINVAL; - uid = scope == UNIT_FILE_USER ? getuid() : 0; + uid = scope == LOOKUP_SCOPE_USER ? getuid() : 0; if (asprintf(ret, UID_FMT, uid) < 0) return -ENOMEM; diff --git a/src/systemctl/systemctl-edit.c b/src/systemctl/systemctl-edit.c index f8f810e1cd..446dfd7dd6 100644 --- a/src/systemctl/systemctl-edit.c +++ b/src/systemctl/systemctl-edit.c @@ -99,7 +99,7 @@ int verb_cat(int argc, char *argv[], void *userdata) { ansi_highlight_red(), ansi_highlight_red(), ansi_highlight_red(), - arg_scope == UNIT_FILE_SYSTEM ? "" : " --user", + arg_scope == LOOKUP_SCOPE_SYSTEM ? "" : " --user", ansi_normal()); r = cat_files(fragment_path, dropin_paths, 0); @@ -406,8 +406,8 @@ static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) { if (!path) { if (!arg_force) { log_info("Run 'systemctl edit%s --force --full %s' to create a new unit.", - arg_scope == UNIT_FILE_GLOBAL ? " --global" : - arg_scope == UNIT_FILE_USER ? " --user" : "", + arg_scope == LOOKUP_SCOPE_GLOBAL ? " --global" : + arg_scope == LOOKUP_SCOPE_USER ? " --user" : "", *name); return -ENOENT; } diff --git a/src/systemctl/systemctl-is-enabled.c b/src/systemctl/systemctl-is-enabled.c index c280d55d69..6f3d0b6eaa 100644 --- a/src/systemctl/systemctl-is-enabled.c +++ b/src/systemctl/systemctl-is-enabled.c @@ -18,7 +18,7 @@ static int show_installation_targets_client_side(const char *name) { flags = UNIT_FILE_DRY_RUN | (arg_runtime ? UNIT_FILE_RUNTIME : 0); - r = unit_file_disable(UNIT_FILE_SYSTEM, flags, NULL, p, &changes, &n_changes); + r = unit_file_disable(LOOKUP_SCOPE_SYSTEM, flags, NULL, p, &changes, &n_changes); if (r < 0) return log_error_errno(r, "Failed to get file links for %s: %m", name); diff --git a/src/systemctl/systemctl-show.c b/src/systemctl/systemctl-show.c index 0f3099b7b5..24e43321cf 100644 --- a/src/systemctl/systemctl-show.c +++ b/src/systemctl/systemctl-show.c @@ -762,7 +762,7 @@ static void print_status_info( getuid(), get_output_flags() | OUTPUT_BEGIN_NEWLINE, SD_JOURNAL_LOCAL_ONLY, - arg_scope == UNIT_FILE_SYSTEM, + arg_scope == LOOKUP_SCOPE_SYSTEM, ellipsized); if (i->need_daemon_reload) diff --git a/src/systemctl/systemctl-start-special.c b/src/systemctl/systemctl-start-special.c index da2336d3a2..9a90122fee 100644 --- a/src/systemctl/systemctl-start-special.c +++ b/src/systemctl/systemctl-start-special.c @@ -242,10 +242,10 @@ int verb_start_special(int argc, char *argv[], void *userdata) { int verb_start_system_special(int argc, char *argv[], void *userdata) { /* Like start_special above, but raises an error when running in user mode */ - if (arg_scope != UNIT_FILE_SYSTEM) + if (arg_scope != LOOKUP_SCOPE_SYSTEM) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Bad action for %s mode.", - arg_scope == UNIT_FILE_GLOBAL ? "--global" : "--user"); + arg_scope == LOOKUP_SCOPE_GLOBAL ? "--global" : "--user"); return verb_start_special(argc, argv, userdata); } diff --git a/src/systemctl/systemctl-start-unit.c b/src/systemctl/systemctl-start-unit.c index 9b215c2e8a..42a5b086c3 100644 --- a/src/systemctl/systemctl-start-unit.c +++ b/src/systemctl/systemctl-start-unit.c @@ -168,8 +168,8 @@ fail: BUS_ERROR_UNIT_MASKED, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE)) log_error("See %s logs and 'systemctl%s status%s %s' for details.", - arg_scope == UNIT_FILE_SYSTEM ? "system" : "user", - arg_scope == UNIT_FILE_SYSTEM ? "" : " --user", + arg_scope == LOOKUP_SCOPE_SYSTEM ? "system" : "user", + arg_scope == LOOKUP_SCOPE_SYSTEM ? "" : " --user", name[0] == '-' ? " --" : "", name); @@ -242,7 +242,7 @@ static const char** make_extra_args(const char *extra_args[static 4]) { assert(extra_args); - if (arg_scope != UNIT_FILE_SYSTEM) + if (arg_scope != LOOKUP_SCOPE_SYSTEM) extra_args[n++] = "--user"; if (arg_transport == BUS_TRANSPORT_REMOTE) { diff --git a/src/systemctl/systemctl-sysv-compat.c b/src/systemctl/systemctl-sysv-compat.c index c6e8defd1b..f6889993ed 100644 --- a/src/systemctl/systemctl-sysv-compat.c +++ b/src/systemctl/systemctl-sysv-compat.c @@ -116,7 +116,7 @@ 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 */ - if (arg_scope != UNIT_FILE_SYSTEM) + if (arg_scope != LOOKUP_SCOPE_SYSTEM) return 0; if (getenv_bool("SYSTEMCTL_SKIP_SYSV") > 0) diff --git a/src/systemctl/systemctl-util.c b/src/systemctl/systemctl-util.c index 0334b8c1fc..6a71bce5fb 100644 --- a/src/systemctl/systemctl-util.c +++ b/src/systemctl/systemctl-util.c @@ -46,7 +46,7 @@ int acquire_bus(BusFocus focus, sd_bus **ret) { if (!buses[focus]) { bool user; - user = arg_scope != UNIT_FILE_SYSTEM; + user = arg_scope != LOOKUP_SCOPE_SYSTEM; if (focus == BUS_MANAGER) r = bus_connect_transport_systemd(arg_transport, arg_host, user, &buses[focus]); @@ -73,7 +73,7 @@ void ask_password_agent_open_maybe(void) { if (arg_dry_run) return; - if (arg_scope != UNIT_FILE_SYSTEM) + if (arg_scope != LOOKUP_SCOPE_SYSTEM) return; ask_password_agent_open_if_enabled(arg_transport, arg_ask_password); @@ -82,7 +82,7 @@ void ask_password_agent_open_maybe(void) { void polkit_agent_open_maybe(void) { /* Open the polkit agent as a child process if necessary */ - if (arg_scope != UNIT_FILE_SYSTEM) + if (arg_scope != LOOKUP_SCOPE_SYSTEM) return; polkit_agent_open_if_enabled(arg_transport, arg_ask_password); @@ -380,7 +380,7 @@ void warn_unit_file_changed(const char *unit) { ansi_highlight_red(), ansi_normal(), unit, - arg_scope == UNIT_FILE_SYSTEM ? "" : " --user"); + arg_scope == LOOKUP_SCOPE_SYSTEM ? "" : " --user"); } int unit_file_find_path(LookupPaths *lp, const char *unit_name, char **ret_unit_path) { @@ -814,7 +814,7 @@ bool install_client_side(void) { if (!isempty(arg_root)) return true; - if (arg_scope == UNIT_FILE_GLOBAL) + if (arg_scope == LOOKUP_SCOPE_GLOBAL) return true; /* Unsupported environment variable, mostly for debugging purposes */ diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index e81703ebe8..97ec51b7d9 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -66,7 +66,7 @@ char **arg_properties = NULL; bool arg_all = false; enum dependency arg_dependency = DEPENDENCY_FORWARD; const char *_arg_job_mode = NULL; -UnitFileScope arg_scope = UNIT_FILE_SYSTEM; +LookupScope arg_scope = LOOKUP_SCOPE_SYSTEM; bool arg_wait = false; bool arg_no_block = false; int arg_legend = -1; /* -1: true, unless --quiet is passed, 1: true */ @@ -616,15 +616,15 @@ static int systemctl_parse_argv(int argc, char *argv[]) { break; case ARG_USER: - arg_scope = UNIT_FILE_USER; + arg_scope = LOOKUP_SCOPE_USER; break; case ARG_SYSTEM: - arg_scope = UNIT_FILE_SYSTEM; + arg_scope = LOOKUP_SCOPE_SYSTEM; break; case ARG_GLOBAL: - arg_scope = UNIT_FILE_GLOBAL; + arg_scope = LOOKUP_SCOPE_GLOBAL; break; case ARG_WAIT: @@ -924,10 +924,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) { /* If we are in --user mode, there's no point in talking to PolicyKit or the infra to query system * passwords */ - if (arg_scope != UNIT_FILE_SYSTEM) + if (arg_scope != LOOKUP_SCOPE_SYSTEM) arg_ask_password = false; - if (arg_transport == BUS_TRANSPORT_REMOTE && arg_scope != UNIT_FILE_SYSTEM) + if (arg_transport == BUS_TRANSPORT_REMOTE && arg_scope != LOOKUP_SCOPE_SYSTEM) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot access user instance remotely."); diff --git a/src/systemctl/systemctl.h b/src/systemctl/systemctl.h index d6b9d7495c..7507398c4a 100644 --- a/src/systemctl/systemctl.h +++ b/src/systemctl/systemctl.h @@ -51,7 +51,7 @@ extern char **arg_properties; extern bool arg_all; extern enum dependency arg_dependency; extern const char *_arg_job_mode; -extern UnitFileScope arg_scope; +extern LookupScope arg_scope; extern bool arg_wait; extern bool arg_no_block; extern int arg_legend; diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c index 428509f4ce..14ae873dc0 100644 --- a/src/sysv-generator/sysv-generator.c +++ b/src/sysv-generator/sysv-generator.c @@ -747,7 +747,7 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) { if (hashmap_contains(all_services, name)) continue; - r = unit_file_exists(UNIT_FILE_SYSTEM, lp, name); + r = unit_file_exists(LOOKUP_SCOPE_SYSTEM, lp, name); if (r < 0 && !IN_SET(r, -ELOOP, -ERFKILL, -EADDRNOTAVAIL)) { log_debug_errno(r, "Failed to detect whether %s exists, skipping: %m", name); continue; @@ -891,7 +891,7 @@ static int run(const char *dest, const char *dest_early, const char *dest_late) assert_se(arg_dest = dest_late); - r = lookup_paths_init_or_warn(&lp, UNIT_FILE_SYSTEM, LOOKUP_PATHS_EXCLUDE_GENERATED, NULL); + r = lookup_paths_init_or_warn(&lp, LOOKUP_SCOPE_SYSTEM, LOOKUP_PATHS_EXCLUDE_GENERATED, NULL); if (r < 0) return r; diff --git a/src/test/test-bpf-firewall.c b/src/test/test-bpf-firewall.c index cbcb525f52..8f4b485073 100644 --- a/src/test/test-bpf-firewall.c +++ b/src/test/test-bpf-firewall.c @@ -97,7 +97,7 @@ int main(int argc, char *argv[]) { /* The simple tests succeeded. Now let's try full unit-based use-case. */ - assert_se(manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m) >= 0); + assert_se(manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_BASIC, &m) >= 0); assert_se(manager_startup(m, NULL, NULL, NULL) >= 0); assert_se(u = unit_new(m, sizeof(Service))); diff --git a/src/test/test-bpf-foreign-programs.c b/src/test/test-bpf-foreign-programs.c index 377019f193..061426f287 100644 --- a/src/test/test-bpf-foreign-programs.c +++ b/src/test/test-bpf-foreign-programs.c @@ -301,7 +301,7 @@ int main(int argc, char *argv[]) { assert_se(set_unit_path(unit_dir) >= 0); assert_se(runtime_dir = setup_fake_runtime_dir()); - assert_se(manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m) >= 0); + assert_se(manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_BASIC, &m) >= 0); assert_se(manager_startup(m, NULL, NULL, NULL) >= 0); assert_se(test_bpf_cgroup_programs(m, diff --git a/src/test/test-bpf-lsm.c b/src/test/test-bpf-lsm.c index 480865d0bc..e0e1b7f38f 100644 --- a/src/test/test-bpf-lsm.c +++ b/src/test/test-bpf-lsm.c @@ -90,7 +90,7 @@ int main(int argc, char *argv[]) { assert_se(set_unit_path(unit_dir) >= 0); assert_se(runtime_dir = setup_fake_runtime_dir()); - assert_se(manager_new(UNIT_FILE_SYSTEM, MANAGER_TEST_RUN_BASIC, &m) >= 0); + assert_se(manager_new(LOOKUP_SCOPE_SYSTEM, MANAGER_TEST_RUN_BASIC, &m) >= 0); assert_se(manager_startup(m, NULL, NULL, NULL) >= 0); /* We need to enable access to the filesystem where the binary is so we diff --git a/src/test/test-cgroup-mask.c b/src/test/test-cgroup-mask.c index 6058f32b0e..57483f72c2 100644 --- a/src/test/test-cgroup-mask.c +++ b/src/test/test-cgroup-mask.c @@ -42,7 +42,7 @@ TEST_RET(cgroup_mask, .sd_booted = true) { assert_se(get_testdata_dir("units", &unit_dir) >= 0); assert_se(set_unit_path(unit_dir) >= 0); assert_se(runtime_dir = setup_fake_runtime_dir()); - r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m); + r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_BASIC, &m); if (IN_SET(r, -EPERM, -EACCES)) { log_error_errno(r, "manager_new: %m"); return log_tests_skipped("cannot create manager"); diff --git a/src/test/test-cgroup-unit-default.c b/src/test/test-cgroup-unit-default.c index 4c8de1e382..94201a3ccc 100644 --- a/src/test/test-cgroup-unit-default.c +++ b/src/test/test-cgroup-unit-default.c @@ -26,7 +26,7 @@ TEST_RET(default_memory_low, .sd_booted = true) { assert_se(get_testdata_dir("units", &unit_dir) >= 0); assert_se(set_unit_path(unit_dir) >= 0); assert_se(runtime_dir = setup_fake_runtime_dir()); - r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m); + r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_BASIC, &m); if (IN_SET(r, -EPERM, -EACCES)) { log_error_errno(r, "manager_new: %m"); return log_tests_skipped("cannot create manager"); diff --git a/src/test/test-engine.c b/src/test/test-engine.c index cd01d1358b..ef055360fb 100644 --- a/src/test/test-engine.c +++ b/src/test/test-engine.c @@ -93,7 +93,7 @@ int main(int argc, char *argv[]) { assert_se(set_unit_path(unit_dir) >= 0); assert_se(runtime_dir = setup_fake_runtime_dir()); - r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m); + r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_BASIC, &m); if (manager_errno_skip_test(r)) return log_tests_skipped_errno(r, "manager_new"); assert_se(r >= 0); diff --git a/src/test/test-execute.c b/src/test/test-execute.c index ba1be2b453..6fce05bb58 100644 --- a/src/test/test-execute.c +++ b/src/test/test-execute.c @@ -1117,7 +1117,7 @@ typedef struct test_entry { #define entry(x) {x, #x} -static int run_tests(UnitFileScope scope, const test_entry tests[], char **patterns) { +static int run_tests(LookupScope scope, const test_entry tests[], char **patterns) { _cleanup_(manager_freep) Manager *m = NULL; int r; @@ -1239,11 +1239,11 @@ int main(int argc, char *argv[]) { assert_se(unsetenv("VAR2") == 0); assert_se(unsetenv("VAR3") == 0); - r = run_tests(UNIT_FILE_USER, user_tests, argv + 1); + r = run_tests(LOOKUP_SCOPE_USER, user_tests, argv + 1); if (r != 0) return r; - r = run_tests(UNIT_FILE_SYSTEM, system_tests, argv + 1); + r = run_tests(LOOKUP_SCOPE_SYSTEM, system_tests, argv + 1); if (r != 0) return r; @@ -1265,11 +1265,11 @@ int main(int argc, char *argv[]) { can_unshare = false; - r = run_tests(UNIT_FILE_USER, user_tests, argv + 1); + r = run_tests(LOOKUP_SCOPE_USER, user_tests, argv + 1); if (r != 0) return r; - return run_tests(UNIT_FILE_SYSTEM, system_tests, argv + 1); + return run_tests(LOOKUP_SCOPE_SYSTEM, system_tests, argv + 1); #else return 0; #endif diff --git a/src/test/test-install-root.c b/src/test/test-install-root.c index dca695d124..a36536b85b 100644 --- a/src/test/test-install-root.c +++ b/src/test/test-install-root.c @@ -23,41 +23,41 @@ TEST(basic_mask_and_enable) { UnitFileChange *changes = NULL; size_t n_changes = 0; - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", NULL) == -ENOENT); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", NULL) == -ENOENT); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", NULL) == -ENOENT); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", NULL) == -ENOENT); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "e.service", NULL) == -ENOENT); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "f.service", NULL) == -ENOENT); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "a.service", NULL) == -ENOENT); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "b.service", NULL) == -ENOENT); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "c.service", NULL) == -ENOENT); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "d.service", NULL) == -ENOENT); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "e.service", NULL) == -ENOENT); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "f.service", NULL) == -ENOENT); p = strjoina(root, "/usr/lib/systemd/system/a.service"); assert_se(write_string_file(p, "[Install]\n" "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", NULL) >= 0); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "a.service", NULL) >= 0); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_DISABLED); p = strjoina(root, "/usr/lib/systemd/system/b.service"); assert_se(symlink("a.service", p) >= 0); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", NULL) >= 0); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ALIAS); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "b.service", NULL) >= 0); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ALIAS); p = strjoina(root, "/usr/lib/systemd/system/c.service"); assert_se(symlink("/usr/lib/systemd/system/a.service", p) >= 0); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", NULL) >= 0); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ALIAS); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "c.service", NULL) >= 0); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ALIAS); p = strjoina(root, "/usr/lib/systemd/system/d.service"); assert_se(symlink("c.service", p) >= 0); /* This one is interesting, as d follows a relative, then an absolute symlink */ - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", NULL) >= 0); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ALIAS); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "d.service", NULL) >= 0); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ALIAS); - assert_se(unit_file_mask(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); + assert_se(unit_file_mask(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "/dev/null")); @@ -67,17 +67,17 @@ TEST(basic_mask_and_enable) { unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_MASKED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_MASKED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_MASKED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_MASKED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_MASKED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_MASKED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_MASKED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_MASKED); /* Enabling a masked unit should fail! */ - assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) == -ERFKILL); + assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) == -ERFKILL); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; - assert_se(unit_file_unmask(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); + assert_se(unit_file_unmask(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type_or_errno == UNIT_FILE_UNLINK); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/a.service"); @@ -85,7 +85,7 @@ TEST(basic_mask_and_enable) { unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; - assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) == 1); + assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) == 1); assert_se(n_changes == 1); assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "../a.service")); @@ -94,18 +94,18 @@ TEST(basic_mask_and_enable) { unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_ENABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ALIAS); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ALIAS); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ALIAS); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ALIAS); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ALIAS); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ALIAS); /* Enabling it again should succeed but be a NOP */ - assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); + assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 0); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; - assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); + assert_se(unit_file_disable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type_or_errno == UNIT_FILE_UNLINK); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/a.service"); @@ -113,19 +113,19 @@ TEST(basic_mask_and_enable) { unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ALIAS); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ALIAS); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ALIAS); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ALIAS); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ALIAS); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ALIAS); /* Disabling a disabled unit must succeed but be a NOP */ - assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); + assert_se(unit_file_disable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 0); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; /* Let's enable this indirectly via a symlink */ - assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("d.service"), &changes, &n_changes) >= 0); + assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("d.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "../a.service")); @@ -134,14 +134,14 @@ TEST(basic_mask_and_enable) { unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_ENABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ALIAS); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ALIAS); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ALIAS); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ALIAS); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ALIAS); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ALIAS); /* Let's try to reenable */ - assert_se(unit_file_reenable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("b.service"), &changes, &n_changes) >= 0); + assert_se(unit_file_reenable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("b.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 2); assert_se(changes[0].type_or_errno == UNIT_FILE_UNLINK); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/a.service"); @@ -152,24 +152,24 @@ TEST(basic_mask_and_enable) { unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_ENABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ALIAS); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ALIAS); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ALIAS); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ALIAS); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ALIAS); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ALIAS); /* Test masking with relative symlinks */ p = strjoina(root, "/usr/lib/systemd/system/e.service"); assert_se(symlink("../../../../../../dev/null", p) >= 0); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "e.service", NULL) >= 0); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "e.service", &state) >= 0 && state == UNIT_FILE_MASKED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "e.service", NULL) >= 0); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "e.service", &state) >= 0 && state == UNIT_FILE_MASKED); assert_se(unlink(p) == 0); assert_se(symlink("/usr/../dev/null", p) >= 0); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "e.service", NULL) >= 0); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "e.service", &state) >= 0 && state == UNIT_FILE_MASKED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "e.service", NULL) >= 0); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "e.service", &state) >= 0 && state == UNIT_FILE_MASKED); assert_se(unlink(p) == 0); @@ -180,10 +180,10 @@ TEST(basic_mask_and_enable) { "[Install]\n" "WantedBy=x.target\n", WRITE_STRING_FILE_CREATE) >= 0); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "f.service", NULL) >= 0); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "f.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "f.service", NULL) >= 0); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "f.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("f.service"), &changes, &n_changes) == 1); + assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("f.service"), &changes, &n_changes) == 1); assert_se(n_changes == 2); assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "../f.service")); @@ -196,7 +196,7 @@ TEST(basic_mask_and_enable) { unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "f.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "f.service", &state) >= 0 && state == UNIT_FILE_ENABLED); } TEST(linked_units) { @@ -236,9 +236,9 @@ TEST(linked_units) { "[Install]\n" "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", NULL) == -ENOENT); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked2.service", NULL) == -ENOENT); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked3.service", NULL) == -ENOENT); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "linked.service", NULL) == -ENOENT); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "linked2.service", NULL) == -ENOENT); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "linked3.service", NULL) == -ENOENT); p = strjoina(root, "/usr/lib/systemd/system/linked2.service"); assert_se(symlink("/opt/linked2.service", p) >= 0); @@ -246,12 +246,12 @@ TEST(linked_units) { p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/linked3.service"); assert_se(symlink("/opt/linked3.service", p) >= 0); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", &state) == -ENOENT); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked2.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked3.service", &state) >= 0 && state == UNIT_FILE_LINKED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "linked.service", &state) == -ENOENT); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "linked2.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "linked3.service", &state) >= 0 && state == UNIT_FILE_LINKED); /* First, let's link the unit into the search path */ - assert_se(unit_file_link(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("/opt/linked.service"), &changes, &n_changes) >= 0); + assert_se(unit_file_link(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("/opt/linked.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "/opt/linked.service")); @@ -260,10 +260,10 @@ TEST(linked_units) { unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", &state) >= 0 && state == UNIT_FILE_LINKED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "linked.service", &state) >= 0 && state == UNIT_FILE_LINKED); /* Let's unlink it from the search path again */ - assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("linked.service"), &changes, &n_changes) >= 0); + assert_se(unit_file_disable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("linked.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type_or_errno == UNIT_FILE_UNLINK); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/linked.service"); @@ -271,10 +271,10 @@ TEST(linked_units) { unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", NULL) == -ENOENT); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "linked.service", NULL) == -ENOENT); /* Now, let's not just link it, but also enable it */ - assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("/opt/linked.service"), &changes, &n_changes) >= 0); + assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("/opt/linked.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 2); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/linked.service"); q = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/linked.service"); @@ -294,10 +294,10 @@ TEST(linked_units) { unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "linked.service", &state) >= 0 && state == UNIT_FILE_ENABLED); /* And let's unlink it again */ - assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("linked.service"), &changes, &n_changes) >= 0); + assert_se(unit_file_disable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("linked.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 2); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/linked.service"); q = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/linked.service"); @@ -315,9 +315,9 @@ TEST(linked_units) { unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", NULL) == -ENOENT); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "linked.service", NULL) == -ENOENT); - assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("linked2.service"), &changes, &n_changes) >= 0); + assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("linked2.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 2); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/linked2.service"); q = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/linked2.service"); @@ -337,7 +337,7 @@ TEST(linked_units) { unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; - assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("linked3.service"), &changes, &n_changes) >= 0); + assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("linked3.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); assert_se(startswith(changes[0].path, root)); @@ -359,18 +359,18 @@ TEST(default) { p = strjoina(root, "/usr/lib/systemd/system/test-default.target"); assert_se(symlink("test-default-real.target", p) >= 0); - assert_se(unit_file_get_default(UNIT_FILE_SYSTEM, root, &def) == -ENOENT); + assert_se(unit_file_get_default(LOOKUP_SCOPE_SYSTEM, root, &def) == -ENOENT); - assert_se(unit_file_set_default(UNIT_FILE_SYSTEM, 0, root, "idontexist.target", &changes, &n_changes) == -ENOENT); + assert_se(unit_file_set_default(LOOKUP_SCOPE_SYSTEM, 0, root, "idontexist.target", &changes, &n_changes) == -ENOENT); assert_se(n_changes == 1); assert_se(changes[0].type_or_errno == -ENOENT); assert_se(streq_ptr(changes[0].path, "idontexist.target")); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; - assert_se(unit_file_get_default(UNIT_FILE_SYSTEM, root, &def) == -ENOENT); + assert_se(unit_file_get_default(LOOKUP_SCOPE_SYSTEM, root, &def) == -ENOENT); - assert_se(unit_file_set_default(UNIT_FILE_SYSTEM, 0, root, "test-default.target", &changes, &n_changes) >= 0); + assert_se(unit_file_set_default(LOOKUP_SCOPE_SYSTEM, 0, root, "test-default.target", &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "test-default-real.target")); @@ -379,7 +379,7 @@ TEST(default) { unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; - assert_se(unit_file_get_default(UNIT_FILE_SYSTEM, root, &def) >= 0); + assert_se(unit_file_get_default(LOOKUP_SCOPE_SYSTEM, root, &def) >= 0); assert_se(streq_ptr(def, "test-default-real.target")); } @@ -400,7 +400,7 @@ TEST(add_dependency) { p = strjoina(root, "/usr/lib/systemd/system/add-dependency-test-service.service"); assert_se(symlink("real-add-dependency-test-service.service", p) >= 0); - assert_se(unit_file_add_dependency(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("add-dependency-test-service.service"), "add-dependency-test-target.target", UNIT_WANTS, &changes, &n_changes) >= 0); + assert_se(unit_file_add_dependency(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("add-dependency-test-service.service"), "add-dependency-test-target.target", UNIT_WANTS, &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "../real-add-dependency-test-service.service")); @@ -418,10 +418,10 @@ TEST(template_enable) { log_info("== %s ==", __func__); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) == -ENOENT); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) == -ENOENT); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) == -ENOENT); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) == -ENOENT); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@.service", &state) == -ENOENT); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@def.service", &state) == -ENOENT); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@foo.service", &state) == -ENOENT); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template-symlink@foo.service", &state) == -ENOENT); p = strjoina(root, "/usr/lib/systemd/system/template@.service"); assert_se(write_string_file(p, @@ -432,16 +432,16 @@ TEST(template_enable) { p = strjoina(root, "/usr/lib/systemd/system/template-symlink@.service"); assert_se(symlink("template@.service", p) >= 0); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ALIAS); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ALIAS); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); log_info("== %s with template@.service enabled ==", __func__); - assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template@.service"), &changes, &n_changes) >= 0); + assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("template@.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "../template@.service")); @@ -450,30 +450,30 @@ TEST(template_enable) { unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_ENABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_ENABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ALIAS); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_ENABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ALIAS); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template@.service"), &changes, &n_changes) >= 0); + assert_se(unit_file_disable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("template@.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type_or_errno == UNIT_FILE_UNLINK); assert_se(streq(changes[0].path, p)); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ALIAS); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ALIAS); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); log_info("== %s with template@foo.service enabled ==", __func__); - assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template@foo.service"), &changes, &n_changes) >= 0); + assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("template@foo.service"), &changes, &n_changes) >= 0); assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "../template@foo.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/template@foo.service"); @@ -481,33 +481,33 @@ TEST(template_enable) { unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@.service", &state) >= 0); assert_se(state == UNIT_FILE_INDIRECT); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_ENABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_ENABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_ENABLED); - assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template@foo.service"), &changes, &n_changes) >= 0); + assert_se(unit_file_disable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("template@foo.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type_or_errno == UNIT_FILE_UNLINK); assert_se(streq(changes[0].path, p)); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@quux.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ALIAS); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@quux.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@quux.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ALIAS); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template-symlink@quux.service", &state) >= 0 && state == UNIT_FILE_DISABLED); log_info("== %s with template-symlink@quux.service enabled ==", __func__); - assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template-symlink@quux.service"), &changes, &n_changes) >= 0); + assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("template-symlink@quux.service"), &changes, &n_changes) >= 0); assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "../template@quux.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/template@quux.service"); @@ -515,14 +515,14 @@ TEST(template_enable) { unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_INDIRECT); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@quux.service", &state) >= 0 && state == UNIT_FILE_ENABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ALIAS); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@quux.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_INDIRECT); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template@quux.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ALIAS); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "template-symlink@quux.service", &state) >= 0 && state == UNIT_FILE_ENABLED); } TEST(indirect) { @@ -531,9 +531,9 @@ TEST(indirect) { UnitFileState state; const char *p; - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirecta.service", &state) == -ENOENT); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectb.service", &state) == -ENOENT); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectc.service", &state) == -ENOENT); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "indirecta.service", &state) == -ENOENT); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "indirectb.service", &state) == -ENOENT); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "indirectc.service", &state) == -ENOENT); p = strjoina(root, "/usr/lib/systemd/system/indirecta.service"); assert_se(write_string_file(p, @@ -548,11 +548,11 @@ TEST(indirect) { p = strjoina(root, "/usr/lib/systemd/system/indirectc.service"); assert_se(symlink("indirecta.service", p) >= 0); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirecta.service", &state) >= 0 && state == UNIT_FILE_INDIRECT); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectb.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectc.service", &state) >= 0 && state == UNIT_FILE_ALIAS); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "indirecta.service", &state) >= 0 && state == UNIT_FILE_INDIRECT); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "indirectb.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "indirectc.service", &state) >= 0 && state == UNIT_FILE_ALIAS); - assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("indirectc.service"), &changes, &n_changes) >= 0); + assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("indirectc.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "../indirectb.service")); @@ -561,11 +561,11 @@ TEST(indirect) { unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirecta.service", &state) >= 0 && state == UNIT_FILE_INDIRECT); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectb.service", &state) >= 0 && state == UNIT_FILE_ENABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectc.service", &state) >= 0 && state == UNIT_FILE_ALIAS); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "indirecta.service", &state) >= 0 && state == UNIT_FILE_INDIRECT); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "indirectb.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "indirectc.service", &state) >= 0 && state == UNIT_FILE_ALIAS); - assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("indirectc.service"), &changes, &n_changes) >= 0); + assert_se(unit_file_disable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("indirectc.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type_or_errno == UNIT_FILE_UNLINK); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/indirectb.service"); @@ -583,8 +583,8 @@ TEST(preset_and_list) { UnitFileList *fl; Hashmap *h; - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) == -ENOENT); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) == -ENOENT); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "preset-yes.service", &state) == -ENOENT); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "preset-no.service", &state) == -ENOENT); p = strjoina(root, "/usr/lib/systemd/system/preset-yes.service"); assert_se(write_string_file(p, @@ -601,10 +601,10 @@ TEST(preset_and_list) { "enable *-yes.*\n" "disable *\n", WRITE_STRING_FILE_CREATE) >= 0); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_preset(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("preset-yes.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); + assert_se(unit_file_preset(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("preset-yes.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "../preset-yes.service")); @@ -613,10 +613,10 @@ TEST(preset_and_list) { unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_ENABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("preset-yes.service"), &changes, &n_changes) >= 0); + assert_se(unit_file_disable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("preset-yes.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type_or_errno == UNIT_FILE_UNLINK); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/preset-yes.service"); @@ -624,18 +624,18 @@ TEST(preset_and_list) { unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_preset(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("preset-no.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); + assert_se(unit_file_preset(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("preset-no.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); assert_se(n_changes == 0); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_preset_all(UNIT_FILE_SYSTEM, 0, root, UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); + assert_se(unit_file_preset_all(LOOKUP_SCOPE_SYSTEM, 0, root, UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); assert_se(n_changes > 0); @@ -653,17 +653,17 @@ TEST(preset_and_list) { unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_ENABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(h = hashmap_new(&string_hash_ops)); - assert_se(unit_file_get_list(UNIT_FILE_SYSTEM, root, h, NULL, NULL) >= 0); + assert_se(unit_file_get_list(LOOKUP_SCOPE_SYSTEM, root, h, NULL, NULL) >= 0); p = strjoina(root, "/usr/lib/systemd/system/preset-yes.service"); q = strjoina(root, "/usr/lib/systemd/system/preset-no.service"); HASHMAP_FOREACH(fl, h) { - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, basename(fl->path), &state) >= 0); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, basename(fl->path), &state) >= 0); assert_se(fl->state == state); if (streq(fl->path, p)) { @@ -687,17 +687,17 @@ TEST(revert) { UnitFileChange *changes = NULL; size_t n_changes = 0; - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "xx.service", NULL) == -ENOENT); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "yy.service", NULL) == -ENOENT); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "xx.service", NULL) == -ENOENT); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "yy.service", NULL) == -ENOENT); p = strjoina(root, "/usr/lib/systemd/system/xx.service"); assert_se(write_string_file(p, "# Empty\n", WRITE_STRING_FILE_CREATE) >= 0); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "xx.service", NULL) >= 0); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "xx.service", &state) >= 0 && state == UNIT_FILE_STATIC); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "xx.service", NULL) >= 0); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "xx.service", &state) >= 0 && state == UNIT_FILE_STATIC); /* Initially there's nothing to revert */ - assert_se(unit_file_revert(UNIT_FILE_SYSTEM, root, STRV_MAKE("xx.service"), &changes, &n_changes) >= 0); + assert_se(unit_file_revert(LOOKUP_SCOPE_SYSTEM, root, STRV_MAKE("xx.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 0); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; @@ -706,7 +706,7 @@ TEST(revert) { assert_se(write_string_file(p, "# Empty override\n", WRITE_STRING_FILE_CREATE) >= 0); /* Revert the override file */ - assert_se(unit_file_revert(UNIT_FILE_SYSTEM, root, STRV_MAKE("xx.service"), &changes, &n_changes) >= 0); + assert_se(unit_file_revert(LOOKUP_SCOPE_SYSTEM, root, STRV_MAKE("xx.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type_or_errno == UNIT_FILE_UNLINK); assert_se(streq(changes[0].path, p)); @@ -717,7 +717,7 @@ TEST(revert) { assert_se(write_string_file(p, "# Empty dropin\n", WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MKDIR_0755) >= 0); /* Revert the dropin file */ - assert_se(unit_file_revert(UNIT_FILE_SYSTEM, root, STRV_MAKE("xx.service"), &changes, &n_changes) >= 0); + assert_se(unit_file_revert(LOOKUP_SCOPE_SYSTEM, root, STRV_MAKE("xx.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 2); assert_se(changes[0].type_or_errno == UNIT_FILE_UNLINK); assert_se(streq(changes[0].path, p)); @@ -735,8 +735,8 @@ TEST(preset_order) { const char *p; UnitFileState state; - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-1.service", &state) == -ENOENT); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-2.service", &state) == -ENOENT); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "prefix-1.service", &state) == -ENOENT); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "prefix-2.service", &state) == -ENOENT); p = strjoina(root, "/usr/lib/systemd/system/prefix-1.service"); assert_se(write_string_file(p, @@ -754,10 +754,10 @@ TEST(preset_order) { "disable prefix-*.service\n" "enable prefix-2.service\n", WRITE_STRING_FILE_CREATE) >= 0); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-1.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-2.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "prefix-1.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "prefix-2.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_preset(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("prefix-1.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); + assert_se(unit_file_preset(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("prefix-1.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "../prefix-1.service")); @@ -766,36 +766,36 @@ TEST(preset_order) { unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-1.service", &state) >= 0 && state == UNIT_FILE_ENABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-2.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "prefix-1.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "prefix-2.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_preset(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("prefix-2.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); + assert_se(unit_file_preset(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("prefix-2.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); assert_se(n_changes == 0); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-1.service", &state) >= 0 && state == UNIT_FILE_ENABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-2.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "prefix-1.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "prefix-2.service", &state) >= 0 && state == UNIT_FILE_DISABLED); } TEST(static_instance) { UnitFileState state; const char *p; - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "static-instance@.service", &state) == -ENOENT); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "static-instance@foo.service", &state) == -ENOENT); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "static-instance@.service", &state) == -ENOENT); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "static-instance@foo.service", &state) == -ENOENT); p = strjoina(root, "/usr/lib/systemd/system/static-instance@.service"); assert_se(write_string_file(p, "[Install]\n" "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "static-instance@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "static-instance@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "static-instance@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "static-instance@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); p = strjoina(root, "/usr/lib/systemd/system/static-instance@foo.service"); assert_se(symlink("static-instance@.service", p) >= 0); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "static-instance@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "static-instance@foo.service", &state) >= 0 && state == UNIT_FILE_STATIC); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "static-instance@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "static-instance@foo.service", &state) >= 0 && state == UNIT_FILE_STATIC); } TEST(with_dropin) { @@ -804,11 +804,11 @@ TEST(with_dropin) { UnitFileChange *changes = NULL; size_t n_changes = 0; - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-1.service", &state) == -ENOENT); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-2.service", &state) == -ENOENT); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-3.service", &state) == -ENOENT); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-4a.service", &state) == -ENOENT); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-4b.service", &state) == -ENOENT); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-1.service", &state) == -ENOENT); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-2.service", &state) == -ENOENT); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-3.service", &state) == -ENOENT); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-4a.service", &state) == -ENOENT); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-4b.service", &state) == -ENOENT); p = strjoina(root, "/usr/lib/systemd/system/with-dropin-1.service"); assert_se(write_string_file(p, @@ -820,7 +820,7 @@ TEST(with_dropin) { "[Install]\n" "WantedBy=graphical.target\n", WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MKDIR_0755) >= 0); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-1.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-1.service", &state) >= 0 && state == UNIT_FILE_DISABLED); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/with-dropin-2.service"); assert_se(write_string_file(p, @@ -832,7 +832,7 @@ TEST(with_dropin) { "[Install]\n" "WantedBy=graphical.target\n", WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MKDIR_0755) >= 0); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-2.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-2.service", &state) >= 0 && state == UNIT_FILE_DISABLED); p = strjoina(root, "/usr/lib/systemd/system/with-dropin-3.service"); assert_se(write_string_file(p, @@ -844,7 +844,7 @@ TEST(with_dropin) { "[Install]\n" "WantedBy=graphical.target\n", WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MKDIR_0755) >= 0); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-3.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-3.service", &state) >= 0 && state == UNIT_FILE_DISABLED); p = strjoina(root, "/usr/lib/systemd/system/with-dropin-4a.service"); assert_se(write_string_file(p, @@ -856,16 +856,16 @@ TEST(with_dropin) { "[Install]\n" "Also=with-dropin-4b.service\n", WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MKDIR_0755) >= 0); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-4a.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-4a.service", &state) >= 0 && state == UNIT_FILE_DISABLED); p = strjoina(root, "/usr/lib/systemd/system/with-dropin-4b.service"); assert_se(write_string_file(p, "[Install]\n" "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-4b.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-4b.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("with-dropin-1.service"), &changes, &n_changes) == 1); + assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("with-dropin-1.service"), &changes, &n_changes) == 1); assert_se(n_changes == 2); assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); assert_se(changes[1].type_or_errno == UNIT_FILE_SYMLINK); @@ -878,8 +878,8 @@ TEST(with_dropin) { unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; - assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("with-dropin-2.service"), &changes, &n_changes) == 1); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-2.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("with-dropin-2.service"), &changes, &n_changes) == 1); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-2.service", &state) >= 0 && state == UNIT_FILE_ENABLED); assert_se(n_changes == 2); assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); assert_se(changes[1].type_or_errno == UNIT_FILE_SYMLINK); @@ -892,8 +892,8 @@ TEST(with_dropin) { unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; - assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("with-dropin-3.service"), &changes, &n_changes) == 1); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-3.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("with-dropin-3.service"), &changes, &n_changes) == 1); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-3.service", &state) >= 0 && state == UNIT_FILE_ENABLED); assert_se(n_changes == 2); assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); assert_se(changes[1].type_or_errno == UNIT_FILE_SYMLINK); @@ -906,8 +906,8 @@ TEST(with_dropin) { unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; - assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("with-dropin-4a.service"), &changes, &n_changes) == 2); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-3.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("with-dropin-4a.service"), &changes, &n_changes) == 2); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-3.service", &state) >= 0 && state == UNIT_FILE_ENABLED); assert_se(n_changes == 2); assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); assert_se(changes[1].type_or_errno == UNIT_FILE_SYMLINK); @@ -920,11 +920,11 @@ TEST(with_dropin) { unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-1.service", &state) >= 0 && state == UNIT_FILE_ENABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-2.service", &state) >= 0 && state == UNIT_FILE_ENABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-3.service", &state) >= 0 && state == UNIT_FILE_ENABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-4a.service", &state) >= 0 && state == UNIT_FILE_ENABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-4b.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-1.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-2.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-3.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-4a.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-4b.service", &state) >= 0 && state == UNIT_FILE_ENABLED); } TEST(with_dropin_template) { @@ -933,9 +933,9 @@ TEST(with_dropin_template) { UnitFileChange *changes = NULL; size_t n_changes = 0; - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-1@.service", &state) == -ENOENT); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-2@.service", &state) == -ENOENT); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-3@.service", &state) == -ENOENT); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-1@.service", &state) == -ENOENT); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-2@.service", &state) == -ENOENT); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-3@.service", &state) == -ENOENT); p = strjoina(root, "/usr/lib/systemd/system/with-dropin-1@.service"); assert_se(write_string_file(p, @@ -947,7 +947,7 @@ TEST(with_dropin_template) { "[Install]\n" "WantedBy=graphical.target\n", WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MKDIR_0755) >= 0); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-1@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-1@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); p = strjoina(root, "/usr/lib/systemd/system/with-dropin-2@.service"); assert_se(write_string_file(p, @@ -959,7 +959,7 @@ TEST(with_dropin_template) { "[Install]\n" "WantedBy=graphical.target\n", WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MKDIR_0755) >= 0); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-2@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-2@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); p = strjoina(root, "/usr/lib/systemd/system/with-dropin-3@.service"); assert_se(write_string_file(p, @@ -972,9 +972,9 @@ TEST(with_dropin_template) { "[Install]\n" "DefaultInstance=instance-2\n", WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MKDIR_0755) >= 0); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-3@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-3@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("with-dropin-1@instance-1.service"), &changes, &n_changes) == 1); + assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("with-dropin-1@instance-1.service"), &changes, &n_changes) == 1); assert_se(n_changes == 2); assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); assert_se(changes[1].type_or_errno == UNIT_FILE_SYMLINK); @@ -987,7 +987,7 @@ TEST(with_dropin_template) { unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; - assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("with-dropin-2@instance-1.service"), &changes, &n_changes) == 1); + assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("with-dropin-2@instance-1.service"), &changes, &n_changes) == 1); assert_se(n_changes == 2); assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); assert_se(changes[1].type_or_errno == UNIT_FILE_SYMLINK); @@ -1000,7 +1000,7 @@ TEST(with_dropin_template) { unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; - assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("with-dropin-2@instance-2.service"), &changes, &n_changes) == 1); + assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("with-dropin-2@instance-2.service"), &changes, &n_changes) == 1); assert_se(n_changes == 1); assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "../with-dropin-2@instance-2.service")); @@ -1009,7 +1009,7 @@ TEST(with_dropin_template) { unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; - assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("with-dropin-3@.service"), &changes, &n_changes) == 1); + assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("with-dropin-3@.service"), &changes, &n_changes) == 1); assert_se(n_changes == 1); assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "../with-dropin-3@.service")); @@ -1018,11 +1018,11 @@ TEST(with_dropin_template) { unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-1@instance-1.service", &state) >= 0 && state == UNIT_FILE_ENABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-2@instance-1.service", &state) >= 0 && state == UNIT_FILE_ENABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-2@instance-2.service", &state) >= 0 && state == UNIT_FILE_ENABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-3@instance-1.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-3@instance-2.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-1@instance-1.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-2@instance-1.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-2@instance-2.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-3@instance-1.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "with-dropin-3@instance-2.service", &state) >= 0 && state == UNIT_FILE_ENABLED); } TEST(preset_multiple_instances) { @@ -1038,7 +1038,7 @@ TEST(preset_multiple_instances) { "DefaultInstance=def\n" "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "foo@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "foo@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); p = strjoina(root, "/usr/lib/systemd/system-preset/test.preset"); assert_se(write_string_file(p, @@ -1046,11 +1046,11 @@ TEST(preset_multiple_instances) { "enable emptylist@.service\n" /* This line ensures the old functionality for templated unit still works */ "disable *\n" , WRITE_STRING_FILE_CREATE) >= 0); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "foo@bar0.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "foo@bar0.service", &state) >= 0 && state == UNIT_FILE_DISABLED); /* Preset a single instantiated unit specified in the list */ - assert_se(unit_file_preset(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("foo@bar0.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "foo@bar0.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_preset(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("foo@bar0.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "foo@bar0.service", &state) >= 0 && state == UNIT_FILE_ENABLED); assert_se(n_changes == 1); assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/foo@bar0.service"); @@ -1058,7 +1058,7 @@ TEST(preset_multiple_instances) { unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; - assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("foo@bar0.service"), &changes, &n_changes) >= 0); + assert_se(unit_file_disable(LOOKUP_SCOPE_SYSTEM, 0, root, STRV_MAKE("foo@bar0.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type_or_errno == UNIT_FILE_UNLINK); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/foo@bar0.service"); @@ -1067,17 +1067,17 @@ TEST(preset_multiple_instances) { changes = NULL; n_changes = 0; /* Check for preset-all case, only instances on the list should be enabled, not including the default instance */ - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "foo@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "foo@bar1.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "foo@bartest.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "foo@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "foo@bar1.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "foo@bartest.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_preset_all(UNIT_FILE_SYSTEM, 0, root, UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); + assert_se(unit_file_preset_all(LOOKUP_SCOPE_SYSTEM, 0, root, UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); assert_se(n_changes > 0); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "foo@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "foo@bar0.service", &state) >= 0 && state == UNIT_FILE_ENABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "foo@bar1.service", &state) >= 0 && state == UNIT_FILE_ENABLED); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "foo@bartest.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "foo@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "foo@bar0.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "foo@bar1.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM, root, "foo@bartest.service", &state) >= 0 && state == UNIT_FILE_ENABLED); unit_file_changes_free(changes, n_changes); } diff --git a/src/test/test-install.c b/src/test/test-install.c index 7a0beb2d24..6c5a036465 100644 --- a/src/test/test-install.c +++ b/src/test/test-install.c @@ -32,13 +32,13 @@ int main(int argc, char* argv[]) { test_setup_logging(LOG_DEBUG); h = hashmap_new(&string_hash_ops); - r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h, NULL, NULL); + r = unit_file_get_list(LOOKUP_SCOPE_SYSTEM, NULL, h, NULL, NULL); assert_se(r == 0); HASHMAP_FOREACH(p, h) { UnitFileState s = _UNIT_FILE_STATE_INVALID; - r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(p->path), &s); + r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, basename(p->path), &s); assert_se((r < 0 && p->state == UNIT_FILE_BAD) || (p->state == s)); @@ -52,18 +52,18 @@ int main(int argc, char* argv[]) { log_info("/*** enable **/"); - r = unit_file_enable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); + r = unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); assert_se(r >= 0); log_info("/*** enable2 **/"); - r = unit_file_enable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); + r = unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); assert_se(r >= 0); dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state); + r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, files[0], &state); assert_se(r >= 0); assert_se(state == UNIT_FILE_ENABLED); @@ -71,13 +71,13 @@ int main(int argc, char* argv[]) { changes = NULL; n_changes = 0; - r = unit_file_disable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); + r = unit_file_disable(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); assert_se(r >= 0); dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state); + r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, files[0], &state); assert_se(r >= 0); assert_se(state == UNIT_FILE_DISABLED); @@ -85,16 +85,16 @@ int main(int argc, char* argv[]) { changes = NULL; n_changes = 0; - r = unit_file_mask(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); + r = unit_file_mask(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); assert_se(r >= 0); log_info("/*** mask2 ***/"); - r = unit_file_mask(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); + r = unit_file_mask(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); assert_se(r >= 0); dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state); + r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, files[0], &state); assert_se(r >= 0); assert_se(state == UNIT_FILE_MASKED); @@ -102,16 +102,16 @@ int main(int argc, char* argv[]) { changes = NULL; n_changes = 0; - r = unit_file_unmask(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); + r = unit_file_unmask(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); assert_se(r >= 0); log_info("/*** unmask2 ***/"); - r = unit_file_unmask(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); + r = unit_file_unmask(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); assert_se(r >= 0); dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state); + r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, files[0], &state); assert_se(r >= 0); assert_se(state == UNIT_FILE_DISABLED); @@ -119,13 +119,13 @@ int main(int argc, char* argv[]) { changes = NULL; n_changes = 0; - r = unit_file_mask(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); + r = unit_file_mask(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); assert_se(r >= 0); dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state); + r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, files[0], &state); assert_se(r >= 0); assert_se(state == UNIT_FILE_MASKED); @@ -133,16 +133,16 @@ int main(int argc, char* argv[]) { changes = NULL; n_changes = 0; - r = unit_file_disable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); + r = unit_file_disable(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); assert_se(r >= 0); log_info("/*** disable2 ***/"); - r = unit_file_disable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); + r = unit_file_disable(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); assert_se(r >= 0); dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state); + r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, files[0], &state); assert_se(r >= 0); assert_se(state == UNIT_FILE_MASKED); @@ -150,13 +150,13 @@ int main(int argc, char* argv[]) { changes = NULL; n_changes = 0; - r = unit_file_unmask(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); + r = unit_file_unmask(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); assert_se(r >= 0); dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state); + r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, files[0], &state); assert_se(r >= 0); assert_se(state == UNIT_FILE_DISABLED); @@ -164,13 +164,13 @@ int main(int argc, char* argv[]) { changes = NULL; n_changes = 0; - r = unit_file_enable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files2, &changes, &n_changes); + r = unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files2, &changes, &n_changes); assert_se(r >= 0); dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); + r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, basename(files2[0]), &state); assert_se(r >= 0); assert_se(state == UNIT_FILE_ENABLED); @@ -178,26 +178,26 @@ int main(int argc, char* argv[]) { changes = NULL; n_changes = 0; - r = unit_file_disable(UNIT_FILE_SYSTEM, 0, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes); + r = unit_file_disable(LOOKUP_SCOPE_SYSTEM, 0, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes); assert_se(r >= 0); dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); + r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, basename(files2[0]), &state); assert_se(r < 0); log_info("/*** link files2 ***/"); changes = NULL; n_changes = 0; - r = unit_file_link(UNIT_FILE_SYSTEM, 0, NULL, (char**) files2, &changes, &n_changes); + r = unit_file_link(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files2, &changes, &n_changes); assert_se(r >= 0); dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); + r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, basename(files2[0]), &state); assert_se(r >= 0); assert_se(state == UNIT_FILE_LINKED); @@ -205,26 +205,26 @@ int main(int argc, char* argv[]) { changes = NULL; n_changes = 0; - r = unit_file_disable(UNIT_FILE_SYSTEM, 0, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes); + r = unit_file_disable(LOOKUP_SCOPE_SYSTEM, 0, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes); assert_se(r >= 0); dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); + r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, basename(files2[0]), &state); assert_se(r < 0); log_info("/*** link files2 ***/"); changes = NULL; n_changes = 0; - r = unit_file_link(UNIT_FILE_SYSTEM, 0, NULL, (char**) files2, &changes, &n_changes); + r = unit_file_link(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files2, &changes, &n_changes); assert_se(r >= 0); dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); + r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, basename(files2[0]), &state); assert_se(r >= 0); assert_se(state == UNIT_FILE_LINKED); @@ -232,13 +232,13 @@ int main(int argc, char* argv[]) { changes = NULL; n_changes = 0; - r = unit_file_reenable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files2, &changes, &n_changes); + r = unit_file_reenable(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files2, &changes, &n_changes); assert_se(r >= 0); dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); + r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, basename(files2[0]), &state); assert_se(r >= 0); assert_se(state == UNIT_FILE_ENABLED); @@ -246,25 +246,25 @@ int main(int argc, char* argv[]) { changes = NULL; n_changes = 0; - r = unit_file_disable(UNIT_FILE_SYSTEM, 0, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes); + r = unit_file_disable(LOOKUP_SCOPE_SYSTEM, 0, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes); assert_se(r >= 0); dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); + r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, basename(files2[0]), &state); assert_se(r < 0); log_info("/*** preset files ***/"); changes = NULL; n_changes = 0; - r = unit_file_preset(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, UNIT_FILE_PRESET_FULL, &changes, &n_changes); + r = unit_file_preset(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, UNIT_FILE_PRESET_FULL, &changes, &n_changes); assert_se(r >= 0); dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files[0]), &state); + r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, basename(files[0]), &state); assert_se(r >= 0); assert_se(state == UNIT_FILE_ENABLED); diff --git a/src/test/test-load-fragment.c b/src/test/test-load-fragment.c index 52341e5199..c3206e1e7a 100644 --- a/src/test/test-load-fragment.c +++ b/src/test/test-load-fragment.c @@ -42,7 +42,7 @@ TEST_RET(unit_file_get_set) { h = hashmap_new(&string_hash_ops); assert_se(h); - r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h, NULL, NULL); + r = unit_file_get_list(LOOKUP_SCOPE_SYSTEM, NULL, h, NULL, NULL); if (IN_SET(r, -EPERM, -EACCES)) return log_tests_skipped_errno(r, "unit_file_get_list"); @@ -101,7 +101,7 @@ TEST(config_parse_exec) { _cleanup_(manager_freep) Manager *m = NULL; _cleanup_(unit_freep) Unit *u = NULL; - r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m); + r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_MINIMAL, &m); if (manager_errno_skip_test(r)) { log_notice_errno(r, "Skipping test: manager_new: %m"); return; @@ -445,7 +445,7 @@ TEST(config_parse_log_extra_fields) { _cleanup_(unit_freep) Unit *u = NULL; ExecContext c = {}; - r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m); + r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_MINIMAL, &m); if (manager_errno_skip_test(r)) { log_notice_errno(r, "Skipping test: manager_new: %m"); return; @@ -528,56 +528,56 @@ TEST(install_printf, .sd_booted = true) { strcpy(i.path, d2); \ } while (false) - expect(UNIT_FILE_SYSTEM, i, "%n", "name.service"); - expect(UNIT_FILE_SYSTEM, i, "%N", "name"); - expect(UNIT_FILE_SYSTEM, i, "%p", "name"); - expect(UNIT_FILE_SYSTEM, i, "%i", ""); - expect(UNIT_FILE_SYSTEM, i, "%j", "name"); - expect(UNIT_FILE_SYSTEM, i, "%g", "root"); - expect(UNIT_FILE_SYSTEM, i, "%G", "0"); - expect(UNIT_FILE_SYSTEM, i, "%u", "root"); - expect(UNIT_FILE_SYSTEM, i, "%U", "0"); + expect(LOOKUP_SCOPE_SYSTEM, i, "%n", "name.service"); + expect(LOOKUP_SCOPE_SYSTEM, i, "%N", "name"); + expect(LOOKUP_SCOPE_SYSTEM, i, "%p", "name"); + expect(LOOKUP_SCOPE_SYSTEM, i, "%i", ""); + expect(LOOKUP_SCOPE_SYSTEM, i, "%j", "name"); + expect(LOOKUP_SCOPE_SYSTEM, i, "%g", "root"); + expect(LOOKUP_SCOPE_SYSTEM, i, "%G", "0"); + expect(LOOKUP_SCOPE_SYSTEM, i, "%u", "root"); + expect(LOOKUP_SCOPE_SYSTEM, i, "%U", "0"); - expect(UNIT_FILE_SYSTEM, i, "%m", mid); - expect(UNIT_FILE_SYSTEM, i, "%b", bid); - expect(UNIT_FILE_SYSTEM, i, "%H", host); + expect(LOOKUP_SCOPE_SYSTEM, i, "%m", mid); + expect(LOOKUP_SCOPE_SYSTEM, i, "%b", bid); + expect(LOOKUP_SCOPE_SYSTEM, i, "%H", host); - expect(UNIT_FILE_SYSTEM, i2, "%g", "root"); - expect(UNIT_FILE_SYSTEM, i2, "%G", "0"); - expect(UNIT_FILE_SYSTEM, i2, "%u", "root"); - expect(UNIT_FILE_SYSTEM, i2, "%U", "0"); + expect(LOOKUP_SCOPE_SYSTEM, i2, "%g", "root"); + expect(LOOKUP_SCOPE_SYSTEM, i2, "%G", "0"); + expect(LOOKUP_SCOPE_SYSTEM, i2, "%u", "root"); + expect(LOOKUP_SCOPE_SYSTEM, i2, "%U", "0"); - expect(UNIT_FILE_USER, i2, "%g", group); - expect(UNIT_FILE_USER, i2, "%G", gid); - expect(UNIT_FILE_USER, i2, "%u", user); - expect(UNIT_FILE_USER, i2, "%U", uid); + expect(LOOKUP_SCOPE_USER, i2, "%g", group); + expect(LOOKUP_SCOPE_USER, i2, "%G", gid); + expect(LOOKUP_SCOPE_USER, i2, "%u", user); + expect(LOOKUP_SCOPE_USER, i2, "%U", uid); /* gcc-12.0.1-0.9.fc36.x86_64 insist that streq(…, NULL) is called, * even though the call is inside of a conditional where the pointer is checked. :( */ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wnonnull" - expect(UNIT_FILE_GLOBAL, i2, "%g", NULL); - expect(UNIT_FILE_GLOBAL, i2, "%G", NULL); - expect(UNIT_FILE_GLOBAL, i2, "%u", NULL); - expect(UNIT_FILE_GLOBAL, i2, "%U", NULL); + expect(LOOKUP_SCOPE_GLOBAL, i2, "%g", NULL); + expect(LOOKUP_SCOPE_GLOBAL, i2, "%G", NULL); + expect(LOOKUP_SCOPE_GLOBAL, i2, "%u", NULL); + expect(LOOKUP_SCOPE_GLOBAL, i2, "%U", NULL); #pragma GCC diagnostic pop - expect(UNIT_FILE_SYSTEM, i3, "%n", "name@inst.service"); - expect(UNIT_FILE_SYSTEM, i3, "%N", "name@inst"); - expect(UNIT_FILE_SYSTEM, i3, "%p", "name"); - expect(UNIT_FILE_USER, i3, "%g", group); - expect(UNIT_FILE_USER, i3, "%G", gid); - expect(UNIT_FILE_USER, i3, "%u", user); - expect(UNIT_FILE_USER, i3, "%U", uid); + expect(LOOKUP_SCOPE_SYSTEM, i3, "%n", "name@inst.service"); + expect(LOOKUP_SCOPE_SYSTEM, i3, "%N", "name@inst"); + expect(LOOKUP_SCOPE_SYSTEM, i3, "%p", "name"); + expect(LOOKUP_SCOPE_USER, i3, "%g", group); + expect(LOOKUP_SCOPE_USER, i3, "%G", gid); + expect(LOOKUP_SCOPE_USER, i3, "%u", user); + expect(LOOKUP_SCOPE_USER, i3, "%U", uid); - expect(UNIT_FILE_SYSTEM, i3, "%m", mid); - expect(UNIT_FILE_SYSTEM, i3, "%b", bid); - expect(UNIT_FILE_SYSTEM, i3, "%H", host); + expect(LOOKUP_SCOPE_SYSTEM, i3, "%m", mid); + expect(LOOKUP_SCOPE_SYSTEM, i3, "%b", bid); + expect(LOOKUP_SCOPE_SYSTEM, i3, "%H", host); - expect(UNIT_FILE_USER, i4, "%g", group); - expect(UNIT_FILE_USER, i4, "%G", gid); - expect(UNIT_FILE_USER, i4, "%u", user); - expect(UNIT_FILE_USER, i4, "%U", uid); + expect(LOOKUP_SCOPE_USER, i4, "%g", group); + expect(LOOKUP_SCOPE_USER, i4, "%G", gid); + expect(LOOKUP_SCOPE_USER, i4, "%u", user); + expect(LOOKUP_SCOPE_USER, i4, "%U", uid); } static uint64_t make_cap(int cap) { @@ -806,7 +806,7 @@ TEST(config_parse_unit_env_file) { _cleanup_strv_free_ char **files = NULL; int r; - r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m); + r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_MINIMAL, &m); if (manager_errno_skip_test(r)) { log_notice_errno(r, "Skipping test: manager_new: %m"); return; @@ -939,7 +939,7 @@ TEST(unit_is_recursive_template_dependency) { Unit *u; int r; - r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m); + r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_MINIMAL, &m); if (manager_errno_skip_test(r)) { log_notice_errno(r, "Skipping test: manager_new: %m"); return; diff --git a/src/test/test-path-lookup.c b/src/test/test-path-lookup.c index dfb7550543..c98a1f4b73 100644 --- a/src/test/test-path-lookup.c +++ b/src/test/test-path-lookup.c @@ -11,7 +11,7 @@ #include "tests.h" #include "tmpfile-util.h" -static void test_paths_one(UnitFileScope scope) { +static void test_paths_one(LookupScope scope) { _cleanup_(rm_rf_physical_and_freep) char *tmp = NULL; _cleanup_(lookup_paths_free) LookupPaths lp_without_env = {}; _cleanup_(lookup_paths_free) LookupPaths lp_with_env = {}; @@ -34,9 +34,9 @@ static void test_paths_one(UnitFileScope scope) { } TEST(paths) { - test_paths_one(UNIT_FILE_SYSTEM); - test_paths_one(UNIT_FILE_USER); - test_paths_one(UNIT_FILE_GLOBAL); + test_paths_one(LOOKUP_SCOPE_SYSTEM); + test_paths_one(LOOKUP_SCOPE_USER); + test_paths_one(LOOKUP_SCOPE_GLOBAL); } TEST(user_and_global_paths) { @@ -48,8 +48,8 @@ TEST(user_and_global_paths) { assert_se(unsetenv("XDG_DATA_DIRS") == 0); assert_se(unsetenv("XDG_CONFIG_DIRS") == 0); - assert_se(lookup_paths_init(&lp_global, UNIT_FILE_GLOBAL, 0, NULL) == 0); - assert_se(lookup_paths_init(&lp_user, UNIT_FILE_USER, 0, NULL) == 0); + assert_se(lookup_paths_init(&lp_global, LOOKUP_SCOPE_GLOBAL, 0, NULL) == 0); + assert_se(lookup_paths_init(&lp_user, LOOKUP_SCOPE_USER, 0, NULL) == 0); g = lp_global.search_path; u = lp_user.search_path; @@ -70,7 +70,7 @@ TEST(user_and_global_paths) { log_info("+ %s", *p); } -static void test_generator_binary_paths_one(UnitFileScope scope) { +static void test_generator_binary_paths_one(LookupScope scope) { _cleanup_(rm_rf_physical_and_freep) char *tmp = NULL; _cleanup_strv_free_ char **gp_without_env = NULL; _cleanup_strv_free_ char **env_gp_without_env = NULL; @@ -85,13 +85,13 @@ static void test_generator_binary_paths_one(UnitFileScope scope) { assert_se(unsetenv("SYSTEMD_ENVIRONMENT_GENERATOR_PATH") == 0); gp_without_env = generator_binary_paths(scope); - env_gp_without_env = env_generator_binary_paths(scope == UNIT_FILE_SYSTEM ? true : false); + env_gp_without_env = env_generator_binary_paths(scope == LOOKUP_SCOPE_SYSTEM ? true : false); - log_info("Generators dirs (%s):", scope == UNIT_FILE_SYSTEM ? "system" : "user"); + log_info("Generators dirs (%s):", scope == LOOKUP_SCOPE_SYSTEM ? "system" : "user"); STRV_FOREACH(dir, gp_without_env) log_info(" %s", *dir); - log_info("Environment generators dirs (%s):", scope == UNIT_FILE_SYSTEM ? "system" : "user"); + log_info("Environment generators dirs (%s):", scope == LOOKUP_SCOPE_SYSTEM ? "system" : "user"); STRV_FOREACH(dir, env_gp_without_env) log_info(" %s", *dir); @@ -104,13 +104,13 @@ static void test_generator_binary_paths_one(UnitFileScope scope) { assert_se(setenv("SYSTEMD_ENVIRONMENT_GENERATOR_PATH", systemd_env_generator_path, 1) == 0); gp_with_env = generator_binary_paths(scope); - env_gp_with_env = env_generator_binary_paths(scope == UNIT_FILE_SYSTEM ? true : false); + env_gp_with_env = env_generator_binary_paths(scope == LOOKUP_SCOPE_SYSTEM ? true : false); - log_info("Generators dirs (%s):", scope == UNIT_FILE_SYSTEM ? "system" : "user"); + log_info("Generators dirs (%s):", scope == LOOKUP_SCOPE_SYSTEM ? "system" : "user"); STRV_FOREACH(dir, gp_with_env) log_info(" %s", *dir); - log_info("Environment generators dirs (%s):", scope == UNIT_FILE_SYSTEM ? "system" : "user"); + log_info("Environment generators dirs (%s):", scope == LOOKUP_SCOPE_SYSTEM ? "system" : "user"); STRV_FOREACH(dir, env_gp_with_env) log_info(" %s", *dir); @@ -119,8 +119,8 @@ static void test_generator_binary_paths_one(UnitFileScope scope) { } TEST(generator_binary_paths) { - test_generator_binary_paths_one(UNIT_FILE_SYSTEM); - test_generator_binary_paths_one(UNIT_FILE_USER); + test_generator_binary_paths_one(LOOKUP_SCOPE_SYSTEM); + test_generator_binary_paths_one(LOOKUP_SCOPE_USER); } DEFINE_TEST_MAIN(LOG_DEBUG); diff --git a/src/test/test-path.c b/src/test/test-path.c index 2690dc0aa4..7fb1f7363c 100644 --- a/src/test/test-path.c +++ b/src/test/test-path.c @@ -33,7 +33,7 @@ static int setup_test(Manager **m) { if (r == -ENOMEDIUM) return log_tests_skipped("cgroupfs not available"); - r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &tmp); + r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_BASIC, &tmp); if (manager_errno_skip_test(r)) return log_tests_skipped_errno(r, "manager_new"); assert_se(r >= 0); diff --git a/src/test/test-sched-prio.c b/src/test/test-sched-prio.c index 35f7be491a..721c4b61a1 100644 --- a/src/test/test-sched-prio.c +++ b/src/test/test-sched-prio.c @@ -30,7 +30,7 @@ int main(int argc, char *argv[]) { assert_se(set_unit_path(unit_dir) >= 0); assert_se(runtime_dir = setup_fake_runtime_dir()); - r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m); + r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_BASIC, &m); if (manager_errno_skip_test(r)) return log_tests_skipped_errno(r, "manager_new"); assert_se(r >= 0); diff --git a/src/test/test-socket-bind.c b/src/test/test-socket-bind.c index 62300c4ae4..59d8cc965b 100644 --- a/src/test/test-socket-bind.c +++ b/src/test/test-socket-bind.c @@ -135,7 +135,7 @@ int main(int argc, char *argv[]) { assert_se(set_unit_path(unit_dir) >= 0); assert_se(runtime_dir = setup_fake_runtime_dir()); - assert_se(manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m) >= 0); + assert_se(manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_BASIC, &m) >= 0); assert_se(manager_startup(m, NULL, NULL, NULL) >= 0); assert_se(test_socket_bind(m, "socket_bind_test.service", netcat_path, "2000", STRV_MAKE("2000"), STRV_MAKE("any")) >= 0); diff --git a/src/test/test-specifier.c b/src/test/test-specifier.c index 947a32acf7..49b4f5a2a3 100644 --- a/src/test/test-specifier.c +++ b/src/test/test-specifier.c @@ -47,7 +47,7 @@ TEST(specifier_escape_strv) { static const Specifier specifier_table[] = { COMMON_SYSTEM_SPECIFIERS, - COMMON_CREDS_SPECIFIERS(UNIT_FILE_USER), + COMMON_CREDS_SPECIFIERS(LOOKUP_SCOPE_USER), { 'h', specifier_user_home, NULL }, COMMON_TMP_SPECIFIERS, diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c index 261bd7412f..dffa2822e6 100644 --- a/src/test/test-unit-file.c +++ b/src/test/test-unit-file.c @@ -35,7 +35,7 @@ TEST(unit_file_build_name_map) { ids = strv_skip(saved_argv, 1); - assert_se(lookup_paths_init(&lp, UNIT_FILE_SYSTEM, 0, NULL) >= 0); + assert_se(lookup_paths_init(&lp, LOOKUP_SCOPE_SYSTEM, 0, NULL) >= 0); assert_se(unit_file_build_name_map(&lp, &mtime, &unit_ids, &unit_names, NULL) == 1); diff --git a/src/test/test-unit-name.c b/src/test/test-unit-name.c index 8cd0e0b4a1..d4dd8dc91c 100644 --- a/src/test/test-unit-name.c +++ b/src/test/test-unit-name.c @@ -228,7 +228,7 @@ TEST_RET(unit_printf, .sd_booted = true) { assert_se(get_home_dir(&home) >= 0); assert_se(get_shell(&shell) >= 0); - r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m); + r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_MINIMAL, &m); if (manager_errno_skip_test(r)) return log_tests_skipped_errno(r, "manager_new"); assert_se(r == 0); diff --git a/src/test/test-unit-serialize.c b/src/test/test-unit-serialize.c index 3ef15f3b1e..f84435f480 100644 --- a/src/test/test-unit-serialize.c +++ b/src/test/test-unit-serialize.c @@ -31,7 +31,7 @@ TEST(deserialize_exec_command) { _cleanup_(manager_freep) Manager *m = NULL; int r; - r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m); + r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_MINIMAL, &m); if (manager_errno_skip_test(r)) { log_notice_errno(r, "Skipping test: manager_new: %m"); return; diff --git a/src/test/test-watch-pid.c b/src/test/test-watch-pid.c index 885ed802d4..8c355c1d5f 100644 --- a/src/test/test-watch-pid.c +++ b/src/test/test-watch-pid.c @@ -26,7 +26,7 @@ int main(int argc, char *argv[]) { assert_se(runtime_dir = setup_fake_runtime_dir()); - assert_se(manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m) >= 0); + assert_se(manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_BASIC, &m) >= 0); assert_se(manager_startup(m, NULL, NULL, NULL) >= 0); assert_se(a = unit_new(m, sizeof(Service))); diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index 17b9c6ab9a..023207bc60 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -2938,7 +2938,7 @@ static int parse_line( { 'S', specifier_directory, UINT_TO_PTR(DIRECTORY_STATE) }, { 't', specifier_directory, UINT_TO_PTR(DIRECTORY_RUNTIME) }, - COMMON_CREDS_SPECIFIERS(arg_user ? UNIT_FILE_USER : UNIT_FILE_SYSTEM), + COMMON_CREDS_SPECIFIERS(arg_user ? LOOKUP_SCOPE_USER : LOOKUP_SCOPE_SYSTEM), COMMON_TMP_SPECIFIERS, {} };