diff --git a/build_library/build_image_util.sh b/build_library/build_image_util.sh index 83f5f7d5708..150e2fc734d 100755 --- a/build_library/build_image_util.sh +++ b/build_library/build_image_util.sh @@ -748,8 +748,30 @@ EOF if [[ $(sudo find "${root_fs_dir}/usr/share/flatcar/etc" -size +0 ! -type d 2>/dev/null | wc -l) -gt 0 ]]; then die "Unexpected non-empty files in ${root_fs_dir}/usr/share/flatcar/etc" fi + # Some backwards-compat symlinks still use this folder as target, + # we can't remove it yet sudo rm -rf "${root_fs_dir}/usr/share/flatcar/etc" sudo cp -a "${root_fs_dir}/etc" "${root_fs_dir}/usr/share/flatcar/etc" + # Now set up a default confext and enable it. + # It's important to use dm-verity not only for stricter image policies + # but also because it allows us the refresh to identify this image and + # skip setting it up again in the final boot, which not only saves us + # a daemon-reload during boot but also from /etc contents shortly + # disappearing until systemd-sysext uses mount beneath for an atomic + # remount. Instead of a temporary directory we first prepare it as + # folder and then convert it to a DDI and remove the folder. + sudo rm -rf "${root_fs_dir}/usr/lib/confexts/00-flatcar-default" + sudo mkdir -p "${root_fs_dir}/usr/lib/confexts/00-flatcar-default" + sudo cp -a "${root_fs_dir}/etc" "${root_fs_dir}/usr/lib/confexts/00-flatcar-default/etc" + sudo mkdir -p "${root_fs_dir}/usr/lib/confexts/00-flatcar-default/etc/extension-release.d/" + echo ID=_any | sudo tee "${root_fs_dir}/usr/lib/confexts/00-flatcar-default/etc/extension-release.d/extension-release.00-flatcar-default" > /dev/null + sudo systemd-repart \ + --private-key="${SYSEXT_SIGNING_KEY_DIR}/sysexts.key" \ + --certificate="${SYSEXT_SIGNING_KEY_DIR}/sysexts.crt" \ + --make-ddi=confext \ + --copy-source="${root_fs_dir}/usr/lib/confexts/00-flatcar-default" \ + "${root_fs_dir}/usr/lib/confexts/00-flatcar-default.raw" + sudo rm -rf "${root_fs_dir}/usr/lib/confexts/00-flatcar-default" # Remove the rootfs state as it should be recreated through the # tmpfiles and may not be present on updating machines. This diff --git a/changelog/changes/2025-12-12-default-systemd-confext.md b/changelog/changes/2025-12-12-default-systemd-confext.md new file mode 100644 index 00000000000..8d3512b4c85 --- /dev/null +++ b/changelog/changes/2025-12-12-default-systemd-confext.md @@ -0,0 +1,2 @@ +- Switched `/etc/` from a custom overlayfs for A/B updates to using a systemd-confext extension providing the default contents by using systemd-confext in the mutable mode where `/etc/` gets used as upperdir [scripts#3555](https://github.com/flatcar/scripts/pull/3555) +- Moved systemd-sysext image mounting into the initrd, so that system extensions can better define the behavior of the final system at boot without workarounds to apply settings late at boot. This means `.wants` symlinks for systemd units work as expected now and, therefore, we dropped the `ensure-sysext.service` workaround. We still recommend extensions to keep their workarounds, e.g., using `.upholds` instead of `.wants`, to better support live reloading. A skipping logic prevents an extension refresh late at boot but only if no changes were found. For extensions that are not stored on a custom filesystem, such as a separate `/var` partition, the new extension mounting from the initrd won't be able to load them early but they will be picked up late at boot through the extension refresh. This is another case where it's good if extensions keep workarounds for late loading. diff --git a/changelog/updates/2025-12-08-update-systemd.md b/changelog/updates/2025-12-08-update-systemd.md new file mode 100644 index 00000000000..62c801457db --- /dev/null +++ b/changelog/updates/2025-12-08-update-systemd.md @@ -0,0 +1 @@ +- systemd (258.2) diff --git a/sdk_container/.repo/manifests/mantle-container b/sdk_container/.repo/manifests/mantle-container index db6a2c240d6..37007a215b0 100644 --- a/sdk_container/.repo/manifests/mantle-container +++ b/sdk_container/.repo/manifests/mantle-container @@ -1 +1 @@ -ghcr.io/flatcar/mantle:git-bed79eb716792cbd6f79301f515bafcdb59ee93d +ghcr.io/flatcar/mantle:pr-720 diff --git a/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-init/coreos-init-9999.ebuild b/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-init/coreos-init-9999.ebuild index 7aa0ec4bd4b..ca1dd0edebf 100644 --- a/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-init/coreos-init-9999.ebuild +++ b/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-init/coreos-init-9999.ebuild @@ -8,7 +8,8 @@ EGIT_REPO_URI="https://github.com/flatcar/init.git" if [[ "${PV}" == 9999 ]]; then KEYWORDS="~amd64 ~arm ~arm64 ~x86" else - EGIT_COMMIT="8bd8a82fb22bc46ea2cf7da94d58655e102ca26d" # flatcar-master + #EGIT_COMMIT="8bd8a82fb22bc46ea2cf7da94d58655e102ca26d" # flatcar-master + EGIT_BRANCH="kai/default-confext" KEYWORDS="amd64 arm arm64 x86" fi diff --git a/sdk_container/src/third_party/coreos-overlay/coreos/config/env/sys-apps/systemd b/sdk_container/src/third_party/coreos-overlay/coreos/config/env/sys-apps/systemd index defe7e8d0ba..fc7e86aa5cf 100644 --- a/sdk_container/src/third_party/coreos-overlay/coreos/config/env/sys-apps/systemd +++ b/sdk_container/src/third_party/coreos-overlay/coreos/config/env/sys-apps/systemd @@ -160,19 +160,6 @@ EOF -e '/^C!* \/etc\/pam\.d/d' \ -e '/^C!* \/etc\/issue/d' || die - ( - # Some OEMs prefer chronyd, so allow them to replace - # systemd-timesyncd with it. - insinto "$(systemd_get_systemunitdir)/systemd-timesyncd.service.d" - newins - flatcar.conf <<'EOF' -# Allow sysexts to ship timesyncd replacements which can have -# a Conflicts=systemd-timesyncd directive that would result -# in systemd-timesyncd not being started. -[Unit] -After=ensure-sysext.service -EOF - ) - ( # Allow @mount syscalls for systemd-udevd.service insinto "$(systemd_get_systemunitdir)/systemd-udevd.service.d" diff --git a/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0001-vpick-Don-t-use-openat-directly-but-resolve-symlinks.patch b/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0001-vpick-Don-t-use-openat-directly-but-resolve-symlinks.patch new file mode 100644 index 00000000000..2c7319246f0 --- /dev/null +++ b/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0001-vpick-Don-t-use-openat-directly-but-resolve-symlinks.patch @@ -0,0 +1,33 @@ +From 6f4b065b626edd8a06ff0c8028173e060b5e444b Mon Sep 17 00:00:00 2001 +From: Kai Lueke +Date: Thu, 20 Nov 2025 23:43:55 +0900 +Subject: [PATCH 03/10] vpick: Don't use openat directly but resolve symlinks + in given root + +With systemd-sysext --root= all symlinks should be followed relative to +the given root and direct openat usage doesn't work. +Change the openat call to use the chase helper function to resolve the +symlink in the given root. +--- + src/shared/vpick.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/shared/vpick.c b/src/shared/vpick.c +index b1b2d93054..dfe58cafa5 100644 +--- a/src/shared/vpick.c ++++ b/src/shared/vpick.c +@@ -471,9 +471,9 @@ static int make_choice( + if (!p) + return log_oom_debug(); + +- object_fd = openat(dir_fd, best_filename, O_CLOEXEC|O_PATH); ++ object_fd = chase_and_openat(toplevel_fd, p, CHASE_AT_RESOLVE_IN_ROOT, O_PATH|O_CLOEXEC, NULL); + if (object_fd < 0) +- return log_debug_errno(errno, "Failed to open '%s/%s': %m", ++ return log_debug_errno(object_fd, "Failed to open '%s/%s': %m", + empty_to_root(toplevel_path), skip_leading_slash(inode_path)); + + return pin_choice( +-- +2.52.0 + diff --git a/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0001-wait-online-set-any-by-default.patch b/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0001-wait-online-set-any-by-default.patch index 1ba8f645005..6cbf8caa1b1 100644 --- a/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0001-wait-online-set-any-by-default.patch +++ b/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0001-wait-online-set-any-by-default.patch @@ -1,7 +1,7 @@ -From 83043596b6cc74b6f049999fa660afd983dc493a Mon Sep 17 00:00:00 2001 +From 61ae07bbf1d7032eef32137b1fe299647602e3de Mon Sep 17 00:00:00 2001 From: David Michael Date: Tue, 16 Apr 2019 02:44:51 +0000 -Subject: [PATCH 1/8] wait-online: set --any by default +Subject: [PATCH] wait-online: set --any by default The systemd-networkd-wait-online command would normally continue waiting after a network interface is usable if other interfaces are @@ -11,22 +11,22 @@ Preserve previous Container Linux behavior for compatibility by setting the --any flag by default. See patches from v241 (or earlier) for the original implementation. --- - src/network/wait-online/wait-online.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) + src/network/wait-online/wait-online.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/network/wait-online/wait-online.c b/src/network/wait-online/wait-online.c -index 6f5aef903a..0acb3e76b9 100644 +index b1d0b9cde2..e07c11d807 100644 --- a/src/network/wait-online/wait-online.c +++ b/src/network/wait-online/wait-online.c -@@ -21,7 +21,7 @@ static Hashmap *arg_interfaces = NULL; +@@ -24,7 +24,7 @@ static Hashmap *arg_interfaces = NULL; static char **arg_ignore = NULL; static LinkOperationalStateRange arg_required_operstate = LINK_OPERSTATE_RANGE_INVALID; static AddressFamily arg_required_family = ADDRESS_FAMILY_NO; -static bool arg_any = false; +static bool arg_any = true; + static bool arg_requires_dns = false; - STATIC_DESTRUCTOR_REGISTER(arg_interfaces, hashmap_free_free_freep); - STATIC_DESTRUCTOR_REGISTER(arg_ignore, strv_freep); + STATIC_DESTRUCTOR_REGISTER(arg_interfaces, hashmap_freep); -- 2.51.0 diff --git a/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0002-discover-image-Follow-symlinks-in-a-given-root.patch b/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0002-discover-image-Follow-symlinks-in-a-given-root.patch new file mode 100644 index 00000000000..fcef9d20ac1 --- /dev/null +++ b/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0002-discover-image-Follow-symlinks-in-a-given-root.patch @@ -0,0 +1,343 @@ +From 9b6f1b1d8e1066a513a2939c613b36c9e887512c Mon Sep 17 00:00:00 2001 +From: Kai Lueke +Date: Thu, 20 Nov 2025 23:43:55 +0900 +Subject: [PATCH 04/10] discover-image: Follow symlinks in a given root + +So far systemd-sysext with --root= specified didn't follow extension +symlinks (such as the "current" symlinks managed by systemd-sysupdate). +The main use case is running systemd-sysext --root=/sysroot for setting +up the overlay mounts already from the initrd. + +Resolve symlinks correctly but don't defend against later symlink races +that would access a path outside of the given root. Malicous live +modifications are not a realistic threat model and anyway for that one +would need to rework how the image entry is passed over up to the point +when the loop device is set up. This change here does not introduce this +weakness nor does it expose it more than before. Thus, make it explicit +that setting up the extensions for a given --root= implies a certain +trust into this given root tree that it does not try do race conditions +with symlinks to trick systemd-sysext to mount a file outside --root=. +Without a strict --image-policy= set we would anyway mount filesystems +right away which is another attack vector but, again, the main use case +is to do this for the final system which is trusted at this stage. +--- + src/shared/discover-image.c | 162 +++++++++++++++++++++++++++--------- + 1 file changed, 122 insertions(+), 40 deletions(-) + +diff --git a/src/shared/discover-image.c b/src/shared/discover-image.c +index 1402303a8e..97c4284eca 100644 +--- a/src/shared/discover-image.c ++++ b/src/shared/discover-image.c +@@ -356,6 +356,8 @@ static int image_make( + + /* We explicitly *do* follow symlinks here, since we want to allow symlinking trees, raw files and block + * devices into /var/lib/machines/, and treat them normally. ++ * Note that if the caller does not want to follow symlinks (and does not care about symlink races) ++ * then the caller should pass in a resolved dir_path and filename and an fd. + * + * This function returns -ENOENT if we can't find the image after all, and -EMEDIUMTYPE if it's not a file we + * recognize. */ +@@ -700,10 +702,7 @@ int image_find(RuntimeScope scope, + const char *root, + Image **ret) { + +- /* As mentioned above, we follow symlinks on this fstatat(), because we want to permit people to +- * symlink block devices into the search path. (For now, we disable that when operating relative to +- * some root directory.) */ +- int open_flags = root ? O_NOFOLLOW : 0, r; ++ int r; + + assert(scope < _RUNTIME_SCOPE_MAX && scope != RUNTIME_SCOPE_GLOBAL); + assert(class >= 0); +@@ -718,16 +717,24 @@ int image_find(RuntimeScope scope, + if (!names) + return -ENOMEM; + ++ _cleanup_close_ int root_fd = AT_FDCWD; ++ if (root) { ++ root_fd = open(root, O_CLOEXEC|O_DIRECTORY|O_PATH); ++ if (root_fd < 0) { ++ log_debug_errno(errno, "Failed to open root directory '%s': %m", root); ++ return -errno; ++ } ++ } ++ + _cleanup_strv_free_ char **search = NULL; + r = pick_image_search_path(scope, class, root, &search); + if (r < 0) + return r; + + STRV_FOREACH(path, search) { +- _cleanup_free_ char *resolved = NULL; + _cleanup_closedir_ DIR *d = NULL; + +- r = chase_and_opendir(*path, root, CHASE_PREFIX_ROOT, &resolved, &d); ++ r = chase_and_opendir(*path, root, CHASE_PREFIX_ROOT, NULL, &d); + if (r == -ENOENT) + continue; + if (r < 0) +@@ -736,11 +743,20 @@ int image_find(RuntimeScope scope, + STRV_FOREACH(n, names) { + _cleanup_free_ char *fname_buf = NULL; + const char *fname = *n; ++ _cleanup_free_ char *fname_path = NULL; ++ _cleanup_free_ char *resolved_file = NULL; ++ _cleanup_close_ int fd = -EBADF; ++ _cleanup_close_ int subdirfd = -EBADF; + +- _cleanup_close_ int fd = openat(dirfd(d), fname, O_PATH|O_CLOEXEC|open_flags); ++ fname_path = path_join(*path, fname); ++ if (!fname_path) ++ return -ENOMEM; ++ ++ /* Follow symlinks only inside given root */ ++ fd = chase_and_open(fname_path, root, CHASE_PREFIX_ROOT, O_PATH|O_CLOEXEC, &resolved_file); + if (fd < 0) { +- if (errno != ENOENT) +- return -errno; ++ if (fd != -ENOENT) ++ return fd; + + continue; + } +@@ -769,10 +785,6 @@ int image_find(RuntimeScope scope, + + *ASSERT_PTR(endswith(suffix, ".v")) = 0; + +- _cleanup_free_ char *vp = path_join(resolved, fname); +- if (!vp) +- return -ENOMEM; +- + PickFilter filter = { + .type_mask = endswith(suffix, ".raw") ? (UINT32_C(1) << DT_REG) | (UINT32_C(1) << DT_BLK) : (UINT32_C(1) << DT_DIR), + .basename = name, +@@ -782,23 +794,27 @@ int image_find(RuntimeScope scope, + + _cleanup_(pick_result_done) PickResult result = PICK_RESULT_NULL; + r = path_pick(root, +- /* toplevel_fd= */ AT_FDCWD, +- vp, ++ root_fd, ++ fname_path, + &filter, +- PICK_ARCHITECTURE|PICK_TRIES, ++ PICK_ARCHITECTURE|PICK_TRIES|PICK_RESOLVE, + &result); + if (r < 0) { +- log_debug_errno(r, "Failed to pick versioned image on '%s', skipping: %m", vp); ++ log_debug_errno(r, "Failed to pick versioned image on '%s/%s', skipping: %m", strempty(root), skip_leading_slash(fname_path)); + continue; + } + if (!result.path) { +- log_debug("Found versioned directory '%s', without matching entry, skipping: %m", vp); ++ log_debug("Found versioned directory '%s/%s', without matching entry, skipping.", strempty(root), skip_leading_slash(fname_path)); + continue; + } + + /* Refresh the stat data for the discovered target */ + st = result.st; +- fd = safe_close(fd); ++ /* Set subdirfd to indicate it should be used instead of dirfd(d). ++ * We reuse the O_PATH fd because it's only used in openat style in image_make(). ++ * This subdirfd can be deleted with https://github.com/systemd/systemd/pull/39970 */ ++ subdirfd = TAKE_FD(fd); ++ close_and_replace(fd, result.fd); + + _cleanup_free_ char *bn = NULL; + r = path_extract_filename(result.path, &bn); +@@ -812,13 +828,38 @@ int image_find(RuntimeScope scope, + return log_oom(); + + fname = fname_buf; ++ fname_path = mfree(fname_path); ++ fname_path = path_join(*path, fname); ++ if (!fname_path) ++ return log_oom(); + ++ resolved_file = mfree(resolved_file); ++ resolved_file = path_join(root, result.path); ++ if (!resolved_file) ++ return log_oom(); + } else if (!S_ISDIR(st.st_mode) && !S_ISBLK(st.st_mode)) { + log_debug("Ignoring non-directory and non-block device file '%s' without suffix.", fname); + continue; + } + +- r = image_make(class, name, dirfd(d), resolved, fname, fd, &st, ret); ++ /* Only put resolved paths into the image entry. ++ * Defending against symlink races is out of scope ++ * and we trust a given root in that regard. */ ++ _cleanup_free_ char *resolved_dir = NULL; ++ _cleanup_free_ char *resolved_fname = NULL; ++ ++ r = path_extract_directory(resolved_file, &resolved_dir); ++ if (r < 0) { ++ log_debug_errno(r, "Failed to extract directory name of image path '%s', skipping: %m", resolved_file); ++ continue; ++ } ++ r = path_extract_filename(resolved_file, &resolved_fname); ++ if (r < 0) { ++ log_debug_errno(r, "Failed to extract basename of image path '%s', skipping: %m", resolved_file); ++ continue; ++ } ++ ++ r = image_make(class, name, subdirfd == -EBADF ? dirfd(d) : subdirfd, resolved_dir, resolved_fname, fd, &st, ret); + if (IN_SET(r, -ENOENT, -EMEDIUMTYPE)) + continue; + if (r < 0) +@@ -899,26 +940,31 @@ int image_discover( + const char *root, + Hashmap **images) { + +- /* As mentioned above, we follow symlinks on this fstatat(), because we want to permit people to +- * symlink block devices into the search path. (For now, we disable that when operating relative to +- * some root directory.) */ +- int open_flags = root ? O_NOFOLLOW : 0, r; ++ int r; + + assert(scope < _RUNTIME_SCOPE_MAX && scope != RUNTIME_SCOPE_GLOBAL); + assert(class >= 0); + assert(class < _IMAGE_CLASS_MAX); + assert(images); + ++ _cleanup_close_ int root_fd = AT_FDCWD; ++ if (root) { ++ root_fd = open(root, O_CLOEXEC|O_DIRECTORY|O_PATH); ++ if (root_fd < 0) { ++ log_debug_errno(errno, "Failed to open root directory '%s': %m", root); ++ return -errno; ++ } ++ } ++ + _cleanup_strv_free_ char **search = NULL; + r = pick_image_search_path(scope, class, root, &search); + if (r < 0) + return r; + + STRV_FOREACH(path, search) { +- _cleanup_free_ char *resolved = NULL; + _cleanup_closedir_ DIR *d = NULL; + +- r = chase_and_opendir(*path, root, CHASE_PREFIX_ROOT, &resolved, &d); ++ r = chase_and_opendir(*path, root, CHASE_PREFIX_ROOT, NULL, &d); + if (r == -ENOENT) + continue; + if (r < 0) +@@ -928,14 +974,23 @@ int image_discover( + _cleanup_free_ char *pretty = NULL, *fname_buf = NULL; + _cleanup_(image_unrefp) Image *image = NULL; + const char *fname = de->d_name; ++ _cleanup_free_ char *fname_path = NULL; ++ _cleanup_free_ char *resolved_file = NULL; ++ _cleanup_close_ int fd = -EBADF; ++ _cleanup_close_ int subdirfd = -EBADF; + + if (dot_or_dot_dot(fname)) + continue; + +- _cleanup_close_ int fd = openat(dirfd(d), fname, O_PATH|O_CLOEXEC|open_flags); ++ fname_path = path_join(*path, fname); ++ if (!fname_path) ++ return -ENOMEM; ++ ++ /* Follow symlinks only inside given root */ ++ fd = chase_and_open(fname_path, root, CHASE_PREFIX_ROOT, O_PATH|O_CLOEXEC, &resolved_file); + if (fd < 0) { +- if (errno != ENOENT) +- return -errno; ++ if (fd != -ENOENT) ++ return fd; + + continue; /* Vanished while we were looking at it */ + } +@@ -977,10 +1032,6 @@ int image_discover( + continue; + } + +- _cleanup_free_ char *vp = path_join(resolved, fname); +- if (!vp) +- return -ENOMEM; +- + PickFilter filter = { + .type_mask = endswith(suffix, ".raw") ? (UINT32_C(1) << DT_REG) | (UINT32_C(1) << DT_BLK) : (UINT32_C(1) << DT_DIR), + .basename = pretty, +@@ -990,23 +1041,27 @@ int image_discover( + + _cleanup_(pick_result_done) PickResult result = PICK_RESULT_NULL; + r = path_pick(root, +- /* toplevel_fd= */ AT_FDCWD, +- vp, ++ root_fd, ++ fname_path, + &filter, +- PICK_ARCHITECTURE|PICK_TRIES, ++ PICK_ARCHITECTURE|PICK_TRIES|PICK_RESOLVE, + &result); + if (r < 0) { +- log_debug_errno(r, "Failed to pick versioned image on '%s', skipping: %m", vp); ++ log_debug_errno(r, "Failed to pick versioned image on '%s/%s', skipping: %m", strempty(root), skip_leading_slash(fname_path)); + continue; + } + if (!result.path) { +- log_debug("Found versioned directory '%s', without matching entry, skipping: %m", vp); ++ log_debug("Found versioned directory '%s/%s', without matching entry, skipping.", strempty(root), skip_leading_slash(fname_path)); + continue; + } + + /* Refresh the stat data for the discovered target */ + st = result.st; +- fd = safe_close(fd); ++ /* Set subdirfd to indicate it should be used instead of dirfd(d). ++ * We reuse the O_PATH fd because it's only used in openat style in image_make(). ++ * This subdirfd can be deleted with https://github.com/systemd/systemd/pull/39970 */ ++ subdirfd = TAKE_FD(fd); ++ close_and_replace(fd, result.fd); + + _cleanup_free_ char *bn = NULL; + r = path_extract_filename(result.path, &bn); +@@ -1020,6 +1075,15 @@ int image_discover( + return log_oom(); + + fname = fname_buf; ++ fname_path = mfree(fname_path); ++ fname_path = path_join(*path, fname); ++ if (!fname_path) ++ return log_oom(); ++ ++ resolved_file = mfree(resolved_file); ++ resolved_file = path_join(root, result.path); ++ if (!resolved_file) ++ return log_oom(); + } else { + r = extract_image_basename( + fname, +@@ -1052,7 +1116,25 @@ int image_discover( + if (hashmap_contains(*images, pretty)) + continue; + +- r = image_make(class, pretty, dirfd(d), resolved, fname, fd, &st, &image); ++ /* Only put resolved paths into the image entry. ++ * Defending against symlink races is out of scope ++ * and we trust a given root in that regard. */ ++ _cleanup_free_ char *resolved_dir = NULL; ++ _cleanup_free_ char *resolved_fname = NULL; ++ ++ r = path_extract_directory(resolved_file, &resolved_dir); ++ if (r < 0) { ++ log_debug_errno(r, "Failed to extract directory name of image path '%s', skipping: %m", resolved_file); ++ continue; ++ } ++ r = path_extract_filename(resolved_file, &resolved_fname); ++ if (r < 0) { ++ log_debug_errno(r, "Failed to extract basename of image path '%s', skipping: %m", resolved_file); ++ continue; ++ } ++ ++ r = image_make(class, pretty, subdirfd == -EBADF ? dirfd(d) : subdirfd, resolved_dir, resolved_fname, fd, &st, &image); ++ + if (IN_SET(r, -ENOENT, -EMEDIUMTYPE)) + continue; + if (r < 0) +-- +2.52.0 + diff --git a/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0003-sysext-Use-correct-image-name-for-extension-release-.patch b/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0003-sysext-Use-correct-image-name-for-extension-release-.patch new file mode 100644 index 00000000000..adedfd3268a --- /dev/null +++ b/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0003-sysext-Use-correct-image-name-for-extension-release-.patch @@ -0,0 +1,57 @@ +From 5480f56002399069f74f30ce3ef620ec44ecf527 Mon Sep 17 00:00:00 2001 +From: Kai Lueke +Date: Thu, 20 Nov 2025 23:43:55 +0900 +Subject: [PATCH 3/7] sysext: Use correct image name for extension release + checks + +For the extension release check the image name is needed and was derived +from the backing file of the loop device. However, this can have a +different name when symlinks were resolved. The surprising behavior was +that it worked when the target name started with the extension name and +_ because that's what's supported to chop off version suffixes. However, +we should not have such strict requirements for the target name and also +allow - as version separator and entirely different names/prefixes, the +same way as we also do for directories instead of raw images. + +Do not use the image name derived from the backing file of the loop +device but directly the extension name we have at hand. +--- + src/shared/discover-image.c | 5 +++++ + src/sysext/sysext.c | 5 +++++ + 2 files changed, 10 insertions(+) + +diff --git a/src/shared/discover-image.c b/src/shared/discover-image.c +index 91f4407b0e..480ffd221c 100644 +--- a/src/shared/discover-image.c ++++ b/src/shared/discover-image.c +@@ -1822,6 +1822,11 @@ int image_read_metadata(Image *i, const ImagePolicy *image_policy) { + if (r < 0) + return r; + ++ /* Do not use the image name derived from the backing file of the loop device */ ++ r = free_and_strdup(&m->image_name, i->name); ++ if (r < 0) ++ return r; ++ + r = dissected_image_acquire_metadata( + m, + /* userns_fd= */ -EBADF, +diff --git a/src/sysext/sysext.c b/src/sysext/sysext.c +index 5d432b42da..72da02cd89 100644 +--- a/src/sysext/sysext.c ++++ b/src/sysext/sysext.c +@@ -1819,6 +1819,11 @@ static int merge_subprocess( + if (r < 0) + return r; + ++ /* Do not use the image name derived from the backing file of the loop device */ ++ r = free_and_strdup(&m->image_name, img->name); ++ if (r < 0) ++ return r; ++ + r = dissected_image_load_verity_sig_partition( + m, + d->fd, +-- +2.51.1 + diff --git a/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0004-test-Add-tests-for-handling-symlinks-with-systemd-sy.patch b/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0004-test-Add-tests-for-handling-symlinks-with-systemd-sy.patch new file mode 100644 index 00000000000..3f5c483ad70 --- /dev/null +++ b/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0004-test-Add-tests-for-handling-symlinks-with-systemd-sy.patch @@ -0,0 +1,334 @@ +From f2e3cd402e64528454d3825681ccf242ff1b46af Mon Sep 17 00:00:00 2001 +From: Kai Lueke +Date: Thu, 20 Nov 2025 23:43:55 +0900 +Subject: [PATCH 4/7] test: Add tests for handling symlinks with systemd-sysext + +When we now allow following symlinks inside a --root= we should also +test that it works in various cases from simple relative and absolute +symlinks to .v being a symlink itself or its contents, both for +directory and for .raw image extensions. While at it, also add a simple +test for .v without symlinks which wasn't there for direct usage of +systemd-sysext. +--- + test/units/TEST-50-DISSECT.sysext.sh | 298 +++++++++++++++++++++++++++ + 1 file changed, 298 insertions(+) + +diff --git a/test/units/TEST-50-DISSECT.sysext.sh b/test/units/TEST-50-DISSECT.sysext.sh +index ecf0b83b1d..3eec224eb6 100755 +--- a/test/units/TEST-50-DISSECT.sysext.sh ++++ b/test/units/TEST-50-DISSECT.sysext.sh +@@ -163,6 +163,24 @@ prepare_extension_image_with_matching_id_like() { + prepend_trap "rm -rf ${ext_dir@Q}" + } + ++prepare_extension_image_raw() { ++ local root=${1:-} ++ local hierarchy=${2:?} ++ local ext_dir ext_release name ++ ++ name="test-extension" ++ ext_dir="$root/var/lib/extensions/$name" ++ ext_release="$ext_dir/usr/lib/extension-release.d/extension-release.$name" ++ mkdir -p "${ext_release%/*}" ++ echo "ID=_any" >"$ext_release" ++ mkdir -p "$ext_dir/$hierarchy" ++ touch "$ext_dir$hierarchy/preexisting-file-in-extension-image" ++ mksquashfs "$ext_dir" "$ext_dir.raw" -all-root -noappend -quiet ++ rm -rf "$ext_dir" ++ ++ prepend_trap "rm -rf ${ext_dir@Q}.raw" ++} ++ + prepare_extension_mutable_dir() { + local dir=${1:?} + +@@ -1104,6 +1122,286 @@ fi + rm "${fake_root}/etc/initrd-release" + ) + ++# A couple of symlink tests follow below ++ ++( init_trap ++: "Check if following a relative extension directory symlink works with and without --root=" ++fake_root=${roots_dir:+"$roots_dir/follow-relative-dir-symlink"} ++hierarchy=/opt ++ ++prepare_root "$fake_root" "$hierarchy" ++prepare_extension_image "$fake_root" "$hierarchy" ++mv -T "$fake_root/var/lib/extensions/test-extension" "$fake_root/var/othername-extension" ++ln -s "../../othername-extension" "$fake_root/var/lib/extensions/test-extension" ++prepare_read_only_hierarchy "$fake_root" "$hierarchy" ++ ++run_systemd_sysext "$fake_root" merge ++extension_verify_after_merge "$fake_root" "$hierarchy" -e -h ++ ++run_systemd_sysext "$fake_root" unmerge ++extension_verify_after_unmerge "$fake_root" "$hierarchy" -h ++rm -rf "$fake_root/var/othername-extension" ++) ++ ++( init_trap ++: "Check if following an absolute extension directory symlink works with and without --root=" ++fake_root=${roots_dir:+"$roots_dir/follow-absolute-dir-symlink"} ++hierarchy=/opt ++ ++prepare_root "$fake_root" "$hierarchy" ++prepare_extension_image "$fake_root" "$hierarchy" ++mv -T "$fake_root/var/lib/extensions/test-extension" "$fake_root/var/othername-extension" ++ln -s "/var/othername-extension" "$fake_root/var/lib/extensions/test-extension" ++prepare_read_only_hierarchy "$fake_root" "$hierarchy" ++ ++run_systemd_sysext "$fake_root" merge ++extension_verify_after_merge "$fake_root" "$hierarchy" -e -h ++ ++run_systemd_sysext "$fake_root" unmerge ++extension_verify_after_unmerge "$fake_root" "$hierarchy" -h ++rm -rf "$fake_root/var/othername-extension" ++) ++ ++( init_trap ++: "Check if following a relative extension image symlink works with and without --root=" ++fake_root=${roots_dir:+"$roots_dir/follow-relative-image-symlink"} ++hierarchy=/opt ++ ++prepare_root "$fake_root" "$hierarchy" ++prepare_extension_image_raw "$fake_root" "$hierarchy" ++mv "$fake_root/var/lib/extensions/test-extension.raw" "$fake_root/var/othername-extension.raw" ++ln -s "../../othername-extension.raw" "$fake_root/var/lib/extensions/test-extension.raw" ++prepare_read_only_hierarchy "$fake_root" "$hierarchy" ++ ++run_systemd_sysext "$fake_root" merge ++extension_verify_after_merge "$fake_root" "$hierarchy" -e -h ++ ++run_systemd_sysext "$fake_root" unmerge ++extension_verify_after_unmerge "$fake_root" "$hierarchy" -h ++rm -rf "$fake_root/var/othername-extension.raw" ++) ++ ++( init_trap ++: "Check if following an absolute extension image symlink works with and without --root=" ++fake_root=${roots_dir:+"$roots_dir/follow-absolute-image-symlink"} ++hierarchy=/opt ++ ++prepare_root "$fake_root" "$hierarchy" ++prepare_extension_image_raw "$fake_root" "$hierarchy" ++mv "$fake_root/var/lib/extensions/test-extension.raw" "$fake_root/var/othername-extension.raw" ++ln -s "/var/othername-extension.raw" "$fake_root/var/lib/extensions/test-extension.raw" ++prepare_read_only_hierarchy "$fake_root" "$hierarchy" ++ ++run_systemd_sysext "$fake_root" merge ++extension_verify_after_merge "$fake_root" "$hierarchy" -e -h ++ ++run_systemd_sysext "$fake_root" unmerge ++extension_verify_after_unmerge "$fake_root" "$hierarchy" -h ++rm -rf "$fake_root/var/othername-extension.raw" ++) ++ ++# And now a couple of vpick tests, including following symlinks ++ ++( init_trap ++: "Check if vpick works for directory extensions" ++fake_root=${roots_dir:+"$roots_dir/vpick-dir"} ++hierarchy=/opt ++ ++prepare_root "$fake_root" "$hierarchy" ++prepare_extension_image "$fake_root" "$hierarchy" ++mkdir -p "$fake_root/var/lib/extensions/test-extension.v" ++mv -T "$fake_root/var/lib/extensions/test-extension" "$fake_root/var/lib/extensions/test-extension.v/test-extension_1.0" ++prepare_read_only_hierarchy "$fake_root" "$hierarchy" ++ ++run_systemd_sysext "$fake_root" merge ++extension_verify_after_merge "$fake_root" "$hierarchy" -e -h ++ ++run_systemd_sysext "$fake_root" unmerge ++extension_verify_after_unmerge "$fake_root" "$hierarchy" -h ++rm -rf "$fake_root/var/lib/extensions/test-extension.v" ++) ++ ++( init_trap ++: "Check if vpick works for image extensions" ++fake_root=${roots_dir:+"$roots_dir/vpick-image"} ++hierarchy=/opt ++ ++prepare_root "$fake_root" "$hierarchy" ++prepare_extension_image_raw "$fake_root" "$hierarchy" ++mkdir -p "$fake_root/var/lib/extensions/test-extension.raw.v" ++mv "$fake_root/var/lib/extensions/test-extension.raw" "$fake_root/var/lib/extensions/test-extension.raw.v/test-extension_1.0.raw" ++prepare_read_only_hierarchy "$fake_root" "$hierarchy" ++ ++run_systemd_sysext "$fake_root" merge ++extension_verify_after_merge "$fake_root" "$hierarchy" -e -h ++ ++run_systemd_sysext "$fake_root" unmerge ++extension_verify_after_unmerge "$fake_root" "$hierarchy" -h ++rm -rf "$fake_root/var/lib/extensions/test-extension.raw.v" ++) ++ ++( init_trap ++: "Check if vpick works for directory extensions if .v is a relative symlink" ++fake_root=${roots_dir:+"$roots_dir/vpick-dir-relative-symlink"} ++hierarchy=/opt ++ ++prepare_root "$fake_root" "$hierarchy" ++prepare_extension_image "$fake_root" "$hierarchy" ++mkdir -p "$fake_root/var/test-extension-vpick" ++mv -T "$fake_root/var/lib/extensions/test-extension" "$fake_root/var/test-extension-vpick/test-extension_1.0" ++ln -s "../../test-extension-vpick" "$fake_root/var/lib/extensions/test-extension.v" ++prepare_read_only_hierarchy "$fake_root" "$hierarchy" ++ ++run_systemd_sysext "$fake_root" merge ++extension_verify_after_merge "$fake_root" "$hierarchy" -e -h ++ ++run_systemd_sysext "$fake_root" unmerge ++extension_verify_after_unmerge "$fake_root" "$hierarchy" -h ++rm -rf "$fake_root/var/lib/extensions/test-extension.v" "$fake_root/var/test-extension-vpick" ++) ++ ++( init_trap ++: "Check if vpick works for directory extensions if .v is an absolute symlink" ++fake_root=${roots_dir:+"$roots_dir/vpick-dir-absolute-symlink"} ++hierarchy=/opt ++ ++prepare_root "$fake_root" "$hierarchy" ++prepare_extension_image "$fake_root" "$hierarchy" ++mkdir -p "$fake_root/var/test-extension-vpick" ++mv -T "$fake_root/var/lib/extensions/test-extension" "$fake_root/var/test-extension-vpick/test-extension_1.0" ++ln -s "/var/test-extension-vpick" "$fake_root/var/lib/extensions/test-extension.v" ++prepare_read_only_hierarchy "$fake_root" "$hierarchy" ++ ++run_systemd_sysext "$fake_root" merge ++extension_verify_after_merge "$fake_root" "$hierarchy" -e -h ++ ++run_systemd_sysext "$fake_root" unmerge ++extension_verify_after_unmerge "$fake_root" "$hierarchy" -h ++rm -rf "$fake_root/var/lib/extensions/test-extension.v" "$fake_root/var/test-extension-vpick" ++) ++ ++( init_trap ++: "Check if vpick works for image extensions if .v is a relative symlink" ++fake_root=${roots_dir:+"$roots_dir/vpick-image-relative-symlink"} ++hierarchy=/opt ++ ++prepare_root "$fake_root" "$hierarchy" ++prepare_extension_image_raw "$fake_root" "$hierarchy" ++mkdir -p "$fake_root/var/test-extension-vpick" ++mv "$fake_root/var/lib/extensions/test-extension.raw" "$fake_root/var/test-extension-vpick/test-extension_1.0.raw" ++ln -s "../../test-extension-vpick" "$fake_root/var/lib/extensions/test-extension.raw.v" ++prepare_read_only_hierarchy "$fake_root" "$hierarchy" ++ ++run_systemd_sysext "$fake_root" merge ++extension_verify_after_merge "$fake_root" "$hierarchy" -e -h ++ ++run_systemd_sysext "$fake_root" unmerge ++extension_verify_after_unmerge "$fake_root" "$hierarchy" -h ++rm -rf "$fake_root/var/lib/extensions/test-extension.raw.v" "$fake_root/var/test-extension-vpick" ++) ++ ++( init_trap ++: "Check if vpick works for image extensions if .v is an absolute symlink" ++fake_root=${roots_dir:+"$roots_dir/vpick-image-absolute-symlink"} ++hierarchy=/opt ++ ++prepare_root "$fake_root" "$hierarchy" ++prepare_extension_image_raw "$fake_root" "$hierarchy" ++mkdir -p "$fake_root/var/test-extension-vpick" ++mv "$fake_root/var/lib/extensions/test-extension.raw" "$fake_root/var/test-extension-vpick/test-extension_1.0.raw" ++ln -s "/var/test-extension-vpick" "$fake_root/var/lib/extensions/test-extension.raw.v" ++prepare_read_only_hierarchy "$fake_root" "$hierarchy" ++ ++run_systemd_sysext "$fake_root" merge ++extension_verify_after_merge "$fake_root" "$hierarchy" -e -h ++ ++run_systemd_sysext "$fake_root" unmerge ++extension_verify_after_unmerge "$fake_root" "$hierarchy" -h ++rm -rf "$fake_root/var/lib/extensions/test-extension.raw.v" "$fake_root/var/test-extension-vpick" ++) ++ ++( init_trap ++: "Check if vpick works for directory extensions if inside a .v there is a relative symlink" ++fake_root=${roots_dir:+"$roots_dir/vpick-dir-relative-symlink-inside"} ++hierarchy=/opt ++ ++prepare_root "$fake_root" "$hierarchy" ++prepare_extension_image "$fake_root" "$hierarchy" ++mv -T "$fake_root/var/lib/extensions/test-extension" "$fake_root/var/othername-extension" ++mkdir -p "$fake_root/var/lib/extensions/test-extension.v" ++ln -s "../../../othername-extension" "$fake_root/var/lib/extensions/test-extension.v/test-extension_1.0" ++prepare_read_only_hierarchy "$fake_root" "$hierarchy" ++ ++run_systemd_sysext "$fake_root" merge ++extension_verify_after_merge "$fake_root" "$hierarchy" -e -h ++ ++run_systemd_sysext "$fake_root" unmerge ++extension_verify_after_unmerge "$fake_root" "$hierarchy" -h ++rm -rf "$fake_root/var/lib/extensions/test-extension.v" "$fake_root/var/othername-extension" ++) ++ ++( init_trap ++: "Check if vpick works for directory extensions if inside a .v there is an absolute symlink" ++fake_root=${roots_dir:+"$roots_dir/vpick-dir-absolute-symlink-inside"} ++hierarchy=/opt ++ ++prepare_root "$fake_root" "$hierarchy" ++prepare_extension_image "$fake_root" "$hierarchy" ++mv -T "$fake_root/var/lib/extensions/test-extension" "$fake_root/var/othername-extension" ++mkdir -p "$fake_root/var/lib/extensions/test-extension.v" ++ln -s "/var/othername-extension" "$fake_root/var/lib/extensions/test-extension.v/test-extension_1.0" ++prepare_read_only_hierarchy "$fake_root" "$hierarchy" ++ ++run_systemd_sysext "$fake_root" merge ++extension_verify_after_merge "$fake_root" "$hierarchy" -e -h ++ ++run_systemd_sysext "$fake_root" unmerge ++extension_verify_after_unmerge "$fake_root" "$hierarchy" -h ++rm -rf "$fake_root/var/lib/extensions/test-extension.v" "$fake_root/var/othername-extension" ++) ++ ++( init_trap ++: "Check if vpick works for image extensions if inside a .v there is a relative symlink" ++fake_root=${roots_dir:+"$roots_dir/vpick-image-relative-symlink-inside"} ++hierarchy=/opt ++ ++prepare_root "$fake_root" "$hierarchy" ++prepare_extension_image_raw "$fake_root" "$hierarchy" ++mv "$fake_root/var/lib/extensions/test-extension.raw" "$fake_root/var/othername-extension.raw" ++mkdir -p "$fake_root/var/lib/extensions/test-extension.raw.v" ++ln -s "../../../othername-extension.raw" "$fake_root/var/lib/extensions/test-extension.raw.v/test-extension_1.0.raw" ++prepare_read_only_hierarchy "$fake_root" "$hierarchy" ++ ++run_systemd_sysext "$fake_root" merge ++extension_verify_after_merge "$fake_root" "$hierarchy" -e -h ++ ++run_systemd_sysext "$fake_root" unmerge ++extension_verify_after_unmerge "$fake_root" "$hierarchy" -h ++rm -rf "$fake_root/var/lib/extensions/test-extension.raw.v" "$fake_root/var/othername-extension.raw" ++) ++ ++( init_trap ++: "Check if vpick works for image extensions if inside a .v there is an absolute symlink" ++fake_root=${roots_dir:+"$roots_dir/vpick-image-absolute-symlink-inside"} ++hierarchy=/opt ++ ++prepare_root "$fake_root" "$hierarchy" ++prepare_extension_image_raw "$fake_root" "$hierarchy" ++mv "$fake_root/var/lib/extensions/test-extension.raw" "$fake_root/var/othername-extension.raw" ++mkdir -p "$fake_root/var/lib/extensions/test-extension.raw.v" ++ln -s "/var/othername-extension.raw" "$fake_root/var/lib/extensions/test-extension.raw.v/test-extension_1.0.raw" ++prepare_read_only_hierarchy "$fake_root" "$hierarchy" ++ ++run_systemd_sysext "$fake_root" merge ++extension_verify_after_merge "$fake_root" "$hierarchy" -e -h ++ ++run_systemd_sysext "$fake_root" unmerge ++extension_verify_after_unmerge "$fake_root" "$hierarchy" -h ++rm -rf "$fake_root/var/lib/extensions/test-extension.raw.v" "$fake_root/var/othername-extension.raw" ++) ++ ++# Done with the above vpick symlink tests for --root= and without ++ + } # End of run_sysext_tests + + +-- +2.51.1 + diff --git a/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0005-Revert-getty-Pass-tty-to-use-by-agetty-via-stdin.patch b/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0005-Revert-getty-Pass-tty-to-use-by-agetty-via-stdin.patch index d380b96a9cc..0bbf3aff06d 100644 --- a/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0005-Revert-getty-Pass-tty-to-use-by-agetty-via-stdin.patch +++ b/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0005-Revert-getty-Pass-tty-to-use-by-agetty-via-stdin.patch @@ -1,7 +1,7 @@ -From 8064e1544a2b89f8389c0469ed4879a287a045a7 Mon Sep 17 00:00:00 2001 +From 306da1d06e84a721ac34fbc303b4629b2c1c7257 Mon Sep 17 00:00:00 2001 From: Sayan Chowdhury Date: Fri, 16 Dec 2022 16:28:26 +0530 -Subject: [PATCH 5/8] Revert "getty: Pass tty to use by agetty via stdin" +Subject: [PATCH] Revert "getty: Pass tty to use by agetty via stdin" This reverts commit b4bf9007cbee7dc0b1356897344ae2a7890df84c. @@ -17,15 +17,15 @@ Signed-off-by: Sayan Chowdhury 4 files changed, 4 insertions(+), 12 deletions(-) diff --git a/units/console-getty.service.in b/units/console-getty.service.in -index 33e6368db1..1f2d8b910f 100644 +index 967d8337ab..cde822afc8 100644 --- a/units/console-getty.service.in +++ b/units/console-getty.service.in -@@ -22,12 +22,10 @@ ConditionPathExists=/dev/console +@@ -20,12 +20,10 @@ Before=getty.target + ConditionPathExists=/dev/console + [Service] - # The '-o' option value tells agetty to replace 'login' arguments with '--' for - # safety, and then the entered username. --ExecStart=-/sbin/agetty -o '-- \\u' --noreset --noclear --keep-baud 115200,57600,38400,9600 - ${TERM} -+ExecStart=-/sbin/agetty -o '-- \\u' --noreset --noclear --keep-baud 115200,57600,38400,9600 console ${TERM} +-ExecStart=-/sbin/agetty --noreset --noclear --issue-file=/etc/issue:/etc/issue.d:/run/issue.d:/usr/lib/issue.d --keep-baud 115200,57600,38400,9600 - ${TERM} ++ExecStart=-/sbin/agetty --noreset --noclear --issue-file=/etc/issue:/etc/issue.d:/run/issue.d:/usr/lib/issue.d --keep-baud 115200,57600,38400,9600 console ${TERM} Type=idle Restart=always UtmpIdentifier=cons @@ -35,15 +35,15 @@ index 33e6368db1..1f2d8b910f 100644 TTYReset=yes TTYVHangup=yes diff --git a/units/container-getty@.service.in b/units/container-getty@.service.in -index 7573532d6d..5f27653d1f 100644 +index e0b27613df..2868d56ad0 100644 --- a/units/container-getty@.service.in +++ b/units/container-getty@.service.in -@@ -27,13 +27,11 @@ Before=rescue.service +@@ -25,13 +25,11 @@ Conflicts=rescue.service + Before=rescue.service + [Service] - # The '-o' option value tells agetty to replace 'login' arguments with '--' for - # safety, and then the entered username. --ExecStart=-/sbin/agetty -o '-- \\u' --noreset --noclear - ${TERM} -+ExecStart=-/sbin/agetty -o '-- \\u' --noreset --noclear pts/%I ${TERM} +-ExecStart=-/sbin/agetty --noreset --noclear --issue-file=/etc/issue:/etc/issue.d:/run/issue.d:/usr/lib/issue.d - ${TERM} ++ExecStart=-/sbin/agetty --noreset --noclear --issue-file=/etc/issue:/etc/issue.d:/run/issue.d:/usr/lib/issue.d pts/%I ${TERM} Type=idle Restart=always RestartSec=0 @@ -54,15 +54,15 @@ index 7573532d6d..5f27653d1f 100644 TTYReset=yes TTYVHangup=yes diff --git a/units/getty@.service.in b/units/getty@.service.in -index f30bba406d..1819627d1c 100644 +index 104c4acc96..bedf0aae54 100644 --- a/units/getty@.service.in +++ b/units/getty@.service.in -@@ -36,13 +36,11 @@ ConditionPathExists=/dev/tty0 +@@ -34,13 +34,11 @@ Before=rescue.service + ConditionPathExists=/dev/tty0 + [Service] - # The '-o' option value tells agetty to replace 'login' arguments with '--' for - # safety, and then the entered username. --ExecStart=-/sbin/agetty -o '-- \\u' --noreset --noclear - ${TERM} -+ExecStart=-/sbin/agetty -o '-- \\u' --noreset --noclear %I ${TERM} +-ExecStart=-/sbin/agetty --noreset --noclear --issue-file=/etc/issue:/etc/issue.d:/run/issue.d:/usr/lib/issue.d - ${TERM} ++ExecStart=-/sbin/agetty --noreset --noclear --issue-file=/etc/issue:/etc/issue.d:/run/issue.d:/usr/lib/issue.d %I ${TERM} Type=idle Restart=always RestartSec=0 @@ -73,15 +73,15 @@ index f30bba406d..1819627d1c 100644 TTYReset=yes TTYVHangup=yes diff --git a/units/serial-getty@.service.in b/units/serial-getty@.service.in -index 20a5eb2754..ba4cbc0edb 100644 +index 0134c83d48..7e5c8797ca 100644 --- a/units/serial-getty@.service.in +++ b/units/serial-getty@.service.in -@@ -32,12 +32,10 @@ Before=rescue.service +@@ -30,12 +30,10 @@ Conflicts=rescue.service + Before=rescue.service + [Service] - # The '-o' option value tells agetty to replace 'login' arguments with '--' for - # safety, and then the entered username. --ExecStart=-/sbin/agetty -o '-- \\u' --noreset --noclear --keep-baud 115200,57600,38400,9600 - ${TERM} -+ExecStart=-/sbin/agetty -o '-- \\u' --noreset --noclear --keep-baud 115200,57600,38400,9600 %I ${TERM} +-ExecStart=-/sbin/agetty --noreset --noclear --issue-file=/etc/issue:/etc/issue.d:/run/issue.d:/usr/lib/issue.d --keep-baud 115200,57600,38400,9600 - ${TERM} ++ExecStart=-/sbin/agetty --noreset --noclear --issue-file=/etc/issue:/etc/issue.d:/run/issue.d:/usr/lib/issue.d --keep-baud 115200,57600,38400,9600 %I ${TERM} Type=idle Restart=always UtmpIdentifier=%I diff --git a/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0005-sysext-Create-mutable-directory-with-the-right-mode.patch b/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0005-sysext-Create-mutable-directory-with-the-right-mode.patch new file mode 100644 index 00000000000..b9cfd819a84 --- /dev/null +++ b/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0005-sysext-Create-mutable-directory-with-the-right-mode.patch @@ -0,0 +1,45 @@ +From cf36f845e6a806161e008def40a271e9e9746c4f Mon Sep 17 00:00:00 2001 +From: Kai Lueke +Date: Wed, 3 Dec 2025 00:02:32 +0900 +Subject: [PATCH 5/7] sysext: Create mutable directory with the right mode + +When the mutable directory didn't exist but gets created with +--mutable=yes then it used to get mode 700 and later it got patched by +a chmod because it is the top layer and must match the target hierarchy. +This meant one could not call the function to resolve the mutable +directory twice before the mount because it has a check for a proper +mode when the directory exists which is the case for the second call. +Also, this resulted in /var/lib/extensions.mutable getting created with +mode 700 which is not really required. + +Don't rely on the chmod for the upper dir but directly create the +directory with the right mode by first creating all missing directories +with 755 as a sane default and then changing the mode as needed for the +mutable directory. +--- + src/sysext/sysext.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/src/sysext/sysext.c b/src/sysext/sysext.c +index 72da02cd89..d63cf39fbb 100644 +--- a/src/sysext/sysext.c ++++ b/src/sysext/sysext.c +@@ -952,10 +952,14 @@ static int resolve_mutable_directory( + if (!path_in_root) + return log_oom(); + +- r = mkdir_p(path_in_root, 0700); ++ /* This also creates /var/lib/extensions.mutable if needed */ ++ r = mkdir_p(path_in_root, 0755); + if (r < 0) + return log_error_errno(r, "Failed to create a directory '%s': %m", path_in_root); + ++ if (chmod(path_in_root, hierarchy_mode) < 0) ++ return log_error_errno(errno, "Failed to chmod directory '%s': %m", path_in_root); ++ + _cleanup_close_ int atfd = open(path_in_root, O_DIRECTORY|O_CLOEXEC); + if (atfd < 0) + return log_error_errno(errno, "Failed to open directory '%s': %m", path_in_root); +-- +2.51.1 + diff --git a/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0006-sysext-Skip-refresh-if-no-changes-are-found.patch b/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0006-sysext-Skip-refresh-if-no-changes-are-found.patch new file mode 100644 index 00000000000..066717d5b66 --- /dev/null +++ b/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0006-sysext-Skip-refresh-if-no-changes-are-found.patch @@ -0,0 +1,1007 @@ +From 34f3aeb2b92388e26cabe51e48dea99845e0930f Mon Sep 17 00:00:00 2001 +From: Kai Lueke +Date: Wed, 26 Nov 2025 00:04:43 +0900 +Subject: [PATCH 1/3] sysext: Skip refresh if no changes are found + +When the extensions for the final system are already set up from the +initrd we should avoid disrupting the boot process with the remount +(which currently isn't atomic) and the daemon reload for +systemd-confext and systemd-sysext. Similarly, when sysupdate ran and +updated extensions it's best to avoid the remount and daemon reload if +no changes are found. +To do this, encode the current extension state in more detail than +before where only the names of the extensions where encoded in the +overlay mount. This can also be used to provide more details about the +extension origin in "systemd-sysext status (--json=)". During the +refresh add a check whether the old state matches the new state and in +this case skip the refresh unless the user provides a flag to always +refresh. Besides the extension name and the resolved path the best +method for identification is the verity hash but that is not available +for plain image files or directories. Therefore, also include data to +check for file/directory replacements. The creation/modification times +are not always real on reproducible images or extracted archive content. +The file handle together with the unique mount ID is the next best +identifier we can use when we have no verity hash. Fall back to an inode +when we get no handle. With the creation/modification time and the path +this should be good enough. Using a unique mount ID is important (with +a fallback to the regular non-unique mount ID) instead of st_dev because +st_dev gets reused too easily, e.g., by a loop device mount and the +mount ID helps to catch this. For the mount ID to be valid it has to be +resolved before we enter the new mount namespace. Thus, it gets provided +by the image dissect logic and handed over to the sysext subprocess +which runs in a new mount namespace. +Luckily, we can rule out online modification of directories or image +files because this is anyway not well supported with overlay mounts, so +we don't do a file checksum nor do we recurse into a directory to look +for the most recently touched files. But, as said, with the +always-refresh flag one can force a reload. Another case that is not +supported is changed values of SYSTEMD_SYSEXT_OVERLAYFS_MOUNT_OPTIONS= +and these also need an explicit refresh to be applied. +--- + man/systemd-sysext.xml | 14 ++ + shell-completion/bash/systemd-sysext | 1 + + src/basic/mountpoint-util.c | 98 ++++++++- + src/basic/mountpoint-util.h | 4 +- + src/include/override/fcntl.h | 5 + + src/shared/discover-image.c | 54 +++++ + src/shared/discover-image.h | 4 + + src/shared/varlink-io.systemd.sysext.c | 1 + + src/sysext/sysext.c | 271 ++++++++++++++++++++++--- + test/units/TEST-50-DISSECT.sysext.sh | 41 ++++ + 10 files changed, 458 insertions(+), 35 deletions(-) + +diff --git a/man/systemd-sysext.xml b/man/systemd-sysext.xml +index 07e97071a5..3f60c85dba 100644 +--- a/man/systemd-sysext.xml ++++ b/man/systemd-sysext.xml +@@ -366,6 +366,20 @@ + + + ++ ++ ++ ++ When refreshing system extensions on /usr/ and ++ /opt/ for sysext and /etc/ for confext, ++ ignore when the existing merged extensions already match what would be merged. ++ By default the refresh is skipped when no changes are found. Note that changes ++ done to an extension directory while it's merged are ignored without this flag ++ (unless an other extension got changed). Note that changing the contents while ++ merged is also undefined behavior in overlayfs. ++ ++ ++ ++ + + + +diff --git a/shell-completion/bash/systemd-sysext b/shell-completion/bash/systemd-sysext +index c605237ed6..69d786c33e 100644 +--- a/shell-completion/bash/systemd-sysext ++++ b/shell-completion/bash/systemd-sysext +@@ -36,6 +36,7 @@ _systemd-sysext() { + [ARG]='--root + --json + --noexec ++ --always-refresh + --image-policy + --mutable' + ) +diff --git a/src/basic/mountpoint-util.c b/src/basic/mountpoint-util.c +index b7c4870931..0d52d4cfea 100644 +--- a/src/basic/mountpoint-util.c ++++ b/src/basic/mountpoint-util.c +@@ -51,12 +51,16 @@ int name_to_handle_at_loop( + const char *path, + struct file_handle **ret_handle, + int *ret_mnt_id, ++ uint64_t *ret_unique_mnt_id, + int flags) { + + size_t n = ORIGINAL_MAX_HANDLE_SZ; + + assert(fd >= 0 || fd == AT_FDCWD); +- assert((flags & ~(AT_SYMLINK_FOLLOW|AT_EMPTY_PATH|AT_HANDLE_FID)) == 0); ++ assert((flags & ~(AT_SYMLINK_FOLLOW|AT_EMPTY_PATH|AT_HANDLE_FID|AT_HANDLE_MNT_ID_UNIQUE)) == 0); ++ ++ if (isempty(path)) ++ flags |= AT_EMPTY_PATH; + + /* We need to invoke name_to_handle_at() in a loop, given that it might return EOVERFLOW when the specified + * buffer is too small. Note that in contrast to what the docs might suggest, MAX_HANDLE_SZ is only good as a +@@ -67,7 +71,8 @@ int name_to_handle_at_loop( + + for (;;) { + _cleanup_free_ struct file_handle *h = NULL; +- int mnt_id = -1; ++ int mnt_id = -1, r; ++ uint64_t unique_mnt_id = 0; + + h = malloc0(offsetof(struct file_handle, f_handle) + n); + if (!h) +@@ -75,12 +80,20 @@ int name_to_handle_at_loop( + + h->handle_bytes = n; + +- if (name_to_handle_at(fd, strempty(path), h, &mnt_id, flags) >= 0) { ++ if (flags & AT_HANDLE_MNT_ID_UNIQUE) ++ /* The kernel will still use this as uint64_t pointer */ ++ r = name_to_handle_at(fd, strempty(path), h, (int *) &unique_mnt_id, flags); ++ else ++ r = name_to_handle_at(fd, strempty(path), h, &mnt_id, flags); ++ ++ if (r >= 0) { + + if (ret_handle) + *ret_handle = TAKE_PTR(h); + +- if (ret_mnt_id) ++ if (ret_unique_mnt_id && flags & AT_HANDLE_MNT_ID_UNIQUE) ++ *ret_unique_mnt_id = unique_mnt_id; ++ if (ret_mnt_id && (flags & AT_HANDLE_MNT_ID_UNIQUE) == 0) + *ret_mnt_id = mnt_id; + + return 0; +@@ -88,13 +101,16 @@ int name_to_handle_at_loop( + if (errno != EOVERFLOW) + return -errno; + +- if (!ret_handle && ret_mnt_id && mnt_id >= 0) { ++ if (!ret_handle && ((ret_mnt_id && mnt_id >= 0) || (ret_unique_mnt_id && unique_mnt_id > 0))) { + + /* As it appears, name_to_handle_at() fills in mnt_id even when it returns EOVERFLOW when the + * buffer is too small, but that's undocumented. Hence, let's make use of this if it appears to + * be filled in, and the caller was interested in only the mount ID an nothing else. */ + +- *ret_mnt_id = mnt_id; ++ if (ret_unique_mnt_id && flags & AT_HANDLE_MNT_ID_UNIQUE) ++ *ret_unique_mnt_id = unique_mnt_id; ++ else if (ret_mnt_id) ++ *ret_mnt_id = mnt_id; + return 0; + } + +@@ -128,11 +144,52 @@ int name_to_handle_at_try_fid( + * we'll try without the flag, in order to support older kernels that didn't have AT_HANDLE_FID + * (i.e. older than Linux 6.5). */ + +- r = name_to_handle_at_loop(fd, path, ret_handle, ret_mnt_id, flags | AT_HANDLE_FID); ++ r = name_to_handle_at_loop(fd, path, ret_handle, ret_mnt_id, NULL, flags | AT_HANDLE_FID); + if (r >= 0 || is_name_to_handle_at_fatal_error(r)) + return r; + +- return name_to_handle_at_loop(fd, path, ret_handle, ret_mnt_id, flags & ~AT_HANDLE_FID); ++ return name_to_handle_at_loop(fd, path, ret_handle, ret_mnt_id, NULL, flags & ~AT_HANDLE_FID); ++} ++ ++int name_to_handle_at_try_unique_mntid_fid( ++ int fd, ++ const char *path, ++ struct file_handle **ret_handle, ++ uint64_t *ret_mnt_id, ++ int flags) { ++ ++ int mnt_id = -1, r; ++ ++ assert(fd >= 0 || fd == AT_FDCWD); ++ ++ /* First issues name_to_handle_at() with AT_HANDLE_MNT_ID_UNIQUE and AT_HANDLE_FID. ++ * If this fails and this is not a fatal error we'll try without the ++ * AT_HANDLE_MNT_ID_UNIQUE flag because it's only available from Linux 6.12 onwards. */ ++ r = name_to_handle_at_loop(fd, path, ret_handle, NULL, ret_mnt_id, flags | AT_HANDLE_MNT_ID_UNIQUE | AT_HANDLE_FID); ++ if (r >= 0 || is_name_to_handle_at_fatal_error(r)) ++ return r; ++ ++ flags &= ~AT_HANDLE_MNT_ID_UNIQUE; ++ ++ /* Then issues name_to_handle_at() with AT_HANDLE_FID. If this fails and this is not a fatal error ++ * we'll try without the flag, in order to support older kernels that didn't have AT_HANDLE_FID ++ * (i.e. older than Linux 6.5). */ ++ ++ r = name_to_handle_at_loop(fd, path, ret_handle, &mnt_id, NULL, flags | AT_HANDLE_FID); ++ if (ret_mnt_id && mnt_id >= 0) { ++ /* See if we can do better because statx can do unique mount IDs since Linux 6.8 ++ * and only if this doesn't work we use the non-unique mnt_id as returned. ++ * The function only sets mnt_id after checking the error code, so omitted above. */ ++ if (path_get_unique_mnt_id_at(fd, path, ret_mnt_id) < 0) ++ *ret_mnt_id = mnt_id; ++ } ++ if (r >= 0 || is_name_to_handle_at_fatal_error(r)) ++ return r; ++ ++ r = name_to_handle_at_loop(fd, path, ret_handle, &mnt_id, NULL, flags & ~AT_HANDLE_FID); ++ if (ret_mnt_id && mnt_id >= 0) ++ *ret_mnt_id = mnt_id; ++ return r; + } + + static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *ret_mnt_id) { +@@ -373,7 +430,7 @@ int path_get_mnt_id_at_fallback(int dir_fd, const char *path, int *ret) { + assert(dir_fd >= 0 || dir_fd == AT_FDCWD); + assert(ret); + +- r = name_to_handle_at_loop(dir_fd, path, NULL, ret, isempty(path) ? AT_EMPTY_PATH : 0); ++ r = name_to_handle_at_loop(dir_fd, path, NULL, ret, NULL, 0); + if (r >= 0 || is_name_to_handle_at_fatal_error(r)) + return r; + +@@ -403,6 +460,29 @@ int path_get_mnt_id_at(int dir_fd, const char *path, int *ret) { + return path_get_mnt_id_at_fallback(dir_fd, path, ret); + } + ++int path_get_unique_mnt_id_at(int dir_fd, const char *path, uint64_t *ret) { ++ struct statx sx; ++ ++ assert(dir_fd >= 0 || dir_fd == AT_FDCWD); ++ assert(ret); ++ ++ if (statx(dir_fd, ++ strempty(path), ++ (isempty(path) ? AT_EMPTY_PATH : AT_SYMLINK_NOFOLLOW) | ++ AT_NO_AUTOMOUNT | /* don't trigger automounts, mnt_id is a local concept */ ++ AT_STATX_DONT_SYNC, /* don't go to the network, mnt_id is a local concept */ ++ STATX_MNT_ID_UNIQUE, ++ &sx) < 0) ++ return -errno; ++ ++ if (FLAGS_SET(sx.stx_mask, STATX_MNT_ID_UNIQUE)) { ++ *ret = sx.stx_mnt_id; ++ return 0; ++ } ++ ++ return -EOPNOTSUPP; ++} ++ + bool fstype_is_network(const char *fstype) { + const char *x; + +diff --git a/src/basic/mountpoint-util.h b/src/basic/mountpoint-util.h +index 004d2b2af5..2d3e8390ba 100644 +--- a/src/basic/mountpoint-util.h ++++ b/src/basic/mountpoint-util.h +@@ -34,8 +34,9 @@ + + bool is_name_to_handle_at_fatal_error(int err); + +-int name_to_handle_at_loop(int fd, const char *path, struct file_handle **ret_handle, int *ret_mnt_id, int flags); ++int name_to_handle_at_loop(int fd, const char *path, struct file_handle **ret_handle, int *ret_mnt_id, uint64_t *ret_unique_mnt_id, int flags); + int name_to_handle_at_try_fid(int fd, const char *path, struct file_handle **ret_handle, int *ret_mnt_id, int flags); ++int name_to_handle_at_try_unique_mntid_fid(int fd, const char *path, struct file_handle **ret_handle, uint64_t *ret_mnt_id, int flags); + + bool file_handle_equal(const struct file_handle *a, const struct file_handle *b); + +@@ -44,6 +45,7 @@ int path_get_mnt_id_at(int dir_fd, const char *path, int *ret); + static inline int path_get_mnt_id(const char *path, int *ret) { + return path_get_mnt_id_at(AT_FDCWD, path, ret); + } ++int path_get_unique_mnt_id_at(int dir_fd, const char *path, uint64_t *ret); + + int is_mount_point_at(int fd, const char *filename, int flags); + int path_is_mount_point_full(const char *path, const char *root, int flags); +diff --git a/src/include/override/fcntl.h b/src/include/override/fcntl.h +index 5f1d90ad79..f244ffa9f1 100644 +--- a/src/include/override/fcntl.h ++++ b/src/include/override/fcntl.h +@@ -17,3 +17,8 @@ + #ifndef AT_HANDLE_FID + #define AT_HANDLE_FID AT_REMOVEDIR + #endif ++ ++/* This is defined since glibc-2.42. */ ++#ifndef AT_HANDLE_MNT_ID_UNIQUE ++#define AT_HANDLE_MNT_ID_UNIQUE 0x001 /* Return the u64 unique mount ID. */ ++#endif +diff --git a/src/shared/discover-image.c b/src/shared/discover-image.c +index d6d41b4ecf..ddb2edaa33 100644 +--- a/src/shared/discover-image.c ++++ b/src/shared/discover-image.c +@@ -35,6 +35,9 @@ + #include "log.h" + #include "loop-util.h" + #include "mkdir.h" ++#include "mountpoint-util.h" ++#include "namespace-util.h" ++#include "nsresource.h" + #include "nulstr-util.h" + #include "os-util.h" + #include "path-util.h" +@@ -125,6 +128,8 @@ static Image* image_free(Image *i) { + free(i->name); + free(i->path); + ++ free(i->fh); ++ + free(i->hostname); + strv_free(i->machine_info); + strv_free(i->os_release); +@@ -194,6 +199,9 @@ static int image_new( + bool read_only, + usec_t crtime, + usec_t mtime, ++ struct file_handle *fh, ++ uint64_t on_mount_id, ++ uint64_t inode, + Image **ret) { + + _cleanup_(image_unrefp) Image *i = NULL; +@@ -215,12 +223,24 @@ static int image_new( + .read_only = read_only, + .crtime = crtime, + .mtime = mtime, ++ .on_mount_id = on_mount_id, ++ .inode = inode, + .usage = UINT64_MAX, + .usage_exclusive = UINT64_MAX, + .limit = UINT64_MAX, + .limit_exclusive = UINT64_MAX, + }; + ++ if (fh) { ++ i->fh = malloc0(offsetof(struct file_handle, f_handle) + fh->handle_bytes); ++ if (!i->fh) ++ return -ENOMEM; ++ ++ i->fh->handle_bytes = fh->handle_bytes; ++ i->fh->handle_type = fh->handle_type; ++ memcpy(i->fh->f_handle, fh->f_handle, fh->handle_bytes); ++ } ++ + i->name = strdup(pretty); + if (!i->name) + return -ENOMEM; +@@ -391,6 +411,28 @@ static int image_make( + (dir_path && path_startswith(dir_path, "/usr")) || + (faccessat(fd, "", W_OK, AT_EACCESS|AT_EMPTY_PATH) < 0 && errno == EROFS); + ++ uint64_t on_mount_id = 0; ++ _cleanup_free_ struct file_handle *fh = NULL; ++ ++ r = name_to_handle_at_try_unique_mntid_fid(fd, NULL, &fh, &on_mount_id, 0); ++ if (r < 0) { ++ if (is_name_to_handle_at_fatal_error(r)) ++ return r; ++ ++ r = path_get_unique_mnt_id_at(fd, NULL, &on_mount_id); ++ if (r < 0) { ++ if (!ERRNO_IS_NEG_NOT_SUPPORTED(r)) ++ return r; ++ ++ int on_mount_id_fallback = -1; ++ r = path_get_mnt_id_at(fd, NULL, &on_mount_id_fallback); ++ if (r < 0) ++ return r; ++ ++ on_mount_id = on_mount_id_fallback; ++ } ++ } ++ + if (S_ISDIR(st->st_mode)) { + unsigned file_attr = 0; + usec_t crtime = 0; +@@ -433,6 +475,9 @@ static int image_make( + info.read_only || read_only, + info.otime, + info.ctime, ++ fh, ++ on_mount_id, ++ (uint64_t) st->st_ino, + ret); + if (r < 0) + return r; +@@ -458,6 +503,9 @@ static int image_make( + read_only || (file_attr & FS_IMMUTABLE_FL), + crtime, + 0, /* we don't use mtime of stat() here, since it's not the time of last change of the tree, but only of the top-level dir */ ++ fh, ++ on_mount_id, ++ (uint64_t) st->st_ino, + ret); + if (r < 0) + return r; +@@ -495,6 +543,9 @@ static int image_make( + !(st->st_mode & 0222) || read_only, + crtime, + timespec_load(&st->st_mtim), ++ fh, ++ on_mount_id, ++ (uint64_t) st->st_ino, + ret); + if (r < 0) + return r; +@@ -553,6 +604,9 @@ static int image_make( + !(st->st_mode & 0222) || read_only, + 0, + 0, ++ fh, ++ on_mount_id, ++ (uint64_t) st->st_ino, + ret); + if (r < 0) + return r; +diff --git a/src/shared/discover-image.h b/src/shared/discover-image.h +index 60f5a4dce1..7b5593f08d 100644 +--- a/src/shared/discover-image.h ++++ b/src/shared/discover-image.h +@@ -27,6 +27,10 @@ typedef struct Image { + usec_t crtime; + usec_t mtime; + ++ struct file_handle *fh; ++ uint64_t on_mount_id; ++ uint64_t inode; ++ + uint64_t usage; + uint64_t usage_exclusive; + uint64_t limit; +diff --git a/src/shared/varlink-io.systemd.sysext.c b/src/shared/varlink-io.systemd.sysext.c +index 90eb8177d1..e48804c148 100644 +--- a/src/shared/varlink-io.systemd.sysext.c ++++ b/src/shared/varlink-io.systemd.sysext.c +@@ -31,6 +31,7 @@ static SD_VARLINK_DEFINE_METHOD( + SD_VARLINK_DEFINE_INPUT_BY_TYPE(class, ImageClass, SD_VARLINK_NULLABLE), + SD_VARLINK_DEFINE_INPUT(force, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE), + SD_VARLINK_DEFINE_INPUT(noReload, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE), ++ SD_VARLINK_DEFINE_INPUT(alwaysRefresh, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE), + SD_VARLINK_DEFINE_INPUT(noexec, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE)); + + static SD_VARLINK_DEFINE_METHOD_FULL( +diff --git a/src/sysext/sysext.c b/src/sysext/sysext.c +index d63cf39fbb..bfe71f2267 100644 +--- a/src/sysext/sysext.c ++++ b/src/sysext/sysext.c +@@ -8,6 +8,7 @@ + #include + #include + ++#include "sd-json.h" + #include "sd-varlink.h" + + #include "argv-util.h" +@@ -87,6 +88,7 @@ static PagerFlags arg_pager_flags = 0; + static bool arg_legend = true; + static bool arg_force = false; + static bool arg_no_reload = false; ++static bool arg_always_refresh = false; + static int arg_noexec = -1; + static ImagePolicy *arg_image_policy = NULL; + static bool arg_varlink = false; +@@ -1401,6 +1403,28 @@ static int write_extensions_file(ImageClass image_class, char **extensions, cons + return 0; + } + ++static int write_origin_file(ImageClass image_class, const char *origin_content, const char *meta_path, const char *hierarchy) { ++ _cleanup_free_ char *f = NULL; ++ int r; ++ ++ assert(meta_path); ++ ++ /* The origin file is compared to know if a refresh can be skipped (opt-in, used at service startup). */ ++ f = path_join(meta_path, image_class_info[image_class].dot_directory_name, "origin"); ++ if (!f) ++ return log_oom(); ++ ++ _cleanup_free_ char *hierarchy_path = path_join(hierarchy, image_class_info[image_class].dot_directory_name, image_class_info[image_class].short_identifier_plural); ++ if (!hierarchy_path) ++ return log_oom(); ++ ++ r = write_string_file_full(AT_FDCWD, f, strempty(origin_content), WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MKDIR_0755|WRITE_STRING_FILE_LABEL|WRITE_STRING_FILE_AVOID_NEWLINE, /* ts= */ NULL, hierarchy_path); ++ if (r < 0) ++ return log_error_errno(r, "Failed to write origin meta file '%s': %m", f); ++ ++ return 0; ++} ++ + static int write_dev_file(ImageClass image_class, const char *meta_path, const char *overlay_path, const char *hierarchy) { + _cleanup_free_ char *f = NULL; + struct stat st; +@@ -1505,6 +1529,7 @@ static int write_work_dir_file(ImageClass image_class, const char *meta_path, co + static int store_info_in_meta( + ImageClass image_class, + char **extensions, ++ const char *origin_content, + const char *meta_path, + const char *overlay_path, + const char *work_dir, +@@ -1537,6 +1562,10 @@ static int store_info_in_meta( + if (r < 0) + return r; + ++ r = write_origin_file(image_class, origin_content, meta_path, hierarchy); ++ if (r < 0) ++ return r; ++ + r = write_dev_file(image_class, meta_path, overlay_path, hierarchy); + if (r < 0) + return r; +@@ -1595,6 +1624,7 @@ static int merge_hierarchy( + int noexec, + char **extensions, + char **paths, ++ const char *origin_content, + const char *meta_path, + const char *overlay_path, + const char *workspace_path) { +@@ -1640,7 +1670,7 @@ static int merge_hierarchy( + if (r < 0) + return r; + +- r = store_info_in_meta(image_class, extensions, meta_path, overlay_path, op->work_dir, op->hierarchy, backing); ++ r = store_info_in_meta(image_class, extensions, origin_content, meta_path, overlay_path, op->work_dir, op->hierarchy, backing); + if (r < 0) + return r; + +@@ -1692,19 +1722,29 @@ static int merge_subprocess( + ImageClass image_class, + char **hierarchies, + bool force, ++ bool always_refresh, + int noexec, + Hashmap *images, + const char *workspace) { + + _cleanup_free_ char *host_os_release_id = NULL, *host_os_release_id_like = NULL, + *host_os_release_version_id = NULL, *host_os_release_api_level = NULL, +- *filename = NULL; ++ *filename = NULL, *old_origin_content = NULL, ++ *extensions_origin_content = NULL, *arg_root_resolved = NULL; + _cleanup_strv_free_ char **extensions = NULL, **extensions_v = NULL, **paths = NULL; ++ _cleanup_(sd_json_variant_unrefp) sd_json_variant *extensions_origin_entries = NULL, ++ *extensions_origin_json = NULL, *mutable_dir_entries = NULL; + size_t n_extensions = 0; + unsigned n_ignored = 0; + Image *img; + int r; + ++ if (!isempty(arg_root)) { ++ r = chase(arg_root, NULL, CHASE_MUST_BE_DIRECTORY, &arg_root_resolved, NULL); ++ if (r < 0) ++ return log_error_errno(r, "Failed to resolve --root='%s': %m", strempty(arg_root)); ++ } ++ + assert(path_startswith(workspace, "/run/")); + + /* Mark the whole of /run as MS_SLAVE, so that we can mount stuff below it that doesn't show up on +@@ -1742,7 +1782,8 @@ static int merge_subprocess( + + /* Let's now mount all images */ + HASHMAP_FOREACH(img, images) { +- _cleanup_free_ char *p = NULL; ++ _cleanup_free_ char *p = NULL, *path_without_root = NULL; ++ _cleanup_(sd_json_variant_unrefp) sd_json_variant *verity_hash = NULL; + + p = path_join(workspace, image_class_info[image_class].short_identifier_plural, img->name); + if (!p) +@@ -1841,6 +1882,12 @@ static int merge_subprocess( + if (r < 0) + return r; + ++ if (verity_settings.root_hash) { ++ r = sd_json_variant_new_hex(&verity_hash, verity_settings.root_hash, verity_settings.root_hash_size); ++ if (r < 0) ++ return log_error_errno(r, "Failed to create origin verity entry for '%s': %m", img->name); ++ } ++ + r = dissected_image_decrypt(m, /* passphrase= */ NULL, &verity_settings, flags); + if (r < 0) + return r; +@@ -1910,6 +1957,59 @@ static int merge_subprocess( + if (r < 0) + return log_oom(); + ++ /* Encode extension image origin to check if we can skip the refresh. ++ * It can also be used to provide more detail in "systemd-sysext status". */ ++ ++ if (!isempty(arg_root)) { ++ const char *without_root = NULL; ++ without_root = path_startswith(img->path, arg_root_resolved); ++ if (!isempty(without_root)) ++ path_without_root = strjoin("/", without_root); ++ } ++ if (!path_without_root) ++ path_without_root = strdup(img->path); ++ ++ /* The verity hash is not available for all extension types, ++ * thus, but only as fallback, also include data to check for ++ * file/directory replacements through a file handle and unique ++ * mount ID (or inode and mount ID as fallback). ++ * A unique mount ID is best because st_dev gets reused too easily, ++ * e.g., by a loop dev mount. For the mount ID to be valid it ++ * has to be resolved before we enter the new mount namespace. ++ * Thus, here it wouldn't work and so instead it gets provided ++ * by the image dissect logic and handed over to this subprocess ++ * we are in. ++ * Online modification is not well supported with overlay ++ * mounts, so we don't do a file checksum nor do we recurse ++ * into a directory to look for touched files. If users want ++ * modifications to be picked up, they need to set the ++ * --always-refresh=yes flag (as will be printed out). */ ++ ++ _cleanup_(sd_json_variant_unrefp) sd_json_variant *origin_entry = NULL; ++ ++ /* We suppress inclusion of weak identifiers when a strong one is there ++ * so that, e.g., a confext image stored on /usr gets identified only ++ * by the verity hash instead of also the mount ID because that changes ++ * when a sysext overlay mount appears but since the verity hash is the ++ * same for the confext it can actually be reused. */ ++ r = sd_json_buildo(&origin_entry, ++ SD_JSON_BUILD_PAIR_STRING("path", path_without_root), ++ SD_JSON_BUILD_PAIR_CONDITION(!!verity_hash, "verityHash", SD_JSON_BUILD_VARIANT(verity_hash)), ++ SD_JSON_BUILD_PAIR_CONDITION(!verity_hash, "onMountId", SD_JSON_BUILD_UNSIGNED(img->on_mount_id)), ++ SD_JSON_BUILD_PAIR_CONDITION(!verity_hash && !!img->fh, "fileHandle", ++ SD_JSON_BUILD_OBJECT(SD_JSON_BUILD_PAIR_INTEGER("type", img->fh->handle_type), ++ SD_JSON_BUILD_PAIR_HEX("handle", img->fh->f_handle, ++ img->fh->handle_bytes))), ++ SD_JSON_BUILD_PAIR_CONDITION(!verity_hash && !img->fh, "inode", SD_JSON_BUILD_UNSIGNED(img->inode)), ++ SD_JSON_BUILD_PAIR_CONDITION(!verity_hash, "crtime", SD_JSON_BUILD_UNSIGNED(img->crtime)), ++ SD_JSON_BUILD_PAIR_CONDITION(!verity_hash, "mtime", SD_JSON_BUILD_UNSIGNED(img->mtime))); ++ if (r < 0) ++ return log_error_errno(r, "Failed to create origin entry for '%s': %m", img->name); ++ ++ r = sd_json_variant_set_field(&extensions_origin_entries, img->name, origin_entry); ++ if (r < 0) ++ return log_error_errno(r, "Failed to add origin entry for '%s': %m", img->name); ++ + n_extensions++; + } + +@@ -1926,6 +2026,96 @@ static int merge_subprocess( + typesafe_qsort(extensions, n_extensions, strverscmp_improvedp); + typesafe_qsort(extensions_v, n_extensions, strverscmp_improvedp); + ++ STRV_FOREACH(h, hierarchies) { ++ _cleanup_(overlayfs_paths_freep) OverlayFSPaths *op = NULL; ++ _cleanup_free_ char *f = NULL, *buf = NULL, *resolved = NULL, *mutable_directory_without_root = NULL; ++ ++ /* The origin file includes the backing directories for mutable overlays. */ ++ r = overlayfs_paths_new(*h, workspace, &op); ++ if (r < 0) ++ return r; ++ ++ if (op->resolved_mutable_directory && !isempty(arg_root)) { ++ const char *without_root = NULL; ++ without_root = path_startswith(op->resolved_mutable_directory, arg_root_resolved); ++ if (!isempty(without_root)) ++ mutable_directory_without_root = strjoin("/", without_root); ++ } ++ if (!mutable_directory_without_root && op->resolved_mutable_directory) ++ mutable_directory_without_root = strdup(op->resolved_mutable_directory); ++ ++ if (mutable_directory_without_root) { ++ r = sd_json_variant_set_field_string(&mutable_dir_entries, *h, mutable_directory_without_root); ++ if (r < 0) ++ return log_error_errno(r, "Failed to add mutable directory to origin JSON entry: %m"); ++ } ++ ++ /* Find existing origin file for comparison. */ ++ r = chase(*h, arg_root, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &resolved, NULL); ++ if (r < 0) ++ return log_error_errno(r, "Failed to resolve hierarchy '%s%s': %m", strempty(arg_root), *h); ++ ++ f = path_join(resolved, image_class_info[image_class].dot_directory_name, "origin"); ++ if (!f) ++ return log_oom(); ++ ++ r = is_our_mount_point(image_class, resolved); ++ if (r < 0) ++ return r; ++ if (r == 0) ++ continue; ++ ++ if (old_origin_content) ++ continue; ++ ++ r = read_full_file(f, &buf, NULL); ++ if (r < 0) { ++ log_debug_errno(r, "Failed to open '%s', continuing search: %m", f); ++ continue; ++ } ++ ++ old_origin_content = TAKE_PTR(buf); ++ } ++ ++ r = sd_json_buildo(&extensions_origin_json, ++ SD_JSON_BUILD_PAIR_OBJECT("mutable", ++ SD_JSON_BUILD_PAIR_INTEGER("mode", arg_mutable), ++ SD_JSON_BUILD_PAIR_CONDITION(!!mutable_dir_entries, ++ "mutableDirs", ++ SD_JSON_BUILD_VARIANT(mutable_dir_entries))), ++ SD_JSON_BUILD_PAIR_CONDITION(!!extensions_origin_entries, ++ "extensions", ++ SD_JSON_BUILD_VARIANT(extensions_origin_entries))); ++ if (r < 0) ++ return log_error_errno(r, "Failed to create extensions origin JSON object: %m"); ++ ++ r = sd_json_variant_format(extensions_origin_json, SD_JSON_FORMAT_PRETTY|SD_JSON_FORMAT_NEWLINE, &extensions_origin_content); ++ if (r < 0) ++ return log_error_errno(r, "Failed to format extension origin as JSON: %m"); ++ ++ log_debug("New extension origin entry (unordered):\n%s\n", extensions_origin_content); ++ ++ if (old_origin_content) { ++ _cleanup_(sd_json_variant_unrefp) sd_json_variant *old_origin_json = NULL; ++ ++ log_debug("Old extension origin entry (unordered):\n%s\n", old_origin_content); ++ r = sd_json_parse(old_origin_content, 0, &old_origin_json, NULL, NULL); ++ if (r < 0) ++ return log_error_errno(r, "Failed to parse existing extension origin content: %m"); ++ ++ /* This works well with unordered entries. */ ++ if (sd_json_variant_equal(extensions_origin_json, old_origin_json)) { ++ if (!always_refresh) { ++ /* This only happens during refresh, not merge, thus talk about refresh here. */ ++ log_info("Skipping extension refresh because no change was found, use --always-refresh=yes to always do a refresh."); ++ return 2; ++ } ++ ++ log_debug("No change found based on origin entry but continuing as requested by --always-refresh=yes."); ++ } else ++ log_debug("Found changes based on origin entry, continuing with the refresh."); ++ } ++ + if (n_extensions == 0) { + assert(arg_mutable != MUTABLE_NO); + log_info("No extensions found, proceeding in mutable mode."); +@@ -2008,6 +2198,7 @@ static int merge_subprocess( + noexec, + extensions, + paths, ++ extensions_origin_content, + meta_path, + overlay_path, + merge_hierarchy_workspace); +@@ -2059,6 +2250,7 @@ static int merge(ImageClass image_class, + char **hierarchies, + bool force, + bool no_reload, ++ bool always_refresh, + int noexec, + Hashmap *images) { + pid_t pid; +@@ -2070,14 +2262,20 @@ static int merge(ImageClass image_class, + if (r == 0) { + /* Child with its own mount namespace */ + +- r = merge_subprocess(image_class, hierarchies, force, noexec, images, "/run/systemd/sysext"); +- if (r < 0) +- _exit(EXIT_FAILURE); ++ r = merge_subprocess(image_class, hierarchies, force, always_refresh, noexec, images, "/run/systemd/sysext"); + + /* Our namespace ceases to exist here, also implicitly detaching all temporary mounts we + * created below /run. Nice! */ + +- _exit(r > 0 ? EXIT_SUCCESS : 123); /* 123 means: didn't find any extensions */ ++ /* 0/123 means: didn't find any extensions, 2/124 means: skipped refresh */ ++ if (r < 0) ++ _exit(EXIT_FAILURE); ++ if (r == 0) ++ _exit(123); ++ if (r == 2) ++ _exit(124); ++ ++ _exit(EXIT_SUCCESS); + } + + r = wait_for_terminate_and_check("(sd-merge)", pid, WAIT_LOG_ABNORMAL); +@@ -2085,6 +2283,8 @@ static int merge(ImageClass image_class, + return r; + if (r == 123) /* exit code 123 means: didn't do anything */ + return 0; ++ if (r == 124) /* exit code 124 means: skipped refresh */ ++ return 1; + if (r > 0) + return log_error_errno(SYNTHETIC_ERRNO(EPROTO), "Failed to merge hierarchies"); + +@@ -2182,6 +2382,7 @@ static int verb_merge(int argc, char **argv, void *userdata) { + arg_hierarchies, + arg_force, + arg_no_reload, ++ arg_always_refresh, + arg_noexec, + images); + } +@@ -2190,16 +2391,18 @@ typedef struct MethodMergeParameters { + const char *class; + int force; + int no_reload; ++ int always_refresh; + int noexec; + } MethodMergeParameters; + + static int parse_merge_parameters(sd_varlink *link, sd_json_variant *parameters, MethodMergeParameters *p) { + + static const sd_json_dispatch_field dispatch_table[] = { +- { "class", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(MethodMergeParameters, class), 0 }, +- { "force", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_tristate, offsetof(MethodMergeParameters, force), 0 }, +- { "noReload", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_tristate, offsetof(MethodMergeParameters, no_reload), 0 }, +- { "noexec", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_tristate, offsetof(MethodMergeParameters, noexec), 0 }, ++ { "class", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(MethodMergeParameters, class), 0 }, ++ { "force", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_tristate, offsetof(MethodMergeParameters, force), 0 }, ++ { "noReload", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_tristate, offsetof(MethodMergeParameters, no_reload), 0 }, ++ { "alwaysRefresh", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_tristate, offsetof(MethodMergeParameters, always_refresh), 0 }, ++ { "noexec", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_tristate, offsetof(MethodMergeParameters, noexec), 0 }, + {} + }; + +@@ -2215,6 +2418,7 @@ static int vl_method_merge(sd_varlink *link, sd_json_variant *parameters, sd_var + MethodMergeParameters p = { + .force = -1, + .no_reload = -1, ++ .always_refresh = -1, + .noexec = -1, + }; + _cleanup_strv_free_ char **hierarchies = NULL; +@@ -2249,6 +2453,7 @@ static int vl_method_merge(sd_varlink *link, sd_json_variant *parameters, sd_var + hierarchies ?: arg_hierarchies, + p.force >= 0 ? p.force : arg_force, + p.no_reload >= 0 ? p.no_reload : arg_no_reload, ++ p.always_refresh >= 0 ? p.always_refresh : arg_always_refresh, + p.noexec >= 0 ? p.noexec : arg_noexec, + images); + if (r < 0) +@@ -2262,6 +2467,7 @@ static int refresh( + char **hierarchies, + bool force, + bool no_reload, ++ bool always_refresh, + int noexec) { + + _cleanup_hashmap_free_ Hashmap *images = NULL; +@@ -2272,9 +2478,10 @@ static int refresh( + return r; + + /* Returns > 0 if it did something, i.e. a new overlayfs is mounted now. When it does so it +- * implicitly unmounts any overlayfs placed there before. Returns == 0 if it did nothing, i.e. no ++ * implicitly unmounts any overlayfs placed there before. It also returns == 1 if there were ++ * no changes found to apply and the mount stays intact. Returns == 0 if it did nothing, i.e. no + * extension images found. In this case the old overlayfs remains in place if there was one. */ +- r = merge(image_class, hierarchies, force, no_reload, noexec, images); ++ r = merge(image_class, hierarchies, force, no_reload, always_refresh, noexec, images); + if (r < 0) + return r; + if (r == 0) /* No images found? Then unmerge. The goal of --refresh is after all that after having +@@ -2286,7 +2493,8 @@ static int refresh( + * 1. If an overlayfs was mounted before and no extensions exist anymore, we'll have unmerged things. + * + * 2. If an overlayfs was mounted before, and there are still extensions installed' we'll have +- * unmerged and then merged things again. ++ * unmerged and then merged things again or we have skipped the refresh because no changes ++ * were found. + * + * 3. If an overlayfs so far wasn't mounted, and there are extensions installed, we'll have it + * mounted now. +@@ -2310,6 +2518,7 @@ static int verb_refresh(int argc, char **argv, void *userdata) { + arg_hierarchies, + arg_force, + arg_no_reload, ++ arg_always_refresh, + arg_noexec); + } + +@@ -2318,6 +2527,7 @@ static int vl_method_refresh(sd_varlink *link, sd_json_variant *parameters, sd_v + MethodMergeParameters p = { + .force = -1, + .no_reload = -1, ++ .always_refresh = -1, + .noexec = -1, + }; + _cleanup_strv_free_ char **hierarchies = NULL; +@@ -2338,6 +2548,7 @@ static int vl_method_refresh(sd_varlink *link, sd_json_variant *parameters, sd_v + hierarchies ?: arg_hierarchies, + p.force >= 0 ? p.force : arg_force, + p.no_reload >= 0 ? p.no_reload : arg_no_reload, ++ p.always_refresh >= 0 ? p.always_refresh : arg_always_refresh, + p.noexec >= 0 ? p.noexec : arg_noexec); + if (r < 0) + return r; +@@ -2456,6 +2667,8 @@ static int verb_help(int argc, char **argv, void *userdata) { + " Generate JSON output\n" + " --force Ignore version incompatibilities\n" + " --no-reload Do not reload the service manager\n" ++ " --always-refresh=yes|no\n" ++ " Do not skip refresh when no changes were found\n" + " --image-policy=POLICY\n" + " Specify disk image dissection policy\n" + " --noexec=BOOL Whether to mount extension overlay with noexec\n" +@@ -2483,21 +2696,23 @@ static int parse_argv(int argc, char *argv[]) { + ARG_IMAGE_POLICY, + ARG_NOEXEC, + ARG_NO_RELOAD, ++ ARG_ALWAYS_REFRESH, + ARG_MUTABLE, + }; + + static const struct option options[] = { +- { "help", no_argument, NULL, 'h' }, +- { "version", no_argument, NULL, ARG_VERSION }, +- { "no-pager", no_argument, NULL, ARG_NO_PAGER }, +- { "no-legend", no_argument, NULL, ARG_NO_LEGEND }, +- { "root", required_argument, NULL, ARG_ROOT }, +- { "json", required_argument, NULL, ARG_JSON }, +- { "force", no_argument, NULL, ARG_FORCE }, +- { "image-policy", required_argument, NULL, ARG_IMAGE_POLICY }, +- { "noexec", required_argument, NULL, ARG_NOEXEC }, +- { "no-reload", no_argument, NULL, ARG_NO_RELOAD }, +- { "mutable", required_argument, NULL, ARG_MUTABLE }, ++ { "help", no_argument, NULL, 'h' }, ++ { "version", no_argument, NULL, ARG_VERSION }, ++ { "no-pager", no_argument, NULL, ARG_NO_PAGER }, ++ { "no-legend", no_argument, NULL, ARG_NO_LEGEND }, ++ { "root", required_argument, NULL, ARG_ROOT }, ++ { "json", required_argument, NULL, ARG_JSON }, ++ { "force", no_argument, NULL, ARG_FORCE }, ++ { "image-policy", required_argument, NULL, ARG_IMAGE_POLICY }, ++ { "noexec", required_argument, NULL, ARG_NOEXEC }, ++ { "no-reload", no_argument, NULL, ARG_NO_RELOAD }, ++ { "always-refresh", required_argument, NULL, ARG_ALWAYS_REFRESH }, ++ { "mutable", required_argument, NULL, ARG_MUTABLE }, + {} + }; + +@@ -2561,6 +2776,12 @@ static int parse_argv(int argc, char *argv[]) { + arg_no_reload = true; + break; + ++ case ARG_ALWAYS_REFRESH: ++ r = parse_boolean_argument("--always-refresh", optarg, &arg_always_refresh); ++ if (r < 0) ++ return r; ++ break; ++ + case ARG_MUTABLE: + r = parse_mutable_mode(optarg); + if (r < 0) +diff --git a/test/units/TEST-50-DISSECT.sysext.sh b/test/units/TEST-50-DISSECT.sysext.sh +index 3eec224eb6..05f691b457 100755 +--- a/test/units/TEST-50-DISSECT.sysext.sh ++++ b/test/units/TEST-50-DISSECT.sysext.sh +@@ -1402,6 +1402,47 @@ rm -rf "$fake_root/var/lib/extensions/test-extension.raw.v" "$fake_root/var/othe + + # Done with the above vpick symlink tests for --root= and without + ++( init_trap ++: "Check if refresh skips correctly" ++fake_root=${roots_dir:+"$roots_dir/refresh-skip"} ++hierarchy=/opt ++ ++findmnt --kernel=listmount >/dev/null || { ++ echo >&2 "Can't run test on old kernel, skipping test." ++ exit 0 ++} ++ ++prepare_root "$fake_root" "$hierarchy" ++prepare_extension_image "$fake_root" "$hierarchy" ++prepare_hierarchy "$fake_root" "$hierarchy" ++ ++run_systemd_sysext "$fake_root" merge ++extension_verify_after_merge "$fake_root" "$hierarchy" -e -h ++# The mountinfo ID gets reused and is useless here, we require a unique ID from listmount ++MOUNTID1=$(findmnt --kernel=listmount -o UNIQ-ID --raw --noheadings --target "$fake_root$hierarchy") ++run_systemd_sysext "$fake_root" refresh ++extension_verify_after_merge "$fake_root" "$hierarchy" -e -h ++MOUNTID2=$(findmnt --kernel=listmount -o UNIQ-ID --raw --noheadings --target "$fake_root$hierarchy") ++if [ "$MOUNTID1" != "$MOUNTID2" ]; then ++ echo >&2 "Unexpected remount with 'refresh'" ++ exit 1 ++fi ++rm -rf "$fake_root/var/lib/extensions/test-extension2" ++cp -ar "$fake_root/var/lib/extensions/test-extension" "$fake_root/var/lib/extensions/test-extension2" ++rm -rf "$fake_root/var/lib/extensions/test-extension" ++mv "$fake_root/var/lib/extensions/test-extension2" "$fake_root/var/lib/extensions/test-extension" ++run_systemd_sysext "$fake_root" refresh ++extension_verify_after_merge "$fake_root" "$hierarchy" -e -h ++MOUNTID3=$(findmnt --kernel=listmount -o UNIQ-ID --raw --noheadings --target "$fake_root$hierarchy") ++if [ "$MOUNTID2" = "$MOUNTID3" ]; then ++ echo >&2 "Unexpected skip with 'refresh'" ++ exit 1 ++fi ++ ++run_systemd_sysext "$fake_root" unmerge ++extension_verify_after_unmerge "$fake_root" "$hierarchy" -h ++) ++ + } # End of run_sysext_tests + + +-- +2.52.0 + diff --git a/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0007-sysext-Get-verity-user-certs-from-given-root.patch b/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0007-sysext-Get-verity-user-certs-from-given-root.patch new file mode 100644 index 00000000000..8df4af8a142 --- /dev/null +++ b/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0007-sysext-Get-verity-user-certs-from-given-root.patch @@ -0,0 +1,361 @@ +From 439fb373b7360ba3759b8978d0354d4fe760c8f2 Mon Sep 17 00:00:00 2001 +From: Kai Lueke +Date: Thu, 27 Nov 2025 17:49:15 +0900 +Subject: [PATCH 2/3] sysext: Get verity user certs from given --root= + +The verity user certs weren't looked up in the given --root= for +systemd-sysext which made it fail to set up extensions with a strict +image policy. +Look up verity user certs from inside the --root= when we operate on +images in it. The main use case where this matters is when the initrd +sets up the extensions for the final system and thus systemd-sysext +should do the same thing as it would do in the final system. + +Signed-off-by: Kai Lueke +--- + src/core/namespace.c | 1 + + src/machine/image-dbus.c | 8 ++-- + src/machine/machined-varlink.c | 2 +- + src/mountfsd/mountwork.c | 1 + + src/portable/portabled-image-bus.c | 2 +- + src/shared/discover-image.c | 2 +- + src/shared/discover-image.h | 2 +- + src/shared/dissect-image.c | 22 ++++++----- + src/shared/dissect-image.h | 2 +- + src/sysext/sysext.c | 4 +- + test/units/TEST-50-DISSECT.sysext.sh | 58 ++++++++++++++++++++++++++++ + 11 files changed, 84 insertions(+), 20 deletions(-) + +diff --git a/src/core/namespace.c b/src/core/namespace.c +index 283a1108ce..97cf008194 100644 +--- a/src/core/namespace.c ++++ b/src/core/namespace.c +@@ -2593,6 +2593,7 @@ int setup_namespace(const NamespaceParameters *p, char **reterr_path) { + r = dissected_image_decrypt( + dissected_image, + NULL, ++ NULL, + p->verity, + dissect_image_flags); + if (r < 0) +diff --git a/src/machine/image-dbus.c b/src/machine/image-dbus.c +index 8bc6565079..2857cd18be 100644 +--- a/src/machine/image-dbus.c ++++ b/src/machine/image-dbus.c +@@ -284,7 +284,7 @@ int bus_image_method_get_hostname( + int r; + + if (!image->metadata_valid) { +- r = image_read_metadata(image, &image_policy_container); ++ r = image_read_metadata(image, NULL, &image_policy_container); + if (r < 0) + return sd_bus_error_set_errnof(error, r, "Failed to read image metadata: %m"); + } +@@ -302,7 +302,7 @@ int bus_image_method_get_machine_id( + int r; + + if (!image->metadata_valid) { +- r = image_read_metadata(image, &image_policy_container); ++ r = image_read_metadata(image, NULL, &image_policy_container); + if (r < 0) + return sd_bus_error_set_errnof(error, r, "Failed to read image metadata: %m"); + } +@@ -330,7 +330,7 @@ int bus_image_method_get_machine_info( + int r; + + if (!image->metadata_valid) { +- r = image_read_metadata(image, &image_policy_container); ++ r = image_read_metadata(image, NULL, &image_policy_container); + if (r < 0) + return sd_bus_error_set_errnof(error, r, "Failed to read image metadata: %m"); + } +@@ -347,7 +347,7 @@ int bus_image_method_get_os_release( + int r; + + if (!image->metadata_valid) { +- r = image_read_metadata(image, &image_policy_container); ++ r = image_read_metadata(image, NULL, &image_policy_container); + if (r < 0) + return sd_bus_error_set_errnof(error, r, "Failed to read image metadata: %m"); + } +diff --git a/src/machine/machined-varlink.c b/src/machine/machined-varlink.c +index 52b1fc12d2..1e8f4ce9a8 100644 +--- a/src/machine/machined-varlink.c ++++ b/src/machine/machined-varlink.c +@@ -621,7 +621,7 @@ static int list_image_one_and_maybe_read_metadata(sd_varlink *link, Image *image + assert(image); + + if (should_acquire_metadata(am) && !image->metadata_valid) { +- r = image_read_metadata(image, &image_policy_container); ++ r = image_read_metadata(image, NULL, &image_policy_container); + if (r < 0 && am != ACQUIRE_METADATA_GRACEFUL) + return log_debug_errno(r, "Failed to read image metadata: %m"); + if (r < 0) +diff --git a/src/mountfsd/mountwork.c b/src/mountfsd/mountwork.c +index bfb8c05c22..260a668525 100644 +--- a/src/mountfsd/mountwork.c ++++ b/src/mountfsd/mountwork.c +@@ -495,6 +495,7 @@ static int vl_method_mount_image( + + r = dissected_image_decrypt( + di, ++ NULL, + p.password, + &verity, + dissect_flags); +diff --git a/src/portable/portabled-image-bus.c b/src/portable/portabled-image-bus.c +index e8bcb900ef..380a6d5d45 100644 +--- a/src/portable/portabled-image-bus.c ++++ b/src/portable/portabled-image-bus.c +@@ -61,7 +61,7 @@ int bus_image_common_get_os_release( + return 1; + + if (!image->metadata_valid) { +- r = image_read_metadata(image, &image_policy_service); ++ r = image_read_metadata(image, NULL, &image_policy_service); + if (r < 0) + return sd_bus_error_set_errnof(error, r, "Failed to read image metadata: %m"); + } +diff --git a/src/shared/discover-image.c b/src/shared/discover-image.c +index 9ce5f028fc..822ea2bd24 100644 +--- a/src/shared/discover-image.c ++++ b/src/shared/discover-image.c +@@ -1766,7 +1766,7 @@ int image_set_pool_limit(ImageClass class, uint64_t referenced_max) { + return 0; + } + +-int image_read_metadata(Image *i, const ImagePolicy *image_policy) { ++int image_read_metadata(Image *i, const char *root, const ImagePolicy *image_policy) { + _cleanup_(release_lock_file) LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT; + int r; + +diff --git a/src/shared/discover-image.h b/src/shared/discover-image.h +index 7b5593f08d..4d64a306c8 100644 +--- a/src/shared/discover-image.h ++++ b/src/shared/discover-image.h +@@ -73,7 +73,7 @@ int image_name_lock(const char *name, int operation, LockFile *ret); + int image_set_limit(Image *i, uint64_t referenced_max); + int image_set_pool_limit(ImageClass class, uint64_t referenced_max); + +-int image_read_metadata(Image *i, const ImagePolicy *image_policy); ++int image_read_metadata(Image *i, const char *root, const ImagePolicy *image_policy); + + bool image_in_search_path(RuntimeScope scope, ImageClass class, const char *root, const char *image); + +diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c +index 715afc8882..8ffb63e1d3 100644 +--- a/src/shared/dissect-image.c ++++ b/src/shared/dissect-image.c +@@ -2611,7 +2611,7 @@ static char* dm_deferred_remove_clean(char *name) { + } + DEFINE_TRIVIAL_CLEANUP_FUNC(char *, dm_deferred_remove_clean); + +-static int validate_signature_userspace(const VeritySettings *verity, DissectImageFlags flags) { ++static int validate_signature_userspace(const VeritySettings *verity, const char *root, DissectImageFlags flags) { + int r; + + if (!FLAGS_SET(flags, DISSECT_IMAGE_ALLOW_USERSPACE_VERITY)) { +@@ -2656,7 +2656,7 @@ static int validate_signature_userspace(const VeritySettings *verity, DissectIma + /* Because installing a signature certificate into the kernel chain is so messy, let's optionally do + * userspace validation. */ + +- r = conf_files_list_nulstr(&certs, ".crt", NULL, CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED, CONF_PATHS_NULSTR("verity.d")); ++ r = conf_files_list_nulstr(&certs, ".crt", root, CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED, CONF_PATHS_NULSTR("verity.d")); + if (r < 0) + return log_debug_errno(r, "Failed to enumerate certificates: %m"); + if (strv_isempty(certs)) { +@@ -2718,6 +2718,7 @@ static int validate_signature_userspace(const VeritySettings *verity, DissectIma + + static int do_crypt_activate_verity( + struct crypt_device *cd, ++ const char *root, + const char *name, + const VeritySettings *verity, + DissectImageFlags flags) { +@@ -2765,7 +2766,7 @@ static int do_crypt_activate_verity( + + /* Preferably propagate the original kernel error, so that the fallback logic can work, + * as the device-mapper is finicky around concurrent activations of the same volume */ +- k = validate_signature_userspace(verity, flags); ++ k = validate_signature_userspace(verity, root, flags); + if (k < 0) + return r < 0 ? r : k; + if (k == 0) +@@ -2805,8 +2806,9 @@ static usec_t verity_timeout(void) { + + static int verity_partition( + PartitionDesignator designator, +- DissectedPartition *m, +- DissectedPartition *v, ++ DissectedPartition *m, /* data partition */ ++ DissectedPartition *v, /* verity partition */ ++ const char *root, /* The root to get user verity certs from (for a sysext) */ + const VeritySettings *verity, + DissectImageFlags flags, + DecryptedImage *d) { +@@ -2886,7 +2888,7 @@ static int verity_partition( + goto check; /* The device already exists. Let's check it. */ + + /* The symlink to the device node does not exist yet. Assume not activated, and let's activate it. */ +- r = do_crypt_activate_verity(cd, name, verity, flags); ++ r = do_crypt_activate_verity(cd, root, name, verity, flags); + if (r >= 0) + goto try_open; /* The device is activated. Let's open it. */ + /* libdevmapper can return EINVAL when the device is already in the activation stage. +@@ -2980,7 +2982,7 @@ static int verity_partition( + */ + sym_crypt_free(cd); + cd = NULL; +- return verity_partition(designator, m, v, verity, flags & ~DISSECT_IMAGE_VERITY_SHARE, d); ++ return verity_partition(designator, m, v, root, verity, flags & ~DISSECT_IMAGE_VERITY_SHARE, d); + } + + return log_debug_errno(SYNTHETIC_ERRNO(EBUSY), "All attempts to activate verity device %s failed.", name); +@@ -3000,6 +3002,7 @@ success: + + int dissected_image_decrypt( + DissectedImage *m, ++ const char *root, /* The root to get user verity certs from (for a sysext) */ + const char *passphrase, + const VeritySettings *verity, + DissectImageFlags flags) { +@@ -3047,7 +3050,7 @@ int dissected_image_decrypt( + if (k >= 0) { + flags |= getenv_bool("SYSTEMD_VERITY_SHARING") != 0 ? DISSECT_IMAGE_VERITY_SHARE : 0; + +- r = verity_partition(i, p, m->partitions + k, verity, flags, d); ++ r = verity_partition(i, p, m->partitions + k, root, verity, flags, d); + if (r < 0) + return r; + } +@@ -3080,7 +3083,7 @@ int dissected_image_decrypt_interactively( + n--; + + for (;;) { +- r = dissected_image_decrypt(m, passphrase, verity, flags); ++ r = dissected_image_decrypt(m, NULL, passphrase, verity, flags); + if (r >= 0) + return r; + if (r == -EKEYREJECTED) +@@ -4367,6 +4370,7 @@ int verity_dissect_and_mount( + r = dissected_image_decrypt( + dissected_image, + NULL, ++ NULL, + verity, + dissect_image_flags); + if (r < 0) +diff --git a/src/shared/dissect-image.h b/src/shared/dissect-image.h +index 97431bca67..004dc46dc3 100644 +--- a/src/shared/dissect-image.h ++++ b/src/shared/dissect-image.h +@@ -171,7 +171,7 @@ void dissected_image_close(DissectedImage *m); + DissectedImage* dissected_image_unref(DissectedImage *m); + DEFINE_TRIVIAL_CLEANUP_FUNC(DissectedImage*, dissected_image_unref); + +-int dissected_image_decrypt(DissectedImage *m, const char *passphrase, const VeritySettings *verity, DissectImageFlags flags); ++int dissected_image_decrypt(DissectedImage *m, const char *root, const char *passphrase, const VeritySettings *verity, DissectImageFlags flags); + int dissected_image_decrypt_interactively(DissectedImage *m, const char *passphrase, const VeritySettings *verity, DissectImageFlags flags); + int dissected_image_mount(DissectedImage *m, const char *where, uid_t uid_shift, uid_t uid_range, int userns_fd, DissectImageFlags flags); + int dissected_image_mount_and_warn(DissectedImage *m, const char *where, uid_t uid_shift, uid_t uid_range, int userns_fd, DissectImageFlags flags); +diff --git a/src/sysext/sysext.c b/src/sysext/sysext.c +index c33ce0d0a4..dbd6df63b4 100644 +--- a/src/sysext/sysext.c ++++ b/src/sysext/sysext.c +@@ -1888,7 +1888,7 @@ static int merge_subprocess( + return log_error_errno(r, "Failed to create origin verity entry for '%s': %m", img->name); + } + +- r = dissected_image_decrypt(m, /* passphrase= */ NULL, &verity_settings, flags); ++ r = dissected_image_decrypt(m, arg_root, /* passphrase= */ NULL, &verity_settings, flags); + if (r < 0) + return r; + +@@ -2308,7 +2308,7 @@ static int image_discover_and_read_metadata(ImageClass image_class, Hashmap **re + return log_error_errno(r, "Failed to discover images: %m"); + + HASHMAP_FOREACH(img, images) { +- r = image_read_metadata(img, image_class_info[image_class].default_image_policy); ++ r = image_read_metadata(img, arg_root, image_class_info[image_class].default_image_policy); + if (r < 0) + return log_error_errno(r, "Failed to read metadata for image %s: %m", img->name); + } +diff --git a/test/units/TEST-50-DISSECT.sysext.sh b/test/units/TEST-50-DISSECT.sysext.sh +index 05f691b457..6e64eea492 100755 +--- a/test/units/TEST-50-DISSECT.sysext.sh ++++ b/test/units/TEST-50-DISSECT.sysext.sh +@@ -181,6 +181,52 @@ prepare_extension_image_raw() { + prepend_trap "rm -rf ${ext_dir@Q}.raw" + } + ++prepare_extension_image_raw_verity() { ++ local root=${1:-} ++ local hierarchy=${2:?} ++ local ext_dir ext_release name tmpcrt ++ ++ name="test-extension" ++ ext_dir="$root/var/lib/extensions/$name" ++ ext_release="$ext_dir/usr/lib/extension-release.d/extension-release.$name" ++ tmpcrt=$(mktemp --directory "/tmp/test-sysext.crt.XXXXXXXXXX") ++ ++ prepend_trap "rm -rf ${ext_dir@Q} ${ext_dir@Q}.raw '$root/etc/verity.d/test-ext.crt' '$tmpcrt'" ++ ++ mkdir -p "${ext_release%/*}" ++ echo "ID=_any" >"$ext_release" ++ mkdir -p "$ext_dir/$hierarchy" ++ touch "$ext_dir$hierarchy/preexisting-file-in-extension-image" ++ tee >"$tmpcrt/verity.openssl.cnf" < +Date: Thu, 17 Jul 2025 05:03:54 -0400 +Subject: [PATCH 1/4] sysext: introduce global config file + +Introduce systemd/{sysext/confext}.conf and systemd/{sysext/confext}.conf.d to provide an +alternative way of setting the cmdline options in systemd-sysext. + +The config file has to have a [Sysext] or [Confext] option respectively, +which will be overridden by the cmdline. + +As an example of supported config, add Mutable= option. +--- + src/sysext/sysext.c | 38 ++++++++++++++++++++++++++++++++++++++ + 1 file changed, 38 insertions(+) + +diff --git a/src/sysext/sysext.c b/src/sysext/sysext.c +index 20acc60724..332fc55bb3 100644 +--- a/src/sysext/sysext.c ++++ b/src/sysext/sysext.c +@@ -18,6 +18,7 @@ + #include "bus-util.h" + #include "capability-util.h" + #include "chase.h" ++#include "conf-parser.h" + #include "devnum-util.h" + #include "discover-image.h" + #include "dissect-image.h" +@@ -150,6 +151,36 @@ static int parse_mutable_mode(const char *p) { + return mutable_mode_from_string(p); + } + ++static DEFINE_CONFIG_PARSE_ENUM(config_parse_mutable_mode, mutable_mode, MutableMode); ++ ++static int parse_config_file(ImageClass image_class) { ++ const char *section = image_class == IMAGE_SYSEXT ? "SysExt" : "ConfExt"; ++ const ConfigTableItem items[] = { ++ { section, "Mutable", config_parse_mutable_mode, 0, &arg_mutable }, ++ {} ++ }; ++ _cleanup_free_ char *config_file = NULL; ++ int r; ++ ++ config_file = strjoin("systemd/", image_class_info[image_class].short_identifier, ".conf"); ++ if (!config_file) ++ return log_oom(); ++ ++ r = config_parse_standard_file_with_dropins_full( ++ arg_root, ++ config_file, ++ image_class == IMAGE_SYSEXT ? "SysExt\0" : "ConfExt\0", ++ config_item_table_lookup, items, ++ CONFIG_PARSE_WARN, ++ /* userdata = */ NULL, ++ /* ret_stats_by_path = */ NULL, ++ /* ret_dropin_files = */ NULL); ++ if (r < 0) ++ return r; ++ ++ return 0; ++} ++ + static int is_our_mount_point( + ImageClass image_class, + const char *p) { +@@ -2828,6 +2859,7 @@ static int run(int argc, char *argv[]) { + + arg_image_class = invoked_as(argv, "systemd-confext") ? IMAGE_CONFEXT : IMAGE_SYSEXT; + ++ /* Parse environment variable first */ + env_var = getenv(image_class_info[arg_image_class].mode_env); + if (env_var) { + r = parse_mutable_mode(env_var); +@@ -2838,6 +2870,12 @@ static int run(int argc, char *argv[]) { + arg_mutable = r; + } + ++ /* Parse configuration file */ ++ r = parse_config_file(arg_image_class); ++ if (r < 0) ++ log_warning_errno(r, "Failed to parse global config file, ignoring: %m"); ++ ++ /* Parse command line */ + r = parse_argv(argc, argv); + if (r <= 0) + return r; +-- +2.51.0 + diff --git a/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0008-units-Make-multi-user.target-the-default-target.patch b/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0008-units-Make-multi-user.target-the-default-target.patch index de0aa6eb46e..a09e66cc703 100644 --- a/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0008-units-Make-multi-user.target-the-default-target.patch +++ b/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0008-units-Make-multi-user.target-the-default-target.patch @@ -1,35 +1,38 @@ -From f0ab1c6c59056afe1650f749d1af6ecc6ee8f5ec Mon Sep 17 00:00:00 2001 +From 3c13363e4b3f2e5bcc762a71460d84b93452f53f Mon Sep 17 00:00:00 2001 From: Krzesimir Nowak Date: Fri, 24 Oct 2025 11:06:57 +0200 -Subject: [PATCH 8/8] units: Make multi-user.target the default target +Subject: [PATCH] units: Make multi-user.target the default target Signed-off-by: Krzesimir Nowak +Signed-off-by: Kai Lueke --- - units/meson.build | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) + units/meson.build | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/units/meson.build b/units/meson.build -index ef18dcae4a..887231840f 100644 +index 4f47a3b2bd..9663e21e0c 100644 --- a/units/meson.build +++ b/units/meson.build -@@ -46,7 +46,7 @@ units = [ +@@ -48,8 +48,7 @@ units = [ + 'symlinks' : ['autovt@.service'], }, { - 'file' : 'graphical.target', -- 'symlinks' : ['default.target'] + (with_runlevels ? ['runlevel5.target'] : []), -+ 'symlinks' : with_runlevels ? ['runlevel5.target'] : [], +- 'file' : 'graphical.target', +- 'symlinks' : ['default.target'], ++ 'file' : 'graphical.target' }, { 'file' : 'halt.target' }, { -@@ -140,7 +140,7 @@ units = [ - { 'file' : 'modprobe@.service' }, - { - 'file' : 'multi-user.target', -- 'symlinks' : with_runlevels ? ['runlevel2.target', 'runlevel3.target', 'runlevel4.target'] : [], -+ 'symlinks' : ['default.target'] + (with_runlevels ? ['runlevel2.target', 'runlevel3.target', 'runlevel4.target'] : []), +@@ -142,7 +141,9 @@ units = [ + 'conditions' : ['ENABLE_MACHINED'], }, + { 'file' : 'modprobe@.service' }, +- { 'file' : 'multi-user.target' }, ++ { 'file' : 'multi-user.target' , ++ 'symlinks' : ['default.target'] ++ }, { 'file' : 'network-online.target' }, { 'file' : 'network-pre.target' }, + { 'file' : 'network.target' }, -- 2.51.0 - diff --git a/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0009-man-sysext.conf-add-systemd-sysext-config-files.patch b/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0009-man-sysext.conf-add-systemd-sysext-config-files.patch new file mode 100644 index 00000000000..94f19211be6 --- /dev/null +++ b/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0009-man-sysext.conf-add-systemd-sysext-config-files.patch @@ -0,0 +1,156 @@ +From 88943429fbf80cf55fc7307ea34b5942524c2f45 Mon Sep 17 00:00:00 2001 +From: Emanuele Giuseppe Esposito +Date: Thu, 17 Jul 2025 05:28:21 -0400 +Subject: [PATCH 2/4] man/sysext.conf: add systemd-sysext config files + +Add sysext.conf, which similar to other configs like coredump, will be +searched in: +/{etc run usr/lib}/systemd/{sysext/confext}.conf +but also +/{etc run usr/lib}/systemd/{sysext/confext}.conf.d/* + +This config is an alternative to command line options, especially useful +if we want to extend the service units without modifying them. +--- + man/rules/meson.build | 1 + + man/sysext.conf.xml | 89 ++++++++++++++++++++++++++++++++++++++++++ + man/systemd-sysext.xml | 8 +++- + 3 files changed, 97 insertions(+), 1 deletion(-) + create mode 100644 man/sysext.conf.xml + +diff --git a/man/rules/meson.build b/man/rules/meson.build +index 33f44b0659..6284183756 100644 +--- a/man/rules/meson.build ++++ b/man/rules/meson.build +@@ -1138,6 +1138,7 @@ manpages = [ + 'systemd-sysext-initrd.service', + 'systemd-sysext.service'], + 'ENABLE_SYSEXT'], ++ ['sysext.conf', '5', ['confext.conf'], 'ENABLE_SYSEXT'], + ['systemd-system-update-generator', '8', [], ''], + ['systemd-system.conf', + '5', +diff --git a/man/sysext.conf.xml b/man/sysext.conf.xml +new file mode 100644 +index 0000000000..cdd88f2447 +--- /dev/null ++++ b/man/sysext.conf.xml +@@ -0,0 +1,89 @@ ++ ++ ++ ++ ++ ++ ++ ++ sysext.conf ++ systemd ++ ++ ++ ++ sysext.conf ++ 5 ++ ++ ++ ++ sysext.conf ++ confext.conf ++ sysext.conf.d ++ confext.conf.d ++ Configuration files for systemd-sysext ++ ++ ++ ++ /etc/systemd/sysext.conf ++ /etc/systemd/sysext.conf.d/*.conf ++ /run/systemd/sysext.conf ++ /run/systemd/sysext.conf.d/*.conf ++ /usr/lib/systemd/sysext.conf ++ /usr/lib/systemd/sysext.conf.d/*.conf ++ /etc/systemd/confext.conf ++ /etc/systemd/confext.conf.d/*.conf ++ /run/systemd/confext.conf ++ /run/systemd/confext.conf.d/*.conf ++ /usr/lib/systemd/confext.conf ++ /usr/lib/systemd/confext.conf.d/*.conf ++ ++ ++ ++ Description ++ ++ These configuration files control the behavior of ++ systemd-sysext8 and ++ systemd-confext8. ++ They are especially useful when needing to customize the behavior of the ++ respective extension service units. ++ ++ ++ ++ ++ ++ Options ++ ++ The following options are understood in both the [Sysext] and ++ [Confext] sections: ++ ++ ++ Section Options ++ ++ ++ ++ Mutable= ++ Set the mutable mode for system extensions. Takes one of no, ++ yes, auto, import, ++ ephemeral, or ephemeral-import. For details about the modes, ++ see the option in ++ systemd-sysext8. ++ Defaults to no. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ See Also ++ ++ systemd1 ++ systemd-sysext8 ++ systemd.syntax7 ++ ++ ++ ++ +diff --git a/man/systemd-sysext.xml b/man/systemd-sysext.xml +index 3f60c85dba..6df2d94e9f 100644 +--- a/man/systemd-sysext.xml ++++ b/man/systemd-sysext.xml +@@ -74,7 +74,12 @@ + System extension images are strictly read-only by default. On mutable host file systems, + /usr/ and /opt/ hierarchies become read-only while extensions + are merged, unless mutability is enabled. Mutability may be enabled via the +- option; see "Mutability" below for more information. ++ option and the Mutable= option in the configuration file; ++ see "Mutability" below for more information. ++ ++ Various command options can be configured globally via configuration files. See ++ sysext.conf5 ++ for details. + + System extensions are supposed to be purely additive, i.e. they are supposed to include only files + that do not exist in the underlying basic OS image. However, the underlying mechanism (overlayfs) also +@@ -491,6 +496,7 @@ + See Also + + systemd1 ++ sysext.conf5 + systemd-nspawn1 + systemd-stub7 + importctl1 +-- +2.51.0 + diff --git a/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0010-sysext-support-ImagePolicy-global-config-option.patch b/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0010-sysext-support-ImagePolicy-global-config-option.patch new file mode 100644 index 00000000000..34979f46f17 --- /dev/null +++ b/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0010-sysext-support-ImagePolicy-global-config-option.patch @@ -0,0 +1,50 @@ +From 363c849b4faed27449a0e3ee41c302709aec0807 Mon Sep 17 00:00:00 2001 +From: Emanuele Giuseppe Esposito +Date: Thu, 17 Jul 2025 10:16:24 -0400 +Subject: [PATCH 3/4] sysext: support ImagePolicy global config option + +Just as Mutable=, support ImagePolicy in systemd/{sysext/confext}.conf and +dropins in systemd/{sysext.confext}.conf.d/* configs. +--- + man/sysext.conf.xml | 12 ++++++++++++ + src/sysext/sysext.c | 1 + + 2 files changed, 13 insertions(+) + +diff --git a/man/sysext.conf.xml b/man/sysext.conf.xml +index cdd88f2447..f717b74426 100644 +--- a/man/sysext.conf.xml ++++ b/man/sysext.conf.xml +@@ -73,6 +73,18 @@ + + + ++ ++ ++ ImagePolicy= ++ Set the image policy. Takes an image policy string as argument, as per ++ systemd.image-policy7. ++ For details, see the option in ++ systemd-sysext8. ++ ++ ++ ++ ++ + + + +diff --git a/src/sysext/sysext.c b/src/sysext/sysext.c +index 332fc55bb3..9656e975c4 100644 +--- a/src/sysext/sysext.c ++++ b/src/sysext/sysext.c +@@ -157,6 +157,7 @@ static int parse_config_file(ImageClass image_class) { + const char *section = image_class == IMAGE_SYSEXT ? "SysExt" : "ConfExt"; + const ConfigTableItem items[] = { + { section, "Mutable", config_parse_mutable_mode, 0, &arg_mutable }, ++ { section, "ImagePolicy", config_parse_image_policy, 0, &arg_image_policy }, + {} + }; + _cleanup_free_ char *config_file = NULL; +-- +2.51.0 + diff --git a/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0011-sysext-Fix-config-file-support-with-root.patch b/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0011-sysext-Fix-config-file-support-with-root.patch new file mode 100644 index 00000000000..92ea3ec8337 --- /dev/null +++ b/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0011-sysext-Fix-config-file-support-with-root.patch @@ -0,0 +1,183 @@ +From 3498a462f517b024b3125e0bb79c8c6c54bb62c9 Mon Sep 17 00:00:00 2001 +From: Kai Lueke +Date: Thu, 11 Dec 2025 19:49:20 +0900 +Subject: [PATCH] sysext: Fix config file support with --root= + +Config files for --root= weren't picked up as expected because the +--root= flag got parsed after the config file. +Switch the order of config file and CLI flag parsing while letting the +CLI flags overwrite things set by the config files by tracking state +during parsing. +--- + src/sysext/sysext.c | 38 +++++++++++++++----- + test/units/TEST-50-DISSECT.sysext.sh | 52 ++++++++++++++++++++++++++++ + 2 files changed, 82 insertions(+), 8 deletions(-) + +diff --git a/src/sysext/sysext.c b/src/sysext/sysext.c +index 9656e975c4..1fb0c72e48 100644 +--- a/src/sysext/sysext.c ++++ b/src/sysext/sysext.c +@@ -92,8 +92,10 @@ static bool arg_no_reload = false; + static bool arg_always_refresh = false; + static int arg_noexec = -1; + static ImagePolicy *arg_image_policy = NULL; ++static bool arg_image_policy_set = false; /* Tracks initialization */ + static bool arg_varlink = false; + static MutableMode arg_mutable = MUTABLE_NO; ++static bool arg_mutable_set = false; /* Tracks initialization */ + + /* Is set to IMAGE_CONFEXT when systemd is called with the confext functionality instead of the default */ + static ImageClass arg_image_class = IMAGE_SYSEXT; +@@ -154,10 +156,13 @@ static int parse_mutable_mode(const char *p) { + static DEFINE_CONFIG_PARSE_ENUM(config_parse_mutable_mode, mutable_mode, MutableMode); + + static int parse_config_file(ImageClass image_class) { ++ _cleanup_(image_policy_freep) ImagePolicy *config_image_policy = NULL; ++ MutableMode config_mutable = MUTABLE_NO; + const char *section = image_class == IMAGE_SYSEXT ? "SysExt" : "ConfExt"; ++ const char *sections = image_class == IMAGE_SYSEXT ? "SysExt\0" : "ConfExt\0"; + const ConfigTableItem items[] = { +- { section, "Mutable", config_parse_mutable_mode, 0, &arg_mutable }, +- { section, "ImagePolicy", config_parse_image_policy, 0, &arg_image_policy }, ++ { section, "Mutable", config_parse_mutable_mode, 0, &config_mutable }, ++ { section, "ImagePolicy", config_parse_image_policy, 0, &config_image_policy }, + {} + }; + _cleanup_free_ char *config_file = NULL; +@@ -170,7 +175,7 @@ static int parse_config_file(ImageClass image_class) { + r = config_parse_standard_file_with_dropins_full( + arg_root, + config_file, +- image_class == IMAGE_SYSEXT ? "SysExt\0" : "ConfExt\0", ++ sections, + config_item_table_lookup, items, + CONFIG_PARSE_WARN, + /* userdata = */ NULL, +@@ -179,6 +184,17 @@ static int parse_config_file(ImageClass image_class) { + if (r < 0) + return r; + ++ /* Because this runs after parse_argv we only overwrite when things aren't set yet. */ ++ if (!arg_mutable_set) { ++ arg_mutable = config_mutable; ++ arg_mutable_set = true; ++ } ++ ++ if (!arg_image_policy_set) { ++ arg_image_policy = TAKE_PTR(config_image_policy); ++ arg_image_policy_set = true; ++ } ++ + return 0; + } + +@@ -2794,6 +2810,9 @@ static int parse_argv(int argc, char *argv[]) { + r = parse_image_policy_argument(optarg, &arg_image_policy); + if (r < 0) + return r; ++ /* When the CLI flag is given we initialize even if NULL ++ * so that the config file entry won't overwrite it */ ++ arg_image_policy_set = true; + break; + + case ARG_NOEXEC: +@@ -2819,6 +2838,7 @@ static int parse_argv(int argc, char *argv[]) { + if (r < 0) + return log_error_errno(r, "Failed to parse argument to --mutable=: %s", optarg); + arg_mutable = r; ++ arg_mutable_set = true; + break; + + case '?': +@@ -2871,11 +2891,6 @@ static int run(int argc, char *argv[]) { + arg_mutable = r; + } + +- /* Parse configuration file */ +- r = parse_config_file(arg_image_class); +- if (r < 0) +- log_warning_errno(r, "Failed to parse global config file, ignoring: %m"); +- + /* Parse command line */ + r = parse_argv(argc, argv); + if (r <= 0) +@@ -2888,6 +2903,13 @@ static int run(int argc, char *argv[]) { + if (r < 0) + return log_error_errno(r, "Failed to parse environment variable: %m"); + ++ /* Parse configuration file after argv because it needs --root=. ++ * The config entries will not overwrite values set already by ++ * env/argv because we track initialization. */ ++ r = parse_config_file(arg_image_class); ++ if (r < 0) ++ log_warning_errno(r, "Failed to parse global config file, ignoring: %m"); ++ + if (arg_varlink) { + _cleanup_(sd_varlink_server_unrefp) sd_varlink_server *varlink_server = NULL; + +diff --git a/test/units/TEST-50-DISSECT.sysext.sh b/test/units/TEST-50-DISSECT.sysext.sh +index 6e64eea492..7a3146a0e7 100755 +--- a/test/units/TEST-50-DISSECT.sysext.sh ++++ b/test/units/TEST-50-DISSECT.sysext.sh +@@ -1501,6 +1501,58 @@ run_systemd_sysext "$fake_root" unmerge + extension_verify_after_unmerge "$fake_root" "$hierarchy" -h + ) + ++ ++( init_trap ++: "Check config file support for --root=" ++fake_root=${roots_dir:+"$roots_dir/config-file"} ++hierarchy=/opt ++extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy" ++ ++[[ "$FSTYPE" == "fuseblk" ]] && exit 0 ++if [ "$roots_dir" = "" ]; then ++ echo >&2 "Skipping test when --root= is not used" ++ exit 0 ++fi ++ ++prepare_root "$fake_root" "$hierarchy" ++prepare_extension_image_raw "$fake_root" "$hierarchy" ++prepare_extension_mutable_dir "$extension_data_dir" ++prepare_read_only_hierarchy "$fake_root" "$hierarchy" ++ ++mkdir -p "$fake_root/etc/systemd/" ++{ echo "[SysExt]" ; echo "Mutable=auto" ; } > "$fake_root/etc/systemd/sysext.conf" ++# Config file should be picked up with --root= set ++run_systemd_sysext "$fake_root" merge ++MNTOPT=$(findmnt "$fake_root$hierarchy" --first-only --direction backward --raw --noheadings -o VFS-OPTIONS | grep -o rw || true) ++if [ "$MNTOPT" != "rw" ]; then ++ echo >&2 "Merge did not pick up mutable setting from config file" ++ exit 1 ++fi ++extension_verify_after_merge "$fake_root" "$hierarchy" -e -h -u ++run_systemd_sysext "$fake_root" unmerge ++ ++# CLI arg should be able to overwrite config file ++run_systemd_sysext "$fake_root" merge --mutable=no ++MNTOPT=$(findmnt "$fake_root$hierarchy" --first-only --direction backward --raw --noheadings -o VFS-OPTIONS | grep -o ro || true) ++if [ "$MNTOPT" != "ro" ]; then ++ echo >&2 "Merge did not pick up CLI arg to overwrite mutable setting from config file" ++ exit 1 ++fi ++extension_verify_after_merge "$fake_root" "$hierarchy" -e -h ++run_systemd_sysext "$fake_root" unmerge ++ ++{ echo "[SysExt]" ; echo "ImagePolicy=root=signed+absent:usr=signed+absent" ; } > "$fake_root/etc/systemd/sysext.conf" ++# Config file should be picked up with --root= set ++if run_systemd_sysext "$fake_root" merge; then ++ echo >&2 "Merge did not fail with strict image policy in config file" ++ exit 1 ++fi ++# CLI arg should be able to overwrite config file ++run_systemd_sysext "$fake_root" merge --image-policy="*" ++extension_verify_after_merge "$fake_root" "$hierarchy" -e -h ++run_systemd_sysext "$fake_root" unmerge ++) ++ + } # End of run_sysext_tests + + +-- +2.52.0 + diff --git a/sdk_container/src/third_party/coreos-overlay/profiles/coreos/base/package.accept_keywords b/sdk_container/src/third_party/coreos-overlay/profiles/coreos/base/package.accept_keywords index e09d468d747..7d43b25235c 100644 --- a/sdk_container/src/third_party/coreos-overlay/profiles/coreos/base/package.accept_keywords +++ b/sdk_container/src/third_party/coreos-overlay/profiles/coreos/base/package.accept_keywords @@ -101,3 +101,6 @@ sys-apps/azure-vm-utils =app-containers/containerd-2.1* ~amd64 ~arm64 =app-containers/runc-1.3* ~amd64 ~arm64 + +# Use new systemd +=sys-apps/systemd-258.2 ~amd64 ~arm64 diff --git a/sdk_container/src/third_party/coreos-overlay/sys-kernel/bootengine/bootengine-9999.ebuild b/sdk_container/src/third_party/coreos-overlay/sys-kernel/bootengine/bootengine-9999.ebuild index f27d8fe5ad3..ef179be391c 100644 --- a/sdk_container/src/third_party/coreos-overlay/sys-kernel/bootengine/bootengine-9999.ebuild +++ b/sdk_container/src/third_party/coreos-overlay/sys-kernel/bootengine/bootengine-9999.ebuild @@ -7,7 +7,8 @@ EGIT_REPO_URI="https://github.com/flatcar/bootengine.git" if [[ "${PV}" == 9999 ]]; then KEYWORDS="~amd64 ~arm ~arm64 ~x86" else - EGIT_COMMIT="5d3ac4819005c92bc1b64d73ccf8d8b959443c3e" # flatcar-master + #EGIT_COMMIT="5d3ac4819005c92bc1b64d73ccf8d8b959443c3e" # flatcar-master + EGIT_BRANCH="kai/default-confext" KEYWORDS="amd64 arm arm64 x86" fi diff --git a/sdk_container/src/third_party/portage-stable/acct-group/clock/clock-0.ebuild b/sdk_container/src/third_party/portage-stable/acct-group/clock/clock-0.ebuild new file mode 100644 index 00000000000..57a7ba93f17 --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/acct-group/clock/clock-0.ebuild @@ -0,0 +1,8 @@ +# Copyright 2025 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI=8 + +inherit acct-group + +ACCT_GROUP_ID=550 diff --git a/sdk_container/src/third_party/portage-stable/acct-group/clock/metadata.xml b/sdk_container/src/third_party/portage-stable/acct-group/clock/metadata.xml new file mode 100644 index 00000000000..31123d01cb4 --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/acct-group/clock/metadata.xml @@ -0,0 +1,7 @@ + + + + + systemd@gentoo.org + + diff --git a/sdk_container/src/third_party/portage-stable/sys-apps/systemd/Manifest b/sdk_container/src/third_party/portage-stable/sys-apps/systemd/Manifest index 33b33288f91..e67e0645c8c 100644 --- a/sdk_container/src/third_party/portage-stable/sys-apps/systemd/Manifest +++ b/sdk_container/src/third_party/portage-stable/sys-apps/systemd/Manifest @@ -1,3 +1,2 @@ -DIST systemd-257.10.tar.gz 16425661 BLAKE2B c8fef145933810110f5470f64dd41213864cc1cae889fb306c817d7a16cc300adbcab27e3a3be91428f0a7d354041f7f9ca431f7745bce9c7cc1e3bb065be84a SHA512 49a2c8cc1cd91363d90165a1145dcc417d524afd428917dad332e4b057ed9fc3ddb5b4beafab094b02a85d930c8aef9b63c8c9c1bc76ef3bdf0ce38a7d46466f -DIST systemd-257.9.tar.gz 16401765 BLAKE2B c3ad528d37b89de8f82548807e950b59aab43f875a533ad983169eb539594e5e8230b6b562caee5297dcec4572e27df0e53ebee04f79e85f429f47862031592e SHA512 23b3d2764e0f990d8373068ccb41177793413bc193f7bd34e38b03d6fc3cd32d07c86e9dcbf07e32904075bb5eeca208f65beab04d628ac0e0b81ba87a975c1b DIST systemd-258.2.tar.gz 16989522 BLAKE2B 55c8a134d2c80241ed654fab6bf2df0a2139313dbbb905f3abf07c9f86940ff03c8787fe7c4604c34bbb84088c15cd73ae5e013929b290b92808b5473550235e SHA512 1dc016a5a037aec2682e08d2add0dcf8d03db15b45ce8c6b677898f734aefd4694ce18e588d579e42514071fc4c167b2bf53808478b2bd3856b257c9fbcde45d +DIST systemd-258.tar.gz 16976853 BLAKE2B c63bc09bff11ba4cf6e87bef689250a6b354bf8f5bfb5af6d2a173fa1e1838aa457a8a7db66f7aad20dae25b7a0defddcb052d53f18a688a2dd6d5f323d4692a SHA512 c488354da1c170ad02e10926f561d1985c3c3393fec878562f295ef764fdf3a1b2877c3b2549253f19bf23e357be6e443a50b937f60f4677f286d3402d611b85 diff --git a/sdk_container/src/third_party/portage-stable/sys-apps/systemd/systemd-257.10.ebuild b/sdk_container/src/third_party/portage-stable/sys-apps/systemd/systemd-257.10.ebuild deleted file mode 100644 index 13fadd0407b..00000000000 --- a/sdk_container/src/third_party/portage-stable/sys-apps/systemd/systemd-257.10.ebuild +++ /dev/null @@ -1,570 +0,0 @@ -# Copyright 2011-2025 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=8 -PYTHON_COMPAT=( python3_{11..13} ) - -# Avoid QA warnings -TMPFILES_OPTIONAL=1 -UDEV_OPTIONAL=1 - -QA_PKGCONFIG_VERSION=$(ver_cut 1) - -if [[ ${PV} == 9999 ]]; then - EGIT_REPO_URI="https://github.com/systemd/systemd.git" - inherit git-r3 -else - MY_PV=${PV/_/-} - MY_P=${PN}-${MY_PV} - S=${WORKDIR}/${MY_P} - SRC_URI="https://github.com/systemd/${PN}/archive/refs/tags/v${MY_PV}.tar.gz -> ${MY_P}.tar.gz" - - if [[ ${PV} != *rc* ]] ; then - KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~loong ~m68k ~mips ~ppc ~ppc64 ~riscv ~s390 ~sparc ~x86" - fi -fi - -inherit bash-completion-r1 linux-info meson-multilib optfeature pam python-single-r1 -inherit secureboot systemd toolchain-funcs udev - -DESCRIPTION="System and service manager for Linux" -HOMEPAGE="https://systemd.io/" - -LICENSE="GPL-2 LGPL-2.1 MIT public-domain" -SLOT="0/2" -IUSE=" - acl apparmor audit boot bpf cgroup-hybrid cryptsetup curl +dns-over-tls elfutils - fido2 +gcrypt gnutls homed http idn importd iptables +kernel-install +kmod - +lz4 lzma +openssl pam pcre pkcs11 policykit pwquality qrcode - +resolvconf +seccomp selinux split-usr +sysv-utils test tpm ukify vanilla xkb +zstd -" -REQUIRED_USE=" - ${PYTHON_REQUIRED_USE} - dns-over-tls? ( || ( gnutls openssl ) ) - fido2? ( cryptsetup openssl ) - homed? ( cryptsetup pam openssl ) - importd? ( curl lzma || ( gcrypt openssl ) ) - pwquality? ( homed ) - boot? ( kernel-install ) - ukify? ( boot ) -" -RESTRICT="!test? ( test )" - -MINKV="4.15" - -COMMON_DEPEND=" - >=sys-apps/util-linux-2.32:0=[${MULTILIB_USEDEP}] - sys-libs/libcap:0=[${MULTILIB_USEDEP}] - virtual/libcrypt:=[${MULTILIB_USEDEP}] - acl? ( sys-apps/acl:0= ) - apparmor? ( >=sys-libs/libapparmor-2.13:0= ) - audit? ( >=sys-process/audit-2:0= ) - bpf? ( >=dev-libs/libbpf-1.4.0:0= ) - cryptsetup? ( >=sys-fs/cryptsetup-2.0.1:0= ) - curl? ( >=net-misc/curl-7.32.0:0= ) - elfutils? ( >=dev-libs/elfutils-0.158:0= ) - fido2? ( dev-libs/libfido2:0= ) - gcrypt? ( >=dev-libs/libgcrypt-1.4.5:0=[${MULTILIB_USEDEP}] ) - gnutls? ( >=net-libs/gnutls-3.6.0:0= ) - http? ( >=net-libs/libmicrohttpd-0.9.33:0=[epoll(+)] ) - idn? ( net-dns/libidn2:= ) - importd? ( - app-arch/bzip2:0= - virtual/zlib:= - ) - kmod? ( >=sys-apps/kmod-15:0= ) - lz4? ( >=app-arch/lz4-0_p131:0=[${MULTILIB_USEDEP}] ) - lzma? ( >=app-arch/xz-utils-5.0.5-r1:0=[${MULTILIB_USEDEP}] ) - iptables? ( net-firewall/iptables:0= ) - openssl? ( >=dev-libs/openssl-1.1.0:0= ) - pam? ( sys-libs/pam:=[${MULTILIB_USEDEP}] ) - pkcs11? ( >=app-crypt/p11-kit-0.23.3:0= ) - pcre? ( dev-libs/libpcre2 ) - pwquality? ( >=dev-libs/libpwquality-1.4.1:0= ) - qrcode? ( >=media-gfx/qrencode-3:0= ) - seccomp? ( >=sys-libs/libseccomp-2.3.3:0= ) - selinux? ( >=sys-libs/libselinux-2.1.9:0= ) - tpm? ( app-crypt/tpm2-tss:0= ) - xkb? ( >=x11-libs/libxkbcommon-0.4.1:0= ) - zstd? ( >=app-arch/zstd-1.4.0:0=[${MULTILIB_USEDEP}] ) -" - -# Newer linux-headers needed by ia64, bug #480218 -DEPEND="${COMMON_DEPEND} - >=sys-kernel/linux-headers-${MINKV} -" - -PEFILE_DEPEND='dev-python/pefile[${PYTHON_USEDEP}]' - -# baselayout-2.2 has /run -RDEPEND="${COMMON_DEPEND} - >=acct-group/adm-0-r1 - >=acct-group/wheel-0-r1 - >=acct-group/kmem-0-r1 - >=acct-group/tty-0-r1 - >=acct-group/utmp-0-r1 - >=acct-group/audio-0-r1 - >=acct-group/cdrom-0-r1 - >=acct-group/dialout-0-r1 - >=acct-group/disk-0-r1 - >=acct-group/input-0-r1 - >=acct-group/kvm-0-r1 - >=acct-group/lp-0-r1 - >=acct-group/render-0-r1 - acct-group/sgx - >=acct-group/tape-0-r1 - acct-group/users - >=acct-group/video-0-r1 - >=acct-group/systemd-journal-0-r1 - >=acct-user/root-0-r1 - acct-user/nobody - >=acct-user/systemd-journal-remote-0-r1 - >=acct-user/systemd-coredump-0-r1 - >=acct-user/systemd-network-0-r1 - acct-user/systemd-oom - >=acct-user/systemd-resolve-0-r1 - >=acct-user/systemd-timesync-0-r1 - >=sys-apps/baselayout-2.2 - ukify? ( - ${PYTHON_DEPS} - $(python_gen_cond_dep "${PEFILE_DEPEND}") - ) - selinux? ( - sec-policy/selinux-base-policy[systemd] - sec-policy/selinux-ntp - ) - sysv-utils? ( - !sys-apps/openrc[sysv-utils(-)] - !sys-apps/sysvinit - ) - !sysv-utils? ( sys-apps/sysvinit ) - resolvconf? ( !net-dns/openresolv ) - !sys-apps/hwids[udev] - !sys-auth/nss-myhostname - !sys-fs/eudev - !sys-fs/udev -" - -# sys-apps/dbus: the daemon only (+ build-time lib dep for tests) -PDEPEND=">=sys-apps/dbus-1.9.8[systemd] - >=sys-fs/udev-init-scripts-34 - policykit? ( sys-auth/polkit ) - !vanilla? ( sys-apps/gentoo-systemd-integration )" - -BDEPEND=" - app-arch/xz-utils:0 - dev-util/gperf - >=dev-build/meson-0.46 - >=sys-apps/coreutils-8.16 - sys-devel/gettext - virtual/pkgconfig - bpf? ( - >=dev-util/bpftool-7.0.0 - sys-devel/bpf-toolchain - ) - test? ( - app-text/tree - dev-lang/perl - sys-apps/dbus - ) - app-text/docbook-xml-dtd:4.2 - app-text/docbook-xml-dtd:4.5 - app-text/docbook-xsl-stylesheets - dev-libs/libxslt:0 - ${PYTHON_DEPS} - $(python_gen_cond_dep " - dev-python/jinja2[\${PYTHON_USEDEP}] - dev-python/lxml[\${PYTHON_USEDEP}] - boot? ( - >=dev-python/pyelftools-0.30[\${PYTHON_USEDEP}] - test? ( ${PEFILE_DEPEND} ) - ) - ") -" - -QA_FLAGS_IGNORED="usr/lib/systemd/boot/efi/.*" -QA_EXECSTACK="usr/lib/systemd/boot/efi/*" - -check_cgroup_layout() { - # https://bugs.gentoo.org/935261 - [[ ${MERGE_TYPE} != buildonly ]] || return - [[ -z ${ROOT} ]] || return - [[ -e /sys/fs/cgroup/unified ]] || return - grep -q 'SYSTEMD_CGROUP_ENABLE_LEGACY_FORCE=1' /proc/cmdline && return - - eerror "This system appears to be booted with the 'hybrid' cgroup layout." - eerror "This layout obsolete and is disabled in systemd." - - if grep -qF 'systemd.unified_cgroup_hierarchy'; then - eerror "Remove the systemd.unified_cgroup_hierarchy option" - eerror "from the kernel command line and reboot." - die "hybrid cgroup layout detected" - fi -} - -pkg_pretend() { - if use split-usr; then - eerror "Please complete the migration to merged-usr." - eerror "https://wiki.gentoo.org/wiki/Merge-usr" - die "systemd no longer supports split-usr" - fi - - check_cgroup_layout - - if use cgroup-hybrid; then - eerror "Disable the 'cgroup-hybrid' USE flag." - eerror "Rebuild any initramfs images after rebuilding systemd." - die "cgroup-hybrid is no longer supported" - fi - - if [[ ${MERGE_TYPE} != buildonly ]]; then - local CONFIG_CHECK="~BLK_DEV_BSG ~CGROUPS - ~CGROUP_BPF ~DEVTMPFS ~EPOLL ~FANOTIFY ~FHANDLE - ~INOTIFY_USER ~IPV6 ~NET ~NET_NS ~PROC_FS ~SIGNALFD ~SYSFS - ~TIMERFD ~TMPFS_XATTR ~UNIX ~USER_NS - ~CRYPTO_HMAC ~CRYPTO_SHA256 ~CRYPTO_USER_API_HASH - ~!GRKERNSEC_PROC ~!IDE ~!SYSFS_DEPRECATED - ~!SYSFS_DEPRECATED_V2" - - use acl && CONFIG_CHECK+=" ~TMPFS_POSIX_ACL" - use bpf && CONFIG_CHECK+=" ~BPF ~BPF_SYSCALL ~BPF_LSM ~DEBUG_INFO_BTF" - use seccomp && CONFIG_CHECK+=" ~SECCOMP ~SECCOMP_FILTER" - - if kernel_is -ge 5 10 20; then - CONFIG_CHECK+=" ~KCMP" - else - CONFIG_CHECK+=" ~CHECKPOINT_RESTORE" - fi - - if kernel_is -ge 4 18; then - CONFIG_CHECK+=" ~AUTOFS_FS" - else - CONFIG_CHECK+=" ~AUTOFS4_FS" - fi - - if linux_config_exists; then - local uevent_helper_path=$(linux_chkconfig_string UEVENT_HELPER_PATH) - if [[ -n ${uevent_helper_path} ]] && [[ ${uevent_helper_path} != '""' ]]; then - ewarn "It's recommended to set an empty value to the following kernel config option:" - ewarn "CONFIG_UEVENT_HELPER_PATH=${uevent_helper_path}" - fi - if linux_chkconfig_present X86; then - CONFIG_CHECK+=" ~DMIID" - fi - fi - - if kernel_is -lt ${MINKV//./ }; then - ewarn "Kernel version at least ${MINKV} required" - fi - - check_extra_config - fi -} - -pkg_setup() { - use boot && secureboot_pkg_setup -} - -src_unpack() { - default - [[ ${PV} != 9999 ]] || git-r3_src_unpack -} - -src_prepare() { - local PATCHES=( - "${FILESDIR}"/systemd-257-cred-util-tpm2.patch - ) - - if ! use vanilla; then - PATCHES+=( - "${FILESDIR}/gentoo-journald-audit-r1.patch" - ) - fi - - default -} - -src_configure() { - # Prevent conflicts with i686 cross toolchain, bug 559726 - tc-export AR CC NM OBJCOPY RANLIB - - python_setup - - multilib-minimal_src_configure -} - -multilib_src_configure() { - local myconf=( - --localstatedir="${EPREFIX}/var" - -Ddocdir="share/doc/${PF}" - # default is developer, bug 918671 - -Dmode=release - -Dsupport-url="https://gentoo.org/support/" - -Dpamlibdir="$(getpam_mod_dir)" - # avoid bash-completion dep - -Dbashcompletiondir="$(get_bashcompdir)" - -Dsplit-bin=false - # Disable compatibility with sysvinit - -Dsysvinit-path= - -Dsysvrcnd-path= - # no deps - -Dima=true - # Match /etc/shells, bug 919749 - -Ddebug-shell="${EPREFIX}/bin/sh" - -Ddefault-user-shell="${EPREFIX}/bin/bash" - # Optional components/dependencies - $(meson_native_use_feature acl) - $(meson_native_use_feature apparmor) - $(meson_native_use_feature audit) - $(meson_native_use_feature boot bootloader) - $(meson_native_use_feature bpf bpf-framework) - -Dbpf-compiler=gcc - $(meson_native_use_feature cryptsetup libcryptsetup) - $(meson_native_use_feature curl libcurl) - $(meson_native_use_bool dns-over-tls dns-over-tls) - $(meson_native_use_feature elfutils) - $(meson_native_use_feature fido2 libfido2) - $(meson_feature gcrypt) - $(meson_native_use_feature gnutls) - $(meson_native_use_feature homed) - $(meson_native_use_feature http microhttpd) - $(meson_native_use_bool idn) - $(meson_native_use_feature importd) - $(meson_native_use_feature importd bzip2) - $(meson_native_use_feature importd zlib) - $(meson_native_use_bool kernel-install) - $(meson_native_use_feature kmod) - $(meson_feature lz4) - $(meson_feature lzma xz) - $(meson_use test tests) - $(meson_feature zstd) - $(meson_native_use_feature iptables libiptc) - $(meson_native_use_feature openssl) - $(meson_feature pam) - $(meson_native_use_feature pkcs11 p11kit) - $(meson_native_use_feature pcre pcre2) - $(meson_native_use_feature policykit polkit) - $(meson_native_use_feature pwquality) - $(meson_native_use_feature qrcode qrencode) - $(meson_native_use_feature seccomp) - $(meson_native_use_feature selinux) - $(meson_native_use_feature tpm tpm2) - $(meson_native_use_feature test dbus) - $(meson_native_use_feature ukify) - $(meson_native_use_feature xkb xkbcommon) - -Dntp-servers="0.gentoo.pool.ntp.org 1.gentoo.pool.ntp.org 2.gentoo.pool.ntp.org 3.gentoo.pool.ntp.org" - # Breaks screen, tmux, etc. - -Ddefault-kill-user-processes=false - -Dcreate-log-dirs=false - - # multilib options - $(meson_native_true backlight) - $(meson_native_true binfmt) - $(meson_native_true coredump) - $(meson_native_true environment-d) - $(meson_native_true firstboot) - $(meson_native_true hibernate) - $(meson_native_true hostnamed) - $(meson_native_true ldconfig) - $(meson_native_true localed) - $(meson_native_enabled man) - $(meson_native_true networkd) - $(meson_native_true quotacheck) - $(meson_native_true randomseed) - $(meson_native_true rfkill) - $(meson_native_true sysusers) - $(meson_native_true timedated) - $(meson_native_true timesyncd) - $(meson_native_true tmpfiles) - $(meson_native_true vconsole) - ) - - case $(tc-arch) in - amd64|arm|arm64|loong|ppc|ppc64|riscv|s390|x86) - # src/vmspawn/vmspawn-util.h: QEMU_MACHINE_TYPE - myconf+=( $(meson_native_enabled vmspawn) ) ;; - *) - myconf+=( -Dvmspawn=disabled ) ;; - esac - - meson_src_configure "${myconf[@]}" -} - -multilib_src_test() { - ( - unset DBUS_SESSION_BUS_ADDRESS XDG_RUNTIME_DIR - export COLUMNS=80 - addpredict /dev - addpredict /proc - addpredict /run - addpredict /sys/fs/cgroup - meson_src_test --timeout-multiplier=10 - ) || die -} - -multilib_src_install_all() { - einstalldocs - dodoc "${FILESDIR}"/nsswitch.conf - - insinto /usr/lib/tmpfiles.d - doins "${FILESDIR}"/legacy.conf - - if ! use resolvconf; then - rm -f "${ED}"/usr/bin/resolvconf || die - fi - - if ! use sysv-utils; then - rm "${ED}"/usr/bin/{halt,init,poweroff,reboot,shutdown} || die - rm "${ED}"/usr/share/man/man1/init.1 || die - rm "${ED}"/usr/share/man/man8/{halt,poweroff,reboot,shutdown}.8 || die - fi - - # https://bugs.gentoo.org/761763 - rm -r "${ED}"/usr/lib/sysusers.d || die - - # Preserve empty dirs in /etc & /var, bug #437008 - keepdir /etc/{binfmt.d,modules-load.d,tmpfiles.d} - keepdir /etc/kernel/install.d - keepdir /etc/systemd/{network,system,user} - keepdir /etc/udev/rules.d - - keepdir /etc/udev/hwdb.d - - keepdir /usr/lib/systemd/{system-sleep,system-shutdown} - keepdir /usr/lib/{binfmt.d,modules-load.d} - keepdir /usr/lib/systemd/user-generators - keepdir /var/lib/systemd - keepdir /var/log/journal - - if use pam; then - if use selinux; then - newpamd "${FILESDIR}"/systemd-user-selinux.pam systemd-user - else - newpamd "${FILESDIR}"/systemd-user.pam systemd-user - fi - fi - - if use kernel-install; then - # Dummy config, remove to make room for sys-kernel/installkernel - rm "${ED}/usr/lib/kernel/install.conf" || die - fi - - use ukify && python_fix_shebang "${ED}" - use boot && secureboot_auto_sign -} - -migrate_locale() { - local envd_locale_def="${EROOT}/etc/env.d/02locale" - local envd_locale=( "${EROOT}"/etc/env.d/??locale ) - local locale_conf="${EROOT}/etc/locale.conf" - - if [[ ! -L ${locale_conf} && ! -e ${locale_conf} ]]; then - # If locale.conf does not exist... - if [[ -e ${envd_locale} ]]; then - # ...either copy env.d/??locale if there's one - ebegin "Moving ${envd_locale} to ${locale_conf}" - mv "${envd_locale}" "${locale_conf}" - eend ${?} || FAIL=1 - else - # ...or create a dummy default - ebegin "Creating ${locale_conf}" - cat > "${locale_conf}" <<-EOF - # This file has been created by the sys-apps/systemd ebuild. - # See locale.conf(5) and localectl(1). - - # LANG=${LANG} - EOF - eend ${?} || FAIL=1 - fi - fi - - if [[ ! -L ${envd_locale} ]]; then - # now, if env.d/??locale is not a symlink (to locale.conf)... - if [[ -e ${envd_locale} ]]; then - # ...warn the user that he has duplicate locale settings - ewarn - ewarn "To ensure consistent behavior, you should replace ${envd_locale}" - ewarn "with a symlink to ${locale_conf}. Please migrate your settings" - ewarn "and create the symlink with the following command:" - ewarn "ln -s -n -f ../locale.conf ${envd_locale}" - ewarn - else - # ...or just create the symlink if there's nothing here - ebegin "Creating ${envd_locale_def} -> ../locale.conf symlink" - ln -n -s ../locale.conf "${envd_locale_def}" - eend ${?} || FAIL=1 - fi - fi -} - -pkg_preinst() { - if [[ -e ${EROOT}/etc/sysctl.conf ]]; then - # Symlink /etc/sysctl.conf for easy migration. - dosym ../../../etc/sysctl.conf /usr/lib/sysctl.d/99-sysctl.conf - fi - - if ! use boot && has_version "sys-apps/systemd[gnuefi(-)]"; then - ewarn "The 'gnuefi' USE flag has been renamed to 'boot'." - ewarn "Make sure to enable the 'boot' USE flag if you use systemd-boot." - fi -} - -pkg_postinst() { - systemd_update_catalog - - # Keep this here in case the database format changes so it gets updated - # when required. - systemd-hwdb --root="${ROOT}" update - - udev_reload || FAIL=1 - - # Bug 465468, make sure locales are respected, and ensure consistency - # between OpenRC & systemd - migrate_locale - - if [[ -z ${REPLACING_VERSIONS} ]]; then - if type systemctl &>/dev/null; then - systemctl --root="${ROOT:-/}" enable getty@.service remote-fs.target || FAIL=1 - fi - elog "To enable a useful set of services, run the following:" - elog " systemctl preset-all --preset-mode=enable-only" - fi - - if [[ -L ${EROOT}/var/lib/systemd/timesync ]]; then - rm "${EROOT}/var/lib/systemd/timesync" - fi - - if [[ -z ${ROOT} && -d /run/systemd/system ]]; then - ebegin "Reexecuting system manager (systemd)" - systemctl daemon-reexec - eend $? || FAIL=1 - - # https://lists.freedesktop.org/archives/systemd-devel/2024-June/050466.html - ebegin "Signaling user managers to reexec" - systemctl kill --kill-whom='main' --signal='SIGRTMIN+25' 'user@*.service' - eend $? - fi - - if [[ ${FAIL} ]]; then - eerror "One of the postinst commands failed. Please check the postinst output" - eerror "for errors. You may need to clean up your system and/or try installing" - eerror "systemd again." - eerror - fi - - if use boot; then - optfeature "installing kernels in systemd-boot's native layout and update loader entries" \ - "sys-kernel/installkernel[systemd-boot]" - fi - if use ukify; then - optfeature "generating unified kernel image on each kernel installation" \ - "sys-kernel/installkernel[ukify]" - fi -} - -pkg_prerm() { - # If removing systemd completely, remove the catalog database. - if [[ ! ${REPLACED_BY_VERSION} ]]; then - rm -f -v "${EROOT}"/var/lib/systemd/catalog/database - fi -} diff --git a/sdk_container/src/third_party/portage-stable/sys-apps/systemd/systemd-257.9.ebuild b/sdk_container/src/third_party/portage-stable/sys-apps/systemd/systemd-257.9.ebuild deleted file mode 100644 index 3cee9769ce1..00000000000 --- a/sdk_container/src/third_party/portage-stable/sys-apps/systemd/systemd-257.9.ebuild +++ /dev/null @@ -1,570 +0,0 @@ -# Copyright 2011-2025 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=8 -PYTHON_COMPAT=( python3_{11..13} ) - -# Avoid QA warnings -TMPFILES_OPTIONAL=1 -UDEV_OPTIONAL=1 - -QA_PKGCONFIG_VERSION=$(ver_cut 1) - -if [[ ${PV} == 9999 ]]; then - EGIT_REPO_URI="https://github.com/systemd/systemd.git" - inherit git-r3 -else - MY_PV=${PV/_/-} - MY_P=${PN}-${MY_PV} - S=${WORKDIR}/${MY_P} - SRC_URI="https://github.com/systemd/${PN}/archive/refs/tags/v${MY_PV}.tar.gz -> ${MY_P}.tar.gz" - - if [[ ${PV} != *rc* ]] ; then - KEYWORDS="~alpha amd64 arm arm64 ~hppa ~loong ~m68k ~mips ppc ppc64 ~riscv ~s390 ~sparc x86" - fi -fi - -inherit bash-completion-r1 linux-info meson-multilib optfeature pam python-single-r1 -inherit secureboot systemd toolchain-funcs udev - -DESCRIPTION="System and service manager for Linux" -HOMEPAGE="https://systemd.io/" - -LICENSE="GPL-2 LGPL-2.1 MIT public-domain" -SLOT="0/2" -IUSE=" - acl apparmor audit boot bpf cgroup-hybrid cryptsetup curl +dns-over-tls elfutils - fido2 +gcrypt gnutls homed http idn importd iptables +kernel-install +kmod - +lz4 lzma +openssl pam pcre pkcs11 policykit pwquality qrcode - +resolvconf +seccomp selinux split-usr +sysv-utils test tpm ukify vanilla xkb +zstd -" -REQUIRED_USE=" - ${PYTHON_REQUIRED_USE} - dns-over-tls? ( || ( gnutls openssl ) ) - fido2? ( cryptsetup openssl ) - homed? ( cryptsetup pam openssl ) - importd? ( curl lzma || ( gcrypt openssl ) ) - pwquality? ( homed ) - boot? ( kernel-install ) - ukify? ( boot ) -" -RESTRICT="!test? ( test )" - -MINKV="4.15" - -COMMON_DEPEND=" - >=sys-apps/util-linux-2.32:0=[${MULTILIB_USEDEP}] - sys-libs/libcap:0=[${MULTILIB_USEDEP}] - virtual/libcrypt:=[${MULTILIB_USEDEP}] - acl? ( sys-apps/acl:0= ) - apparmor? ( >=sys-libs/libapparmor-2.13:0= ) - audit? ( >=sys-process/audit-2:0= ) - bpf? ( >=dev-libs/libbpf-1.4.0:0= ) - cryptsetup? ( >=sys-fs/cryptsetup-2.0.1:0= ) - curl? ( >=net-misc/curl-7.32.0:0= ) - elfutils? ( >=dev-libs/elfutils-0.158:0= ) - fido2? ( dev-libs/libfido2:0= ) - gcrypt? ( >=dev-libs/libgcrypt-1.4.5:0=[${MULTILIB_USEDEP}] ) - gnutls? ( >=net-libs/gnutls-3.6.0:0= ) - http? ( >=net-libs/libmicrohttpd-0.9.33:0=[epoll(+)] ) - idn? ( net-dns/libidn2:= ) - importd? ( - app-arch/bzip2:0= - virtual/zlib:= - ) - kmod? ( >=sys-apps/kmod-15:0= ) - lz4? ( >=app-arch/lz4-0_p131:0=[${MULTILIB_USEDEP}] ) - lzma? ( >=app-arch/xz-utils-5.0.5-r1:0=[${MULTILIB_USEDEP}] ) - iptables? ( net-firewall/iptables:0= ) - openssl? ( >=dev-libs/openssl-1.1.0:0= ) - pam? ( sys-libs/pam:=[${MULTILIB_USEDEP}] ) - pkcs11? ( >=app-crypt/p11-kit-0.23.3:0= ) - pcre? ( dev-libs/libpcre2 ) - pwquality? ( >=dev-libs/libpwquality-1.4.1:0= ) - qrcode? ( >=media-gfx/qrencode-3:0= ) - seccomp? ( >=sys-libs/libseccomp-2.3.3:0= ) - selinux? ( >=sys-libs/libselinux-2.1.9:0= ) - tpm? ( app-crypt/tpm2-tss:0= ) - xkb? ( >=x11-libs/libxkbcommon-0.4.1:0= ) - zstd? ( >=app-arch/zstd-1.4.0:0=[${MULTILIB_USEDEP}] ) -" - -# Newer linux-headers needed by ia64, bug #480218 -DEPEND="${COMMON_DEPEND} - >=sys-kernel/linux-headers-${MINKV} -" - -PEFILE_DEPEND='dev-python/pefile[${PYTHON_USEDEP}]' - -# baselayout-2.2 has /run -RDEPEND="${COMMON_DEPEND} - >=acct-group/adm-0-r1 - >=acct-group/wheel-0-r1 - >=acct-group/kmem-0-r1 - >=acct-group/tty-0-r1 - >=acct-group/utmp-0-r1 - >=acct-group/audio-0-r1 - >=acct-group/cdrom-0-r1 - >=acct-group/dialout-0-r1 - >=acct-group/disk-0-r1 - >=acct-group/input-0-r1 - >=acct-group/kvm-0-r1 - >=acct-group/lp-0-r1 - >=acct-group/render-0-r1 - acct-group/sgx - >=acct-group/tape-0-r1 - acct-group/users - >=acct-group/video-0-r1 - >=acct-group/systemd-journal-0-r1 - >=acct-user/root-0-r1 - acct-user/nobody - >=acct-user/systemd-journal-remote-0-r1 - >=acct-user/systemd-coredump-0-r1 - >=acct-user/systemd-network-0-r1 - acct-user/systemd-oom - >=acct-user/systemd-resolve-0-r1 - >=acct-user/systemd-timesync-0-r1 - >=sys-apps/baselayout-2.2 - ukify? ( - ${PYTHON_DEPS} - $(python_gen_cond_dep "${PEFILE_DEPEND}") - ) - selinux? ( - sec-policy/selinux-base-policy[systemd] - sec-policy/selinux-ntp - ) - sysv-utils? ( - !sys-apps/openrc[sysv-utils(-)] - !sys-apps/sysvinit - ) - !sysv-utils? ( sys-apps/sysvinit ) - resolvconf? ( !net-dns/openresolv ) - !sys-apps/hwids[udev] - !sys-auth/nss-myhostname - !sys-fs/eudev - !sys-fs/udev -" - -# sys-apps/dbus: the daemon only (+ build-time lib dep for tests) -PDEPEND=">=sys-apps/dbus-1.9.8[systemd] - >=sys-fs/udev-init-scripts-34 - policykit? ( sys-auth/polkit ) - !vanilla? ( sys-apps/gentoo-systemd-integration )" - -BDEPEND=" - app-arch/xz-utils:0 - dev-util/gperf - >=dev-build/meson-0.46 - >=sys-apps/coreutils-8.16 - sys-devel/gettext - virtual/pkgconfig - bpf? ( - >=dev-util/bpftool-7.0.0 - sys-devel/bpf-toolchain - ) - test? ( - app-text/tree - dev-lang/perl - sys-apps/dbus - ) - app-text/docbook-xml-dtd:4.2 - app-text/docbook-xml-dtd:4.5 - app-text/docbook-xsl-stylesheets - dev-libs/libxslt:0 - ${PYTHON_DEPS} - $(python_gen_cond_dep " - dev-python/jinja2[\${PYTHON_USEDEP}] - dev-python/lxml[\${PYTHON_USEDEP}] - boot? ( - >=dev-python/pyelftools-0.30[\${PYTHON_USEDEP}] - test? ( ${PEFILE_DEPEND} ) - ) - ") -" - -QA_FLAGS_IGNORED="usr/lib/systemd/boot/efi/.*" -QA_EXECSTACK="usr/lib/systemd/boot/efi/*" - -check_cgroup_layout() { - # https://bugs.gentoo.org/935261 - [[ ${MERGE_TYPE} != buildonly ]] || return - [[ -z ${ROOT} ]] || return - [[ -e /sys/fs/cgroup/unified ]] || return - grep -q 'SYSTEMD_CGROUP_ENABLE_LEGACY_FORCE=1' /proc/cmdline && return - - eerror "This system appears to be booted with the 'hybrid' cgroup layout." - eerror "This layout obsolete and is disabled in systemd." - - if grep -qF 'systemd.unified_cgroup_hierarchy'; then - eerror "Remove the systemd.unified_cgroup_hierarchy option" - eerror "from the kernel command line and reboot." - die "hybrid cgroup layout detected" - fi -} - -pkg_pretend() { - if use split-usr; then - eerror "Please complete the migration to merged-usr." - eerror "https://wiki.gentoo.org/wiki/Merge-usr" - die "systemd no longer supports split-usr" - fi - - check_cgroup_layout - - if use cgroup-hybrid; then - eerror "Disable the 'cgroup-hybrid' USE flag." - eerror "Rebuild any initramfs images after rebuilding systemd." - die "cgroup-hybrid is no longer supported" - fi - - if [[ ${MERGE_TYPE} != buildonly ]]; then - local CONFIG_CHECK="~BLK_DEV_BSG ~CGROUPS - ~CGROUP_BPF ~DEVTMPFS ~EPOLL ~FANOTIFY ~FHANDLE - ~INOTIFY_USER ~IPV6 ~NET ~NET_NS ~PROC_FS ~SIGNALFD ~SYSFS - ~TIMERFD ~TMPFS_XATTR ~UNIX ~USER_NS - ~CRYPTO_HMAC ~CRYPTO_SHA256 ~CRYPTO_USER_API_HASH - ~!GRKERNSEC_PROC ~!IDE ~!SYSFS_DEPRECATED - ~!SYSFS_DEPRECATED_V2" - - use acl && CONFIG_CHECK+=" ~TMPFS_POSIX_ACL" - use bpf && CONFIG_CHECK+=" ~BPF ~BPF_SYSCALL ~BPF_LSM ~DEBUG_INFO_BTF" - use seccomp && CONFIG_CHECK+=" ~SECCOMP ~SECCOMP_FILTER" - - if kernel_is -ge 5 10 20; then - CONFIG_CHECK+=" ~KCMP" - else - CONFIG_CHECK+=" ~CHECKPOINT_RESTORE" - fi - - if kernel_is -ge 4 18; then - CONFIG_CHECK+=" ~AUTOFS_FS" - else - CONFIG_CHECK+=" ~AUTOFS4_FS" - fi - - if linux_config_exists; then - local uevent_helper_path=$(linux_chkconfig_string UEVENT_HELPER_PATH) - if [[ -n ${uevent_helper_path} ]] && [[ ${uevent_helper_path} != '""' ]]; then - ewarn "It's recommended to set an empty value to the following kernel config option:" - ewarn "CONFIG_UEVENT_HELPER_PATH=${uevent_helper_path}" - fi - if linux_chkconfig_present X86; then - CONFIG_CHECK+=" ~DMIID" - fi - fi - - if kernel_is -lt ${MINKV//./ }; then - ewarn "Kernel version at least ${MINKV} required" - fi - - check_extra_config - fi -} - -pkg_setup() { - use boot && secureboot_pkg_setup -} - -src_unpack() { - default - [[ ${PV} != 9999 ]] || git-r3_src_unpack -} - -src_prepare() { - local PATCHES=( - "${FILESDIR}"/systemd-257-cred-util-tpm2.patch - ) - - if ! use vanilla; then - PATCHES+=( - "${FILESDIR}/gentoo-journald-audit-r1.patch" - ) - fi - - default -} - -src_configure() { - # Prevent conflicts with i686 cross toolchain, bug 559726 - tc-export AR CC NM OBJCOPY RANLIB - - python_setup - - multilib-minimal_src_configure -} - -multilib_src_configure() { - local myconf=( - --localstatedir="${EPREFIX}/var" - -Ddocdir="share/doc/${PF}" - # default is developer, bug 918671 - -Dmode=release - -Dsupport-url="https://gentoo.org/support/" - -Dpamlibdir="$(getpam_mod_dir)" - # avoid bash-completion dep - -Dbashcompletiondir="$(get_bashcompdir)" - -Dsplit-bin=false - # Disable compatibility with sysvinit - -Dsysvinit-path= - -Dsysvrcnd-path= - # no deps - -Dima=true - # Match /etc/shells, bug 919749 - -Ddebug-shell="${EPREFIX}/bin/sh" - -Ddefault-user-shell="${EPREFIX}/bin/bash" - # Optional components/dependencies - $(meson_native_use_feature acl) - $(meson_native_use_feature apparmor) - $(meson_native_use_feature audit) - $(meson_native_use_feature boot bootloader) - $(meson_native_use_feature bpf bpf-framework) - -Dbpf-compiler=gcc - $(meson_native_use_feature cryptsetup libcryptsetup) - $(meson_native_use_feature curl libcurl) - $(meson_native_use_bool dns-over-tls dns-over-tls) - $(meson_native_use_feature elfutils) - $(meson_native_use_feature fido2 libfido2) - $(meson_feature gcrypt) - $(meson_native_use_feature gnutls) - $(meson_native_use_feature homed) - $(meson_native_use_feature http microhttpd) - $(meson_native_use_bool idn) - $(meson_native_use_feature importd) - $(meson_native_use_feature importd bzip2) - $(meson_native_use_feature importd zlib) - $(meson_native_use_bool kernel-install) - $(meson_native_use_feature kmod) - $(meson_feature lz4) - $(meson_feature lzma xz) - $(meson_use test tests) - $(meson_feature zstd) - $(meson_native_use_feature iptables libiptc) - $(meson_native_use_feature openssl) - $(meson_feature pam) - $(meson_native_use_feature pkcs11 p11kit) - $(meson_native_use_feature pcre pcre2) - $(meson_native_use_feature policykit polkit) - $(meson_native_use_feature pwquality) - $(meson_native_use_feature qrcode qrencode) - $(meson_native_use_feature seccomp) - $(meson_native_use_feature selinux) - $(meson_native_use_feature tpm tpm2) - $(meson_native_use_feature test dbus) - $(meson_native_use_feature ukify) - $(meson_native_use_feature xkb xkbcommon) - -Dntp-servers="0.gentoo.pool.ntp.org 1.gentoo.pool.ntp.org 2.gentoo.pool.ntp.org 3.gentoo.pool.ntp.org" - # Breaks screen, tmux, etc. - -Ddefault-kill-user-processes=false - -Dcreate-log-dirs=false - - # multilib options - $(meson_native_true backlight) - $(meson_native_true binfmt) - $(meson_native_true coredump) - $(meson_native_true environment-d) - $(meson_native_true firstboot) - $(meson_native_true hibernate) - $(meson_native_true hostnamed) - $(meson_native_true ldconfig) - $(meson_native_true localed) - $(meson_native_enabled man) - $(meson_native_true networkd) - $(meson_native_true quotacheck) - $(meson_native_true randomseed) - $(meson_native_true rfkill) - $(meson_native_true sysusers) - $(meson_native_true timedated) - $(meson_native_true timesyncd) - $(meson_native_true tmpfiles) - $(meson_native_true vconsole) - ) - - case $(tc-arch) in - amd64|arm|arm64|loong|ppc|ppc64|riscv|s390|x86) - # src/vmspawn/vmspawn-util.h: QEMU_MACHINE_TYPE - myconf+=( $(meson_native_enabled vmspawn) ) ;; - *) - myconf+=( -Dvmspawn=disabled ) ;; - esac - - meson_src_configure "${myconf[@]}" -} - -multilib_src_test() { - ( - unset DBUS_SESSION_BUS_ADDRESS XDG_RUNTIME_DIR - export COLUMNS=80 - addpredict /dev - addpredict /proc - addpredict /run - addpredict /sys/fs/cgroup - meson_src_test --timeout-multiplier=10 - ) || die -} - -multilib_src_install_all() { - einstalldocs - dodoc "${FILESDIR}"/nsswitch.conf - - insinto /usr/lib/tmpfiles.d - doins "${FILESDIR}"/legacy.conf - - if ! use resolvconf; then - rm -f "${ED}"/usr/bin/resolvconf || die - fi - - if ! use sysv-utils; then - rm "${ED}"/usr/bin/{halt,init,poweroff,reboot,shutdown} || die - rm "${ED}"/usr/share/man/man1/init.1 || die - rm "${ED}"/usr/share/man/man8/{halt,poweroff,reboot,shutdown}.8 || die - fi - - # https://bugs.gentoo.org/761763 - rm -r "${ED}"/usr/lib/sysusers.d || die - - # Preserve empty dirs in /etc & /var, bug #437008 - keepdir /etc/{binfmt.d,modules-load.d,tmpfiles.d} - keepdir /etc/kernel/install.d - keepdir /etc/systemd/{network,system,user} - keepdir /etc/udev/rules.d - - keepdir /etc/udev/hwdb.d - - keepdir /usr/lib/systemd/{system-sleep,system-shutdown} - keepdir /usr/lib/{binfmt.d,modules-load.d} - keepdir /usr/lib/systemd/user-generators - keepdir /var/lib/systemd - keepdir /var/log/journal - - if use pam; then - if use selinux; then - newpamd "${FILESDIR}"/systemd-user-selinux.pam systemd-user - else - newpamd "${FILESDIR}"/systemd-user.pam systemd-user - fi - fi - - if use kernel-install; then - # Dummy config, remove to make room for sys-kernel/installkernel - rm "${ED}/usr/lib/kernel/install.conf" || die - fi - - use ukify && python_fix_shebang "${ED}" - use boot && secureboot_auto_sign -} - -migrate_locale() { - local envd_locale_def="${EROOT}/etc/env.d/02locale" - local envd_locale=( "${EROOT}"/etc/env.d/??locale ) - local locale_conf="${EROOT}/etc/locale.conf" - - if [[ ! -L ${locale_conf} && ! -e ${locale_conf} ]]; then - # If locale.conf does not exist... - if [[ -e ${envd_locale} ]]; then - # ...either copy env.d/??locale if there's one - ebegin "Moving ${envd_locale} to ${locale_conf}" - mv "${envd_locale}" "${locale_conf}" - eend ${?} || FAIL=1 - else - # ...or create a dummy default - ebegin "Creating ${locale_conf}" - cat > "${locale_conf}" <<-EOF - # This file has been created by the sys-apps/systemd ebuild. - # See locale.conf(5) and localectl(1). - - # LANG=${LANG} - EOF - eend ${?} || FAIL=1 - fi - fi - - if [[ ! -L ${envd_locale} ]]; then - # now, if env.d/??locale is not a symlink (to locale.conf)... - if [[ -e ${envd_locale} ]]; then - # ...warn the user that he has duplicate locale settings - ewarn - ewarn "To ensure consistent behavior, you should replace ${envd_locale}" - ewarn "with a symlink to ${locale_conf}. Please migrate your settings" - ewarn "and create the symlink with the following command:" - ewarn "ln -s -n -f ../locale.conf ${envd_locale}" - ewarn - else - # ...or just create the symlink if there's nothing here - ebegin "Creating ${envd_locale_def} -> ../locale.conf symlink" - ln -n -s ../locale.conf "${envd_locale_def}" - eend ${?} || FAIL=1 - fi - fi -} - -pkg_preinst() { - if [[ -e ${EROOT}/etc/sysctl.conf ]]; then - # Symlink /etc/sysctl.conf for easy migration. - dosym ../../../etc/sysctl.conf /usr/lib/sysctl.d/99-sysctl.conf - fi - - if ! use boot && has_version "sys-apps/systemd[gnuefi(-)]"; then - ewarn "The 'gnuefi' USE flag has been renamed to 'boot'." - ewarn "Make sure to enable the 'boot' USE flag if you use systemd-boot." - fi -} - -pkg_postinst() { - systemd_update_catalog - - # Keep this here in case the database format changes so it gets updated - # when required. - systemd-hwdb --root="${ROOT}" update - - udev_reload || FAIL=1 - - # Bug 465468, make sure locales are respected, and ensure consistency - # between OpenRC & systemd - migrate_locale - - if [[ -z ${REPLACING_VERSIONS} ]]; then - if type systemctl &>/dev/null; then - systemctl --root="${ROOT:-/}" enable getty@.service remote-fs.target || FAIL=1 - fi - elog "To enable a useful set of services, run the following:" - elog " systemctl preset-all --preset-mode=enable-only" - fi - - if [[ -L ${EROOT}/var/lib/systemd/timesync ]]; then - rm "${EROOT}/var/lib/systemd/timesync" - fi - - if [[ -z ${ROOT} && -d /run/systemd/system ]]; then - ebegin "Reexecuting system manager (systemd)" - systemctl daemon-reexec - eend $? || FAIL=1 - - # https://lists.freedesktop.org/archives/systemd-devel/2024-June/050466.html - ebegin "Signaling user managers to reexec" - systemctl kill --kill-whom='main' --signal='SIGRTMIN+25' 'user@*.service' - eend $? - fi - - if [[ ${FAIL} ]]; then - eerror "One of the postinst commands failed. Please check the postinst output" - eerror "for errors. You may need to clean up your system and/or try installing" - eerror "systemd again." - eerror - fi - - if use boot; then - optfeature "installing kernels in systemd-boot's native layout and update loader entries" \ - "sys-kernel/installkernel[systemd-boot]" - fi - if use ukify; then - optfeature "generating unified kernel image on each kernel installation" \ - "sys-kernel/installkernel[ukify]" - fi -} - -pkg_prerm() { - # If removing systemd completely, remove the catalog database. - if [[ ! ${REPLACED_BY_VERSION} ]]; then - rm -f -v "${EROOT}"/var/lib/systemd/catalog/database - fi -} diff --git a/sdk_container/src/third_party/portage-stable/sys-apps/systemd/systemd-9999.ebuild b/sdk_container/src/third_party/portage-stable/sys-apps/systemd/systemd-9999.ebuild deleted file mode 100644 index e0d808b2954..00000000000 --- a/sdk_container/src/third_party/portage-stable/sys-apps/systemd/systemd-9999.ebuild +++ /dev/null @@ -1,576 +0,0 @@ -# Copyright 2011-2025 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=8 -PYTHON_COMPAT=( python3_{11..14} ) - -# Avoid QA warnings -TMPFILES_OPTIONAL=1 -UDEV_OPTIONAL=1 - -QA_PKGCONFIG_VERSION=$(ver_cut 1) - -if [[ ${PV} == 9999 ]]; then - EGIT_REPO_URI="https://github.com/systemd/systemd.git" - inherit git-r3 -else - MY_PV=${PV/_/-} - MY_P=${PN}-${MY_PV} - S=${WORKDIR}/${MY_P} - SRC_URI="https://github.com/systemd/${PN}/archive/refs/tags/v${MY_PV}.tar.gz -> ${MY_P}.tar.gz" - - if [[ ${PV} != *rc* ]] ; then - KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~loong ~m68k ~mips ~ppc ~ppc64 ~riscv ~s390 ~sparc ~x86" - fi -fi - -inherit bash-completion-r1 linux-info meson-multilib optfeature pam python-single-r1 -inherit secureboot systemd toolchain-funcs udev - -DESCRIPTION="System and service manager for Linux" -HOMEPAGE="https://systemd.io/" - -LICENSE="GPL-2 LGPL-2.1 MIT public-domain" -SLOT="0/2" -IUSE=" - acl apparmor audit boot bpf cgroup-hybrid cryptsetup curl +dns-over-tls elfutils - fido2 +gcrypt gnutls homed http idn importd iptables +kernel-install +kmod - +lz4 lzma +openssl pam passwdqc pcre pkcs11 policykit pwquality qrcode - +resolvconf +seccomp selinux split-usr +sysv-utils test tpm ukify vanilla xkb +zstd -" -REQUIRED_USE=" - ${PYTHON_REQUIRED_USE} - dns-over-tls? ( openssl ) - fido2? ( cryptsetup openssl ) - homed? ( cryptsetup pam openssl ) - importd? ( curl lzma openssl ) - ?? ( passwdqc pwquality ) - passwdqc? ( homed ) - pwquality? ( homed ) - boot? ( kernel-install ) - ukify? ( boot ) -" -RESTRICT="!test? ( test )" - -MINKV="4.15" - -COMMON_DEPEND=" - >=sys-apps/util-linux-2.32:0=[${MULTILIB_USEDEP}] - sys-libs/libcap:0=[${MULTILIB_USEDEP}] - virtual/libcrypt:=[${MULTILIB_USEDEP}] - acl? ( sys-apps/acl:0= ) - apparmor? ( >=sys-libs/libapparmor-2.13:0= ) - audit? ( >=sys-process/audit-2:0= ) - bpf? ( >=dev-libs/libbpf-1.4.0:0= ) - cryptsetup? ( >=sys-fs/cryptsetup-2.0.1:0= ) - curl? ( >=net-misc/curl-7.32.0:0= ) - elfutils? ( >=dev-libs/elfutils-0.158:0= ) - fido2? ( - dev-libs/libfido2:0= - ) - gcrypt? ( >=dev-libs/libgcrypt-1.4.5:0=[${MULTILIB_USEDEP}] ) - gnutls? ( >=net-libs/gnutls-3.6.0:0= ) - http? ( >=net-libs/libmicrohttpd-0.9.33:0=[epoll(+)] ) - idn? ( net-dns/libidn2:= ) - importd? ( - app-arch/bzip2:0= - virtual/zlib:= - ) - kmod? ( >=sys-apps/kmod-15:0= ) - lz4? ( >=app-arch/lz4-0_p131:0=[${MULTILIB_USEDEP}] ) - lzma? ( >=app-arch/xz-utils-5.0.5-r1:0=[${MULTILIB_USEDEP}] ) - iptables? ( net-firewall/iptables:0= ) - openssl? ( >=dev-libs/openssl-1.1.0:0= ) - pam? ( sys-libs/pam:=[${MULTILIB_USEDEP}] ) - passwdqc? ( sys-auth/passwdqc:0= ) - pkcs11? ( >=app-crypt/p11-kit-0.23.3:0= ) - pcre? ( dev-libs/libpcre2 ) - pwquality? ( >=dev-libs/libpwquality-1.4.1:0= ) - qrcode? ( >=media-gfx/qrencode-3:0= ) - seccomp? ( >=sys-libs/libseccomp-2.3.3:0= ) - selinux? ( >=sys-libs/libselinux-2.1.9:0= ) - tpm? ( app-crypt/tpm2-tss:0= ) - xkb? ( >=x11-libs/libxkbcommon-0.4.1:0= ) - zstd? ( >=app-arch/zstd-1.4.0:0=[${MULTILIB_USEDEP}] ) -" - -# Newer linux-headers needed by ia64, bug #480218 -DEPEND="${COMMON_DEPEND} - >=sys-kernel/linux-headers-${MINKV} -" - -PEFILE_DEPEND='dev-python/pefile[${PYTHON_USEDEP}]' - -# baselayout-2.2 has /run -RDEPEND="${COMMON_DEPEND} - >=acct-group/adm-0-r1 - >=acct-group/wheel-0-r1 - >=acct-group/kmem-0-r1 - >=acct-group/tty-0-r1 - >=acct-group/utmp-0-r1 - >=acct-group/audio-0-r1 - >=acct-group/cdrom-0-r1 - acct-group/clock - >=acct-group/dialout-0-r1 - >=acct-group/disk-0-r1 - >=acct-group/input-0-r1 - >=acct-group/kvm-0-r1 - >=acct-group/lp-0-r1 - >=acct-group/render-0-r1 - acct-group/sgx - >=acct-group/tape-0-r1 - acct-group/users - >=acct-group/video-0-r1 - >=acct-group/systemd-journal-0-r1 - >=acct-user/root-0-r1 - acct-user/nobody - >=acct-user/systemd-journal-remote-0-r1 - >=acct-user/systemd-coredump-0-r1 - >=acct-user/systemd-network-0-r1 - acct-user/systemd-oom - >=acct-user/systemd-resolve-0-r1 - >=acct-user/systemd-timesync-0-r1 - >=sys-apps/baselayout-2.2 - ukify? ( - ${PYTHON_DEPS} - $(python_gen_cond_dep "${PEFILE_DEPEND}") - ) - selinux? ( - sec-policy/selinux-base-policy[systemd] - sec-policy/selinux-ntp - ) - sysv-utils? ( - !sys-apps/openrc[sysv-utils(-)] - !sys-apps/sysvinit - ) - !sysv-utils? ( sys-apps/sysvinit ) - resolvconf? ( !net-dns/openresolv ) - !sys-apps/hwids[udev] - !sys-auth/nss-myhostname - !sys-fs/eudev - !sys-fs/udev -" - -# sys-apps/dbus: the daemon only (+ build-time lib dep for tests) -PDEPEND=">=sys-apps/dbus-1.9.8[systemd] - >=sys-fs/udev-init-scripts-34 - policykit? ( sys-auth/polkit ) - !vanilla? ( sys-apps/gentoo-systemd-integration )" - -BDEPEND=" - app-arch/xz-utils:0 - dev-util/gperf - >=dev-build/meson-0.46 - >=sys-apps/coreutils-8.16 - sys-devel/gettext - virtual/pkgconfig - bpf? ( - >=dev-util/bpftool-7.0.0 - sys-devel/bpf-toolchain - ) - test? ( - app-text/tree - dev-lang/perl - sys-apps/dbus - ) - app-text/docbook-xml-dtd:4.2 - app-text/docbook-xml-dtd:4.5 - app-text/docbook-xsl-stylesheets - dev-libs/libxslt:0 - ${PYTHON_DEPS} - $(python_gen_cond_dep " - dev-python/jinja2[\${PYTHON_USEDEP}] - dev-python/lxml[\${PYTHON_USEDEP}] - boot? ( - >=dev-python/pyelftools-0.30[\${PYTHON_USEDEP}] - test? ( ${PEFILE_DEPEND} ) - ) - ") -" - -QA_FLAGS_IGNORED="usr/lib/systemd/boot/efi/.*" -QA_EXECSTACK="usr/lib/systemd/boot/efi/*" - -check_cgroup_layout() { - # https://bugs.gentoo.org/935261 - [[ ${MERGE_TYPE} != buildonly ]] || return - [[ -z ${ROOT} ]] || return - [[ -e /sys/fs/cgroup/unified ]] || return - grep -q 'SYSTEMD_CGROUP_ENABLE_LEGACY_FORCE=1' /proc/cmdline && return - - eerror "This system appears to be booted with the 'hybrid' cgroup layout." - eerror "This layout obsolete and is disabled in systemd." - - if grep -qF 'systemd.unified_cgroup_hierarchy'; then - eerror "Remove the systemd.unified_cgroup_hierarchy option" - eerror "from the kernel command line and reboot." - die "hybrid cgroup layout detected" - fi -} - -pkg_pretend() { - if use split-usr; then - eerror "Please complete the migration to merged-usr." - eerror "https://wiki.gentoo.org/wiki/Merge-usr" - die "systemd no longer supports split-usr" - fi - - check_cgroup_layout - - if use cgroup-hybrid; then - eerror "Disable the 'cgroup-hybrid' USE flag." - eerror "Rebuild any initramfs images after rebuilding systemd." - die "cgroup-hybrid is no longer supported" - fi - - if [[ ${MERGE_TYPE} != buildonly ]]; then - local CONFIG_CHECK="~BLK_DEV_BSG ~CGROUPS - ~CGROUP_BPF ~DEVTMPFS ~EPOLL ~FANOTIFY ~FHANDLE - ~INOTIFY_USER ~IPV6 ~NET ~NET_NS ~PROC_FS ~SIGNALFD ~SYSFS - ~TIMERFD ~TMPFS_XATTR ~UNIX ~USER_NS - ~CRYPTO_HMAC ~CRYPTO_SHA256 ~CRYPTO_USER_API_HASH - ~!GRKERNSEC_PROC ~!IDE ~!SYSFS_DEPRECATED - ~!SYSFS_DEPRECATED_V2" - - use acl && CONFIG_CHECK+=" ~TMPFS_POSIX_ACL" - use bpf && CONFIG_CHECK+=" ~BPF ~BPF_SYSCALL ~BPF_LSM ~DEBUG_INFO_BTF" - use seccomp && CONFIG_CHECK+=" ~SECCOMP ~SECCOMP_FILTER" - - if kernel_is -ge 5 10 20; then - CONFIG_CHECK+=" ~KCMP" - else - CONFIG_CHECK+=" ~CHECKPOINT_RESTORE" - fi - - if kernel_is -ge 4 18; then - CONFIG_CHECK+=" ~AUTOFS_FS" - else - CONFIG_CHECK+=" ~AUTOFS4_FS" - fi - - if linux_config_exists; then - local uevent_helper_path=$(linux_chkconfig_string UEVENT_HELPER_PATH) - if [[ -n ${uevent_helper_path} ]] && [[ ${uevent_helper_path} != '""' ]]; then - ewarn "It's recommended to set an empty value to the following kernel config option:" - ewarn "CONFIG_UEVENT_HELPER_PATH=${uevent_helper_path}" - fi - if linux_chkconfig_present X86; then - CONFIG_CHECK+=" ~DMIID" - fi - fi - - if kernel_is -lt ${MINKV//./ }; then - ewarn "Kernel version at least ${MINKV} required" - fi - - check_extra_config - fi -} - -pkg_setup() { - use boot && secureboot_pkg_setup -} - -src_unpack() { - default - [[ ${PV} != 9999 ]] || git-r3_src_unpack -} - -src_prepare() { - local PATCHES=( - ) - - if ! use vanilla; then - PATCHES+=( - "${FILESDIR}/gentoo-journald-audit-r2.patch" - ) - fi - - default -} - -src_configure() { - # Prevent conflicts with i686 cross toolchain, bug 559726 - tc-export AR CC NM OBJCOPY RANLIB - - python_setup - - multilib-minimal_src_configure -} - -multilib_src_configure() { - local myconf=( - --localstatedir="${EPREFIX}/var" - -Ddocdir="share/doc/${PF}" - # default is developer, bug 918671 - -Dmode=release - -Dsupport-url="https://gentoo.org/support/" - -Dpamlibdir="$(getpam_mod_dir)" - # avoid bash-completion dep - -Dbashcompletiondir="$(get_bashcompdir)" - -Dsplit-bin=false - # Disable compatibility with sysvinit - -Dsysvinit-path= - -Dsysvrcnd-path= - # no deps - -Dima=true - # Match /etc/shells, bug 919749 - -Ddebug-shell="${EPREFIX}/bin/sh" - -Ddefault-user-shell="${EPREFIX}/bin/bash" - # Optional components/dependencies - $(meson_native_use_feature acl) - $(meson_native_use_feature apparmor) - $(meson_native_use_feature audit) - $(meson_native_use_feature boot bootloader) - $(meson_native_use_feature bpf bpf-framework) - -Dbpf-compiler=gcc - $(meson_native_use_feature cryptsetup libcryptsetup) - $(meson_native_use_feature curl libcurl) - $(meson_native_use_bool dns-over-tls dns-over-tls) - $(meson_native_use_feature elfutils) - $(meson_native_use_feature fido2 libfido2) - $(meson_feature gcrypt) - $(meson_native_use_feature gnutls) - $(meson_native_use_feature homed) - $(meson_native_use_feature http microhttpd) - $(meson_native_use_bool idn) - $(meson_native_use_feature importd) - $(meson_native_use_feature importd bzip2) - $(meson_native_use_feature importd zlib) - $(meson_native_use_bool kernel-install) - $(meson_native_use_feature kmod) - $(meson_feature lz4) - $(meson_feature lzma xz) - $(meson_use test tests) - $(meson_feature zstd) - $(meson_native_use_feature iptables libiptc) - $(meson_native_use_feature openssl) - $(meson_feature pam) - $(meson_native_use_feature passwdqc) - $(meson_native_use_feature pkcs11 p11kit) - $(meson_native_use_feature pcre pcre2) - $(meson_native_use_feature policykit polkit) - $(meson_native_use_feature pwquality) - $(meson_native_use_feature qrcode qrencode) - $(meson_native_use_feature seccomp) - $(meson_native_use_feature selinux) - $(meson_native_use_feature tpm tpm2) - $(meson_native_use_feature test dbus) - $(meson_native_use_feature ukify) - $(meson_native_use_feature xkb xkbcommon) - -Dntp-servers="0.gentoo.pool.ntp.org 1.gentoo.pool.ntp.org 2.gentoo.pool.ntp.org 3.gentoo.pool.ntp.org" - # Breaks screen, tmux, etc. - -Ddefault-kill-user-processes=false - -Dcreate-log-dirs=false - - # multilib options - $(meson_native_true backlight) - $(meson_native_true binfmt) - $(meson_native_true coredump) - $(meson_native_true environment-d) - $(meson_native_true firstboot) - $(meson_native_true hibernate) - $(meson_native_true hostnamed) - $(meson_native_true ldconfig) - $(meson_native_true localed) - $(meson_native_enabled man) - $(meson_native_true networkd) - $(meson_native_true quotacheck) - $(meson_native_true randomseed) - $(meson_native_true rfkill) - $(meson_native_true sysusers) - $(meson_native_true timedated) - $(meson_native_true timesyncd) - $(meson_native_true tmpfiles) - $(meson_native_true vconsole) - ) - - case $(tc-arch) in - amd64|arm|arm64|loong|ppc|ppc64|riscv|s390|x86) - # src/vmspawn/vmspawn-util.h: QEMU_MACHINE_TYPE - myconf+=( $(meson_native_enabled vmspawn) ) ;; - *) - myconf+=( -Dvmspawn=disabled ) ;; - esac - - meson_src_configure "${myconf[@]}" -} - -multilib_src_test() { - ( - unset DBUS_SESSION_BUS_ADDRESS XDG_RUNTIME_DIR - export COLUMNS=80 - addpredict /dev - addpredict /proc - addpredict /run - addpredict /sys/fs/cgroup - meson_src_test --timeout-multiplier=10 - ) || die -} - -multilib_src_install_all() { - einstalldocs - dodoc "${FILESDIR}"/nsswitch.conf - - insinto /usr/lib/tmpfiles.d - doins "${FILESDIR}"/legacy.conf - - if ! use resolvconf; then - rm -f "${ED}"/usr/bin/resolvconf || die - fi - - if ! use sysv-utils; then - rm "${ED}"/usr/bin/{halt,init,poweroff,reboot,shutdown} || die - rm "${ED}"/usr/share/man/man1/init.1 || die - rm "${ED}"/usr/share/man/man8/{halt,poweroff,reboot,shutdown}.8 || die - fi - - # https://bugs.gentoo.org/761763 - rm -r "${ED}"/usr/lib/sysusers.d || die - - # Preserve empty dirs in /etc & /var, bug #437008 - keepdir /etc/{binfmt.d,modules-load.d,tmpfiles.d} - keepdir /etc/kernel/install.d - keepdir /etc/systemd/{network,system,user} - keepdir /etc/udev/rules.d - - keepdir /etc/udev/hwdb.d - - keepdir /usr/lib/systemd/{system-sleep,system-shutdown} - keepdir /usr/lib/{binfmt.d,modules-load.d} - keepdir /usr/lib/systemd/user-generators - keepdir /var/lib/systemd - keepdir /var/log/journal - - if use pam; then - if use selinux; then - newpamd "${FILESDIR}"/systemd-user-selinux.pam systemd-user - else - newpamd "${FILESDIR}"/systemd-user.pam systemd-user - fi - fi - - if use kernel-install; then - # Dummy config, remove to make room for sys-kernel/installkernel - rm "${ED}/usr/lib/kernel/install.conf" || die - fi - - use ukify && python_fix_shebang "${ED}" - use boot && secureboot_auto_sign -} - -migrate_locale() { - local envd_locale_def="${EROOT}/etc/env.d/02locale" - local envd_locale=( "${EROOT}"/etc/env.d/??locale ) - local locale_conf="${EROOT}/etc/locale.conf" - - if [[ ! -L ${locale_conf} && ! -e ${locale_conf} ]]; then - # If locale.conf does not exist... - if [[ -e ${envd_locale} ]]; then - # ...either copy env.d/??locale if there's one - ebegin "Moving ${envd_locale} to ${locale_conf}" - mv "${envd_locale}" "${locale_conf}" - eend ${?} || FAIL=1 - else - # ...or create a dummy default - ebegin "Creating ${locale_conf}" - cat > "${locale_conf}" <<-EOF - # This file has been created by the sys-apps/systemd ebuild. - # See locale.conf(5) and localectl(1). - - # LANG=${LANG} - EOF - eend ${?} || FAIL=1 - fi - fi - - if [[ ! -L ${envd_locale} ]]; then - # now, if env.d/??locale is not a symlink (to locale.conf)... - if [[ -e ${envd_locale} ]]; then - # ...warn the user that he has duplicate locale settings - ewarn - ewarn "To ensure consistent behavior, you should replace ${envd_locale}" - ewarn "with a symlink to ${locale_conf}. Please migrate your settings" - ewarn "and create the symlink with the following command:" - ewarn "ln -s -n -f ../locale.conf ${envd_locale}" - ewarn - else - # ...or just create the symlink if there's nothing here - ebegin "Creating ${envd_locale_def} -> ../locale.conf symlink" - ln -n -s ../locale.conf "${envd_locale_def}" - eend ${?} || FAIL=1 - fi - fi -} - -pkg_preinst() { - if [[ -e ${EROOT}/etc/sysctl.conf ]]; then - # Symlink /etc/sysctl.conf for easy migration. - dosym ../../../etc/sysctl.conf /usr/lib/sysctl.d/99-sysctl.conf - fi - - if ! use boot && has_version "sys-apps/systemd[gnuefi(-)]"; then - ewarn "The 'gnuefi' USE flag has been renamed to 'boot'." - ewarn "Make sure to enable the 'boot' USE flag if you use systemd-boot." - fi -} - -pkg_postinst() { - systemd_update_catalog - - # Keep this here in case the database format changes so it gets updated - # when required. - systemd-hwdb --root="${ROOT}" update - - udev_reload || FAIL=1 - - # Bug 465468, make sure locales are respected, and ensure consistency - # between OpenRC & systemd - migrate_locale - - if [[ -z ${REPLACING_VERSIONS} ]]; then - if type systemctl &>/dev/null; then - systemctl --root="${ROOT:-/}" enable getty@.service remote-fs.target || FAIL=1 - fi - elog "To enable a useful set of services, run the following:" - elog " systemctl preset-all --preset-mode=enable-only" - fi - - if [[ -L ${EROOT}/var/lib/systemd/timesync ]]; then - rm "${EROOT}/var/lib/systemd/timesync" - fi - - if [[ -z ${ROOT} && -d /run/systemd/system ]]; then - ebegin "Reexecuting system manager (systemd)" - systemctl daemon-reexec - eend $? || FAIL=1 - - # https://lists.freedesktop.org/archives/systemd-devel/2024-June/050466.html - ebegin "Signaling user managers to reexec" - systemctl kill --kill-whom='main' --signal='SIGRTMIN+25' 'user@*.service' - eend $? - fi - - if [[ ${FAIL} ]]; then - eerror "One of the postinst commands failed. Please check the postinst output" - eerror "for errors. You may need to clean up your system and/or try installing" - eerror "systemd again." - eerror - fi - - if use boot; then - optfeature "installing kernels in systemd-boot's native layout and update loader entries" \ - "sys-kernel/installkernel[systemd-boot]" - fi - if use ukify; then - optfeature "generating unified kernel image on each kernel installation" \ - "sys-kernel/installkernel[ukify]" - fi -} - -pkg_prerm() { - # If removing systemd completely, remove the catalog database. - if [[ ! ${REPLACED_BY_VERSION} ]]; then - rm -f -v "${EROOT}"/var/lib/systemd/catalog/database - fi -}