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/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.
diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml
index c0c98a0e88..dd3553aa18 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.
@@ -1876,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/meson.build b/meson.build
index a2d397d5fc..e68791b8b4 100644
--- a/meson.build
+++ b/meson.build
@@ -2450,7 +2450,7 @@ public_programs += executable(
install_rpath : rootlibexecdir,
install : true)
-public_programs += executable(
+systemctl = executable(
'systemctl',
systemctl_sources,
include_directories : includes,
@@ -2464,6 +2464,7 @@ public_programs += executable(
install_rpath : rootlibexecdir,
install : true,
install_dir : rootbindir)
+public_programs += systemctl
if conf.get('ENABLE_PORTABLED') == 1
dbus_programs += executable(
@@ -3282,13 +3283,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/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-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/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/env-file.c b/src/basic/env-file.c
index 3efd77909c..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,78 +379,69 @@ 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) {
- char ***m = userdata;
+ void *userdata) {
+
+ char ***m = ASSERT_PTR(userdata);
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)
+ return free_and_replace(t[1], value);
+ else
+ return free_and_strdup(t+1, "");
+ }
+
r = strv_extend(m, key);
if (r < 0)
- return -ENOMEM;
+ return r;
- if (!value) {
- r = strv_extend(m, "");
- if (r < 0)
- return -ENOMEM;
- } else {
- r = strv_push(m, value);
- if (r < 0)
- return r;
- }
-
- if (n_pushed)
- (*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;
@@ -488,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(
@@ -500,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/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/src/basic/path-lookup.c b/src/basic/path-lookup.c
index 2dd587fd8a..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");
@@ -508,8 +508,8 @@ static int get_paths_from_environ(const char *var, char ***paths, bool *append)
}
int lookup_paths_init(
- LookupPaths *p,
- UnitFileScope scope,
+ LookupPaths *lp,
+ LookupScope scope,
LookupPathsFlags flags,
const char *root_dir) {
@@ -526,16 +526,16 @@ 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);
+ 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,
@@ -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,46 +741,56 @@ int lookup_paths_init(
return 0;
}
-void lookup_paths_free(LookupPaths *p) {
- if (!p)
- return;
+int lookup_paths_init_or_warn(LookupPaths *lp, LookupScope 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));
}
}
-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;
@@ -795,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 af85dc7b4f..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,9 +57,10 @@ struct LookupPaths {
/* A temporary directory when running in test mode, to be nuked */
char *temporary_dir;
-};
+} LookupPaths;
-int lookup_paths_init(LookupPaths *p, 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);
@@ -67,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/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/basic/unit-file.c b/src/basic/unit-file.c
index d44b886440..7c1ae515e1 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;
@@ -82,7 +82,8 @@ int unit_validate_alias_symlink_and_warn(const char *filename, const char *targe
*
* -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);
@@ -92,51 +93,56 @@ 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 */
+ 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_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;
}
@@ -259,6 +265,110 @@ static int directory_name_is_valid(const char *name) {
return false;
}
+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, *_dir = NULL, *_filename = NULL;
+ int r;
+
+ /* 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.
+ *
+ * Returns an error, false if this is an alias, true if it's a linked unit file. */
+
+ 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);
+ 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);
+
+ assert(path_is_absolute(simplified));
+
+ /* 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*.
+ */
+ const char *tail = path_startswith_strv(simplified, search_path);
+ if (tail) { /* An alias */
+ _cleanup_free_ char *target_name = NULL;
+
+ r = path_extract_filename(simplified, &target_name);
+ if (r < 0)
+ return r;
+
+ r = unit_validate_alias_symlink_or_warn(LOG_NOTICE, filename, simplified);
+ if (r < 0)
+ return r;
+ 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);
+
+ } 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);
+ return !tail; /* true if linked unit file */
+}
+
int unit_file_build_name_map(
const LookupPaths *lp,
uint64_t *cache_timestamp_hash,
@@ -308,10 +418,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 +504,35 @@ 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,
+ /* resolve_destination_target= */ false,
+ &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;
}
}
diff --git a/src/basic/unit-file.h b/src/basic/unit-file.h
index cc731a9e06..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,21 +28,23 @@ 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_;
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);
+
+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/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 d10fb58a61..4493103298 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");
@@ -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/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/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/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 155f731936..0c10b161f0 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)
@@ -1539,7 +1539,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;
@@ -1573,7 +1573,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))
@@ -1717,7 +1717,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;
@@ -1753,7 +1753,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/condition.c b/src/shared/condition.c
index b9fca7bf0b..8165513cc9 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-printf.c b/src/shared/install-printf.c
index 9c121cbaf7..5436aa483b 100644
--- a/src/shared/install-printf.c
+++ b/src/shared/install-printf.c
@@ -97,7 +97,11 @@ 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(
+ LookupScope scope,
+ const UnitFileInstallInfo *info,
+ const char *format,
+ char **ret) {
/* This is similar to unit_name_printf() */
const Specifier table[] = {
@@ -109,13 +113,13 @@ int install_name_printf(const UnitFileInstallInfo *i, const char *format, const
COMMON_SYSTEM_SPECIFIERS,
- COMMON_CREDS_SPECIFIERS,
+ COMMON_CREDS_SPECIFIERS(scope),
{}
};
- 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 5ca9406797..6a9ab24e15 100644
--- a/src/shared/install-printf.h
+++ b/src/shared/install-printf.h
@@ -4,4 +4,8 @@
#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(
+ LookupScope scope,
+ const UnitFileInstallInfo *info,
+ const char *format,
+ char **ret);
diff --git a/src/shared/install.c b/src/shared/install.c
index 53b5418804..f807947a3c 100644
--- a/src/shared/install.c
+++ b/src/shared/install.c
@@ -47,6 +47,7 @@ typedef enum SearchFlags {
} SearchFlags;
typedef struct {
+ LookupScope scope;
OrderedHashmap *will_process;
OrderedHashmap *have_processed;
} InstallContext;
@@ -92,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);
@@ -319,7 +321,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! */
@@ -338,7 +340,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)
@@ -360,75 +362,115 @@ 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:
+ 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 -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:
- 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:
+ 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);
}
/**
- * 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(
@@ -439,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;
@@ -479,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;
}
@@ -590,8 +628,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;
@@ -603,21 +640,42 @@ static int remove_marked_symlinks_fd(
return -ENOMEM;
path_simplify(p);
- q = chase_symlinks(p, NULL, CHASE_NONEXISTENT, &dest, NULL);
- if (q == -ENOENT)
- continue;
- if (q < 0) {
- 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, 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 *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);
}
- /* 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. */
+ 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));
+
+ }
- 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;
@@ -638,7 +696,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;
@@ -717,8 +775,9 @@ static int find_symlinks_in_directory(
DIR *dir,
const char *dir_path,
const char *root_dir,
- const UnitFileInstallInfo *i,
- bool match_aliases,
+ const UnitFileInstallInfo *info,
+ bool ignore_destination,
+ bool match_name,
bool ignore_same_name,
const char *config_path,
bool *same_name_link) {
@@ -726,53 +785,69 @@ 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;
+
+ /* 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;
+ }
+
+ /* Make absolute */
+ if (!path_is_absolute(dest)) {
+ char *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);
}
- /* Make absolute */
- if (!path_is_absolute(dest)) {
- char *x;
+ assert(unit_name_is_valid(info->name, UNIT_NAME_ANY));
- x = path_join(dir_path, dest);
- if (!x)
- return -ENOMEM;
+ /* 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. */
- free_and_replace(dest, x);
+ 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);
}
- assert(unit_name_is_valid(i->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);
-
- /* Check if what the symlink points to matches what we are looking for */
- found_dest = streq(basename(dest), i->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(i->name, config_path);
+ t = path_make_absolute(info->name, config_path);
if (!p || !t)
return -ENOMEM;
@@ -783,11 +858,11 @@ 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] */
- 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)
@@ -838,26 +913,36 @@ 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;
}
- 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)
- 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. */
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(
- UnitFileScope scope,
+ LookupScope scope,
const LookupPaths *lp,
- const UnitFileInstallInfo *i,
+ const UnitFileInstallInfo *info,
bool match_name,
UnitFileState *state) {
@@ -867,7 +952,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
@@ -876,7 +961,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) {
@@ -889,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;
}
@@ -916,7 +1001,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;
}
@@ -929,7 +1014,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;
}
@@ -949,7 +1034,6 @@ static int find_symlinks_in_scope(
}
static void install_info_free(UnitFileInstallInfo *i) {
-
if (!i)
return;
@@ -965,21 +1049,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(
@@ -1013,7 +1097,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,
@@ -1023,7 +1107,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
@@ -1036,7 +1120,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;
@@ -1076,7 +1160,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;
@@ -1131,8 +1215,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);
@@ -1149,11 +1233,12 @@ 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, &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);
+ r = install_info_add(ctx, printed, NULL, info->root, /* auxiliary= */ true, NULL);
if (r < 0)
return r;
@@ -1179,7 +1264,8 @@ static int config_parse_default_instance(
void *data,
void *userdata) {
- UnitFileInstallInfo *i = data;
+ InstallContext *ctx = ASSERT_PTR(data);
+ UnitFileInstallInfo *info = ASSERT_PTR(userdata);
_cleanup_free_ char *printed = NULL;
int r;
@@ -1196,24 +1282,23 @@ 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(ctx->scope, info, rvalue, &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);
- 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,
@@ -1224,7 +1309,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 },
{}
};
@@ -1297,8 +1382,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"
@@ -1318,7 +1403,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;
@@ -1330,87 +1415,40 @@ 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) {
-
- _cleanup_free_ char *resolved = NULL;
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;
- 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;
+ 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 (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;
-
- info->type = UNIT_FILE_TYPE_SYMLINK;
- }
+ else if (outside_search_path)
+ info->type = UNIT_FILE_TYPE_LINKED;
+ else
+ info->type = UNIT_FILE_TYPE_ALIAS;
return 0;
}
static int unit_file_search(
- InstallContext *c,
+ InstallContext *ctx,
UnitFileInstallInfo *info,
const LookupPaths *lp,
SearchFlags flags) {
@@ -1429,7 +1467,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);
@@ -1446,7 +1484,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;
@@ -1469,7 +1507,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;
@@ -1525,38 +1563,38 @@ 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);
+ return log_debug_errno(r, "Failed to load conf file \"%s\": %m", *p);
}
return result;
}
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 (!IN_SET(info->type, UNIT_FILE_TYPE_ALIAS, UNIT_FILE_TYPE_LINKED))
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);
}
/**
@@ -1564,8 +1602,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,
@@ -1577,14 +1614,14 @@ 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;
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)
@@ -1598,7 +1635,9 @@ static int install_info_traverse(
return -ELOOP;
}
- r = install_info_follow(c, 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;
@@ -1625,7 +1664,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;
@@ -1635,12 +1674,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;
@@ -1661,12 +1700,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)) {
@@ -1674,14 +1713,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,
@@ -1689,16 +1727,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);
@@ -1706,25 +1744,30 @@ 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,
+ UnitFileChange **changes,
+ size_t *n_changes) {
+
_cleanup_free_ char *dst_updated = NULL;
int r;
@@ -1734,6 +1777,11 @@ int unit_file_verify_alias(const UnitFileInstallInfo *i, const char *dst, char *
* 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, '/');
@@ -1751,26 +1799,32 @@ int unit_file_verify_alias(const UnitFileInstallInfo *i, const char *dst, char *
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;
/* 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);
+ 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
@@ -1778,9 +1832,11 @@ 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);
- if (type < 0)
- return log_error_errno(type, "Failed to extract instance name from %s: %m", i->name);
+ UnitNameFlags type = unit_name_to_instance(info->name, &inst);
+ 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);
@@ -1790,10 +1846,16 @@ int unit_file_verify_alias(const UnitFileInstallInfo *i, const char *dst, char *
}
}
- r = unit_validate_alias_symlink_and_warn(dst_updated ?: dst, i->name);
- if (r < 0)
+ 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,
+ dst_updated ?: dst,
+ info->name);
+ return r;
+ }
}
*ret_dst = TAKE_PTR(dst_updated);
@@ -1801,7 +1863,8 @@ int unit_file_verify_alias(const UnitFileInstallInfo *i, const char *dst, char *
}
static int install_info_symlink_alias(
- UnitFileInstallInfo *i,
+ LookupScope scope,
+ UnitFileInstallInfo *info,
const LookupPaths *lp,
const char *config_path,
bool force,
@@ -1810,37 +1873,43 @@ 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);
- if (q < 0)
- return q;
-
- q = unit_file_verify_alias(i, dst, &dst_updated);
- if (q < 0)
+ 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;
continue;
+ }
+
+ 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;
+ }
alias_path = path_make_absolute(dst_updated ?: dst, config_path);
if (!alias_path)
return -ENOMEM;
- q = create_symlink(lp, i->path, alias_path, force, changes, n_changes);
- if (r == 0)
- r = q;
+ q = create_symlink(lp, info->name, alias_path, force, changes, n_changes);
+ r = r < 0 ? r : q;
}
return r;
}
static int install_info_symlink_wants(
- UnitFileScope scope,
+ LookupScope scope,
UnitFileFlags file_flags,
- UnitFileInstallInfo *i,
+ UnitFileInstallInfo *info,
const LookupPaths *lp,
const char *config_path,
char **list,
@@ -1853,18 +1922,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,
};
@@ -1872,7 +1941,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;
@@ -1895,15 +1964,17 @@ 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;
+ _cleanup_free_ char *dst = NULL;
- q = install_name_printf(i, *s, i->root, &dst);
- if (q < 0)
+ q = install_name_printf(scope, info, *s, &dst);
+ 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
@@ -1927,23 +1998,27 @@ 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, i->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;
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,
@@ -1953,28 +2028,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,
+ LookupScope scope,
UnitFileFlags file_flags,
- UnitFileInstallInfo *i,
+ UnitFileInstallInfo *info,
const LookupPaths *lp,
const char *config_path,
UnitFileChange **changes,
@@ -1982,38 +2057,39 @@ 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);
-
- q = install_info_symlink_wants(scope, file_flags, i, lp, config_path, i->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);
- if (r == 0)
- r = q;
-
- q = install_info_symlink_link(i, lp, config_path, force, changes, n_changes);
+ 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 && q < 0)
+ 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);
+ if (r == 0)
+ r = q;
+
+ q = install_info_symlink_wants(scope, file_flags, info, lp, config_path, info->required_by, ".requires/", changes, n_changes);
+ if (r == 0)
r = q;
return r;
}
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,
@@ -2022,26 +2098,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);
@@ -2068,7 +2144,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;
@@ -2081,8 +2157,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,
@@ -2092,26 +2167,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);
@@ -2145,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,
@@ -2157,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)
@@ -2190,7 +2265,7 @@ int unit_file_mask(
}
int unit_file_unmask(
- UnitFileScope scope,
+ LookupScope scope,
UnitFileFlags flags,
const char *root_dir,
char **files,
@@ -2205,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)
@@ -2282,7 +2357,7 @@ int unit_file_unmask(
}
int unit_file_link(
- UnitFileScope scope,
+ LookupScope scope,
UnitFileFlags flags,
const char *root_dir,
char **files,
@@ -2296,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)
@@ -2382,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,
@@ -2533,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,
@@ -2543,13 +2618,13 @@ 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;
assert(scope >= 0);
- assert(scope < _UNIT_FILE_SCOPE_MAX);
+ assert(scope < _LOOKUP_SCOPE_MAX);
assert(target);
if (!IN_SET(dep, UNIT_WANTS, UNIT_REQUIRES))
@@ -2566,7 +2641,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;
@@ -2576,21 +2651,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);
@@ -2598,42 +2673,30 @@ 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);
}
-int unit_file_enable(
- UnitFileScope scope,
- UnitFileFlags file_flags,
- const char *root_dir,
+static int do_unit_file_enable(
+ const LookupPaths *lp,
+ LookupScope scope,
+ 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 c = {};
- const char *config_path;
- UnitFileInstallInfo *i;
+ _cleanup_(install_context_done) InstallContext ctx = { .scope = scope };
+ UnitFileInstallInfo *info;
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;
-
- config_path = config_path_from_flags(&lp, file_flags);
- if (!config_path)
- 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
@@ -2641,11 +2704,12 @@ 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, flags, config_path,
+ SEARCH_LOAD, changes, n_changes);
}
-int unit_file_disable(
- UnitFileScope scope,
+int unit_file_enable(
+ LookupScope scope,
UnitFileFlags flags,
const char *root_dir,
char **files,
@@ -2653,67 +2717,173 @@ int unit_file_disable(
size_t *n_changes) {
_cleanup_(lookup_paths_free) LookupPaths lp = {};
- _cleanup_(install_context_done) InstallContext c = {};
- _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
- const char *config_path;
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)
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;
+ return do_unit_file_enable(&lp, scope, flags, config_path, files, changes, n_changes);
+}
+
+static int do_unit_file_disable(
+ const LookupPaths *lp,
+ LookupScope 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(&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;
- return remove_marked_symlinks(remove_symlinks_to, config_path, &lp, flags & UNIT_FILE_DRY_RUN, changes, n_changes);
+ return remove_marked_symlinks(remove_symlinks_to, config_path, lp, flags & UNIT_FILE_DRY_RUN, changes, n_changes);
}
-int unit_file_reenable(
- UnitFileScope scope,
+
+int unit_file_disable(
+ LookupScope scope,
UnitFileFlags flags,
const char *root_dir,
char **files,
UnitFileChange **changes,
size_t *n_changes) {
- char **n;
+ _cleanup_(lookup_paths_free) LookupPaths lp = {};
int r;
- size_t l, i;
+
+ assert(scope >= 0);
+ assert(scope < _LOOKUP_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_disable(&lp, scope, flags, config_path, files, changes, n_changes);
+}
+
+static int normalize_linked_files(
+ LookupScope 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(
+ LookupScope scope,
+ UnitFileFlags flags,
+ const char *root_dir,
+ char **names_or_paths,
+ UnitFileChange **changes,
+ size_t *n_changes) {
+
+ _cleanup_(lookup_paths_free) LookupPaths lp = {};
+ _cleanup_strv_free_ char **names = NULL, **files = NULL;
+ int r;
+
+ assert(scope >= 0);
+ assert(scope < _LOOKUP_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;
+
+ 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... */
- l = strv_length(files);
- n = newa(char*, l+1);
- for (i = 0; i < l; i++)
- n[i] = basename(files[i]);
- n[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(
- UnitFileScope scope,
+ LookupScope scope,
UnitFileFlags flags,
const char *root_dir,
const char *name,
@@ -2721,13 +2891,13 @@ 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;
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 */
@@ -2739,42 +2909,42 @@ 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->name, new_path, flags & UNIT_FILE_FORCE, changes, n_changes);
}
int unit_file_get_default(
- UnitFileScope scope,
+ LookupScope scope,
const char *root_dir,
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;
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);
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;
@@ -2783,13 +2953,13 @@ int unit_file_get_default(
}
int unit_file_lookup_state(
- UnitFileScope scope,
+ LookupScope scope,
const LookupPaths *lp,
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;
@@ -2799,23 +2969,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;
@@ -2824,12 +2994,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) {
@@ -2837,7 +3007,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) {
@@ -2848,7 +3018,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)
@@ -2856,15 +3026,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;
@@ -2881,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) {
@@ -2890,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);
@@ -2900,8 +3070,8 @@ 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) {
- _cleanup_(install_context_done) InstallContext c = {};
+int unit_file_exists(LookupScope scope, const LookupPaths *lp, const char *name) {
+ _cleanup_(install_context_done) InstallContext c = { .scope = scope };
int r;
assert(lp);
@@ -2910,7 +3080,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)
@@ -2952,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();
@@ -2970,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);
@@ -3150,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;
@@ -3166,7 +3336,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,
@@ -3187,7 +3356,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;
@@ -3199,9 +3368,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;
@@ -3214,7 +3384,7 @@ static int execute_preset(
}
static int preset_prepare_one(
- UnitFileScope scope,
+ LookupScope scope,
InstallContext *plus,
InstallContext *minus,
LookupPaths *lp,
@@ -3223,20 +3393,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;
}
@@ -3247,27 +3417,27 @@ 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;
}
int unit_file_preset(
- UnitFileScope scope,
+ LookupScope scope,
UnitFileFlags file_flags,
const char *root_dir,
char **files,
@@ -3282,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);
@@ -3303,11 +3473,11 @@ 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(
- UnitFileScope scope,
+ LookupScope scope,
UnitFileFlags file_flags,
const char *root_dir,
UnitFilePresetMode mode,
@@ -3321,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);
@@ -3357,14 +3527,14 @@ 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, -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;
}
}
- 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) {
@@ -3382,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,
@@ -3392,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 cdc5435035..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 {
@@ -70,7 +71,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,
@@ -94,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 **files,
+ 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,
@@ -123,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,
@@ -178,22 +180,27 @@ 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);
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;
@@ -204,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 a02012407b..16eb8830dc 100644
--- a/src/shared/specifier.c
+++ b/src/shared/specifier.c
@@ -18,6 +18,7 @@
#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"
@@ -162,7 +163,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
@@ -269,44 +271,54 @@ 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 -EUNATCH. This means that something is seriously wrong with the
+ * installation. */
+
+static int parse_os_release_specifier(const char *root, const char *id, char **ret) {
+ int r;
+
+ assert(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) {
- assert(ret);
- return parse_os_release(root, "ID", 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) {
+ LookupScope scope = PTR_TO_INT(data);
char *t;
assert(ret);
- t = gid_to_name(getgid());
+ if (scope == LOOKUP_SCOPE_GLOBAL)
+ return -EINVAL;
+
+ t = gid_to_name(scope == LOOKUP_SCOPE_USER ? getgid() : 0);
if (!t)
return -ENOMEM;
@@ -315,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) {
+ LookupScope scope = PTR_TO_INT(data);
+ gid_t gid;
+
assert(ret);
- if (asprintf(ret, UID_FMT, getgid()) < 0)
+ if (scope == LOOKUP_SCOPE_GLOBAL)
+ return -EINVAL;
+
+ gid = scope == LOOKUP_SCOPE_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) {
+ LookupScope 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 == LOOKUP_SCOPE_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 == 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.
+
+ * 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;
@@ -344,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) {
+ LookupScope scope = PTR_TO_INT(data);
+ uid_t uid;
+
assert(ret);
- if (asprintf(ret, UID_FMT, getuid()) < 0)
+ if (scope == LOOKUP_SCOPE_GLOBAL)
+ return -EINVAL;
+
+ uid = scope == LOOKUP_SCOPE_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/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/systemctl/systemctl-edit.c b/src/systemctl/systemctl-edit.c
index 6ef6cc54a8..446dfd7dd6 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)
@@ -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;
}
@@ -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-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 7a6cef3c5e..cfd0078964 100644
--- a/src/systemctl/systemctl-start-special.c
+++ b/src/systemctl/systemctl-start-special.c
@@ -246,10 +246,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 017dba2034..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)
@@ -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/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 a81df6600b..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,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, LOOKUP_SCOPE_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-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-env-file.c b/src/test/test-env-file.c
index f97206b4d6..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" \
@@ -55,18 +60,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 +75,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 +106,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-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-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-install-root.c b/src/test/test-install-root.c
index f718689c3a..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,27 +85,27 @@ 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, "/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);
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,63 +113,63 @@ 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, "/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);
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");
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;
- 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,13 +180,13 @@ 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, "/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);
@@ -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,16 +271,17 @@ 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");
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;
@@ -293,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");
@@ -314,15 +315,16 @@ 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");
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;
@@ -335,12 +337,12 @@ 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));
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;
}
@@ -357,27 +359,27 @@ 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, "/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);
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"));
}
@@ -398,10 +400,10 @@ 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, "/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);
@@ -416,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,
@@ -430,96 +432,97 @@ 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, "/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);
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, "/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@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@.service", &state) >= 0);
+ assert_se(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_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, "/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);
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) {
@@ -528,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,
@@ -545,24 +548,24 @@ 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, "/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);
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");
@@ -580,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,
@@ -598,22 +601,22 @@ 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, "/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);
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");
@@ -621,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);
@@ -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);
@@ -650,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)) {
@@ -684,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;
@@ -703,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));
@@ -714,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));
@@ -732,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,
@@ -751,48 +754,48 @@ 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, "/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);
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) {
@@ -801,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,
@@ -817,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,
@@ -829,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,
@@ -841,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,
@@ -853,21 +856,21 @@ 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);
- 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");
@@ -875,13 +878,13 @@ 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);
- 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");
@@ -889,13 +892,13 @@ 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);
- 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");
@@ -903,13 +906,13 @@ 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);
- 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");
@@ -917,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) {
@@ -930,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,
@@ -944,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,
@@ -956,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,
@@ -969,14 +972,14 @@ 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);
- 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");
@@ -984,12 +987,12 @@ 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);
- 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");
@@ -997,29 +1000,29 @@ 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, "/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);
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, "/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);
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) {
@@ -1035,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,
@@ -1043,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");
@@ -1055,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");
@@ -1064,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);
}
@@ -1091,7 +1094,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-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 52f6096eee..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;
@@ -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, &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(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(i, "%m", mid);
- expect(i, "%b", bid);
- expect(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(i2, "%g", group);
- expect(i2, "%G", gid);
- expect(i2, "%u", user);
- expect(i2, "%U", uid);
+ 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(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(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);
- 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(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(i4, "%g", group);
- expect(i4, "%G", gid);
- expect(i4, "%u", user);
- expect(i4, "%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(LOOKUP_SCOPE_SYSTEM, i3, "%m", mid);
+ expect(LOOKUP_SCOPE_SYSTEM, i3, "%b", bid);
+ expect(LOOKUP_SCOPE_SYSTEM, i3, "%H", host);
+
+ 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) {
@@ -791,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;
@@ -924,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-os-util.c b/src/test/test-os-util.c
index eb5466259a..2cee6470c4 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,61 @@ 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) == 0);
+ 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) == 0);
+ 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);
+ 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"));
+
+ 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", "the-id",
+ "NAME", "the-name")));
+
+ assert_se(unsetenv("SYSTEMD_OS_RELEASE") == 0);
+}
+
DEFINE_TEST_MAIN(LOG_DEBUG);
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-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);
diff --git a/src/test/test-specifier.c b/src/test/test-specifier.c
index 231625de95..49b4f5a2a3 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(LOOKUP_SCOPE_USER),
{ 'h', specifier_user_home, NULL },
COMMON_TMP_SPECIFIERS,
@@ -138,4 +139,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) == -EUNATCH);
+ assert_se(streq(resolved, "-----"));
+
+ assert_se(unsetenv("SYSTEMD_OS_RELEASE") == 0);
+}
+
DEFINE_TEST_MAIN(LOG_DEBUG);
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";
diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c
index 9b05a191e6..dffa2822e6 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) {
@@ -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 f0190f9b4c..023207bc60 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 ? LOOKUP_SCOPE_USER : LOOKUP_SCOPE_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/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..ac1bcc1cc7
--- /dev/null
+++ b/test/test-systemctl-enable.sh
@@ -0,0 +1,693 @@
+#!/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}
+systemd_id128=${2:-systemd-id128}
+
+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
+}
+
+: '------enable nonexistent------------------------------------'
+( ! "$systemctl" --root="$root" enable test1.service )
+
+: '------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/test1a.service" <"$root/etc/systemd/system/test2.socket" <"$root/etc/systemd/system/test2.service" <"$root/link1.path" <"$root/link3.suffix" <"$root/etc/systemd/system/link5-also.service" <"$root/etc/systemd/system/myown.d/link5.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" <"$root/etc/os-release" <"$root/etc/os-release" <"$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@'
+
+check_alias p 'some-some-link6'
+
+check_alias v "$(uname -r)"
+
+# % is not legal in unit name
+( ! check_alias % '%' )
+
+# %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
+# expansion is performed.
+
+cat >"$root/etc/systemd/system/some-some-link7.socket" <"$root/etc/os-release2" <