#!/bin/sh usage() { cat >&2 < [command] [args ...] options: --resize --btrfs-options (default: compress) --no-chroot EOF exit $1 } error() { printf '%s: Error: %s\n' "$0" "$*" >&2 exit 1 } warning() { printf '%s: Warning: %s\n' "$0" "$*" >&2 } have_root() { [ "$(id -u)" = 0 ] } main() { have_root || error "you are not root" iso_file=$1 shift iso_file_clone=${iso_file}.clone.tmp mountpoint=${iso_file%.iso}.mnt.tmp [ -f "$iso_file" ] || error "not a file: $iso_file" [ ! -f "$iso_file_clone" ] || error "refusing to clobber existing file: $iso_file_clone" [ -d "$mountpoint" ] || mkdir "$mountpoint" || error "could not create directory $mountpoint" ! mountpoint -q "$mountpoint" || error "directory is already a mountpoint: $mountpoint" cp --reflink=always "$iso_file" "$iso_file_clone" || error "cp failed" trap 'rm -f "$iso_file_clone"' EXIT if [ "$RESIZE" ]; then truncate --size="$RESIZE" "$iso_file_clone" || error "failed to resize image with truncate" fi btrfstune -f -S 0 "$iso_file_clone" 2>/dev/null || error "btrfstune failed" mount_options=rw,loop${BTRFS_OPTIONS:+,$BTRFS_OPTIONS} mount -o "$mount_options" "$iso_file_clone" "$mountpoint" || error "failed to mount $iso_file" if [ "$RESIZE" ]; then btrfs filesystem resize max "$mountpoint" || error "btrfs filesystem resize" fi if [ "$CHROOT" ]; then chroot "$mountpoint" "$@" else "$@" "$mountpoint" fi result=$? umount "$mountpoint" || warning "umount $mountpoint failed! You had better do something about it" rmdir "$mountpoint" if [ "$result" = 0 ]; then btrfstune -S 1 "$iso_file_clone" || error "btrfstune failed. The original ISO is unmodified." mv "$iso_file_clone" "$iso_file" else warning "The command executed within the chroot failed. The original ISO is unmodified." rm "$iso_file_clone" fi } [ $# = 0 ] && usage 0 CHROOT=y eval set -- "$(getopt -o '' --long shrink,no-chroot,resize:,fork:,btrfs-options: -n "$0" -- "$@")" || error 'getopt error' while [ $# -gt 0 ]; do case "$1" in --) shift; break;; --resize) RESIZE=$2; shift 2;; --fork) FORK=$2; shift 2;; --btrfs-options) BTRFS_OPTIONS=$2; shift 2;; --no-chroot) CHROOT=; shift;; --shrink) SHRINK=y; shift;; *) error "unrecognized option: $1" esac done : ${BTRFS_OPTIONS:=compress} [ "$FORK" ] && error "unimplemented option: --fork" main "$@"