sysupdate: fix root cleanup and default feature selection (#43154)

This commit is contained in:
Yu Watanabe
2026-07-26 20:28:33 +09:00
committed by GitHub
3 changed files with 114 additions and 7 deletions
+33 -2
View File
@@ -112,6 +112,27 @@ static int installdb_make_names(const char *path, const char *pattern, char **re
return 0;
}
static const char* context_root_relative_path(const Context *c, const char *path) {
const char *p;
assert(c);
assert(path);
if (!c->root)
return path;
p = path_startswith_full(path, c->root, PATH_STARTSWITH_RETURN_LEADING_SLASH);
if (p)
return p;
/* path_startswith_full(..., PATH_STARTSWITH_RETURN_LEADING_SLASH) cannot return a pointer
* to a leading slash before the start of the original string when both paths are identical. */
if (path_equal(path, c->root))
return "/";
return NULL;
}
int context_installdb_record(
Context *c,
const char *path,
@@ -129,7 +150,11 @@ int context_installdb_record(
return 0;
/* The provided path comes with c->root prefixed. Strip it here again */
const char *p = c->root ? ASSERT_PTR(path_startswith(path, c->root)) : path;
const char *p = context_root_relative_path(c, path);
if (!p)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Resolved resource path '%s' is not below root '%s'.",
path, c->root);
r = context_installdb_acquire_fd(c, /* make= */ true);
if (r < 0)
@@ -170,7 +195,13 @@ static int context_is_path_currently_owned(
if (!RESOURCE_IS_FILESYSTEM(t->target.type))
continue;
if (!path_equal(t->target.path, path))
const char *target_path = context_root_relative_path(c, t->target.path);
if (!target_path)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Resolved target path '%s' is not below root '%s'.",
t->target.path, c->root);
if (!path_equal(target_path, path))
continue;
/* OK, so we found a transfer that covers this directory. Now let's see if any of its patterns match */
+3 -5
View File
@@ -2949,15 +2949,13 @@ static int context_list_components(Context *context, char ***ret_component_names
if (ret_component_names)
*ret_component_names = TAKE_PTR(z);
/* Does the system have at least one transfer file in /etc/sysupdate.d, which can be considered a
* TARGET_HOST? See target_get_argument() in sysupdated.c */
/* Does the system have at least one transfer file in sysupdate.d, which can be considered the
* default component-less installation? */
if (ret_has_default_component)
*ret_has_default_component =
!context->definitions &&
!context->component &&
!context->root &&
!context->image &&
context->n_transfers > 0;
context->n_transfers + context->n_disabled_transfers > 0;
return 0;
}
+78
View File
@@ -907,6 +907,40 @@ test ! -f "$CLEANUP/target/alpha-v2.bin"
rm -rf "$CONFIGDIR" "$INSTALLDB" "$CLEANUP"
# Under --root=, cleanup must compare current transfer target paths in the same
# root-relative form stored in the install database, and keep still-owned files.
ROOT_CLEANUP="$WORKDIR/root-cleanup"
ROOT_CLEANUP_ROOT="$ROOT_CLEANUP/root"
ROOT_CLEANUP_DB_VALUE="/target/./alpha-@v.bin"
ROOT_CLEANUP_DB_KEY="$(printf '%s' "$ROOT_CLEANUP_DB_VALUE" | sha256sum | cut -d' ' -f1)"
rm -rf "$ROOT_CLEANUP"
mkdir -p "$ROOT_CLEANUP_ROOT/etc/sysupdate.d" \
"$ROOT_CLEANUP_ROOT/target" \
"$ROOT_CLEANUP_ROOT/var/lib/systemd/sysupdate/installdb"
cat >"$ROOT_CLEANUP_ROOT/etc/sysupdate.d/01-alpha.transfer" <<EOF
[Source]
Type=regular-file
Path=/source
MatchPattern=alpha-@v.bin
[Target]
Type=regular-file
Path=/target
MatchPattern=alpha-@v.bin
InstancesMax=2
EOF
echo "$RANDOM" >"$ROOT_CLEANUP_ROOT/target/alpha-v1.bin"
ln -s "$ROOT_CLEANUP_DB_VALUE" \
"$ROOT_CLEANUP_ROOT/var/lib/systemd/sysupdate/installdb/$ROOT_CLEANUP_DB_KEY"
"$SYSUPDATE" --root="$ROOT_CLEANUP_ROOT" --verify=no cleanup
test -f "$ROOT_CLEANUP_ROOT/target/alpha-v1.bin"
test -L "$ROOT_CLEANUP_ROOT/var/lib/systemd/sysupdate/installdb/$ROOT_CLEANUP_DB_KEY"
rm -rf "$ROOT_CLEANUP"
# Briefly check the "--component-all" switch of the "cleanup" verb. Each component
# keeps its own install database (installdb.<component>), and "cleanup
# --component-all" must clean up orphaned resources across *all* of them in one
@@ -1799,6 +1833,50 @@ assert_dropin "$(feat_enable_dropin_default featc)" yes
test ! -e "$(feat_enable_dropin_default featb)"
set_machine_tags ""
# --component-all must still include the default component when all of its
# transfers are currently disabled by features.
compfeat_reset
compfeat_source v1
mkdir -p /run/sysupdate.d
compfeat_transfer /run/sysupdate.d/50-feata.transfer feata "$CF/target-default" feata
cat >/run/sysupdate.d/feata.feature <<EOF
[Feature]
Description=Feature A
EOF
"$SYSUPDATE" --component-all enable-feature --feature-all
assert_dropin "$(feat_enable_dropin_default feata)" yes
# --component-all must include the default component under --root= too.
ROOT_FEATURE="$WORKDIR/root-feature"
ROOT_FEATURE_ROOT="$ROOT_FEATURE/root"
rm -rf "$ROOT_FEATURE"
mkdir -p "$ROOT_FEATURE_ROOT/etc/sysupdate.d" \
"$ROOT_FEATURE_ROOT/source" \
"$ROOT_FEATURE_ROOT/target"
cat >"$ROOT_FEATURE_ROOT/etc/sysupdate.d/50-feata.transfer" <<EOF
[Transfer]
Features=feata
[Source]
Type=regular-file
Path=/source
MatchPattern=feata-@v.bin
[Target]
Type=regular-file
Path=/target
MatchPattern=feata-@v.bin
InstancesMax=2
EOF
cat >"$ROOT_FEATURE_ROOT/etc/sysupdate.d/feata.feature" <<EOF
[Feature]
Description=Feature A
EOF
"$SYSUPDATE" --root="$ROOT_FEATURE_ROOT" --component-all enable-feature --feature-all
assert_dropin "$ROOT_FEATURE_ROOT$(feat_enable_dropin_default feata)" yes
rm -rf "$ROOT_FEATURE"
# ---------------------------------------------------------------------------
# Features scoped to a named component, and across all components at once
# ---------------------------------------------------------------------------