blob: 14686c08f481459ebcd5c1fbb85d4fad982dd0cb [file] [edit]
#!/bin/bash
#
# ==============================================================================
# Ferrochrome Rootfs Chroot Utility
# ==============================================================================
#
# This utility mounts a root filesystem image and enters a chroot environment
# with optional extra directory bindings and command execution support.
#
# Key Features:
# 1. Mounts the root partition to a temporary workspace.
# 2. Binds essential system directories (/dev, /proc, /sys).
# 3. Supports custom directory bindings via the -b option.
# 4. Automatically handles DNS configuration via /etc/resolv.conf.
# 5. Ensures clean unmounting on exit or error.
#
# Usage: sudo ./chroot_rootfs.sh [OPTIONS] ${rootfs_path}
# ==============================================================================
set -eo pipefail
### --- Configuration & State --- ###
CHROOT_MOUNT_ARGS=()
CHROOT_WORKSPACE=$(mktemp -d)
CHROOT_COMMAND=""
ROOTFS_IMAGE_PATH=""
### --- Utilities --- ###
# Log informational messages in green
log() { echo -e "\033[1;32m[INFO]\033[0m $1"; }
# Log error messages in red and exit
error() { echo -e "\033[1;31m[ERROR]\033[0m $1" >&2; exit 1; }
check_sudo() {
if [ "$EUID" -ne 0 ]; then
error "This script must be run as root (sudo)."
fi
}
show_help() {
echo "Usage: sudo $0 [OPTION] ${rootfs_path}"
echo "Mount rootfs and chroot into it."
echo ""
echo "Options:"
echo "-b SRC:DST Bind extra directory (can be repeated)"
echo "-c COMMAND Command to invoke via /bin/bash -c"
echo "-h Print usage and this help message"
}
### --- Functions --- ###
# Parse command line options
parse_options() {
while getopts "b:c:h" option; do
case ${option} in
b) CHROOT_MOUNT_ARGS+=("${OPTARG}") ;;
c) CHROOT_COMMAND="${OPTARG}" ;;
h) show_help ; exit ;;
*) error "Invalid option: $OPTARG" ;;
esac
done
shift $((OPTIND - 1))
if [[ "$#" -ne 1 ]]; then
show_help
error "Rootfs path is required."
fi
ROOTFS_IMAGE_PATH="${1}"
}
# Mount the rootfs and setup the chroot environment
mount_environment() {
log "Mounting rootfs to ${CHROOT_WORKSPACE}..."
mount "${ROOTFS_IMAGE_PATH}" "${CHROOT_WORKSPACE}"
# Process extra directory bindings
for arg in "${CHROOT_MOUNT_ARGS[@]}"; do
local src=${arg%:*}
local dst=${arg#*:}
[[ -z "${src}" || -z "${dst}" ]] && error "Invalid mount binding: ${arg}"
mkdir -p "${CHROOT_WORKSPACE}/${dst}"
mount --bind "${src}" "${CHROOT_WORKSPACE}/${dst}"
done
# Bind essential system virtual filesystems
mount --rbind /dev "${CHROOT_WORKSPACE}/dev"
mount --rbind /proc "${CHROOT_WORKSPACE}/proc"
mount --rbind /sys "${CHROOT_WORKSPACE}/sys"
# Configure DNS inside chroot via bind mount (temporary, not baked into image)
local target_resolv="${CHROOT_WORKSPACE}/etc/resolv.conf"
if [[ -e "${target_resolv}" || -L "${target_resolv}" ]]; then
mv "${target_resolv}" "${target_resolv}.bak"
fi
touch "${target_resolv}"
mount --bind /etc/resolv.conf "${target_resolv}"
}
# Enter the chroot environment and execute command if provided
enter_chroot() {
if [[ -n "${CHROOT_COMMAND}" ]]; then
log "Executing command inside chroot: ${CHROOT_COMMAND}"
chroot "${CHROOT_WORKSPACE}" /bin/bash -c "${CHROOT_COMMAND}"
else
log "Entering interactive chroot session..."
chroot "${CHROOT_WORKSPACE}"
fi
}
# Perform cleanup: unmount all directories and restore configurations
cleanup() {
log "Cleaning up chroot environment..."
# Restore original DNS configuration
local target_resolv="${CHROOT_WORKSPACE}/etc/resolv.conf"
if mountpoint -q "${target_resolv}"; then
umount "${target_resolv}"
fi
if [[ -e "${target_resolv}.bak" || -L "${target_resolv}.bak" ]]; then
mv -f "${target_resolv}.bak" "${target_resolv}"
else
rm -f "${target_resolv}"
fi
# Unmount extra bindings in reverse order
for (( i=${#CHROOT_MOUNT_ARGS[@]}-1; i>=0; i-- )); do
local dst=${CHROOT_MOUNT_ARGS[$i]#*:}
umount "${CHROOT_WORKSPACE}/${dst}" || true
done
# Unmount virtual and root filesystems
umount -R "${CHROOT_WORKSPACE}" || true
# Remove temporary workspace directory
rm -rf "${CHROOT_WORKSPACE}"
}
### --- Main Execution --- ###
check_sudo
parse_options "$@"
# Setup cleanup trap to ensure unmounting happens on any exit
trap cleanup EXIT
mount_environment
enter_chroot