shared/install: correctly install alias for units outside search path
Currently, if a unit file is enabled from outside of the search path,
and that unit has an alias, then the symlink ends up pointing outside of
the search path too. For example:
$ cat /tmp/a.service
[Service]
ExecStart=sleep infinity
[Install]
Alias=b.service
WantedBy=multi-user.target
$ systemctl enable /tmp/a.service
Created symlink /etc/systemd/system/a.service → /tmp/a.service.
Created symlink /etc/systemd/system/b.service → /tmp/a.service.
Created symlink /etc/systemd/system/multi-user.target.wants/a.service → /tmp/a.service.
This then means the alias is treated as a separate unit:
$ systemctl start a.service
$ sudo systemctl status a
● a.service
Loaded: loaded (/etc/systemd/system/a.service; enabled; preset: enabled)
Active: active (running) since Fri 2024-03-15 15:17:49 EDT; 9s ago
Main PID: 769593 (sleep)
Tasks: 1 (limit: 18898)
Memory: 220.0K
CPU: 5ms
CGroup: /system.slice/a.service
└─769593 sleep infinity
Mar 15 15:17:49 six systemd[1]: Started a.service.
$ sudo systemctl status b
○ b.service
Loaded: loaded (/etc/systemd/system/b.service; alias)
Active: inactive (dead)
To fix this, make sure the alias uses a target that is inside the search
path. Since the unit file itself is outside of the search path, a
symlink inside the search path will have been created already. Hence,
just point the alias symlink to that recently created symlink.
This commit is contained in:
committed by
Luca Boccassi
parent
ce88017255
commit
6fec0fed10
+14
-2
@@ -1941,7 +1941,7 @@ static int install_info_symlink_alias(
|
||||
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) {
|
||||
@@ -1960,6 +1960,18 @@ static int install_info_symlink_alias(
|
||||
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) {
|
||||
@@ -1968,7 +1980,7 @@ static int install_info_symlink_alias(
|
||||
}
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user