mirror of
https://github.com/systemd/systemd
synced 2024-10-15 12:34:37 +00:00
Merge pull request #31435 from bluca/portable_fix_versioned
portable: assorted bug fixes
This commit is contained in:
commit
c1e7f938ca
|
@ -61,6 +61,39 @@ bool image_name_is_valid(const char *s) {
|
|||
return true;
|
||||
}
|
||||
|
||||
int path_extract_image_name(const char *path, char **ret) {
|
||||
_cleanup_free_ char *fn = NULL;
|
||||
int r;
|
||||
|
||||
assert(path);
|
||||
assert(ret);
|
||||
|
||||
/* Extract last component from path, without any "/" suffixes. */
|
||||
r = path_extract_filename(path, &fn);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (r != O_DIRECTORY) {
|
||||
/* Chop off any image suffixes we recognize (unless we already know this must refer to some dir */
|
||||
FOREACH_STRING(suffix, ".sysext.raw", ".confext.raw", ".raw") {
|
||||
char *m = endswith(fn, suffix);
|
||||
if (m) {
|
||||
*m = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Truncate the version/counting suffixes */
|
||||
fn[strcspn(fn, "_+")] = 0;
|
||||
|
||||
if (!image_name_is_valid(fn))
|
||||
return -EINVAL;
|
||||
|
||||
*ret = TAKE_PTR(fn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int path_is_extension_tree(ImageClass image_class, const char *path, const char *extension, bool relax_extension_release_check) {
|
||||
int r;
|
||||
|
||||
|
@ -230,9 +263,25 @@ int open_extension_release_at(
|
|||
continue;
|
||||
}
|
||||
|
||||
if (!relax_extension_release_check &&
|
||||
extension_release_strict_xattr_value(fd, dir_path, de->d_name) != 0)
|
||||
continue;
|
||||
if (!relax_extension_release_check) {
|
||||
_cleanup_free_ char *base_image_name = NULL, *base_extension = NULL;
|
||||
|
||||
r = path_extract_image_name(image_name, &base_image_name);
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "Failed to extract image name from %s/%s, ignoring: %m", dir_path, de->d_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
r = path_extract_image_name(extension, &base_extension);
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "Failed to extract image name from %s, ignoring: %m", extension);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!streq(base_image_name, base_extension) &&
|
||||
extension_release_strict_xattr_value(fd, dir_path, image_name) != 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We already found what we were looking for, but there's another candidate? We treat this as
|
||||
* an error, as we want to enforce that there are no ambiguities in case we are in the
|
||||
|
|
|
@ -25,6 +25,7 @@ ImageClass image_class_from_string(const char *s) _pure_;
|
|||
* in accordance with the OS extension specification, rather than for /usr/lib/ or /etc/os-release. */
|
||||
|
||||
bool image_name_is_valid(const char *s) _pure_;
|
||||
int path_extract_image_name(const char *path, char **ret);
|
||||
|
||||
int path_is_extension_tree(ImageClass image_class, const char *path, const char *extension, bool relax_extension_release_check);
|
||||
static inline int path_is_os_tree(const char *path) {
|
||||
|
|
|
@ -1664,9 +1664,8 @@ int portable_attach(
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool marker_matches_images(const char *marker, const char *name_or_path, char **extension_image_paths) {
|
||||
static bool marker_matches_images(const char *marker, const char *name_or_path, char **extension_image_paths, bool match_all) {
|
||||
_cleanup_strv_free_ char **root_and_extensions = NULL;
|
||||
const char *a;
|
||||
int r;
|
||||
|
||||
assert(marker);
|
||||
|
@ -1676,7 +1675,9 @@ static bool marker_matches_images(const char *marker, const char *name_or_path,
|
|||
* list of images/paths. We enforce strict 1:1 matching, so that we are sure
|
||||
* we are detaching exactly what was attached.
|
||||
* For each image, starting with the root, we look for a token in the marker,
|
||||
* and return a negative answer on any non-matching combination. */
|
||||
* and return a negative answer on any non-matching combination.
|
||||
* If a partial match is allowed, then return immediately once it is found, otherwise
|
||||
* ensure that everything matches. */
|
||||
|
||||
root_and_extensions = strv_new(name_or_path);
|
||||
if (!root_and_extensions)
|
||||
|
@ -1686,70 +1687,33 @@ static bool marker_matches_images(const char *marker, const char *name_or_path,
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
STRV_FOREACH(image_name_or_path, root_and_extensions) {
|
||||
_cleanup_free_ char *image = NULL;
|
||||
/* Ensure the number of images passed matches the number of images listed in the marker */
|
||||
while (!isempty(marker))
|
||||
STRV_FOREACH(image_name_or_path, root_and_extensions) {
|
||||
_cleanup_free_ char *image = NULL, *base_image = NULL, *base_image_name_or_path = NULL;
|
||||
|
||||
r = extract_first_word(&marker, &image, ":", EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to parse marker: %s", marker);
|
||||
if (r == 0)
|
||||
return false;
|
||||
|
||||
a = last_path_component(image);
|
||||
|
||||
if (image_name_is_valid(*image_name_or_path)) {
|
||||
const char *e, *underscore;
|
||||
|
||||
/* We shall match against an image name. In that case let's compare the last component, and optionally
|
||||
* allow either a suffix of ".raw" or a series of "/".
|
||||
* But allow matching on a different version of the same image, when a "_" is used as a separator. */
|
||||
underscore = strchr(*image_name_or_path, '_');
|
||||
if (underscore) {
|
||||
if (strneq(a, *image_name_or_path, underscore - *image_name_or_path))
|
||||
continue;
|
||||
return false;
|
||||
}
|
||||
|
||||
e = startswith(a, *image_name_or_path);
|
||||
if (!e)
|
||||
r = extract_first_word(&marker, &image, ":", EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to parse marker: %s", marker);
|
||||
if (r == 0)
|
||||
return false;
|
||||
|
||||
if(!(e[strspn(e, "/")] == 0 || streq(e, ".raw")))
|
||||
return false;
|
||||
} else {
|
||||
const char *b, *underscore;
|
||||
size_t l;
|
||||
r = path_extract_image_name(image, &base_image);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to extract image name from %s, ignoring: %m", image);
|
||||
|
||||
/* We shall match against a path. Let's ignore any prefix here though, as often there are many ways to
|
||||
* reach the same file. However, in this mode, let's validate any file suffix.
|
||||
* But also ensure that we don't fail if both components don't have a '/' at all
|
||||
* (strcspn returns the full length of the string in that case, which might not
|
||||
* match as the versions might differ). */
|
||||
r = path_extract_image_name(*image_name_or_path, &base_image_name_or_path);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to extract image name from %s, ignoring: %m", *image_name_or_path);
|
||||
|
||||
l = strcspn(a, "/");
|
||||
b = last_path_component(*image_name_or_path);
|
||||
|
||||
if ((a[l] != '/') != !strchr(b, '/')) /* One is a directory, the other is not */
|
||||
return false;
|
||||
|
||||
if (a[l] != 0 && strcspn(b, "/") != l)
|
||||
return false;
|
||||
|
||||
underscore = strchr(b, '_');
|
||||
if (underscore)
|
||||
l = underscore - b;
|
||||
else { /* Either component could be versioned */
|
||||
underscore = strchr(a, '_');
|
||||
if (underscore)
|
||||
l = underscore - a;
|
||||
}
|
||||
|
||||
if (!strneq(a, b, l))
|
||||
return false;
|
||||
if (!streq(base_image, base_image_name_or_path)) {
|
||||
if (match_all)
|
||||
return false;
|
||||
} else if (!match_all)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return match_all;
|
||||
}
|
||||
|
||||
static int test_chroot_dropin(
|
||||
|
@ -1804,7 +1768,9 @@ static int test_chroot_dropin(
|
|||
if (!name_or_path)
|
||||
r = true;
|
||||
else
|
||||
r = marker_matches_images(marker, name_or_path, extension_image_paths);
|
||||
/* When detaching we want to match exactly on all images, but when inspecting we only need
|
||||
* to get the state of one component */
|
||||
r = marker_matches_images(marker, name_or_path, extension_image_paths, ret_marker != NULL);
|
||||
|
||||
if (ret_marker)
|
||||
*ret_marker = TAKE_PTR(marker);
|
||||
|
|
|
@ -139,6 +139,19 @@ grep -q -F "LogExtraFields=PORTABLE_EXTENSION_NAME_AND_VERSION=app" /run/systemd
|
|||
|
||||
portablectl detach --now --runtime --extension /usr/share/app0.raw /usr/share/minimal_1.raw app0
|
||||
|
||||
# Ensure versioned images are accepted without needing to use --force to override the extension-release
|
||||
# matching
|
||||
|
||||
cp /usr/share/app0.raw /tmp/app0_1.0.raw
|
||||
portablectl "${ARGS[@]}" attach --now --runtime --extension /tmp/app0_1.0.raw /usr/share/minimal_0.raw app0
|
||||
|
||||
systemctl is-active app0.service
|
||||
status="$(portablectl is-attached --extension app0_1 minimal_0)"
|
||||
[[ "${status}" == "running-runtime" ]]
|
||||
|
||||
portablectl detach --now --runtime --extension /tmp/app0_1.0.raw /usr/share/minimal_1.raw app0
|
||||
rm -f /tmp/app0_1.0.raw
|
||||
|
||||
portablectl "${ARGS[@]}" attach --now --runtime --extension /usr/share/app1.raw /usr/share/minimal_0.raw app1
|
||||
|
||||
systemctl is-active app1.service
|
||||
|
@ -211,6 +224,36 @@ test -f /run/systemd/system.attached/app0.service
|
|||
test -L /run/systemd/system.attached/app0.service.d/10-profile.conf
|
||||
portablectl detach --runtime --extension /usr/share/app0.raw /usr/share/minimal_0.raw app0
|
||||
|
||||
# Ensure that when two portables share the same base image, removing one doesn't remove the other too
|
||||
|
||||
portablectl "${ARGS[@]}" attach --runtime --extension /usr/share/app0.raw /usr/share/minimal_0.raw app0
|
||||
portablectl "${ARGS[@]}" attach --runtime --extension /usr/share/app1.raw /usr/share/minimal_0.raw app1
|
||||
|
||||
status="$(portablectl is-attached --extension app0 minimal_0)"
|
||||
[[ "${status}" == "attached-runtime" ]]
|
||||
status="$(portablectl is-attached --extension app1 minimal_0)"
|
||||
[[ "${status}" == "attached-runtime" ]]
|
||||
|
||||
(! portablectl detach --runtime /usr/share/minimal_0.raw app)
|
||||
|
||||
status="$(portablectl is-attached --extension app0 minimal_0)"
|
||||
[[ "${status}" == "attached-runtime" ]]
|
||||
status="$(portablectl is-attached --extension app1 minimal_0)"
|
||||
[[ "${status}" == "attached-runtime" ]]
|
||||
|
||||
# Ensure 'portablectl list' shows the correct status for both images
|
||||
portablectl list
|
||||
portablectl list | grep -F "minimal_0" | grep -q -F "attached-runtime"
|
||||
portablectl list | grep -F "app0" | grep -q -F "attached-runtime"
|
||||
portablectl list | grep -F "app1" | grep -q -F "attached-runtime"
|
||||
|
||||
portablectl detach --runtime --extension /usr/share/app0.raw /usr/share/minimal_0.raw app
|
||||
|
||||
status="$(portablectl is-attached --extension app1 minimal_0)"
|
||||
[[ "${status}" == "attached-runtime" ]]
|
||||
|
||||
portablectl detach --runtime --extension /usr/share/app1.raw /usr/share/minimal_0.raw app
|
||||
|
||||
# portablectl also works with directory paths rather than images
|
||||
|
||||
mkdir /tmp/rootdir /tmp/app0 /tmp/app1 /tmp/overlay /tmp/os-release-fix /tmp/os-release-fix/etc
|
||||
|
|
Loading…
Reference in a new issue