mirror of
https://github.com/LibreELEC/LibreELEC.tv.git
synced 2025-07-24 11:16:51 +00:00
systemd: fix non-working service aliases
Origin of applied patches:
[0400] b2751cf039
[0500] https://github.com/systemd/systemd/pull/31816
This commit is contained in:
parent
7dd19fd76c
commit
4de42ea671
@ -0,0 +1,136 @@
|
||||
From b2751cf0394d36c24590b5f7b33e9f864b57ba0d Mon Sep 17 00:00:00 2001
|
||||
From: Mike Yuan <me@yhndnzj.com>
|
||||
Date: Thu, 29 Feb 2024 18:53:26 +0800
|
||||
Subject: [PATCH] shared/install: use RET_GATHER more
|
||||
|
||||
---
|
||||
src/shared/install.c | 54 ++++++++++++++++++--------------------------
|
||||
1 file changed, 22 insertions(+), 32 deletions(-)
|
||||
|
||||
diff --git a/src/shared/install.c b/src/shared/install.c
|
||||
index 32f504c32763a..42b725c076dda 100644
|
||||
--- a/src/shared/install.c
|
||||
+++ b/src/shared/install.c
|
||||
@@ -1892,7 +1892,7 @@ static int install_info_symlink_alias(
|
||||
InstallChange **changes,
|
||||
size_t *n_changes) {
|
||||
|
||||
- int r = 0, q;
|
||||
+ int r, ret = 0;
|
||||
|
||||
assert(info);
|
||||
assert(lp);
|
||||
@@ -1900,20 +1900,17 @@ static int install_info_symlink_alias(
|
||||
|
||||
STRV_FOREACH(s, info->aliases) {
|
||||
_cleanup_free_ char *alias_path = NULL, *dst = NULL, *dst_updated = NULL;
|
||||
- bool broken;
|
||||
|
||||
- q = install_name_printf(scope, info, *s, &dst);
|
||||
- if (q < 0) {
|
||||
- install_changes_add(changes, n_changes, q, *s, NULL);
|
||||
- r = r < 0 ? r : q;
|
||||
+ r = install_name_printf(scope, info, *s, &dst);
|
||||
+ if (r < 0) {
|
||||
+ RET_GATHER(ret, install_changes_add(changes, n_changes, r, *s, NULL));
|
||||
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;
|
||||
+ r = unit_file_verify_alias(info, dst, &dst_updated, changes, n_changes);
|
||||
+ if (r < 0) {
|
||||
+ if (r != -ELOOP)
|
||||
+ RET_GATHER(ret, r);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1921,18 +1918,18 @@ static int install_info_symlink_alias(
|
||||
if (!alias_path)
|
||||
return -ENOMEM;
|
||||
|
||||
- q = chase(alias_path, lp->root_dir, CHASE_NONEXISTENT, NULL, NULL);
|
||||
- if (q < 0 && q != -ENOENT) {
|
||||
- r = r < 0 ? r : q;
|
||||
+ bool broken;
|
||||
+ r = chase(alias_path, lp->root_dir, CHASE_NONEXISTENT, /* ret_path = */ NULL, /* ret_fd = */ NULL);
|
||||
+ if (r < 0 && r != -ENOENT) {
|
||||
+ RET_GATHER(ret, r);
|
||||
continue;
|
||||
}
|
||||
- broken = q == 0; /* symlink target does not exist? */
|
||||
+ broken = r == 0; /* symlink target does not exist? */
|
||||
|
||||
- q = create_symlink(lp, info->path, alias_path, force || broken, changes, n_changes);
|
||||
- r = r < 0 ? r : q;
|
||||
+ RET_GATHER(ret, create_symlink(lp, info->path, alias_path, force || broken, changes, n_changes));
|
||||
}
|
||||
|
||||
- return r;
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
static int install_info_symlink_wants(
|
||||
@@ -1995,10 +1992,7 @@ static int install_info_symlink_wants(
|
||||
|
||||
q = install_name_printf(scope, info, *s, &dst);
|
||||
if (q < 0) {
|
||||
- install_changes_add(changes, n_changes, q, *s, NULL);
|
||||
- if (r >= 0)
|
||||
- r = q;
|
||||
-
|
||||
+ RET_GATHER(r, install_changes_add(changes, n_changes, q, *s, NULL));
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -2010,15 +2004,13 @@ static int install_info_symlink_wants(
|
||||
* 'systemctl enable serial-getty@.service' should fail, the user should specify an
|
||||
* instance like in 'systemctl enable serial-getty@ttyS0.service'.
|
||||
*/
|
||||
- if (file_flags & UNIT_FILE_IGNORE_AUXILIARY_FAILURE)
|
||||
+ if (FLAGS_SET(file_flags, UNIT_FILE_IGNORE_AUXILIARY_FAILURE))
|
||||
continue;
|
||||
|
||||
if (unit_name_is_valid(dst, UNIT_NAME_ANY))
|
||||
- q = install_changes_add(changes, n_changes, -EIDRM, dst, n);
|
||||
+ RET_GATHER(r, install_changes_add(changes, n_changes, -EIDRM, dst, n));
|
||||
else
|
||||
- q = install_changes_add(changes, n_changes, -EUCLEAN, dst, NULL);
|
||||
- if (r >= 0)
|
||||
- r = q;
|
||||
+ RET_GATHER(r, install_changes_add(changes, n_changes, -EUCLEAN, dst, NULL));
|
||||
|
||||
continue;
|
||||
}
|
||||
@@ -2027,7 +2019,7 @@ static int install_info_symlink_wants(
|
||||
if (!path)
|
||||
return -ENOMEM;
|
||||
|
||||
- q = create_symlink(lp, info->path, path, true, changes, n_changes);
|
||||
+ q = create_symlink(lp, info->path, path, /* force = */ true, changes, n_changes);
|
||||
if ((q < 0 && r >= 0) || r == 0)
|
||||
r = q;
|
||||
|
||||
@@ -2418,7 +2410,7 @@ int unit_file_link(
|
||||
_cleanup_strv_free_ char **todo = NULL;
|
||||
const char *config_path;
|
||||
size_t n_todo = 0;
|
||||
- int r, q;
|
||||
+ int r;
|
||||
|
||||
assert(scope >= 0);
|
||||
assert(scope < _RUNTIME_SCOPE_MAX);
|
||||
@@ -2487,9 +2479,7 @@ int unit_file_link(
|
||||
if (!new_path)
|
||||
return -ENOMEM;
|
||||
|
||||
- q = create_symlink(&lp, *i, new_path, flags & UNIT_FILE_FORCE, changes, n_changes);
|
||||
- if (q < 0 && r >= 0)
|
||||
- r = q;
|
||||
+ RET_GATHER(r, create_symlink(&lp, *i, new_path, flags & UNIT_FILE_FORCE, changes, n_changes));
|
||||
}
|
||||
|
||||
return r;
|
@ -0,0 +1,193 @@
|
||||
From 9db7710a3e4ae7900b22c50b21479c941b3f33ed Mon Sep 17 00:00:00 2001
|
||||
From: Nick Rosbrook <enr0n@ubuntu.com>
|
||||
Date: Fri, 15 Mar 2024 15:14:05 -0400
|
||||
Subject: [PATCH] shared/install: correctly install alias for units outside
|
||||
search path
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
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.
|
||||
---
|
||||
src/shared/install.c | 16 ++++++++++++++--
|
||||
src/test/test-install-root.c | 25 +++++++++++++++++++------
|
||||
test/test-systemctl-enable.sh | 4 ++--
|
||||
3 files changed, 35 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/src/shared/install.c b/src/shared/install.c
|
||||
index 81f898f28a477..12bf083a2e60d 100644
|
||||
--- a/src/shared/install.c
|
||||
+++ b/src/shared/install.c
|
||||
@@ -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;
|
||||
diff --git a/src/test/test-install-root.c b/src/test/test-install-root.c
|
||||
index efd75b2a6798b..c55445079c6c6 100644
|
||||
--- a/src/test/test-install-root.c
|
||||
+++ b/src/test/test-install-root.c
|
||||
@@ -200,7 +200,7 @@ TEST(basic_mask_and_enable) {
|
||||
}
|
||||
|
||||
TEST(linked_units) {
|
||||
- const char *p, *q;
|
||||
+ const char *p, *q, *s;
|
||||
UnitFileState state;
|
||||
InstallChange *changes = NULL;
|
||||
size_t n_changes = 0, i;
|
||||
@@ -224,6 +224,7 @@ TEST(linked_units) {
|
||||
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");
|
||||
@@ -275,31 +276,41 @@ TEST(linked_units) {
|
||||
|
||||
/* 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);
|
||||
|
||||
@@ -307,10 +318,12 @@ TEST(linked_units) {
|
||||
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;
|
||||
|
||||
diff --git a/test/test-systemctl-enable.sh b/test/test-systemctl-enable.sh
|
||||
index 8427f6849bfd9..5615c900f4861 100644
|
||||
--- a/test/test-systemctl-enable.sh
|
||||
+++ b/test/test-systemctl-enable.sh
|
||||
@@ -534,8 +534,8 @@ test ! -h "$root/etc/systemd/system/link5alias2.service"
|
||||
|
||||
"$systemctl" --root="$root" enable '/link5copy.service'
|
||||
islink "$root/etc/systemd/system/link5copy.service" '/link5copy.service'
|
||||
-islink "$root/etc/systemd/system/link5alias.service" '/link5copy.service'
|
||||
-islink "$root/etc/systemd/system/link5alias2.service" '/link5copy.service'
|
||||
+islink "$root/etc/systemd/system/link5alias.service" '/etc/systemd/system/link5copy.service'
|
||||
+islink "$root/etc/systemd/system/link5alias2.service" '/etc/systemd/system/link5copy.service'
|
||||
|
||||
"$systemctl" --root="$root" disable 'link5copy.service'
|
||||
test ! -h "$root/etc/systemd/system/link5copy.service"
|
Loading…
x
Reference in New Issue
Block a user