system: add support for merged-bin (branch yem/merged-bin)
v3 cover system: add support for merged-bin (branch yem/merged-bin)
Hello All!
This series introduces support for so-called merged-bin, where /usr/sbin is merged with /usr/bin, as an extra step after merged-usr, now just requested, but in the future required, by systemd.
The series is organised in a few steps:
1. patches 1-3 are cleanups in the Kconfig menu, related to the merged-usr prompt, to the defaults for PATH, and to the rationale for selecting merged-usr with systemd; those can be applied without considering the rest of the series;
2. then patches 4-9 prepare support/scripts/check-merged-usr.sh to check for more than merged-usr: a good cleanup, and better check the merged state; those patch can also be applied without considering the rest of the series;
3. with patches 9-12, support for merged-bin is added, and the merge level of skeleton and overlays properly enforced to match the configured merge setup; those require the two set of patches above to be applied first;
4. then, patches 13-17 introduce workarounds for a few packages to properly support merged-bin. For ease of review, those are separate patches, but that means the series _may_ break if the merged-bin support is applied but not these per-package workarounds; these require that all patches above be applied first, of course;
5. the last patch makes merged-bin mandatory for systemd and extend the systemd runtime test to catch future tainted flag; again, that requires that everything before is applied, too.
The series was tested with a large set of packages and a large set of toolchains, and although it is a critical change, it is still pretty well confined to just a few spots.
Changes v2 -> v3;
- add fix for merged-bin to net-tools
Changes v1 -> v2:
- add Arnout's Acked-by tag where appropriate
- totally rewrite the test for merged status
- reject unexpectedly merged skeletons or overlays
- add runtime test to catch systemd tainted flags
- typos
Regards,
Yann E. MORIN.
----------------------------------------------------------------
Yann E. MORIN (18):
system: reword merged-usr prompt
system: drop superfluous negative condition for default PATH package/systemd: select merged-usr from package, not init support/scripts: comonalise checking merged status support/scripts: prepare for a more complex check for merged directories support/scripts: also exit in error on improperly merged-usr support/scripts: move merged-usr errors message into check-merged-usr.sh support/scripts: fix and restrict conditions to accept merged dirs support/scripts: rename check-merged-usr.sh
support/scripts; teach check-merged what to check
system: add support for merged /usr/sbin (aka merged-bin) support/scripts: reject skeletons or overlays that are unexpectedly merged package/coreutils: no need for chroot workaround with merged-bin package/kmod: adjust paths for merged-bin
package/util-linux: adjust paths for merged-bin package/net-tools: no need for ifconfig+route workarounds with merged-bin toolchain/external: support merged-bin
package/systemd: require merged-bin
Makefile | 19 ++-- package/coreutils/coreutils.mk | 2 + package/kmod/kmod.mk | 12 ++- package/net-tools/net-tools.mk | 10 +- package/skeleton-custom/skeleton-custom.mk | 25 ++--- package/systemd/Config.in | 2 + package/util-linux/util-linux.mk | 8 +- support/scripts/check-merged | 146 +++++++++++++++++++++++++++++ support/scripts/check-merged-usr.sh | 39 -------- support/testing/tests/init/test_systemd.py | 19 ++++ system/Config.in | 20 ++-- system/skeleton/usr/sbin/.empty | 0 system/system.mk | 14 ++- toolchain/helpers.mk | 8 +- 14 files changed, 240 insertions(+), 84 deletions(-) create mode 100755 support/scripts/check-merged delete mode 100755 support/scripts/check-merged-usr.sh delete mode 100644 system/skeleton/usr/sbin/.empty
--
.-----------------.--------------------.------------------.--------------------.
| Yann E. MORIN | Real-Time Embedded | /"\ ASCII RIBBON | Erics' conspiracy: | | +33 662 376 056 | Software Designer | \ / CAMPAIGN | ___ | | +33 561 099 427 `------------.-------: X AGAINST | \e/ There is no | | http://ymorin.is-a-geek.org/ | _/*\_ | / \ HTML MAIL | v conspiracy. |
'------------------------------^-------^------------------^--------------------'
_______________________________________________
buildroot mailing list
[email protected]
https://lists.buildroot.org/mailman/listinfo/buildroot
PATCH v3 1/18 system: reword merged-usr prompt
The current prompt is overly verbose, and departs from the usual terminology used to refer to merged /usr, which, 10 years later [0], makes it a little bit difficult to find or understand.
Furthermore, we're going to add another similar prompt for merged /usr/sbin, and there's no way we want to introduce as similarly convoluted prompt then.
Reword the prompt for the merged /usr option to the explicit "merged /usr" everyone expects and understands.
[0] see commit c5bd8af65e50 (system: add options for /bin /sbin and /lib to be symlinks into /usr)
---
Changes v1 -> v2:
- typos
--- system/Config.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
system/Config.in +1 -1
@@ -337,7 +337,7 @@ config BR2_ROOTFS_DEVICE_TABLE_SUPPORTS_EXTENDED_ATTRIBUTES Support extended attributes handling in device tables config BR2_ROOTFS_MERGED_USR - bool "Use symlinks to /usr for /bin, /sbin and /lib" + bool "Merged /usr" help If you say 'n' here, then /bin, /sbin and /lib and their counterparts in /usr will be separate directories. This
Signature · 6 lines
2.51.0 _______________________________________________ buildroot mailing list [email protected] https://lists.buildroot.org/mailman/listinfo/buildroot
PATCH v3 2/18 system: drop superfluous negative condition for default PATH
In reply to Yann E. MORIN via buildrootKconfig applies the default values in the order they are defined, and stops at the first which condition is met. In this case, the two conditions are mutually exclusive, so we can drop the second one. This also makes it obvious there actually is a default value.
--- system/Config.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
system/Config.in +1 -1
@@ -535,7 +535,7 @@ endif # BR2_ROOTFS_SKELETON_DEFAULT config BR2_SYSTEM_DEFAULT_PATH string "Set the system's default PATH" default "/usr/bin:/usr/sbin" if BR2_ROOTFS_MERGED_USR - default "/bin:/sbin:/usr/bin:/usr/sbin" if !BR2_ROOTFS_MERGED_USR + default "/bin:/sbin:/usr/bin:/usr/sbin" help Sets the system's default PATH. It is being used in /etc/profile in the skeleton-init-common package and by some
Signature · 6 lines
2.51.0 _______________________________________________ buildroot mailing list [email protected] https://lists.buildroot.org/mailman/listinfo/buildroot
PATCH v3 3/18 package/systemd: select merged-usr from package, not init
In reply to Yann E. MORIN via buildrootSince version 255, systemd no longer supports split-usr [0].
Move the select from the init system to the package, to explicitly expose that fact.
Drop our comment about our design decision, as it no longer applies.
[0] https://github.com/systemd/systemd/blob/v255/NEWS#L7
---
Changes v1 -> v2:
- typo
--- package/systemd/Config.in | 1 + system/Config.in | 5 ----- 2 files changed, 1 insertion(+), 5 deletions(-)
package/systemd/Config.in +1 -0
@@ -24,6 +24,7 @@ menuconfig BR2_PACKAGE_SYSTEMD depends on BR2_TOOLCHAIN_HEADERS_AT_LEAST_3_15 depends on BR2_TOOLCHAIN_GCC_AT_LEAST_8 depends on BR2_HOST_GCC_AT_LEAST_8 # host-systemd + select BR2_ROOTFS_MERGED_USR select BR2_PACKAGE_HAS_UDEV select BR2_PACKAGE_DBUS if !BR2_PACKAGE_DBUS_BROKER # runtime select BR2_PACKAGE_LIBCAP
system/Config.in +0 -5
@@ -115,10 +115,6 @@ comment "openrc needs a glibc or musl toolchain w/ dynamic library" depends on BR2_USE_MMU depends on BR2_STATIC_LIBS && BR2_TOOLCHAIN_USES_UCLIBC -# In Buildroot, we decided not to support a split-usr when systemd is -# used as an init system. This is a design decision, not a systemd -# issue. Thus the select is with BR2_INIT_SYSTEMD (below) rather than -# with BR2_PACKAGE_SYSTEMD. config BR2_INIT_SYSTEMD bool "systemd" depends on BR2_PACKAGE_SYSTEMD_ARCH_SUPPORTS
@@ -130,7 +126,6 @@ config BR2_INIT_SYSTEMD depends on BR2_TOOLCHAIN_HEADERS_AT_LEAST_3_15 depends on BR2_TOOLCHAIN_GCC_AT_LEAST_8 depends on BR2_HOST_GCC_AT_LEAST_8 - select BR2_ROOTFS_MERGED_USR select BR2_PACKAGE_SYSTEMD select BR2_PACKAGE_SKELETON_INIT_SYSTEMD if BR2_ROOTFS_SKELETON_DEFAULT
Signature · 6 lines
2.51.0 _______________________________________________ buildroot mailing list [email protected] https://lists.buildroot.org/mailman/listinfo/buildroot
PATCH v3 4/18 support/scripts: comonalise checking merged status
In reply to Yann E. MORIN via buildrootRather than repeat the same canned sequence over and over again, move it to a function that we can reuse as many times as needed. This will come handy when we later need to check merged-bin.
Switch to using bash as it allows for nicer functions (local variables), but we anyway require it globally already so that's not an additional dependency.
--- support/scripts/check-merged-usr.sh | 46 ++++++++++++++++------------- 1 file changed, 26 insertions(+), 20 deletions(-)
support/scripts/check-merged-usr.sh +26 -20
@@ -1,4 +1,4 @@ -#!/bin/sh +#!/usr/bin/env bash # # Check if a given custom skeleton or overlay complies to the merged /usr # requirements:
@@ -10,30 +10,36 @@ # /usr/lib/ # /usr/sbin/ # -# Output: the list of non-compliant paths (empty if compliant). +# Input: +# $1: the root directory (skeleton, overlay) to check +# Output: +# stdout: the list of non-compliant paths (empty if compliant). # +# The directory to check for merged-usr +root="${1}" + # Extract the inode numbers for all of those directories. In case any is # a symlink, we want to get the inode of the pointed-to directory, so we # append '/.' to be sure we get the target directory. Since the symlinks # can be anyway (/bin -> /usr/bin or /usr/bin -> /bin), we do that for -# all of them. +# each of them. # -lib_inode=$(stat -c '%i' "${1}/lib/." 2>/dev/null) -bin_inode=$(stat -c '%i' "${1}/bin/." 2>/dev/null) -sbin_inode=$(stat -c '%i' "${1}/sbin/." 2>/dev/null) -usr_lib_inode=$(stat -c '%i' "${1}/usr/lib/." 2>/dev/null) -usr_bin_inode=$(stat -c '%i' "${1}/usr/bin/." 2>/dev/null) -usr_sbin_inode=$(stat -c '%i' "${1}/usr/sbin/." 2>/dev/null) -not_merged_dirs="" -test -z "$lib_inode" || \ - test "$lib_inode" = "$usr_lib_inode" || \ - not_merged_dirs="/lib" -test -z "$bin_inode" || \ - test "$bin_inode" = "$usr_bin_inode" || \ - not_merged_dirs="$not_merged_dirs /bin" -test -z "$sbin_inode" || \ - test "$sbin_inode" = "$usr_sbin_inode" || \ - not_merged_dirs="$not_merged_dirs /sbin" -echo "${not_merged_dirs# }" +test_merged() { + local root="${1}" + local dir1="${2}" + local dir2="${3}" + local inode1 inode2 + + inode1="$(stat -c '%i' "${root}${dir1}/." 2>/dev/null)" + inode2="$(stat -c '%i' "${root}${dir2}/." 2>/dev/null)" + + test -z "${inode1}" || \ + test "${inode1}" = "${inode2}" || \ + printf '%s\n' "${dir1}" +} + +test_merged "${root}" "/lib" "/usr/lib" +test_merged "${root}" "/bin" "/usr/bin" +test_merged "${root}" "/sbin" "/usr/sbin"
Signature · 6 lines
2.51.0 _______________________________________________ buildroot mailing list [email protected] https://lists.buildroot.org/mailman/listinfo/buildroot
PATCH v3 5/18 support/scripts: prepare for a more complex check for merged directories
In reply to Yann E. MORIN via buildroot--- support/scripts/check-merged-usr.sh | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-)
support/scripts/check-merged-usr.sh +12 -4
@@ -26,7 +26,7 @@ root="${1}" # each of them. # -test_merged() { +is_valid_merged() { local root="${1}" local dir1="${2}" local dir2="${3}"
@@ -35,9 +35,17 @@ test_merged() { inode1="$(stat -c '%i' "${root}${dir1}/." 2>/dev/null)" inode2="$(stat -c '%i' "${root}${dir2}/." 2>/dev/null)" - test -z "${inode1}" || \ - test "${inode1}" = "${inode2}" || \ - printf '%s\n' "${dir1}" + test -z "${inode1}" || test "${inode1}" = "${inode2}" +} + +test_merged() { + local root="${1}" + local dir1="${2}" + local dir2="${3}" + + if ! is_valid_merged "${root}" "${dir1}" "${dir2}"; then + printf '%s\n' "${dir1}" + fi } test_merged "${root}" "/lib" "/usr/lib"
Signature · 6 lines
2.51.0 _______________________________________________ buildroot mailing list [email protected] https://lists.buildroot.org/mailman/listinfo/buildroot
PATCH v3 6/18 support/scripts: also exit in error on improperly merged-usr
In reply to Yann E. MORIN via buildroot--- support/scripts/check-merged-usr.sh | 7 +++++++ 1 file changed, 7 insertions(+)
support/scripts/check-merged-usr.sh +7 -0
@@ -14,6 +14,9 @@ # $1: the root directory (skeleton, overlay) to check # Output: # stdout: the list of non-compliant paths (empty if compliant). +# Exit code: +# 0: in case of success (stdout will be empty) +# !0: if any path is improperly merged # # The directory to check for merged-usr
@@ -45,9 +48,13 @@ test_merged() { if ! is_valid_merged "${root}" "${dir1}" "${dir2}"; then printf '%s\n' "${dir1}" + is_success=false fi } +is_success=true test_merged "${root}" "/lib" "/usr/lib" test_merged "${root}" "/bin" "/usr/bin" test_merged "${root}" "/sbin" "/usr/sbin" + +${is_success}
Signature · 6 lines
2.51.0 _______________________________________________ buildroot mailing list [email protected] https://lists.buildroot.org/mailman/listinfo/buildroot
PATCH v3 7/18 support/scripts: move merged-usr errors message into check-merged-usr.sh
In reply to Yann E. MORIN via buildrootBy moving the loop over the overlays into the script, we can generate better error messages about how and why a skeleton or a specific overlay is improperly setup for merged-usr.
We can also now rely on its exit code to decicde whether the skeleton or the overlays are properly setup, rather than stash the stdout/stderr to a Makefile variable and test the emptiness thereof.
Introduce a --type option to pass the type of root to verify, for better error reporting. This will incidentally be usefull in a future commit, when we need to take different actions based on whether the root is a skeleton or an overlay.
--- Makefile | 15 ++--- package/skeleton-custom/skeleton-custom.mk | 21 +++---- support/scripts/check-merged-usr.sh | 65 +++++++++++++++++----- 3 files changed, 64 insertions(+), 37 deletions(-)
Makefile +4 -11
@@ -782,17 +782,10 @@ endif # For a merged /usr, ensure that /lib, /bin and /sbin and their /usr # counterparts are appropriately setup as symlinks ones to the others. ifeq ($(BR2_ROOTFS_MERGED_USR),y) - - $(foreach d, $(call qstrip,$(BR2_ROOTFS_OVERLAY)), \ - @$(call MESSAGE,"Sanity check in overlay $(d)")$(sep) \ - $(Q)not_merged_dirs="$$(support/scripts/check-merged-usr.sh $(d))"; \ - test -n "$$not_merged_dirs" && { \ - echo "ERROR: The overlay in $(d) is not" \ - "using a merged /usr for the following directories:" \ - $$not_merged_dirs; \ - exit 1; \ - } || true$(sep)) - + @$(call MESSAGE,"Sanity check in overlays $(call qstrip,$(BR2_ROOTFS_OVERLAY))") + support/scripts/check-merged-usr.sh \ + --type overlay \ + $(call qstrip,$(BR2_ROOTFS_OVERLAY)) endif # merged /usr $(foreach d, $(call qstrip,$(BR2_ROOTFS_OVERLAY)), \
package/skeleton-custom/skeleton-custom.mk +9 -12
@@ -26,17 +26,16 @@ endif # For a merged /usr, ensure that /lib, /bin and /sbin and their /usr # counterparts are appropriately setup as symlinks ones to the others. ifeq ($(BR2_ROOTFS_MERGED_USR),y) -SKELETON_CUSTOM_NOT_MERGED_USR_DIRS = \ - $(shell support/scripts/check-merged-usr.sh $(SKELETON_CUSTOM_PATH)) +define SKELETON_CUSTOM_NOT_MERGED_USR_DIRS + support/scripts/check-merged-usr.sh \ + --type skeleton \ + $(SKELETON_CUSTOM_PATH) +endef endif # merged /usr -ifeq ($(BR2_PACKAGE_SKELETON_CUSTOM)$(BR_BUILDING),yy) -ifneq ($(SKELETON_CUSTOM_NOT_MERGED_USR_DIRS),) -$(error The custom skeleton in $(SKELETON_CUSTOM_PATH) is not \ - using a merged /usr for the following directories: \ - $(SKELETON_CUSTOM_NOT_MERGED_USR_DIRS)) -endif -endif +define SKELETON_CUSTOM_CONFIGURE_CMDS + $(SKELETON_CUSTOM_NOT_MERGED_USR_DIRS) +endef # The target-dir-warning file and the lib{32,64} symlinks are the only # things we customise in the custom skeleton.
@@ -49,9 +48,7 @@ define SKELETON_CUSTOM_INSTALL_TARGET_CMDS endef # For the staging dir, we don't really care what we install, but we -# need the /lib and /usr/lib appropriately setup. Since we ensure, -# above, that they are correct in the skeleton, we can simply copy the -# skeleton to staging. +# need the /lib and /usr/lib appropriately setup. define SKELETON_CUSTOM_INSTALL_STAGING_CMDS $(call SYSTEM_RSYNC,$(SKELETON_CUSTOM_PATH),$(STAGING_DIR)) $(call SYSTEM_USR_SYMLINKS_OR_DIRS,$(STAGING_DIR))
support/scripts/check-merged-usr.sh +51 -14
86 lines not on this page · raw message
Signature · 6 lines
2.51.0 _______________________________________________ buildroot mailing list [email protected] https://lists.buildroot.org/mailman/listinfo/buildroot
Re: [Buildroot] [PATCH 07/18 v3] support/scripts: move merged-usr errors message into check-merged-usr.sh
Hello Yann, All,
Le 01/09/2025 à 11:01, Yann E. MORIN via buildroot a écrit :
Quoted 5 lines
By moving the loop over the overlays into the script, we can generate better error messages about how and why a skeleton or a specific overlay is improperly setup for merged-usr.
We can also now rely on its exit code to decicde whether the skeleton or
decicde/decide
Quoted 29 lines
the overlays are properly setup, rather than stash the stdout/stderr to a
Makefilevariable and test the emptiness thereof.Introduce a --type option to pass the type of root to verify, for better error reporting. This will incidentally be usefull in a future commit, when we need to take different actions based on whether the root is a skeleton or an overlay.
Signed-off-by Yann E. MORIN <[email protected]>Cc Arnout Vandecappelle (Essensium/Mind) <[email protected]>--- Makefile | 15 ++--- package/skeleton-custom/skeleton-custom.mk | 21 +++---- support/scripts/check-merged-usr.sh | 65 +++++++++++++++++----- 3 files changed, 64 insertions(+), 37 deletions(-)Makefile +0
-5@@ -782,17 +782,10 @@ endif # For a merged /usr, ensure that /lib, /bin and /sbin and their /usr # counterparts are appropriately setup as symlinks ones to the others. ifeq ($(BR2_ROOTFS_MERGED_USR),y) - - $(foreach d, $(call qstrip,$(BR2_ROOTFS_OVERLAY)), \ - @$(call MESSAGE,"Sanity check in overlay $(d)")$(sep) \ - $(Q)not_merged_dirs="$$(support/scripts/check-merged-usr.sh $(d))"; \ - test -n "$$not_merged_dirs" && { \
Makefile endif · line 788
Quoted 10 lines
Makefile +4
-6- echo "ERROR: The overlay in $(d) is not" \ - "using a merged /usr for the following directories:" \ - $$not_merged_dirs; \ - exit 1; \ - } || true$(sep)) - + @$(call MESSAGE,"Sanity check in overlays $(call qstrip,$(BR2_ROOTFS_OVERLAY))") + support/scripts/check-merged-usr.sh \ + --type overlay \ + $(call qstrip,$(BR2_ROOTFS_OVERLAY))
BR2_ROOTFS_OVERLAY can have a list of overlay directory. We had a foreach loop to check all of them.
Quoted 119 lines
Makefile +0
-0endif # merged /usr $(foreach d, $(call qstrip,$(BR2_ROOTFS_OVERLAY)), \package/skeleton-custom/skeleton-custom.mk +9
-12@@ -26,17 +26,16 @@ endif # For a merged /usr, ensure that /lib, /bin and /sbin and their /usr # counterparts are appropriately setup as symlinks ones to the others. ifeq ($(BR2_ROOTFS_MERGED_USR),y) -SKELETON_CUSTOM_NOT_MERGED_USR_DIRS = \ - $(shell support/scripts/check-merged-usr.sh $(SKELETON_CUSTOM_PATH)) +define SKELETON_CUSTOM_NOT_MERGED_USR_DIRS + support/scripts/check-merged-usr.sh \ + --type skeleton \ + $(SKELETON_CUSTOM_PATH) +endef endif # merged /usr -ifeq ($(BR2_PACKAGE_SKELETON_CUSTOM)$(BR_BUILDING),yy) -ifneq ($(SKELETON_CUSTOM_NOT_MERGED_USR_DIRS),) -$(error The custom skeleton in $(SKELETON_CUSTOM_PATH) is not \ - using a merged /usr for the following directories: \ - $(SKELETON_CUSTOM_NOT_MERGED_USR_DIRS)) -endif -endif +define SKELETON_CUSTOM_CONFIGURE_CMDS + $(SKELETON_CUSTOM_NOT_MERGED_USR_DIRS) +endef # The target-dir-warning file and the lib{32,64} symlinks are the only # things we customise in the custom skeleton.@@ -49,9 +48,7 @@ define SKELETON_CUSTOM_INSTALL_TARGET_CMDS endef # For the staging dir, we don't really care what we install, but we -# need the /lib and /usr/lib appropriately setup. Since we ensure, -# above, that they are correct in the skeleton, we can simply copy the -# skeleton to staging. +# need the /lib and /usr/lib appropriately setup. define SKELETON_CUSTOM_INSTALL_STAGING_CMDS $(call SYSTEM_RSYNC,$(SKELETON_CUSTOM_PATH),$(STAGING_DIR)) $(call SYSTEM_USR_SYMLINKS_OR_DIRS,$(STAGING_DIR))support/scripts/check-merged-usr.sh +43
-11@@ -11,16 +11,48 @@ # /usr/sbin/ # # Input: -# $1: the root directory (skeleton, overlay) to check +# --type TYPE the type of root to check: 'skeleton' or 'overlay' +# $*: the root directories (skeleton, overlays) to check # Output: -# stdout: the list of non-compliant paths (empty if compliant). +# stdout: the list of non-compliant paths (empty if compliant). # Exit code: -# 0: in case of success (stdout will be empty) -# !0: if any path is improperly merged +# 0: in case of success (stdout will be empty) +# !0: if any path is improperly merged # -# The directory to check for merged-usr -root="${1}" +opts="type:" +ARGS="$(getopt -n check-merged -o "" -l "${opts}" -- "${@}")" || exit 1 +eval set -- "${ARGS}" + +type= +while :; do + case "${1}" in + (--type) + type="${2}" + shift 2 + ;; + (--) + shift + break + ;; + esac +done + +report_error() { + local type="${1}" + local root="${2}" + local fmt="${3}" + shift 3 + + if ${first}; then + printf "The %s in %s is not properly setup:\n" \ + "${type}" "${root}" + fi + first=false + # shellcheck disable=SC2059 # fmt *is* a format string + printf " - ${fmt}" "${@}" + is_success=false +} # Extract the inode numbers for all of those directories. In case any is # a symlink, we want to get the inode of the pointed-to directory, so we@@ -42,19 +74,24 @@ is_valid_merged() { } test_merged() { - local root="${1}" - local dir1="${2}" - local dir2="${3}" + local type="${1}" + local root="${2}" + local dir1="${3}" + local dir2="${4}" if ! is_valid_merged "${root}" "${dir1}" "${dir2}"; then - printf '%s\n' "${dir1}" - is_success=false + report_error "${type}" "${root}" \
support/scripts/check-merged-usr.sh is_valid_merged() { · line 90
Quoted 10 lines
support/scripts/check-merged-usr.sh +3
-3+ '%s should be missing, or be a relative symlink to %s\n' \ + "${dir1}" "${dir2}" fi } is_success=true -test_merged "${root}" "/lib" "/usr/lib" -test_merged "${root}" "/bin" "/usr/bin" -test_merged "${root}" "/sbin" "/usr/sbin" +for root; do
I'm not sure to follow here.
Where root is defined?
Best regards,
Romain
support/scripts/check-merged-usr.sh is_valid_merged() { · line 97
Quoted 7 lines
support/scripts/check-merged-usr.sh +5
-0+ first=true + test_merged "${type}" "${root}" "/lib" "/usr/lib" + test_merged "${type}" "${root}" "/bin" "/usr/bin" + test_merged "${type}" "${root}" "/sbin" "/usr/sbin" +done ${is_success}
_______________________________________________
buildroot mailing list
[email protected]
https://lists.buildroot.org/mailman/listinfo/buildroot
Re: [Buildroot] [PATCH 07/18 v3] support/scripts: move merged-usr errors message into check-merged-usr.sh
Romain, All,
On 2025-11-05 11:52 +0100, Romain Naour spake thusly:
Quoted 1 line
Le 01/09/2025 à 11:01, Yann E. MORIN via buildroot a écrit :
[--SNIP--]
Quoted 6 lines
Makefile endif · line 788
Quoted 4 lines
Makefile +4
-0+ @$(call MESSAGE,"Sanity check in overlays $(call qstrip,$(BR2_ROOTFS_OVERLAY))") + support/scripts/check-merged-usr.sh \ + --type overlay \ + $(call qstrip,$(BR2_ROOTFS_OVERLAY))
BR2_ROOTFS_OVERLAYcan have a list of overlay directory. We had a foreach loop to check all of them.
Exactly. Now they are passed as arguments to the check-merged-usr.sh script, so that...
[--SNIP--]
Quoted 3 lines
Quoted 1 line
+for root; do
I'm not sure to follow here.
Where root is defined?
... they now iterated over by this for-loop.
When there is no 'in' part to a for loop, it iterates over the positional parameters:
$ cat foo
#!/bin/sh
for i; do printf 'i=%s\n' "${i}"; done # ./foo a b c d
i=a
i=b
i=c
i=dSo, those two lines are equivalent:
for i; do
for i in "${@}"; do
See section 2.9.4.2 of the Open Group Base Specifications Issue 8:
https://pubs.opengroup.org/onlinepubs/9799919799/utilities/V3_chap02.html#tag_19_09_04
Regards,
Yann E. MORIN.
Signature · 10 lines
.-----------------.--------------------.------------------.--------------------. | Yann E. MORIN | Real-Time Embedded | /"\ ASCII RIBBON | Erics' conspiracy: | | +33 662 376 056 | Software Designer | \ / CAMPAIGN | ___ | | +33 561 099 427 `------------.-------: X AGAINST | \e/ There is no | | http://ymorin.is-a-geek.org/ | _/*\_ | / \ HTML MAIL | v conspiracy. | '------------------------------^-------^------------------^--------------------' _______________________________________________ buildroot mailing list [email protected] https://lists.buildroot.org/mailman/listinfo/buildroot
Re: [Buildroot] [PATCH 07/18 v3] support/scripts: move merged-usr errors message into check-merged-usr.sh
Hello Yann, All,
Le 05/11/2025 à 16:59, Yann E. MORIN a écrit :
Quoted 35 lines
Romain, All,
On 2025-11-05 11:52 +0100, Romain Naour spake thusly:
Quoted 1 line
Le 01/09/2025 à 11:01, Yann E. MORIN via buildroot a écrit :
[--SNIP--]
Quoted 6 lines
Makefile endif · line 788
Quoted 4 lines
Makefile +4
-0+ @$(call MESSAGE,"Sanity check in overlays $(call qstrip,$(BR2_ROOTFS_OVERLAY))") + support/scripts/check-merged-usr.sh \ + --type overlay \ + $(call qstrip,$(BR2_ROOTFS_OVERLAY))
BR2_ROOTFS_OVERLAYcan have a list of overlay directory. We had a foreach loop to check all of them.Exactly. Now they are passed as arguments to the
check-merged-usr.shscript, so that...[--SNIP--]
Quoted 3 lines
Quoted 1 line
+for root; do
I'm not sure to follow here.
Where root is defined?... they now iterated over by this for-loop.
When there is no 'in' part to a for loop, it iterates over the positional parameters:
$ cat foo #!/bin/sh for i; do printf 'i=%s\n' "${i}"; done# ./foo a b c d i=a i=b i=c i=d
Quoted 7 lines
So, those two lines are equivalent:
for i; do
for i in "${@}"; doSee section 2.9.4.2 of the Open Group Base Specifications Issue 8:
https://pubs.opengroup.org/onlinepubs/9799919799/utilities/V3_chap02.html#tag_19_09_04
Thanks for the explanation.
I personally don't really like this implicit use of positional parameters but it's matter of taste :)
Best regards,
Romain
Quoted 4 lines
Regards,
Yann E. MORIN.
_______________________________________________
buildroot mailing list
[email protected]
https://lists.buildroot.org/mailman/listinfo/buildroot
Re: [Buildroot] [PATCH 07/18 v3] support/scripts: move merged-usr errors message into check-merged-usr.sh
In reply to Yann E. MORIN via buildrootHello Yann,
Sorry, I am late to the party. I haven't followed this whole work, but this specific patch is causing an issue on my side, see below.
support/scripts/check-merged-usr.sh line 24
Quoted 4 lines · On Mon, 1 Sep 2025 11:01:16 +0200 "Yann E. MORIN via buildroot"…
support/scripts/check-merged-usr.sh +2
-2-# The directory to check for merged-usr -root="${1}" +opts="type:" +ARGS="$(getopt -n check-merged -o "" -l "${opts}" -- "${@}")" || exit 1
You're introducing the use of "getopt" here, which is part of util-linux, and not necessarily installed by default in distributions. For example the minimal Fedora 42 container that I use for Buildroot builds now fails to complete a Buildroot build with:
support/scripts/check-merged: line 38: getopt: command not found
make: *** [Makefile:758: target-finalize] Error 1
One option is to check for getopt in support/dependencies and update the documentation to make installing util-linux a requirement.
However, in several other shell scripts (such as dl-wrapper), we use getopts which is a bash built-in. For the sake of consistency, it would probably be better to also use getopts here. Do you think it would be possible?
Thanks a lot for your feedback!
Thomas
Signature · 7 lines
Thomas Petazzoni, co-owner and CEO, Bootlin Embedded Linux and Kernel engineering and training https://bootlin.com _______________________________________________ buildroot mailing list [email protected] https://lists.buildroot.org/mailman/listinfo/buildroot
Re: [Buildroot] [PATCH 07/18 v3] support/scripts: move merged-usr errors message into check-merged-usr.sh
Thomas, All,
On 2025-11-20 21:52 +0100, Thomas Petazzoni spake thusly:
Quoted 8 lines
support/scripts/check-merged-usr.sh line 24
Quoted 4 lines · On Mon, 1 Sep 2025 11:01:16 +0200 "Yann E. MORIN via buildroot"…
support/scripts/check-merged-usr.sh +2
-2-# The directory to check for merged-usr -root="${1}" +opts="type:" +ARGS="$(getopt -n check-merged -o "" -l "${opts}" -- "${@}")" || exit 1You're introducing the use of "getopt" here, which is part of util-linux, and not necessarily installed by default in distributions.
Damn, thanks for the report. I've sent a patch switching to using getopts instead:
https://lore.kernel.org/buildroot/[email protected]/T/#u
Regards,
Yann E. MORIN.
Signature · 10 lines
.-----------------.--------------------.------------------.--------------------. | Yann E. MORIN | Real-Time Embedded | /"\ ASCII RIBBON | Erics' conspiracy: | | +33 662 376 056 | Software Designer | \ / CAMPAIGN | ___ | | +33 561 099 427 `------------.-------: X AGAINST | \e/ There is no | | http://ymorin.is-a-geek.org/ | _/*\_ | / \ HTML MAIL | v conspiracy. | '------------------------------^-------^------------------^--------------------' _______________________________________________ buildroot mailing list [email protected] https://lists.buildroot.org/mailman/listinfo/buildroot
PATCH v3 8/18 support/scripts: fix and restrict conditions to accept merged dirs
In reply to Yann E. MORIN via buildrootCurrently, we accept that the merged usr is backward, i.e. that the /usr/bin, /usr/sbin, and /usr/lib entries be symlinks to, resp., /bin, /sbin, and /lib. We also allow either entries to be symlinks to other parts of the root. Both are accepted despite the comment at the top of the script explaining what should be accepted.
However, a properly merged usr is the other way around: /bin, /sbin, and /lib are the symlinks to resp. /usr/bin, /usr/sbin, and /usr/lib, which are actual directories.
Fix the check-merged-usr script accordingly: implement the test as we mean it, by testing the conditions rather than resorting to a convoluted and incorrect use of stat(1).
Even though the split between test_dir() and test_merged() seems superfluous, it'll come useful when we introduce support for merged-bin in a later patch.
For skeletons, we require that the directories do exist, while we allow them to be missing for overlays; indeed, it is perfectly legit to provide an overlay that only contains totally unrelated directories (e.g. /var/www to populate a webroot for example).
Extend the heading-comment to be more explicit (and drop '/' as there is nothing to say about it).
---
Changes v1 -> v2;
- complete rewrite of the test
- slight rephrase of commit log
- typoes
--- support/scripts/check-merged-usr.sh | 87 +++++++++++++++++------------ 1 file changed, 51 insertions(+), 36 deletions(-)
support/scripts/check-merged-usr.sh +51 -36
@@ -2,13 +2,14 @@ # # Check if a given custom skeleton or overlay complies to the merged /usr # requirements: -# / -# /bin -> usr/bin -# /lib -> usr/lib -# /sbin -> usr/sbin -# /usr/bin/ -# /usr/lib/ -# /usr/sbin/ +# /bin missing, or a relative symlink to usr/bin +# /lib missing, or a relative symlink to usr/lib +# /sbin missing, or a relative symlink to usr/sbin +# /usr/bin/ missing*, or an existing directory; not a symlink +# /usr/lib/ missing*, or an existing directory; not a symlink +# /usr/sbin/ missing*, or an existing directory; not a symlink +# +# *: must be present for skeletons, can be missing for overlays # # Input: # --type TYPE the type of root to check: 'skeleton' or 'overlay'
@@ -17,7 +18,7 @@ # stdout: the list of non-compliant paths (empty if compliant). # Exit code: # 0: in case of success (stdout will be empty) -# !0: if any path is improperly merged +# !0: if any directory to check is improperly merged # opts="type:"
@@ -38,6 +39,12 @@ while :; do esac done +if [ "${type}" = "skeleton" ]; then + strict=true +else + strict=false +fi + report_error() { local type="${1}" local root="${2}"
@@ -54,44 +61,52 @@ report_error() { is_success=false } -# Extract the inode numbers for all of those directories. In case any is -# a symlink, we want to get the inode of the pointed-to directory, so we -# append '/.' to be sure we get the target directory. Since the symlinks -# can be anyway (/bin -> /usr/bin or /usr/bin -> /bin), we do that for -# each of them. -# - -is_valid_merged() { - local root="${1}" - local dir1="${2}" - local dir2="${3}" - local inode1 inode2 - - inode1="$(stat -c '%i' "${root}${dir1}/." 2>/dev/null)" - inode2="$(stat -c '%i' "${root}${dir2}/." 2>/dev/null)" - - test -z "${inode1}" || test "${inode1}" = "${inode2}" -} - test_merged() { local type="${1}" local root="${2}" - local dir1="${3}" - local dir2="${4}" + local base="${3}" + local dir1="${4}" + local dir2="${5}" - if ! is_valid_merged "${root}" "${dir1}" "${dir2}"; then - report_error "${type}" "${root}" \ - '%s should be missing, or be a relative symlink to %s\n' \ - "${dir1}" "${dir2}" + if ! test -e "${root}${base}${dir1}"; then + return 0 + elif [ "$(readlink "${root}${base}${dir1}")" = "${dir2}" ]; then + return 0 fi + + # Otherwise, this directory is not merged + report_error "${type}" "${root}" \ + '%s%s should be missing, or be a relative symlink to %s\n' \ + "${base}" "${dir1}" "${dir2}" +} + +test_dir() { + local type="${1}" + local root="${2}" + local base="${3}" + local dir="${4}" + + if ! test -e "${root}${base}${dir}" && ! ${strict}; then + return 0 + elif test -d "${root}${base}${dir}" && ! test -L "${root}${base}${dir}"; then + return 0 + fi + + # Otherwise, this entry is not a proper directory + report_error "${type}" "${root}" \ + "%s%s should exist, be a directory, and not be a symlink\n" \ + "${base}" "${dir}" } is_success=true for root; do first=true - test_merged "${type}" "${root}" "/lib" "/usr/lib" - test_merged "${type}" "${root}" "/bin" "/usr/bin" - test_merged "${type}" "${root}" "/sbin" "/usr/sbin" + test_dir "${type}" "${root}" "/" "usr/bin" + test_dir "${type}" "${root}" "/" "usr/lib" + test_dir "${type}" "${root}" "/" "usr/sbin" + test_merged "${type}" "${root}" "/" "bin" "usr/bin" + test_merged "${type}" "${root}" "/" "lib" "usr/lib" + test_merged "${type}" "${root}" "/" "sbin" "usr/sbin" done ${is_success}
Signature · 6 lines
2.51.0 _______________________________________________ buildroot mailing list [email protected] https://lists.buildroot.org/mailman/listinfo/buildroot
PATCH v3 9/18 support/scripts: rename check-merged-usr.sh
In reply to Yann E. MORIN via buildrootWe're going to need it to check merged-bin, so the naming would be misleading as it would no longer be just about merged-usr.
Also drop the extension, it's useless.
---
Makefile | 2 +-
package/skeleton-custom/skeleton-custom.mk | 2 +-
support/scripts/{check-merged-usr.sh => check-merged} | 0
3 files changed, 2 insertions(+), 2 deletions(-)
rename support/scripts/{check-merged-usr.sh => check-merged} (100%)Makefile +1 -1
@@ -783,7 +783,7 @@ endif # counterparts are appropriately setup as symlinks ones to the others. ifeq ($(BR2_ROOTFS_MERGED_USR),y) @$(call MESSAGE,"Sanity check in overlays $(call qstrip,$(BR2_ROOTFS_OVERLAY))") - support/scripts/check-merged-usr.sh \ + support/scripts/check-merged \ --type overlay \ $(call qstrip,$(BR2_ROOTFS_OVERLAY)) endif # merged /usr
package/skeleton-custom/skeleton-custom.mk +1 -1
@@ -27,7 +27,7 @@ endif # counterparts are appropriately setup as symlinks ones to the others. ifeq ($(BR2_ROOTFS_MERGED_USR),y) define SKELETON_CUSTOM_NOT_MERGED_USR_DIRS - support/scripts/check-merged-usr.sh \ + support/scripts/check-merged \ --type skeleton \ $(SKELETON_CUSTOM_PATH) endef
support/scripts/check-merged renamed from support/scripts/check-merged-usr.sh +0 -0
Signature · 6 lines
2.51.0 _______________________________________________ buildroot mailing list [email protected] https://lists.buildroot.org/mailman/listinfo/buildroot
PATCH v3 10/18 support/scripts; teach check-merged what to check
In reply to Yann E. MORIN via buildroot--- Makefile | 3 +-- package/skeleton-custom/skeleton-custom.mk | 11 ++--------- support/scripts/check-merged | 22 +++++++++++++++------- 3 files changed, 18 insertions(+), 18 deletions(-)
Makefile +1 -2
@@ -781,12 +781,11 @@ endif # For a merged /usr, ensure that /lib, /bin and /sbin and their /usr # counterparts are appropriately setup as symlinks ones to the others. -ifeq ($(BR2_ROOTFS_MERGED_USR),y) @$(call MESSAGE,"Sanity check in overlays $(call qstrip,$(BR2_ROOTFS_OVERLAY))") support/scripts/check-merged \ --type overlay \ + $(if $(BR2_ROOTFS_MERGED_USR),--merged-usr) \ $(call qstrip,$(BR2_ROOTFS_OVERLAY)) -endif # merged /usr $(foreach d, $(call qstrip,$(BR2_ROOTFS_OVERLAY)), \ @$(call MESSAGE,"Copying overlay $(d)")$(sep) \
package/skeleton-custom/skeleton-custom.mk +2 -9
@@ -23,19 +23,12 @@ $(error No path specified for the custom skeleton) endif endif -# For a merged /usr, ensure that /lib, /bin and /sbin and their /usr -# counterparts are appropriately setup as symlinks ones to the others. -ifeq ($(BR2_ROOTFS_MERGED_USR),y) -define SKELETON_CUSTOM_NOT_MERGED_USR_DIRS +define SKELETON_CUSTOM_CONFIGURE_CMDS support/scripts/check-merged \ --type skeleton \ + $(if $(BR2_ROOTFS_MERGED_USR),--merged-usr) \ $(SKELETON_CUSTOM_PATH) endef -endif # merged /usr - -define SKELETON_CUSTOM_CONFIGURE_CMDS - $(SKELETON_CUSTOM_NOT_MERGED_USR_DIRS) -endef # The target-dir-warning file and the lib{32,64} symlinks are the only # things we customise in the custom skeleton.
support/scripts/check-merged +15 -7
@@ -13,6 +13,7 @@ # # Input: # --type TYPE the type of root to check: 'skeleton' or 'overlay' +# --merged-usr check for merged /usr # $*: the root directories (skeleton, overlays) to check # Output: # stdout: the list of non-compliant paths (empty if compliant).
@@ -21,17 +22,22 @@ # !0: if any directory to check is improperly merged # -opts="type:" +opts="type:,merged-usr" ARGS="$(getopt -n check-merged -o "" -l "${opts}" -- "${@}")" || exit 1 eval set -- "${ARGS}" type= +merged_usr=false while :; do case "${1}" in (--type) type="${2}" shift 2 ;; + (--merged-usr) + merged_usr=true + shift + ;; (--) shift break
@@ -101,12 +107,14 @@ test_dir() { is_success=true for root; do first=true - test_dir "${type}" "${root}" "/" "usr/bin" - test_dir "${type}" "${root}" "/" "usr/lib" - test_dir "${type}" "${root}" "/" "usr/sbin" - test_merged "${type}" "${root}" "/" "bin" "usr/bin" - test_merged "${type}" "${root}" "/" "lib" "usr/lib" - test_merged "${type}" "${root}" "/" "sbin" "usr/sbin" + if ${merged_usr}; then + test_dir "${type}" "${root}" "/" "usr/bin" + test_dir "${type}" "${root}" "/" "usr/lib" + test_dir "${type}" "${root}" "/" "usr/sbin" + test_merged "${type}" "${root}" "/" "bin" "usr/bin" + test_merged "${type}" "${root}" "/" "lib" "usr/lib" + test_merged "${type}" "${root}" "/" "sbin" "usr/sbin" + fi done ${is_success}
Signature · 6 lines
2.51.0 _______________________________________________ buildroot mailing list [email protected] https://lists.buildroot.org/mailman/listinfo/buildroot
PATCH v3 11/18 system: add support for merged /usr/sbin (aka merged-bin)
In reply to Yann E. MORIN via buildrootStarting with version 256 [0], systemd warns when /usr/bin and /usr/sbin are different directories; in the future, it may even refuse to boot in such a situation.
Add support for merged-bin, not unlike the support we have for merged-usr; we also make merged-bin a sub-case of merged-usr (i.e. it is not possible to do merged-bin without merged-usr).
[0] https://github.com/systemd/systemd/blob/v256/NEWS#L265
---
Changes v1 -> v2:
- fix typo (Edgar)
--- Makefile | 1 + package/skeleton-custom/skeleton-custom.mk | 1 + support/scripts/check-merged | 22 +++++++++++++++++++--- system/Config.in | 11 +++++++++++ system/skeleton/usr/sbin/.empty | 0 system/system.mk | 14 +++++++++++++- 6 files changed, 45 insertions(+), 4 deletions(-) delete mode 100644 system/skeleton/usr/sbin/.empty
Makefile +1 -0
@@ -785,6 +785,7 @@ endif support/scripts/check-merged \ --type overlay \ $(if $(BR2_ROOTFS_MERGED_USR),--merged-usr) \ + $(if $(BR2_ROOTFS_MERGED_BIN),--merged-bin) \ $(call qstrip,$(BR2_ROOTFS_OVERLAY)) $(foreach d, $(call qstrip,$(BR2_ROOTFS_OVERLAY)), \
package/skeleton-custom/skeleton-custom.mk +1 -0
@@ -27,6 +27,7 @@ define SKELETON_CUSTOM_CONFIGURE_CMDS support/scripts/check-merged \ --type skeleton \ $(if $(BR2_ROOTFS_MERGED_USR),--merged-usr) \ + $(if $(BR2_ROOTFS_MERGED_BIN),--merged-bin) \ $(SKELETON_CUSTOM_PATH) endef
support/scripts/check-merged +19 -3
@@ -1,7 +1,9 @@ #!/usr/bin/env bash # -# Check if a given custom skeleton or overlay complies to the merged /usr +# Check if a given custom skeleton or overlay complies to the merged # requirements: +# +# - for merged-usr: # /bin missing, or a relative symlink to usr/bin # /lib missing, or a relative symlink to usr/lib # /sbin missing, or a relative symlink to usr/sbin
@@ -11,9 +13,14 @@ # # *: must be present for skeletons, can be missing for overlays # +# - for merged-bin: all of the above, except: +# /usr/sbin missing, or a relative symlink to bin (thus points +# to /usr/bin) +# # Input: # --type TYPE the type of root to check: 'skeleton' or 'overlay' # --merged-usr check for merged /usr +# --merged-bin check for merged /usr/bin # $*: the root directories (skeleton, overlays) to check # Output: # stdout: the list of non-compliant paths (empty if compliant).
@@ -22,12 +29,13 @@ # !0: if any directory to check is improperly merged # -opts="type:,merged-usr" +opts="type:,merged-usr,merged-bin" ARGS="$(getopt -n check-merged -o "" -l "${opts}" -- "${@}")" || exit 1 eval set -- "${ARGS}" type= merged_usr=false +merged_bin=false while :; do case "${1}" in (--type)
@@ -38,6 +46,10 @@ while :; do merged_usr=true shift ;; + (--merged-bin) + merged_bin=true + shift + ;; (--) shift break
@@ -110,10 +122,14 @@ for root; do if ${merged_usr}; then test_dir "${type}" "${root}" "/" "usr/bin" test_dir "${type}" "${root}" "/" "usr/lib" - test_dir "${type}" "${root}" "/" "usr/sbin" test_merged "${type}" "${root}" "/" "bin" "usr/bin" test_merged "${type}" "${root}" "/" "lib" "usr/lib" test_merged "${type}" "${root}" "/" "sbin" "usr/sbin" + if ${merged_bin}; then + test_merged "${type}" "${root}" "/usr/" "sbin" "bin" + else + test_dir "${type}" "${root}" "/" "usr/sbin" + fi fi done
system/Config.in +11 -0
@@ -343,6 +343,16 @@ config BR2_ROOTFS_MERGED_USR symlinks to their counterparts in /usr. In this case, /usr can not be a separate filesystem. +config BR2_ROOTFS_MERGED_BIN + bool "Merged /usr/bin" + depends on BR2_ROOTFS_MERGED_USR + help + If you say 'n' here, then /usr/bin and /usr/sbin will be + separate directories; this is the historical UNIX way. + + If you say 'y' here, then /usr/sbin will be a relative + symlink to /usr/bin. + if BR2_ROOTFS_SKELETON_DEFAULT config BR2_TARGET_ENABLE_ROOT_LOGIN
@@ -529,6 +539,7 @@ endif # BR2_ROOTFS_SKELETON_DEFAULT config BR2_SYSTEM_DEFAULT_PATH string "Set the system's default PATH" + default "/usr/bin" if BR2_ROOTFS_MERGED_BIN default "/usr/bin:/usr/sbin" if BR2_ROOTFS_MERGED_USR default "/bin:/sbin:/usr/bin:/usr/sbin" help
system/skeleton/usr/sbin/.empty deleted +0 -0
system/system.mk +13 -1
@@ -32,18 +32,30 @@ # set inittab to remount root read-write or read-only # -# This function handles the merged or non-merged /usr cases +# This function handles the merged or non-merged /usr, and merged or +# non-merged /usr/bin cases ifeq ($(BR2_ROOTFS_MERGED_USR),y) +ifeq ($(BR2_ROOTFS_MERGED_BIN),y) +define SYSTEM_SBIN_SYMLINKS_OR_DIRS + ln -snf bin $(1)/usr/sbin +endef +else +define SYSTEM_SBIN_SYMLINKS_OR_DIRS + $(INSTALL) -d -m 0755 $(1)/usr/sbin +endef +endif define SYSTEM_USR_SYMLINKS_OR_DIRS ln -snf usr/bin $(1)/bin ln -snf usr/sbin $(1)/sbin ln -snf usr/lib $(1)/lib + $(SYSTEM_SBIN_SYMLINKS_OR_DIRS) endef else define SYSTEM_USR_SYMLINKS_OR_DIRS $(INSTALL) -d -m 0755 $(1)/bin $(INSTALL) -d -m 0755 $(1)/sbin $(INSTALL) -d -m 0755 $(1)/lib + $(INSTALL) -d -m 0755 $(1)/usr/sbin endef endif
Signature · 6 lines
2.51.0 _______________________________________________ buildroot mailing list [email protected] https://lists.buildroot.org/mailman/listinfo/buildroot
PATCH v3 12/18 support/scripts: reject skeletons or overlays that are unexpectedly merged
In reply to Yann E. MORIN via buildrootCurrently, we partially accept that a skeleton or a rootfs overlay be merged:
- for unmerged, we accept all kind of situations: unmerged, partially merged, badly merged, merged-usr or merged-bin, arbitrary relative or absolute symlinks, and whatnots;
- for merged-usr, we strictly require a properly set up merged-usr,
and we refuse a merged-bin;
- for merged-bin, we stricty require a properly set up merged-bin.
The unmerged case is inconsistent with the other cases, especially it allows for arbitrary symlinks that may point to arbitrary locations that may even not belong to $(TARGET_DIR) at all...
We fix that by ensuring that the skeleton and overlays strictly adhere to the merge-level of the configuration; i.e. for an unmerged config, we require that the skeleton and overlays be strictly unmerged, that is, /bin, /lib, and /sbin, and their counterparts in /usr, are actual directories.
Thus, for all three types of merge level, the skeleton and overlays must match the configured merge level.
--- support/scripts/check-merged | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-)
support/scripts/check-merged +16 -6
@@ -3,16 +3,21 @@ # Check if a given custom skeleton or overlay complies to the merged # requirements: # -# - for merged-usr: -# /bin missing, or a relative symlink to usr/bin -# /lib missing, or a relative symlink to usr/lib -# /sbin missing, or a relative symlink to usr/sbin +# - for unmerged: +# /bin missing*, or an existing directory; not a symlink +# /lib missing*, or an existing directory; not a symlink +# /sbin missing*, or an existing directory; not a symlink # /usr/bin/ missing*, or an existing directory; not a symlink # /usr/lib/ missing*, or an existing directory; not a symlink # /usr/sbin/ missing*, or an existing directory; not a symlink # # *: must be present for skeletons, can be missing for overlays # +# - for merged-usr: all of the above, except: +# /bin missing, or a relative symlink to usr/bin +# /lib missing, or a relative symlink to usr/lib +# /sbin missing, or a relative symlink to usr/sbin +# # - for merged-bin: all of the above, except: # /usr/sbin missing, or a relative symlink to bin (thus points # to /usr/bin)
@@ -119,9 +124,9 @@ test_dir() { is_success=true for root; do first=true + test_dir "${type}" "${root}" "/" "usr/bin" + test_dir "${type}" "${root}" "/" "usr/lib" if ${merged_usr}; then - test_dir "${type}" "${root}" "/" "usr/bin" - test_dir "${type}" "${root}" "/" "usr/lib" test_merged "${type}" "${root}" "/" "bin" "usr/bin" test_merged "${type}" "${root}" "/" "lib" "usr/lib" test_merged "${type}" "${root}" "/" "sbin" "usr/sbin"
@@ -130,6 +135,11 @@ for root; do else test_dir "${type}" "${root}" "/" "usr/sbin" fi + else + test_dir "${type}" "${root}" "/" "bin" + test_dir "${type}" "${root}" "/" "lib" + test_dir "${type}" "${root}" "/" "sbin" + test_dir "${type}" "${root}" "/" "usr/sbin" fi done
Signature · 6 lines
2.51.0 _______________________________________________ buildroot mailing list [email protected] https://lists.buildroot.org/mailman/listinfo/buildroot
PATCH v3 13/18 package/coreutils: no need for chroot workaround with merged-bin
In reply to Yann E. MORIN via buildroot--- package/coreutils/coreutils.mk | 2 ++ 1 file changed, 2 insertions(+)
package/coreutils/coreutils.mk +2 -0
@@ -125,6 +125,7 @@ define COREUTILS_CREATE_TEST_SYMLINK endef COREUTILS_POST_INSTALL_TARGET_HOOKS += COREUTILS_CREATE_TEST_SYMLINK +ifeq ($(BR2_ROOTFS_MERGED_BIN),) # gnu thinks chroot is in bin, debian thinks it's in sbin ifeq ($(BR2_PACKAGE_COREUTILS_INDIVIDUAL_BINARIES),y) define COREUTILS_FIX_CHROOT_LOCATION
@@ -137,6 +138,7 @@ define COREUTILS_FIX_CHROOT_LOCATION endef endif COREUTILS_POST_INSTALL_TARGET_HOOKS += COREUTILS_FIX_CHROOT_LOCATION +endif # Explicitly install ln and realpath, which we *are* insterested in. # A lot of other programs still get installed, however, but disabling
Signature · 6 lines
2.51.0 _______________________________________________ buildroot mailing list [email protected] https://lists.buildroot.org/mailman/listinfo/buildroot
PATCH v3 14/18 package/kmod: adjust paths for merged-bin
In reply to Yann E. MORIN via buildroot--- package/kmod/kmod.mk | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
package/kmod/kmod.mk +10 -2
@@ -68,16 +68,24 @@ ifeq ($(BR2_PACKAGE_KMOD_TOOLS),y) KMOD_LICENSE += , GPL-2.0+ (tools) KMOD_LICENSE_FILES += COPYING -# /sbin is really /usr/sbin with merged /usr, so adjust relative symlink +# /sbin is really /usr/sbin with merged /usr, and /usr/sbin is +# really /usr/bin with merged-bin, so adjust relative symlink ifeq ($(BR2_ROOTFS_MERGED_USR),y) +ifeq ($(BR2_ROOTFS_MERGED_BIN),y) +KMOD_BIN_PATH = kmod +KMOD_SBIN_DIR = bin +else KMOD_BIN_PATH = ../bin/kmod +KMOD_SBIN_DIR = sbin +endif else KMOD_BIN_PATH = ../usr/bin/kmod +KMOD_SBIN_DIR = sbin endif define KMOD_INSTALL_TOOLS for i in depmod insmod lsmod modinfo modprobe rmmod; do \ - ln -sf $(KMOD_BIN_PATH) $(TARGET_DIR)/sbin/$$i; \ + ln -sf $(KMOD_BIN_PATH) $(TARGET_DIR)/$(KMOD_SBIN_DIR)/$$i; \ done endef
Signature · 6 lines
2.51.0 _______________________________________________ buildroot mailing list [email protected] https://lists.buildroot.org/mailman/listinfo/buildroot
PATCH v3 15/18 package/util-linux: adjust paths for merged-bin
In reply to Yann E. MORIN via buildroot--- package/util-linux/util-linux.mk | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
package/util-linux/util-linux.mk +7 -1
@@ -75,7 +75,13 @@ endif # ${usrlib_execdir} (/usr/lib) to ${libdir} (/lib), since both paths are # the same when merged usr is in use. ifeq ($(BR2_ROOTFS_MERGED_USR),y) -UTIL_LINUX_CONF_OPTS += --bindir=/usr/bin --sbindir=/usr/sbin --libdir=/usr/lib +UTIL_LINUX_CONF_OPTS += --bindir=/usr/bin --libdir=/usr/lib +# Ditto for /usr/sbin and /usr/bin when merge sbin is in use +ifeq ($(BR2_ROOTFS_MERGED_BIN),y) +UTIL_LINUX_CONF_OPTS += --sbindir=/usr/bin +else +UTIL_LINUX_CONF_OPTS += --sbindir=/usr/sbin +endif endif ifeq ($(BR2_PACKAGE_SYSTEMD),y)
Signature · 6 lines
2.51.0 _______________________________________________ buildroot mailing list [email protected] https://lists.buildroot.org/mailman/listinfo/buildroot
PATCH v3 16/18 package/net-tools: no need for ifconfig+route workarounds with merged-bin
In reply to Yann E. MORIN via buildrootWith a merged-bin setup, there is no need to move ifconfig and route, as they would already be in the proper place.
--- package/net-tools/net-tools.mk | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
package/net-tools/net-tools.mk +8 -2
@@ -42,10 +42,16 @@ endef # ifconfig & route reside in /sbin for busybox, so ensure we don't end # up with two versions of those. -define NET_TOOLS_INSTALL_TARGET_CMDS - $(TARGET_MAKE_ENV) $(MAKE) -C $(@D) DESTDIR=$(TARGET_DIR) install +ifeq ($(BR2_ROOTFS_MERGED_BIN),) +define NET_TOOLS_INSTALL_MV_BINS mv -f $(TARGET_DIR)/bin/ifconfig $(TARGET_DIR)/sbin/ifconfig mv -f $(TARGET_DIR)/bin/route $(TARGET_DIR)/sbin/route endef +endif + +define NET_TOOLS_INSTALL_TARGET_CMDS + $(TARGET_MAKE_ENV) $(MAKE) -C $(@D) DESTDIR=$(TARGET_DIR) install + $(NET_TOOLS_INSTALL_MV_BINS) +endef $(eval $(generic-package))
Signature · 6 lines
2.51.0 _______________________________________________ buildroot mailing list [email protected] https://lists.buildroot.org/mailman/listinfo/buildroot
PATCH v3 17/18 toolchain/external: support merged-bin
In reply to Yann E. MORIN via buildrootWhen an external toolchain does not have a merged-bin, we can end up with a situation where the toolchain installs an staging/usr/sbin/ directory, overriding the sbin symlink with an actual directory. When not using PPD, this does not cause any harm.
However, with PPD, the build fails when preparing the staging (the host/) for packages when the skeleton is eventually rsynced, e.g.:
$ cat defconfig
BR2_aarch64=y
BR2_TOOLCHAIN_EXTERNAL=y
BR2_TOOLCHAIN_EXTERNAL_BOOTLIN=y
BR2_PER_PACKAGE_DIRECTORIES=y
BR2_INIT_NONE=y
BR2_ROOTFS_MERGED_USR=y
BR2_ROOTFS_MERGED_SBIN=y
# BR2_PACKAGE_BUSYBOX is not set
BR2_PACKAGE_ZLIB=y
# BR2_TARGET_ROOTFS_TAR is not set $ make zlib
[...]Quoted 1 line
Quoted 1 line
Quoted 1 line
zlib Configuring
mkdir -p [...]/per-package/zlib/host
rsync -a --hard-links --link-dest=[...]/per-package/host-skeleton/host/ [...]/per-package/host-skeleton/host/ [...]/per-package/zlib/host
rsync -a --hard-links --link-dest=[...]/per-package/libzlib/host/ [...]/per-package/libzlib/host/ [...]/per-package/zlib/host
rsync -a --hard-links --link-dest=[...]/per-package/skeleton/host/ [...]/per-package/skeleton/host/ [...]/per-package/zlib/host
could not make way for new symlink: aarch64-buildroot-linux-gnu/sysroot/usr/sbin
cannot delete non-empty directory: aarch64-buildroot-linux-gnu/sysroot/usr/sbin
rsync error: some files/attrs were not transferred (see previous errors) (code 23) at main.c(1338) [sender=3.3.0]
make[1]: *** [package/pkg-generic.mk:256: [...]/build/zlib/.stamp_configured] Error 23
make: *** [Makefile:23: _all] Error 2The root cause is that, in the skeleton, we end up with [staging]/usr/sbin as a synlink to bin, but when the external toolchain gets installed, the symlinbk is replaced by a directory. Later, when we aggregate the PPD before configuring a package, it often happens that a dependant package be rsynced before the toolchain and the skeleton, as seen above, in which case the sbin directory from the toolchain, by way of the dependency to a package, is already present when rsync wants to create a symlink as rsynced from the skeleton.
In the example above, this plays in this order:
1. skeleton gets installed, provides a symlink
2. toolchain-external-bootlin rsyncs from skeleton, gets a symlink
3. toolchain-external-bootlin gets installed, replaces symlink with a directory
4. libzlib rsyncs from skeleton, gets a symlink, then rsyncs from toolchain-e-b, gets a directory
5. zlib rsyncs from libzlib first (because alphabetical ordering), gets a directory, then rsyncs from skeleton, which rsyncs from a symlink, but the destination is a non-empty directory, so rsync fails.
It is perfectly legit that an external toolchain does not use a merged-bin setup, so we must accept that as input. We do so by treating the /usr/sbin entry specially, like we already do for a few others, of which /sbin itself for example.
Note that the merged-usr setup has no issue, because we already handle the lib*/ directories specially too.
--- toolchain/helpers.mk | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
toolchain/helpers.mk +6 -2
@@ -96,6 +96,10 @@ copy_toolchain_lib_root = \ # Note that the 'locale' directories are not copied. They are huge # (400+MB) in CodeSourcery toolchains, and they are not really useful. # +# usr/sbin may be a directory in the source toolchain, but a symlink +# in the destination sysroot, when we are using a merged-bin. Account +# for that. +# # $1: main sysroot directory of the toolchain # $2: arch specific sysroot directory of the toolchain # $3: arch specific subdirectory in the sysroot
@@ -109,13 +113,13 @@ copy_toolchain_sysroot = \ ARCH_SUBDIR="$(strip $3)"; \ ARCH_LIB_DIR="$(strip $4)" ; \ SUPPORT_LIB_DIR="$(strip $5)" ; \ - for i in etc $${ARCH_LIB_DIR} sbin usr usr/$${ARCH_LIB_DIR}; do \ + for i in etc $${ARCH_LIB_DIR} sbin usr usr/$${ARCH_LIB_DIR} usr/sbin; do \ if [ ! -d $${ARCH_SYSROOT_DIR}/$$i ] ; then \ continue ; \ fi ; \ if [ "$$i" = "usr" ]; then \ rsync -au --chmod=u=rwX,go=rX --exclude 'locale/' \ - --include '/libexec*/' --exclude '/lib*/' \ + --include '/libexec*/' --exclude '/lib*/' --exclude '/sbin' \ $${ARCH_SYSROOT_DIR}/$$i/ $(STAGING_DIR)/$$i/ ; \ else \ rsync -au --chmod=u=rwX,go=rX --exclude 'locale/' \
Signature · 6 lines
2.51.0 _______________________________________________ buildroot mailing list [email protected] https://lists.buildroot.org/mailman/listinfo/buildroot
PATCH v3 18/18 package/systemd: require merged-bin
In reply to Yann E. MORIN via buildrootSince version 256, systemd will taint the system if /usr/bin and /usr/sbin are not merged, known as merged-bin:
# systemctl --no-pager status
● buildroot
State: running
Units: 166 loaded (incl. loaded aliases)
Jobs: 0 queued
Failed: 0 units
Since: Mon 2025-07-07 19:48:05 UTC; 19s ago
systemd: 257.7
Tainted: unmerged-bin
CGroup: /
├─init.scope
[...]Although this is not yet an error, it will be in the future.
To be as ready as we can be when that happens, forcibly enable merged-bin, like we did when we initially added merged-usr (except this time we carry the select from systemd, even though it is not yet strictly required, rather than from the init entry).
Extend the runtime test to catch any tainted flag.
---
Changes v1 -> v2:
- add the runtime test
=> do not add the Acked-by Arnout gave on v1, since the runtime test was not reviewed then.
--- package/systemd/Config.in | 1 + support/testing/tests/init/test_systemd.py | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+)
package/systemd/Config.in +1 -0
@@ -25,6 +25,7 @@ menuconfig BR2_PACKAGE_SYSTEMD depends on BR2_TOOLCHAIN_GCC_AT_LEAST_8 depends on BR2_HOST_GCC_AT_LEAST_8 # host-systemd select BR2_ROOTFS_MERGED_USR + select BR2_ROOTFS_MERGED_BIN select BR2_PACKAGE_HAS_UDEV select BR2_PACKAGE_DBUS if !BR2_PACKAGE_DBUS_BROKER # runtime select BR2_PACKAGE_LIBCAP
support/testing/tests/init/test_systemd.py +19 -0
@@ -31,6 +31,25 @@ class InitSystemSystemdBase(InitSystemBase): self.start_emulator(fs) self.check_init("/lib/systemd/systemd") + # Test there is no tainted flag. + output, ret = self.emulator.run("systemctl --no-pager status") + self.assertEqual(ret, 0, f"'systemctl status' failed with exit code {ret}, with:\n{output}") + try: + # 'support-ended' tainted flag is only set based on the + # SUPPORT_END variable in /etc/os-release; as we don't set + # it in Buildroot, we can't get that flag in the runtime + # tests, even on our maintenance branches, so we don't need + # to filter it out. + tainted_flags = [ + "".join(line.split(":")[1:]).strip() + for line in output + if line.strip().startswith("Tainted: ") + ][0] + raise RuntimeError(f"Tainted flags: {tainted_flags}") + except IndexError: + # No tainted flag \o/ + pass + # Test all units are OK output, _ = self.emulator.run("systemctl --no-pager --failed --no-legend") self.assertEqual(len(output), 0)
Signature · 6 lines
2.51.0 _______________________________________________ buildroot mailing list [email protected] https://lists.buildroot.org/mailman/listinfo/buildroot
Hello All,
On 2025-09-01 11:01 +0200, Yann E. MORIN spake thusly:
Quoted 3 lines
This series introduces support for so-called merged-bin, where
/usr/sbinis merged with/usr/bin, as an extra step after merged-usr, now just requested, but in the future required, by systemd.
[--SNIP--]
Ping? Any feedback on this series?
Regards,
Yann E. MORIN.
Signature · 10 lines
.-----------------.--------------------.------------------.--------------------. | Yann E. MORIN | Real-Time Embedded | /"\ ASCII RIBBON | Erics' conspiracy: | | +33 662 376 056 | Software Designer | \ / CAMPAIGN | ___ | | +33 561 099 427 `------------.-------: X AGAINST | \e/ There is no | | http://ymorin.is-a-geek.org/ | _/*\_ | / \ HTML MAIL | v conspiracy. | '------------------------------^-------^------------------^--------------------' _______________________________________________ buildroot mailing list [email protected] https://lists.buildroot.org/mailman/listinfo/buildroot
Romain Naour via buildroot
AppliedHello Yann, All,
Le 01/09/2025 à 11:01, Yann E. MORIN via buildroot a écrit :
Quoted 23 lines
Hello All!
This series introduces support for so-called merged-bin, where
/usr/sbinis merged with/usr/bin, as an extra step after merged-usr, now just requested, but in the future required, by systemd.The series is organised in a few steps:
1. patches 1-3 are cleanups in the
Kconfigmenu, related to the merged-usr prompt, to the defaults for PATH, and to the rationale for selecting merged-usr with systemd; those can be applied without considering the rest of the series;2. then patches 4-9 prepare
support/scripts/check-merged-usr.shto check for more than merged-usr: a good cleanup, and better check the merged state; those patch can also be applied without considering the rest of the series;3. with patches 9-12, support for merged-bin is added, and the merge level of skeleton and overlays properly enforced to match the configured merge setup; those require the two set of patches above to be applied first;
Quoted 5 lines
4. then, patches 13-17 introduce workarounds for a few packages to properly support merged-bin. For ease of review, those are separate patches, but that means the series _may_ break if the merged-bin support is applied but not these per-package workarounds; these require that all patches above be applied first, of course;
Theses workaround already uses BR2_ROOTFS_MERGED_BIN option, so we can't easily re-order the series before adding merged-bin commit.
The series breaks only with the new BR2_ROOTFS_MERGED_BIN option already enabled, so existing defconfig should works fine by keeping merged-bin disabled.
Quoted 4 lines
5. the last patch makes merged-bin mandatory for systemd and extend the systemd runtime test to catch future tainted flag; again, that requires that everything before is applied, too.
Can you send a followup patch to update the documentation since we have some explanation for BR2_ROOTFS_MERGED_USR:
https://gitlab.com/buildroot.org/buildroot/-/commit/dc7c6487cff0a418a6605060670571ea9111050a
Quoted 4 lines
The series was tested with a large set of packages and a large set of toolchains, and although it is a critical change, it is still pretty well confined to just a few spots.
Thanks Yann for the initial testing!
Applied to master, thanks.
Best regards,
Romain
Quoted 61 lines
Changes v2 -> v3;
- add fix for merged-bin to net-toolsChanges v1 -> v2:
- add Arnout's Acked-by tag where appropriate
- totally rewrite the test for merged status
- reject unexpectedly merged skeletons or overlays
- add runtime test to catch systemd tainted flags
- typosRegards,
Yann E. MORIN.----------------------------------------------------------------
Yann E. MORIN (18):
system: reword merged-usr prompt
system: drop superfluous negative condition for default PATH package/systemd: select merged-usr from package, not init support/scripts: comonalise checking merged status support/scripts: prepare for a more complex check for merged directories support/scripts: also exit in error on improperly merged-usr support/scripts: move merged-usr errors message intocheck-merged-usr.shsupport/scripts: fix and restrict conditions to accept merged dirs support/scripts: renamecheck-merged-usr.sh
support/scripts; teach check-merged what to check
system: add support for merged/usr/sbin(aka merged-bin) support/scripts: reject skeletons or overlays that are unexpectedly merged package/coreutils: no need for chroot workaround with merged-bin package/kmod: adjust paths for merged-bin
package/util-linux: adjust paths for merged-bin package/net-tools: no need for ifconfig+route workarounds with merged-bin toolchain/external: support merged-bin
package/systemd: require merged-binMakefile | 19 ++-- package/coreutils/coreutils.mk | 2 + package/kmod/kmod.mk | 12 ++- package/net-tools/net-tools.mk | 10 +- package/skeleton-custom/skeleton-custom.mk | 25 ++--- package/systemd/Config.in | 2 + package/util-linux/util-linux.mk | 8 +- support/scripts/check-merged | 146 +++++++++++++++++++++++++++++ support/scripts/check-merged-usr.sh | 39 -------- support/testing/tests/init/test_systemd.py | 19 ++++ system/Config.in | 20 ++-- system/skeleton/usr/sbin/.empty | 0 system/system.mk | 14 ++- toolchain/helpers.mk | 8 +- 14 files changed, 240 insertions(+), 84 deletions(-) create mode 100755 support/scripts/check-merged delete mode 100755 support/scripts/check-merged-usr.sh delete mode 100644 system/skeleton/usr/sbin/.empty--
.-----------------.--------------------.------------------.--------------------.| Yann E. MORIN | Real-Time Embedded | /"\ ASCII RIBBON | Erics' conspiracy: | | +33 662 376 056 | Software Designer | \ / CAMPAIGN | ___ | | +33 561 099 427 `------------.-------: X AGAINST | \e/ There is no | | http://ymorin.is-a-geek.org/ | _/*\_ | / \ HTML MAIL | v conspiracy. |
Quoted 5 lines
'------------------------------^-------^------------------^--------------------'
_______________________________________________
buildroot mailing list
[email protected]
https://lists.buildroot.org/mailman/listinfo/buildroot
_______________________________________________
buildroot mailing list
[email protected]
https://lists.buildroot.org/mailman/listinfo/buildroot