From 06c57b2ede691d44b9cd98400217277c812d3e97 Mon Sep 17 00:00:00 2001 From: Paul Menzel Date: Wed, 21 Oct 2026 07:10:34 +0200 Subject: [PATCH] beesh: Add --fakeroot to fake root only for install and packaging MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit bee-mxqsub runs all of beesh under fakeroot, so every process of the configure and build steps inherits `LD_PRELOAD=libfakeroot.so`, and their stat, chmod and chown calls are all served by the one faked daemon. Large packages pay for this most: the Firefox build on a full 256-processor MXQ node was killed while packaging: 11:18.27 toolkit/library/build/libxul.so 13:21.72 ipc/app/plugin-container 14:38.60 E make[2]: *** Waiting for unfinished jobs.... /home/pmenzel/bee-files/scripts/bee-mxqsub: line 1: 222979 CPU time limit exceeded (core dumped) ${sandbox[@]+"${sandbox[@]}"} fakeroot beesh "${beesh_args[@]}" "${beefile}" Without the preload, the same `mach build` took 11:34 instead of 17:37. With the new option `--fakeroot`, beesh starts faked right before the install step and stops it after packaging, so only install, crosscheck and packaging see a fake root. bee-files had to work around this one by one so far, like firefox.be0 with `env -u LD_PRELOAD`. Starting faked late also keeps its database clean. If the build deletes files outside of fakeroot, faked keeps their ownership records, and a new file reusing the inode inherits the stale owner. In a test, 8 of 300 files copied with `cp -a` or `mv` into the image had the owner recorded for deleted files. With faked started at the install step, there are no such records. beesh does not reimplement fakeroot’s setup: it runs `fakeroot` as a coprocess, which reports FAKEROOTKEY, LD_PRELOAD and LD_LIBRARY_PATH, and keeps faked alive until its standard input is closed, by bee_fakeroot_stop() or by beesh exiting. Under fakeroot already, beesh says so and keeps using the existing faked daemon. The new help lines are indented with tabs like the rest of the `<<-EOF` here-document, which strips only tabs, although `git diff --check` warns about them: src/beesh.sh.in:114: tab in indent. Tested with a package whose Makefile installs with `-o root`, mode 4755 and `-o 1234`: the package built with `beesh --fakeroot` has the same owners and modes as one built with `fakeroot beesh`, while the build step ran with the real UID. A failing install leaves no faked behind. Assisted-by: Claude Opus 5.5 (Claude Code) --- DEPENDENCIES | 4 +++ src/beesh.sh.in | 88 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/DEPENDENCIES b/DEPENDENCIES index 08b62ec..f817311 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -27,4 +27,8 @@ gzip, bzip2, xz, ..: man: to read our minimalistic manpages 8) +fakeroot: + only for beesh --fakeroot, which runs the install and packaging + steps under fakeroot + to be continued - please let us know if you find additional dependencies. diff --git a/src/beesh.sh.in b/src/beesh.sh.in index 4ffdcdd..323aa85 100644 --- a/src/beesh.sh.in +++ b/src/beesh.sh.in @@ -111,6 +111,8 @@ function show_help() { -h, --help display this help --no-archive-build do not archive the build directory --check run mee_check, mee_check_pre and mee_check_post + --fakeroot run only the install and packaging steps + under fakeroot instead of all of beesh EOF } @@ -705,6 +707,74 @@ function bee_archivebuild() { --transform="s,^${BEE_BEEDIR},${PKGALLPKG}/files," } +#### bee_fakeroot_start() ##################################################### + +# Under fakeroot, the stat, chmod and chown calls of every process go through +# the one faked daemon, which slows down file-heavy builds a lot. With +# --fakeroot, only the steps that need the files in ${D} to look owned by root +# run under it: install, crosscheck and packaging. +# +# Starting faked only now also keeps its database clean: files deleted by the +# build outside of fakeroot would leave stale ownership records behind, which +# a new file reusing the inode inherits. +# +# fakeroot keeps faked running only as long as its command, so the command +# reports the environment to use and then waits until its standard input is +# closed, by bee_fakeroot_stop() or by beesh exiting. +function bee_fakeroot_start() { + local key preload library_path v + + [ "${OPT_FAKEROOT}" = "yes" ] || return 0 + + if [ -n "${FAKEROOTKEY}" ] ; then + print_info "already running under fakeroot (FAKEROOTKEY=${FAKEROOTKEY})" + return 0 + fi + + bee_fakeroot_saved_env=() + for v in LD_PRELOAD LD_LIBRARY_PATH ; do + if [ -n "${!v+set}" ] ; then + bee_fakeroot_saved_env+=( "${v}=${!v}" ) + fi + done + + coproc BEE_FAKEROOT { + fakeroot -- sh -c 'printf "%s\n" "${FAKEROOTKEY}" "${LD_PRELOAD}" "${LD_LIBRARY_PATH}"; exec cat > /dev/null' + } + bee_fakeroot_pid=${BEE_FAKEROOT_PID} + + if ! { read -r key && read -r preload && read -r library_path ; } <&"${BEE_FAKEROOT[0]}" \ + || [ -z "${key}" ] ; then + print_error "ERROR: cannot start fakeroot" + exit 1 + fi + + print_info "starting fakeroot (FAKEROOTKEY=${key})" + + export FAKEROOTKEY=${key} + export LD_PRELOAD=${preload} + export LD_LIBRARY_PATH=${library_path} +} + +#### bee_fakeroot_stop() ###################################################### + +function bee_fakeroot_stop() { + local e + + [ -n "${bee_fakeroot_pid}" ] || return 0 + + print_info "stopping fakeroot" + + unset FAKEROOTKEY LD_PRELOAD LD_LIBRARY_PATH + for e in "${bee_fakeroot_saved_env[@]}" ; do + export "${e}" + done + + exec {BEE_FAKEROOT[1]}>&- + wait "${bee_fakeroot_pid}" + unset bee_fakeroot_pid +} + function load_buildmagic() { local oIFS=${IFS} local IFS=":${IFS}" @@ -870,6 +940,7 @@ OPTIONS=$("${BEE_BINDIR}/beegetopt" --name beesh \ --option no-archive-build \ --option ignore-issue \ --option check \ + --option fakeroot \ -- "$@") if [ $? != 0 ] ; then @@ -884,6 +955,7 @@ eval set -- "${OPTIONS}" : ${OPT_CHECK:="no"} : ${OPT_ARCHIVE_BUILD:="yes"} : ${OPT_IGNORE_ISSUE:="no"} +: ${OPT_FAKEROOT:="no"} while true ; do case "$1" in @@ -925,6 +997,10 @@ while true ; do OPT_CHECK="yes" shift ;; + --fakeroot) + OPT_FAKEROOT="yes" + shift + ;; --debug) DEBUG=$2 shift 2 @@ -940,6 +1016,14 @@ while true ; do esac done +# Find out now, not after a build of hours, that the install step cannot run. +if [ "${OPT_FAKEROOT}" = "yes" -a -z "${FAKEROOTKEY}" ] ; then + if ! fakeroot -- true ; then + print_error "ERROR: --fakeroot needs a working fakeroot" + exit 1 + fi +fi + config_init echo -e "${COLOR_CYAN}BEE v${BEE_VERSION} 2009-2016" @@ -1093,6 +1177,8 @@ if [ "${OPT_CHECK}" != "no" ] ; then bee_run check fi +bee_fakeroot_start + bee_run install print_info "changing to image directory: ${D}" @@ -1102,6 +1188,8 @@ bee_crosscheck bee_pkg_pack +bee_fakeroot_stop + function bee_check_conflicts() { "${BEE_LIBEXECDIR}/bee/bee-cache-inventory" CONTENT \ --prepend "${PKGALLPKG} " \