diff sbin/ftjail @ 241:acf16a85900f

Mount and unmount template datasets
author Franz Glasner <fzglas.hg@dom66.de>
date Sat, 10 Sep 2022 10:09:42 +0200
parents 04fde1941966
children 59e933b81dcf
line wrap: on
line diff
--- a/sbin/ftjail	Fri Sep 09 23:13:20 2022 +0200
+++ b/sbin/ftjail	Sat Sep 10 10:09:42 2022 +0200
@@ -38,6 +38,18 @@
 
     The datasets will not be mounted.
 
+  mount-tmpl [ OPTIONS ] BASE-RO SKELETON-RW MOUNTPOINT
+
+    Canonically mount the RO base and the RW skeleton into MOUNTPOINT and
+    MOUNTPOINT/skeleton
+
+    -n        Do not really mount but show what would be mounted where
+    -u        Alias of -n
+
+  umount-tmpl BASE-RO SKELETON_RW
+
+    Unmount mounted datasets BASE-RO and SKELETON-RW
+
 ENVIRONMENT:
 
   All environment variables that affect "zfs" are effective also.
@@ -265,40 +277,17 @@
 
 
 #
-# "mount" -- recursively mount a dataset including subordinate datasets
+# _do_mount dataset mountpoint dry-run mount-natural
 #
-# command_mount dataset mountpoint
-#
-command_mount() {
-    local _dsname _mountpoint
+_do_mount() {
+    local _dsname _mountpoint _dry_run _mount_natural
     local _name _mp _canmount _mounted
     local _rootds_mountpoint _relative_mp _real_mp
-    local _dry_run _mount_outside _mount_natural
 
-    _dry_run=""
-    _mount_outside=""
-    _mount_natural=""
-    while getopts "ONnu" _opt ; do
-        case ${_opt} in
-            O)
-                _mount_outside="yes"
-                ;;
-            N)
-                _mount_natural="yes"
-                ;;
-            n|u)
-                _dry_run="yes"
-                ;;
-            \?|:)
-                return 2;
-                ;;
-        esac
-    done
-    shift $((OPTIND-1))
-    OPTIND=1
-
-    _dsname="${1-}"
-    _mountpoint="${2-}"
+    _dsname="${1}"
+    _mountpoint="${2}"
+    _dry_run="${3}"
+    _mount_natural="${4}"
 
     if [ -z "${_dsname}" ]; then
         echo "ERROR: no dataset given" >&2
@@ -306,7 +295,7 @@
     fi
 
     _rootds_mountpoint="$(zfs list -H -o mountpoint -t filesystem "${_dsname}")"  || \
-        { echo "ERROR: root dataset does not exist" >&2; return 1; }
+        { echo "ERROR: root dataset \`${_dsname}' does not exist" >&2; return 1; }
 
     if [ -z "${_mountpoint}" ]; then
         if [ "${_mount_natural}" = "yes" ]; then
@@ -317,7 +306,7 @@
         fi
     else
         if [ "${_mount_natural}" = "yes" ]; then
-            echo "ERROR: Cannot have a custom mountpoint when \"-O\" is given" >&2
+            echo "ERROR: Cannot have a custom mountpoint when mount-natural is activated" >&2
             return 2
         fi
     fi
@@ -375,16 +364,7 @@
                     fi
                     ;;
                 *)
-                    if [ "${_mount_outside}" = "yes" ]; then
-                        if [ "${_dry_run}" = "yes" ]; then
-                            echo "Would mount ${_name} on configured ZFS dataset mountpoint ${_mp}"
-                        else
-                            echo "Mounting ${_name} on configured ZFS dataset mountpoint ${_mp}"
-                            zfs mount "${_name}" || return 1
-                        fi
-                    else
-                        echo "Skipping ${_name} because its configured ZFS mountpoint is not relative to given root dataset" 2>&1
-                    fi
+                    echo "Skipping ${_name} because its configured ZFS mountpoint is not relative to given root dataset" 2>&1
                     ;;
             esac
         done
@@ -395,21 +375,60 @@
 
 
 #
-# "umount" -- Recursively unmount ZFS datasets
+# "mount-tmpl" -- recursively mount a base and skeleton datasets including subordinate datasets
+#
+# command_mount_tmpl base-ro skeleton-rw  mountpoint
 #
-# command_umount dataset
+command_mount_tmpl() {
+    local _ds_base _ds_skel _mountpoint
+
+    local _dry_run _opt
+
+    _dry_run=""
+
+    while getopts "nu" _opt ; do
+        case ${_opt} in
+            n|u)
+                _dry_run="yes"
+                ;;
+            \?|:)
+                return 2;
+                ;;
+        esac
+    done
+    shift $((OPTIND-1))
+    OPTIND=1
+
+    _ds_base="${1-}"
+    _ds_skel="${2-}"
+    _mountpoint="${3-}"
+
+    _do_mount "${_ds_base}" "${_mountpoint}" "${_dry_run}" "" || return
+    if [ "${_dry_run}" != "yes" ]; then
+        if [ ! -d "${_mountpoint}/skeleton" ]; then
+            mkdir "${_mountpoint}/skeleton" || return
+        fi
+    fi
+    _do_mount "${_ds_skel}" "${_mountpoint}/skeleton" "${_dry_run}" "" || return
+
+    return 0
+}
+
+
 #
-command_umount() {
+# _do_umount dataset
+#
+_do_umount() {
     local _dsname
     local _name _mp _rest
     local _rootds_mountpoint
 
-    _dsname="${1-}"
-    [ -z "${_dsname}" ] && \
-        { echo "ERROR: no dataset given" >&2; return 2; }
+    _dsname="${1}"
+    [ -z "${_dsname}" ] && { echo "ERROR: no dataset given" >&2; return 2; }
 
     # Just determine whether the given dataset name exists
-    _rootds_mountpoint="$(zfs list -H -o mountpoint -t filesystem "${_dsname}")" || { echo "ERROR: dataset not found" >&2; return 1; }
+    _rootds_mountpoint="$(zfs list -H -o mountpoint -t filesystem "${_dsname}")" || \
+        { echo "ERROR: dataset not found" >&2; return 1; }
 
     mount -t zfs -p \
     | grep -E "^${_dsname}(/|\s)" \
@@ -425,6 +444,27 @@
 
 
 #
+# "umount-tmpl" -- umount skeleton and base datasets
+#
+# command_umount_tmpl ds-base ds-skeleton
+#
+command_umount_tmpl() {
+    local _ds_base _ds_skel
+
+    _ds_base="${1-}"
+    _ds_skel="${2-}"
+
+    [ -z "${_ds_base}" ] && { echo "ERROR: no RO base dataset given" >&2; return 2; }
+    [ -z "${_ds_skel}" ] && { echo "ERROR: no RW skeleton dataset given" >&2; return 2; }
+
+    _do_umount "${_ds_skel}" || return
+    _do_umount "${_ds_base}" || return
+
+    return 0
+}
+
+
+#
 # Global option handling
 #
 while getopts "Vh" _opt ; do
@@ -463,6 +503,12 @@
     datasets-tmpl)
         command_datasets_tmpl "$@"
         ;;
+    mount-tmpl)
+        command_mount_tmpl "$@"
+        ;;
+    umount-tmpl|unmount-tmpl)
+        command_umount_tmpl "$@"
+        ;;
     populate)
         command_populate "$@"
         ;;