125 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
			
		
		
	
	
			125 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
#!/usr/bin/env bash
 | 
						|
# 2018 Luke Shumaker
 | 
						|
declare -r NAME=osi-mount
 | 
						|
declare -r VERSION=20180812
 | 
						|
 | 
						|
set -euE
 | 
						|
source ./lib/osi.sh
 | 
						|
 | 
						|
main() {
 | 
						|
	needs_root
 | 
						|
 | 
						|
	local arg_orig=("$@")
 | 
						|
	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 "set -- $args"
 | 
						|
		while true; do
 | 
						|
			case "$1" in
 | 
						|
				--inside) shift; arg_mode=inside;;
 | 
						|
				--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
 | 
						|
		case "$arg_mode" in
 | 
						|
			outside|inside)
 | 
						|
				arg_device=$1
 | 
						|
				arg_mountpoint=$2
 | 
						|
				arg_cmd=("${@:3}")
 | 
						|
				;;
 | 
						|
		esac
 | 
						|
	fi
 | 
						|
 | 
						|
	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_orig[@]}"
 | 
						|
			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
 | 
						|
			fi
 | 
						|
			;;
 | 
						|
		inside)
 | 
						|
			needs_sudo
 | 
						|
			mount --make-rslave /
 | 
						|
			case "$arg_user" in
 | 
						|
				user)
 | 
						|
					mount_opt=ro
 | 
						|
					;;
 | 
						|
				root)
 | 
						|
					mount_opt=rw
 | 
						|
					# TODO: make the rest of the system RO
 | 
						|
					;;
 | 
						|
			esac
 | 
						|
 | 
						|
			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"
 | 
						|
			fi
 | 
						|
			trap "umount --no-mtab -- ${arg_mountpoint@Q}" EXIT
 | 
						|
 | 
						|
			case "$arg_user" 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 "$@"
 |