Added scripts. v0.1
authorRalph Ronnquist <rrq@rrq.au>
Sat, 20 Apr 2024 13:03:09 +0000 (23:03 +1000)
committerRalph Ronnquist <rrq@rrq.au>
Sat, 20 Apr 2024 13:03:09 +0000 (23:03 +1000)
mount.nbd [new file with mode: 0755]
mount.nbdfuse [new file with mode: 0755]

diff --git a/mount.nbd b/mount.nbd
new file mode 100755 (executable)
index 0000000..df07503
--- /dev/null
+++ b/mount.nbd
@@ -0,0 +1,67 @@
+#!/bin/sh
+#
+# Helper script to run an nbd client and mount its device to the given
+# mount point. This script is invoked by "mount" with
+# $1 = source (here it's an nbd URL like nbd://server/export
+# $2 = mount point
+# $3 = -o
+# $4 = client and mount options separated by comma
+#   block-size=N => "-b N"
+#   connections=N => "-C N"
+#   timeout=N => "-t N"
+#
+# The script starts a nbd-client service client before mounting, and
+# spawns a cleanup daemon that uses inotify to "discover" unmount to
+# terminate the service client.
+
+# Find a free /dev/nbd*
+for ADM in /dev/nbd* ; do nbd-client -c $ADM > /dev/null || break ; done
+
+if [ -z "$ADM" ] ; then
+    echo "** No available /dev/nbd* device node" >&2
+    exit 1
+fi
+
+if grep -qF " $ADM "  /proc/mounts ; then
+    echo "*** $1 is already mounted" >&2
+    exit 1
+fi
+
+# Split up options between partition and loop options
+POPTS=""
+LOPTS=""
+for X in $(echo $4 | tr , ' ') ; do
+    case $X in
+       block-size=*) POPTS="$POPTS -b ${X#*=}" ;;
+       connections=*) POPTS="$POPTS -C ${X#*=}" ;;
+       timeout=*) POPTS="$POPTS -t ${X#*=}" ;;
+       *) LOPTS="$LOPTS,$X" ;;
+    esac
+done
+
+# Set up the device node service
+# $1 = nbd://$host[:$port]/$export
+read S P N <<EOF
+$(echo "${1#nbd://}" | sed 's|/| |;s|[ :]| |')
+EOF
+[ -z "$N" ] && N=$P && P=
+[ -z "$P" ] || P="-port $P"
+POPTS="-persist $POPTS"
+nbd-client $S $P -name $N $POPTS > /dev/null || exit 1
+
+sleep 0.2
+for i in 0 1 2 3 4 5 6 7 8 9 ; do
+    # Loop-mount the nbdfuse "device" and spawn a cleanup daemon
+    if mount -o$LOPTS $ADM "$2" 2> /dev/null ; then
+       # Spawn a process to stop $ADM service when "$2" is umount-ed
+       ( (
+           inotifywait -e delete_self "$2" > /dev/null 2>&1
+           nbd-client -d $ADM
+       ) & ) &
+       exit 0
+    fi
+    sleep 0.2
+done
+
+# Coming here if something wrong
+nbd-client -d $ADM
diff --git a/mount.nbdfuse b/mount.nbdfuse
new file mode 100755 (executable)
index 0000000..3bdb322
--- /dev/null
@@ -0,0 +1,55 @@
+#!/bin/sh
+#
+# Helper script to run an nbd client and mount its device to the given
+# mount point. This script is invoked by "mount" with
+# $1 = source (here it's an nbd URL like nbd://server/export
+# $2 = mount point
+# $3 = -o
+# $4 = mount options
+#
+# The script starts a nbdfuse service client before mounting, and
+# spawns a cleanup daemon that uses inotify to "discover" unmount to
+# terminate the service client.
+
+# Use an /run directory mangled from the source URL as "device node"
+ADM="/run/$(echo -n "$1" | tr -c "[[:alnum:]-]" "_")"
+if grep -qF " $ADM "  /proc/mounts ; then
+    echo "*** $1 is already mounted" >&2
+    exit 1
+fi
+mkdir -p $ADM
+
+# Split up options between partition and loop options
+POPTS=""
+LOPTS=""
+for X in $(echo $4 | tr , ' ') ; do
+    case $X in
+       kernel_cache|allow_other) POPTS="$POPTS -o $X" ;;
+       *) LOPTS="$LOPTS,$X" ;;
+    esac
+done
+
+# Set up the device node service
+modprobe fuse || exit 1
+nohup nbdfuse -C 1 $POPTS $ADM "$1" > /dev/null 2>&1 &
+
+sleep 0.2
+for i in 1 2 3 4 5 6 7 8 9 ; do
+    # Loop-mount the nbdfuse "device" and spawn a cleanup daemon
+    if mount -oloop,$LOPTS $ADM/nbd "$2" 2> /dev/null ; then
+       # Spawn a process to umount $ADM when "$2" is umount-ed
+       ( (
+           inotifywait -e delete_self "$2" > /dev/null 2>&1
+           sleep 0.2
+           for i in 1 2 3 4 ; do
+               umount $ADM 2> /dev/null && exit 0
+               sleep 0.2
+           done
+       ) & ) &
+       exit 0
+    fi
+    sleep 0.2
+done
+
+# Coming here if something wrong
+umount $ADM