osi-tools/osi-mount

123 lines
3.1 KiB
Plaintext
Raw Normal View History

#!/usr/bin/env bash
# 2018 Luke Shumaker
declare -r NAME=osi-mount
declare -r VERSION=20180812
set -euE
source "${BASH_SOURCE[0]%/*}/lib/osi.sh"
main() {
needs_root
local arg_mode=outside
local arg_user=
local args
if ! args="$(getopt -n "${0##*/}" -o hV -l inside:,user,root,help,version -- "$@")"; then
arg_mode=error
else
eval "args=($args)"
set -- "${args[@]}"
while true; do
case "$1" in
--inside) shift; arg_mode=$1; shift;;
--user|--root)
if [[ -n $arg_user ]]; then
error 0 "Multiple --user/--root flags given"
arg_mode=error
fi
arg_user=${1#--}
shift
;;
-V|--version) shift; arg_mode=version;;
-h|--help) shift; arg_mode=usage;;
--) shift; break;;
*) error 1 'Internal error. The programmer writing this tool screwed up.';;
esac
done
case "$arg_mode" in
outside)
case "$#" in
0) error 0 "Must specify an image, mountpoint, and a command"; arg_mode=error;;
1) error 0 "Must specify a mountpoint and a command"; arg_mode=error;;
2) error 0 "Must specify a command"; arg_mode=error;;
esac
if [[ -z $arg_user ]]; then
error 0 "Must specify either --root or --user"
arg_mode=error
fi
;;
esac
fi
arg_device=$1
arg_mountpoint=$2
arg_cmd=("${@:3}")
case "$arg_mode" in
error) print "Try '%q --help' for more information" "${0##*/}" >&2; return 2;;
version)
print "%s (notsystemd) %s" "$NAME" "$VERSION"
return 0
;;
usage)
print 'Usage: %s [OPTIONS] --<user|root> FILENAME.img COMMAND...' "${0##*/}"
print 'Operating System Image: Mount'
echo
print 'OPTIONS:'
# --inside is internal-only; undocumented
print ' --user mount the image RO, run COMMAND as SUDO_USER'
print ' --root mount the image RW, run COMMAND as root, protect the rest of the system'
echo
print ' -h, --help display this help'
print ' -V, --version output version information'
return 0
;;
outside)
if out="$(losetup --associated "$arg_device")" && [[ -n $out ]]; then
error 0 "Seems to already be mounted somewhere: %s" "$arg_device"
printf '%s\n' "$out"
exit 1
fi
unshare --mount "${BASH_SOURCE[0]}" --inside="$arg_user" "${args[@]}"
2018-08-14 15:37:29 +00:00
if out="$(losetup --associated "$arg_device")" && [[ -n $out ]]; then
error 0 "umount'ed, but file is still associated with a loop device: %s" "$arg_device"
printf '%s\n' "$out"
exit 1
2018-08-13 04:47:18 +00:00
fi
;;
2018-08-14 15:37:29 +00:00
user|root)
needs_sudo
mount --make-rslave /
2018-08-14 15:37:29 +00:00
case "$arg_mode" in
user)
mount_opt=ro
losetup_flags=(--read-only)
;;
root)
mount_opt=rw
losetup_flags=()
# TODO: make the rest of the system RO
;;
esac
2018-08-13 04:47:18 +00:00
cmd=(mount --no-mtab -o "${mount_opt},discard" -- "$arg_device" "$arg_mountpoint")
r=0
out=$("${cmd[@]}" 2>&1) || r=$?
if (( r != 0)); then
error $r '%s: %s' "${cmd[*]@Q}" "$out"
2018-08-13 04:47:18 +00:00
fi
trap "umount --no-mtab -- ${arg_mountpoint@Q}" EXIT
2018-08-13 04:47:18 +00:00
case "$arg_mode" in
user) sudo -u "#${SUDO_UID}" -- "${arg_cmd[@]}";;
root) command -- "${arg_cmd[@]}";;
esac
;;
*) error 1 'Internal error. The programmer writing this tool screwed up.';;
esac
}
main "$@"