changeset 647:b0e8b5cf5d33

Implement "_check_no_open_files_on_filesystem()" as common function and use it in ftjail. It checks for open files and memory mapping on a given file system. It uses the standard command "fstat -m -f <PATH>".
author Franz Glasner <fzglas.hg@dom66.de>
date Fri, 27 Sep 2024 19:17:21 +0200
parents 1d5f87e68078
children cd4aea87dbfa
files sbin/ftjail share/local-bsdtools/common.subr
diffstat 2 files changed, 51 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/sbin/ftjail	Fri Sep 27 17:28:49 2024 +0200
+++ b/sbin/ftjail	Fri Sep 27 19:17:21 2024 +0200
@@ -870,6 +870,7 @@
     local _res _jailname _dir_mounts _dir_fn_fstab _dir_fn_fstab2
     local _dir_basename _dir_fn_tldir
     local _root_dataset _root_mountpoint _root_type _root_options
+    local _mnt_device _mnt_mountpoint _mnt_type _mnt_options
     local _clone_extra_props _canmount_prop
     local _line _opt
     local _root_readonly _root_origin
@@ -947,9 +948,9 @@
     # mountpoint in ZFS.
     # Also check that it is a clone proper.
     #
-    IFS=$'\t' read -r _root_dataset _root_mountpoint _root_type _root_options _line <<EOF4tHGCSS
+    IFS=$'\t' read -r _root_dataset _root_mountpoint _root_type _root_options _line <<EOF4tHGCSSf5d7d9cf
 ${_dir_mounts}
-EOF4tHGCSS
+EOF4tHGCSSf5d7d9cf
     [ "${_root_mountpoint}" != "${_directory}" ] && { echo "ERROR: found root mountpoint does not match given directory" 1>&2; return 1; }
     [ "${_root_type}" != "zfs" ] && { echo "ERROR: root mountpoint is not from a ZFS dataset" 1>&2; return 1; }
     _root_readonly="$(zfs list -H -o readonly "${_root_dataset}")"
@@ -960,6 +961,17 @@
     else
         [ "${_root_origin}" = '-' ] &&  { echo "ERROR: the root dataset is not a ZFS clone" 1>&2; return 1; }
     fi
+    #
+    # Check for open files on all the mounted filesystems
+    #
+    while IFS=$'\t' read -r _mnt_device _mnt_mountpoint _mnt_type _mnt_options _line; do
+        if ! _check_no_open_files_on_filesystem "${_mnt_mountpoint}" ; then
+            err "There are open files or memory mapping on file system \`${_mnt_mountpoint}'"
+            return 1
+        fi
+    done <<EOF4tHGCAASLfafbf1b5
+${_dir_mounts}
+EOF4tHGCAASLfafbf1b5
 
     # Determine we need to clone with a custom (non inherited) "mountpoint"
     _clone_extra_props="$(_get_clone_extra_prop_for_mountpoint "${_root_dataset}") "
--- a/share/local-bsdtools/common.subr	Fri Sep 27 17:28:49 2024 +0200
+++ b/share/local-bsdtools/common.subr	Fri Sep 27 19:17:21 2024 +0200
@@ -627,6 +627,43 @@
 
 
 #:
+#: Use :command:`/usr/bin/fstat` to check if there are opened files or
+#: VM mappings onr a given file system.
+#:
+#: Args:
+#:   $1 (str, optional): The filesystem (aka mountpoint).
+#:       This should be an absolute path.
+#:       The root directory :file:`/` is allowed.
+#:       A `null` value is treated as if the root directory :file:`/` is given
+#:       as argument.
+#:
+#: Returns:
+#:   int: 0 if there are no opened files found,
+#:        10 if there are opened files found.
+#:        Other error codes may also returned on errors.
+#:
+_check_no_open_files_on_filesystem() {
+    local _fspath
+
+    local _count
+
+    _fspath="${1:-/}"
+
+    _count="$(LC_ALL=C /usr/bin/fstat -m -f "${_fspath}" | LC_ALL=C /usr/bin/wc -l)"
+    if [ -z "${_count}" ]; then
+        # this is an error
+        return 1
+    fi
+    # Note that fstat always prints a header: account for the header line
+    if [ "${_count}" -gt 1 ]; then
+        return 10
+    else
+        return 0
+    fi
+}
+
+
+#:
 #: Check the validity of ZFS dataset names.
 #:
 #: See: ZFS Component Naming Requirements