qemu-mount - Tools for mounting QEMU images
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

155 lines
3.7 KiB

#!/bin/sh
#
# mount qemu image file into a directory
#
prog=$(basename "$0")
# use sudo for unprivileged users
SUDO=
[ "$(id -u)" -ne 0 ] && SUDO=sudo
# print error message
error() {
echo "$prog:" "$@" 2>&1
exit 1
}
# print usage
usage() {
if [ $# -ge 1 ]; then
[ -n "$*" ] && echo "$prog:" "$@" 2>&1
echo 2>&1
fi
cat << EOF >&2
Mount the qemu image file into a directory.
Usage: $prog [OPTIONS] qemu_image mount_point
Options:
-p partition_number select, which partition to mount, default #1
-r mount read-only
-t fstype set filesystem type
-o mount_options additional mount options
-u set owner to current user
Without arguments it prints a list of mounted images.
EOF
exit 1
}
# Without arguments: print mounted images
if [ $# -eq 0 ]; then
for file in /tmp/nbd*.mount; do
nbd=$(basename "$file" .mount)
[ "$nbd" = "nbd*" ] && exit 0
image=
while read -r line; do
if [ -z "$image" ]; then
image="$line"
else
mdir="$line"
echo "$nbd: $image -> $mdir"
break
fi
done < "$file"
done
exit 0
fi
# parse command line
partition=1
read_only=
fstype=
mnt_options=
set_uid=
while getopts ":p:rt:o:u" opt; do
case $opt in
p) partition="$OPTARG"
echo "$partition" | grep -q -x "[0-9][0-9]*" || \
error "partition number must be numeric" ;;
r) read_only=1 ;;
t) fstype=$OPTARG ;;
o) mnt_options="${mnt_options},${OPTARG}" ;;
u) set_uid=1 ;;
\?) usage "illegal option -- $OPTARG" ;;
:) usage "option requires an argument -- $OPTARG" ;;
esac
done
shift $((OPTIND-1)) # remove parsed options and args from $@ list
mnt_options=${mnt_options#,}
[ $# -ne 2 ] && usage "wrong number of arguments"
image="$1"
mdir="$2"
# check file types
[ -e "$image" ] || error "$image: no such file"
[ -f "$image" ] || error "$image must be a regular file"
[ -e "$mdir" ] || error "$mdir: no such directory"
[ -d "$mdir" ] || error "$mdir must be a directory"
full_image=$(readlink -f "$image")
full_mdir=$(readlink -f "$mdir")
img_fmt=$(qemu-img info "$image" | sed -n 's/^file format: \(.*\)/\1/p')
[ -n "$img_fmt" ] || error "$image has unknown format"
# load kernel module, check if sudo works
$SUDO modprobe nbd nbds_max=16 max_part=31 || exit $?
# load FAT filesystem module
$SUDO modprobe vfat 2> /dev/null
# lock
umask=$(umask); umask 0
(
flock -w 5 9 || error "Can't get mount lock"
umask "$umask"
# already in use?
grep -q -F -x "$full_image" /tmp/nbd*.mount 2> /dev/null &&
error "$image already mounted"
grep -q -F -x "$full_mdir" /tmp/nbd*.mount 2> /dev/null &&
error "$mdir already in use"
# find free nbd device
nbd_size=1
for nbd in /sys/class/block/nbd*; do
[ -n "${nbd##*/nbd[0-9]}" ] && \
[ -n "${nbd##*/nbd[0-9][0-9]}" ] && \
continue
nbd_size=$(cat "${nbd}/size")
[ "$nbd_size" -gt 0 ] || break
done
[ "$nbd_size" -gt 0 ] && error "no free nbd devices"
nbd=$(basename "$nbd")
# reserve nbd device
printf "%s\n%s\n" "$full_image" "$full_mdir" > "/tmp/${nbd}.mount" || exit $?
# qemu-nbd
$SUDO qemu-nbd -c "/dev/$nbd" -f "$img_fmt" "$full_image"
ret=$?
if [ $ret -ne 0 ]; then
rm -f "/tmp/${nbd}.mount"
exit $ret
fi
# mount
nbd_dev=/dev/$nbd
[ "$partition" -gt 0 ] && nbd_dev="${nbd_dev}p${partition}"
options=$mnt_options
[ -n "$read_only" ] && options="$options,ro"
[ -n "$set_uid" ] && options="$options,uid=$(id -u),gid=$(id -g)"
options=${options#,}
$SUDO mount ${fstype:+-t "$fstype"} ${options:+-o "$options"} \
"$nbd_dev" "$full_mdir"
ret=$?
if [ $ret -eq 0 ]; then
echo "$prog completed, using device $nbd_dev"
else
sync
$SUDO qemu-nbd -d "/dev/$nbd" > /dev/null 2>&1
rm -f "/tmp/${nbd}.mount"
fi
exit $ret
) 9>> /var/lock/qemu-mount.lock