From 78cd054d59df0e4b9f44c4a2205aa32885ecca65 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Sat, 10 Jan 2026 17:50:28 +0200 Subject: [PATCH] BuildSystem: Write my own disk image perm updater If user's bash does not have bultin stat, updating image perms was terribly slow. This patch adds a simple c program that does the job without exec overhead --- .gitignore | 1 + script/build.sh | 8 +++++ script/config.sh | 2 ++ script/image.sh | 51 ++++++++++---------------------- tools/update-image-perms.c | 60 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 87 insertions(+), 35 deletions(-) create mode 100644 tools/update-image-perms.c diff --git a/.gitignore b/.gitignore index 6f2b0700..339da63f 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ build/ base/ script/fakeroot-context +tools/update-image-perms diff --git a/script/build.sh b/script/build.sh index fc2ed403..016e5ab8 100755 --- a/script/build.sh +++ b/script/build.sh @@ -42,9 +42,17 @@ build_toolchain () { $BANAN_TOOLCHAIN_DIR/build.sh } +build_tools() { + perm_tool="$BANAN_TOOLS_DIR/update-image-perms" + if [ ! -f "$perm_tool" ] || [ "$perm_tool" -ot "$perm_tool.c" ]; then + gcc -O2 -Wall -Wextra -Werror -o "$perm_tool" "$perm_tool.c" || exit 1 + fi +} + create_image () { build_target all build_target install + build_tools $BANAN_SCRIPT_DIR/image.sh "$1" } diff --git a/script/config.sh b/script/config.sh index fb8dda33..075c168c 100644 --- a/script/config.sh +++ b/script/config.sh @@ -19,6 +19,8 @@ export BANAN_BUILD_DIR="$BANAN_ROOT_DIR/build" export BANAN_PORT_DIR="$BANAN_ROOT_DIR/ports" +export BANAN_TOOLS_DIR="$BANAN_ROOT_DIR/tools" + export BANAN_SYSROOT="$BANAN_BUILD_DIR/sysroot" export BANAN_FAKEROOT="$BANAN_BUILD_DIR/fakeroot-context" diff --git a/script/image.sh b/script/image.sh index 8bf8c4b4..c1443f39 100755 --- a/script/image.sh +++ b/script/image.sh @@ -20,57 +20,38 @@ if [ -z $BANAN_BUILD_DIR ]; then exit 1 fi -if [ "$1" == "full" ] || [ ! -f $BANAN_DISK_IMAGE_PATH ]; then - $BANAN_SCRIPT_DIR/image-create.sh || exit 1 +if [ "$1" == "full" ] || [ ! -f "$BANAN_DISK_IMAGE_PATH" ]; then + "$BANAN_SCRIPT_DIR/image-create.sh" || exit 1 fi set -u MOUNT_DIR="$BANAN_BUILD_DIR/mount" -mkdir -p $MOUNT_DIR +mkdir -p "$MOUNT_DIR" -LOOP_DEV="$(sudo losetup --show -Pf $BANAN_DISK_IMAGE_PATH || exit 1)" +LOOP_DEV="$(sudo losetup --show -Pf "$BANAN_DISK_IMAGE_PATH" || exit 1)" ROOT_PARTITION="${LOOP_DEV}p2" -if [ ! -b $ROOT_PARTITION ]; then +if [ ! -b "$ROOT_PARTITION" ]; then echo "Failed to probe partitions for banan disk image." >&2 - sudo losetup -d $LOOP_DEV + sudo losetup -d "$LOOP_DEV" exit 1 fi -if sudo mount $ROOT_PARTITION $MOUNT_DIR; then +if sudo mount "$ROOT_PARTITION" "$MOUNT_DIR"; then if (($BANAN_INITRD)); then - fakeroot -i $BANAN_FAKEROOT tar -C $BANAN_SYSROOT -cf $BANAN_SYSROOT.initrd . + fakeroot -i "$BANAN_FAKEROOT" tar -C "$BANAN_SYSROOT" -cf "$BANAN_SYSROOT.initrd" . - sudo mkdir -p $MOUNT_DIR/boot - sudo cp $BANAN_BUILD_DIR/kernel/banan-os.kernel $MOUNT_DIR/boot/banan-os.kernel - sudo mv $BANAN_SYSROOT.initrd $MOUNT_DIR/boot/banan-os.initrd + sudo mkdir -p "$MOUNT_DIR/boot" + sudo cp "$BANAN_BUILD_DIR/kernel/banan-os.kernel" "$MOUNT_DIR/boot/banan-os.kernel" + sudo mv "$BANAN_SYSROOT.initrd" "$MOUNT_DIR/boot/banan-os.initrd" else - sudo rsync -rulHpt $BANAN_SYSROOT/ $MOUNT_DIR + sudo rsync -rulHpt "$BANAN_SYSROOT/" "$MOUNT_DIR" - fakeroot -i $BANAN_FAKEROOT find $BANAN_SYSROOT -printf './%P|%U|%G|%04m\n' >$BANAN_BUILD_DIR/sysroot-perms.txt - sudo bash -c " - if enable stat &>/dev/null; then - while IFS='|' read -r path uid gid mode; do - full=\"$MOUNT_DIR/\$path\" - stat \"\$full\" - if [[ \${STAT[uid]} != \$uid ]] || [[ \${STAT[gid]} != \$gid ]] || [[ \${STAT[perms]} != \$mode ]]; then - chown -h \"\$uid:\$gid\" \"\$full\" - test ! -h \"\$full\" && chmod \"\$mode\" \"\$full\" - fi - done <$BANAN_BUILD_DIR/sysroot-perms.txt - else - while IFS='|' read -r path uid gid mode; do - full=\"$MOUNT_DIR/\$path\" - if [[ \$(stat -c '%u %g %a' \"\$full\") != \"\$uid \$gid \$mode\" ]]; then - chown -h \"\$uid:\$gid\" \"\$full\" - test ! -h \"\$full\" && chmod \"\$mode\" \"\$full\" - fi - done <$BANAN_BUILD_DIR/sysroot-perms.txt - fi - " + fakeroot -i "$BANAN_FAKEROOT" find "$BANAN_SYSROOT" -printf '%P|%U|%G|%04m\n' >"$BANAN_BUILD_DIR/sysroot-perms.txt" + sudo "$BANAN_TOOLS_DIR/update-image-perms" "$MOUNT_DIR" "$BANAN_BUILD_DIR/sysroot-perms.txt" fi - sudo umount $MOUNT_DIR + sudo umount "$MOUNT_DIR" fi -sudo losetup -d $LOOP_DEV +sudo losetup -d "$LOOP_DEV" diff --git a/tools/update-image-perms.c b/tools/update-image-perms.c new file mode 100644 index 00000000..94e9d705 --- /dev/null +++ b/tools/update-image-perms.c @@ -0,0 +1,60 @@ +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char** argv) +{ + if (argc != 3) + { + fprintf(stderr, "usage: %s MOUNT_POINT PERMS_FILE\n", argv[0]); + return 1; + } + + int mount_fd = open(argv[1], O_RDONLY | O_DIRECTORY); + if (mount_fd == -1) + { + fprintf(stderr, "could not open %s: %s\n", argv[1], strerror(errno)); + return 1; + } + + FILE* perm_fp = fopen(argv[2], "r"); + if (perm_fp == NULL) + { + fprintf(stderr, "could not open %s: %s\n", argv[2], strerror(errno)); + return 1; + } + + char buffer[1024]; + while (fgets(buffer, sizeof(buffer), perm_fp)) + { + char path[PATH_MAX]; + uid_t uid; + gid_t gid; + mode_t mode; + + if (sscanf(buffer, "%[^|\n]|%d|%d|%o\n", path, &uid, &gid, &mode) != 4) + continue; + + struct stat st; + if (fstatat(mount_fd, path, &st, AT_SYMLINK_NOFOLLOW) != 0) + continue; + + if (st.st_uid != uid || st.st_gid != gid) + if (fchownat(mount_fd, path, uid, gid, AT_SYMLINK_NOFOLLOW) != 0) + fprintf(stderr, "fchownat: %s: %s\n", path, strerror(errno)); + + const mode_t mode_mask = S_ISUID | S_ISGID | S_ISVTX | 0777; + if (mode != (st.st_mode & mode_mask)) + if (fchmodat(mount_fd, path, mode, AT_SYMLINK_NOFOLLOW) != 0) + fprintf(stderr, "fchmodat: %s: %s\n", path, strerror(errno)); + } + + fclose(perm_fp); + close(mount_fd); + + return 0; +}