+# Hey Emacs, this is a -*- shell-script -*- !!!
+
+# This file provides functions to implement loopback mounting and
+# access/update of disk images, either via qemu-nbd/nbd (for qcow2
+# images) or via loopback (for raw (or reflink) images).
+
+######################################################################
+
+diskimage_mount_loopback ()
+{
+ local disk="$1"
+
+ local device extra_mount_options
+
+ _setup_image "$disk"
+
+ echo "Mounting disk ${disk}..."
+ local m o
+ for m in $SYSTEM_DISK_MOUNTS ; do
+ local mount_ok=0
+ o="${m#*:}" # Offset is after colon
+ m="${m%:*}" # Mountpoint is before colon
+ echo " mount ${m} from offset ${o}"
+ local i
+ for i in $(seq 1 5); do
+ mount -o offset=${o}${extra_mount_options} $device "mnt${m}" && {
+ mount_ok=1
+ break
+ }
+ umount mnt 2>/dev/null || true
+ sleep 1
+ done
+ [ $mount_ok = 1 ] || die "Failed to mount $disk"
+ done
+
+ [ -d "$mnt/root" ] || {
+ echo "Mounted directory does not look like a root filesystem"
+ ls -latr mnt
+ exit 1
+ }
+}
+
+# unmount a qemu image
+diskimage_unmount_loopback ()
+{
+ echo "Unmounting disk"
+ sync; sync;
+
+ # umounts are done in reverse. Be lazy and construct a reverse
+ # list, since the shell will handle any strange whitespace for
+ # us... ;-)
+ local umounts=""
+ local m
+ for m in $SYSTEM_DISK_MOUNTS ; do
+ umounts="${m%:*}${umounts:+ }${umounts}"
+ done
+ for m in $umounts ; do
+ echo " umount ${m}"
+ umount "mnt${m}" || umount "mnt${m}" || true
+ done
+ _cleanup_image
+}
+
+diskimage_mkdir_p_loopback ()
+{
+ mkdir -p "mnt$1"
+}
+
+diskimage_substitute_vars_loopback ()
+{
+ substitute_vars "$1" "mnt$2"
+}
+
+diskimage_chmod_loopback ()
+{
+ local mode="$1" ; shift
+ local i
+ for i ; do
+ # this should handle wildcards
+ eval chmod "$mode" "mnt$i"
+ done
+}
+
+diskimage_chmod_reference_loopback ()
+{
+ local ref="$1" ; shift
+ local i
+ for i ; do
+ # this should handle wildcards
+ eval chmod --reference="$ref" "mnt$i"
+ done
+}
+
+diskimage_is_directory_loopback ()
+{
+ [ -d "mnt$1" ]
+}
+
+diskimage_append_text_file_loopback ()
+{
+ cat "$1" >> "mnt$2"
+}
+
+diskimage_append_text_loopback ()
+{
+ echo "$1" >> "mnt$2"
+}
+
+diskimage_sed_loopback ()
+{
+ local file="$1" ; shift
+ sed -i.org "$@" "mnt$file"
+}
+
+diskimage_put_loopback ()
+{
+ cp "$1" "mnt$2"
+}
+
+diskimage_ln_s_loopback ()
+{
+ ln -s "$1" "mnt$2"
+}
+
+diskimage_command_loopback ()
+{
+ chroot mnt "$@"
+}
+
+######################################################################
+
+# Private functions
+
+# mount a qemu image via nbd
+_connect_nbd() {
+ echo "Connecting nbd to $1"
+ mkdir -p mnt
+ modprobe nbd
+ killall -9 -q $QEMU_NBD || true
+ $QEMU_NBD -p 1300 $1 &
+ sleep 1
+ [ -r $NBD_DEVICE ] || {
+ mknod $NBD_DEVICE b 43 0
+ }
+ umount mnt 2> /dev/null || true
+ nbd-client -d $NBD_DEVICE > /dev/null 2>&1 || true
+ killall -9 -q nbd-client || true
+ nbd-client localhost 1300 $NBD_DEVICE > /dev/null 2>&1 || true &
+ sleep 1
+}
+
+# disconnect nbd
+_disconnect_nbd() {
+ echo "Disconnecting nbd"
+ sync; sync
+ nbd-client -d $NBD_DEVICE > /dev/null 2>&1 || true
+ killall -9 -q nbd-client || true
+ killall -q $QEMU_NBD || true
+}
+
+_setup_image ()
+{
+ local disk="$1"
+
+ case "$SYSTEM_DISK_FORMAT" in
+ qcow2)
+ _connect_nbd "$disk"
+ device=$NBD_DEVICE
+ extra_mount_options=""
+ ;;
+ raw|reflink)
+ device="$disk"
+ extra_mount_options=",loop"
+ ;;
+ *)
+ die "Error: unknown SYSTEM_DISK_FORMAT=${SYSTEM_DISK_FORMAT}."
+ esac
+}
+
+_cleanup_image ()
+{
+ case "$SYSTEM_DISK_FORMAT" in
+ qcow2)
+ _disconnect_nbd
+ ;;
+ raw|reflink)
+ :
+ ;;
+ *)
+ die "Error: unknown SYSTEM_DISK_FORMAT=${SYSTEM_DISK_FORMAT}."
+ esac
+}
+