#!/bin/sh # Copyright (C) 2023 Umorpha Systems # SPDX-License-Identifier: AGPL-3.0-or-later # This script is intended to work both in an initramfs and as a # developer-friendly tool on a real OS. Therefore, it has very few # dependencies and must be tolerant of different implementations: # # - sh (bash or busybox) # - getopt (busybox or util-linux) # - mkdir (busybox or coreutils) # - mount (util-linux) set -eu usage() { echo "Usage: $0 OPTIONS" echo "Mount devices using the Umorpha overlay-partition scheme." echo echo "OPTIONS:" echo " -h, --help Show this help text" echo " --root SPEC (required) The read-only root device ant its mount arguments" echo " --overlay SPEC (required) The writable overlay device ant its mount arguments" echo " --boot SPEC (optional) The device to mount at /boot" echo " --basedir DIR (required) Scratch directory to mount the root device and the overlay device" echo " --final-mountpoint DIR (optional) Where to mount the overlayfs (default: \${basedir}/mnt" echo echo "A SPEC is of the form" echo " DEVICE[:[FSTYPE][:OPTS]]" echo "If FSTYPE value isn't present, or is empty, then \`auto\` is used." } main() { mode=run if O=$(getopt -n "${0##*/}" -l help,root:,overlay:,boot:,basedir:,final-mountpoint: -o h -- "$@"); then eval "set -- $O" while true; do case "$1" in --help|-h) usage; exit 0;; --root) root_all=$2; shift 2;; --overlay) overlay_all=$2; shift 2;; --boot) boot_all=$2; shift 2;; --basedir) basedir=$2; shift 2;; --final-mountpoint) union_mnt=$2; shift 2;; --) shift; break;; esac done if [[ "$#" -gt 0 ]]; then echo >&2 "${0##*/}: unexpected positional arguments: $*" mode=error fi if [[ -z "${root_all:-}" ]]; then echo >&2 "${0##*/}: missing required --root flag" mode=error fi if [[ -z "${overlay_all:-}" ]]; then echo >&2 "${0##*/}: missing required --overlay flag" mode=error fi if [[ -z "${basedir:-}" ]]; then echo >&2 "${0##*/}: missing required --basedir flag" mode=error fi else mode=error fi if [[ $mode == error ]]; then echo "Try '${0##*/} --help' for more information." exit 2 fi IFS=: read -r root_dev root_typ root_opt < <(echo "$root_all") root_mnt=$basedir/root IFS=: read -r overlay_dev overlay_typ overlay_opt < <(echo "$overlay_all") overlay_mnt=$basedir/overlay union_dev=umorpha-rootfs union_typ=overlay # BusyBox ash supports weird Bash-isms like "<(process # substitution)" and the special "[[" syntax, but supporting # "+=" to append to a variable is too much bloat!?? union_opt='' union_opt="${union_opt:+${union_opt},}lowerdir=${root_mnt}" union_opt="${union_opt:+${union_opt},}upperdir=${overlay_mnt}/upperdir" union_opt="${union_opt:+${union_opt},}workdir=${overlay_mnt}/workdir" # > Offline changes to the lower tree are only allowed if the # > "metadata only copy up", "inode index", "xino" and # > "redirect_dir" features have not been used. # # -- https://www.kernel.org/doc/html/v6.6/filesystems/overlayfs.html#changes-to-underlying-filesystems union_opt="${union_opt:+${union_opt},}metacopy=off" union_opt="${union_opt:+${union_opt},}index=off" union_opt="${union_opt:+${union_opt},}xino=off" union_opt="${union_opt:+${union_opt},}redirect_dir=off" union_mnt=${union_mnt:-${basedir:-}/mnt} if [[ -n "${boot_all:-}" ]]; then IFS=: read -r boot_dev boot_typ boot_opt < <(echo "$boot_all") boot_mnt=$union_mnt/boot fi set -x mount --mkdir -t "${root_typ:-auto}" -o "$root_opt" "$root_dev" "$root_mnt" mount --mkdir -t "${overlay_typ:-auto}" -o "$overlay_opt" "$overlay_dev" "$overlay_mnt" mkdir -p -- "$overlay_mnt/upperdir" "$overlay_mnt/workdir" mount --mkdir -t "${union_typ:-auto}" -o "$union_opt" "$union_dev" "$union_mnt" if [[ -n "${boot_all:-}" ]]; then mount --mkdir -t "${boot_typ:-auto}" -o "$boot_opt" "$boot_dev" "$boot_mnt" fi } main "$@"