assert(config_path);
STRV_FOREACH(s, info->aliases) {
- _cleanup_free_ char *alias_path = NULL, *dst = NULL, *dst_updated = NULL;
+ _cleanup_free_ char *alias_path = NULL, *alias_target = NULL, *dst = NULL, *dst_updated = NULL;
r = install_name_printf(scope, info, *s, &dst);
if (r < 0) {
if (!alias_path)
return -ENOMEM;
+ r = in_search_path(lp, info->path);
+ if (r < 0)
+ return r;
+ if (r == 0) {
+ /* The unit path itself is outside of the search path. To
+ * correctly apply the alias, we need the alias symlink to
+ * point to the symlink that was created in the search path. */
+ alias_target = path_join(config_path, info->name);
+ if (!alias_target)
+ return -ENOMEM;
+ }
+
bool broken;
r = chase(alias_path, lp->root_dir, CHASE_NONEXISTENT, /* ret_path = */ NULL, /* ret_fd = */ NULL);
if (r < 0 && r != -ENOENT) {
}
broken = r == 0; /* symlink target does not exist? */
- RET_GATHER(ret, create_symlink(lp, info->path, alias_path, force || broken, changes, n_changes));
+ RET_GATHER(ret, create_symlink(lp, alias_target ?: info->path, alias_path, force || broken, changes, n_changes));
}
return ret;
}
TEST(linked_units) {
- const char *p, *q;
+ const char *p, *q, *s;
UnitFileState state;
InstallChange *changes = NULL;
size_t n_changes = 0, i;
p = strjoina(root, "/opt/linked.service");
assert_se(write_string_file(p,
"[Install]\n"
+ "Alias=linked-alias.service\n"
"WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0);
p = strjoina(root, "/opt/linked2.service");
/* Now, let's not just link it, but also enable it */
assert_se(unit_file_enable(RUNTIME_SCOPE_SYSTEM, 0, root, STRV_MAKE("/opt/linked.service"), &changes, &n_changes) >= 0);
- assert_se(n_changes == 2);
+ assert_se(n_changes == 3);
p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/linked.service");
q = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/linked.service");
+ s = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/linked-alias.service");
for (i = 0 ; i < n_changes; i++) {
assert_se(changes[i].type == INSTALL_CHANGE_SYMLINK);
- assert_se(streq(changes[i].source, "/opt/linked.service"));
+
+ if (s && streq(changes[i].path, s))
+ /* The alias symlink should point within the search path. */
+ assert_se(streq(changes[i].source, SYSTEM_CONFIG_UNIT_DIR"/linked.service"));
+ else
+ assert_se(streq(changes[i].source, "/opt/linked.service"));
if (p && streq(changes[i].path, p))
p = NULL;
else if (q && streq(changes[i].path, q))
q = NULL;
+ else if (s && streq(changes[i].path, s))
+ s = NULL;
else
assert_not_reached();
}
- assert_se(!p && !q);
+ assert_se(!p && !q && !s);
install_changes_free(changes, n_changes);
changes = NULL; n_changes = 0;
assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM, root, "linked.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+ assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM, root, "linked-alias.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
/* And let's unlink it again */
assert_se(unit_file_disable(RUNTIME_SCOPE_SYSTEM, 0, root, STRV_MAKE("linked.service"), &changes, &n_changes) >= 0);
- assert_se(n_changes == 2);
+ assert_se(n_changes == 3);
p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/linked.service");
q = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/linked.service");
+ s = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/linked-alias.service");
for (i = 0; i < n_changes; i++) {
assert_se(changes[i].type == INSTALL_CHANGE_UNLINK);
p = NULL;
else if (q && streq(changes[i].path, q))
q = NULL;
+ else if (s && streq(changes[i].path, s))
+ s = NULL;
else
assert_not_reached();
}
- assert_se(!p && !q);
+ assert_se(!p && !q && !s);
install_changes_free(changes, n_changes);
changes = NULL; n_changes = 0;