changeset 644:0c7917469e04

Put the check for opened files with "procstat" into a subroutine and use it
author Franz Glasner <fzglas.hg@dom66.de>
date Fri, 27 Sep 2024 17:23:01 +0200
parents 4f2257ea7d0a
children aa21ec8b86c5
files sbin/ftjail share/local-bsdtools/common.subr
diffstat 2 files changed, 128 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- a/sbin/ftjail	Fri Sep 27 17:07:57 2024 +0200
+++ b/sbin/ftjail	Fri Sep 27 17:23:01 2024 +0200
@@ -931,22 +931,9 @@
             return 1
         fi
     done
-    #
-    # Check whether there are any open files within the jail.
-    #
-    # "procstat file" also lists fifo, socket, message queue, kgueue et al.
-    # file types.
-    #
-    # Note that procstat places extra whitespace at the end of lines sometimes.
-    #
-    #
-    if procstat -a file | /usr/bin/grep -E '['$'\t '']+'"${_directory}"'(/|(['$'\t '']*)$)' ; then
-        echo "ERROR: There are open files within the jail" >&2
-        return 1
-    fi
-    # The same for memory mappings
-    if procstat -a vm | /usr/bin/grep -E '['$'\t '']+'"${_directory}"'(/|(['$'\t '']*)$)' ; then
-        echo "ERROR: There are open memory mappings within the jail" >&2
+    # Check whether there are any open files or VM mappings  within the jail.
+    if ! _check_no_open_files_from_all_proc "${_directory}" ; then
+        err "There are open files or memory mappings within the jail"
         return 1
     fi
 
--- a/share/local-bsdtools/common.subr	Fri Sep 27 17:07:57 2024 +0200
+++ b/share/local-bsdtools/common.subr	Fri Sep 27 17:23:01 2024 +0200
@@ -11,6 +11,16 @@
 #: :ID:        @(#)@@SIMPLEVERSIONTAG@@
 #:
 
+#
+# "procstat --libxo=json,no-locale -a file | jq -r $'.procstat.files | map(.) | .[] | [ .command, .files.[] | .fd, .fd_type, .path] | @tsv '
+#
+# WORKING (without the command name)
+# procstat --libxo=json,no-locale -a file | jq -r $'.procstat.files | map(.)| .[] | .files.[] | [.fd, .fd_type, .path] | @tsv '
+#
+# FULL WITH command name
+# procstat --libxo=json,no-locale -a file | jq -r $'.procstat.files | map(.) | .[] | .command as $cmd | .files[] | [ $cmd, .fd, .fd_type, .vode_type, .path ] | @tsv '
+
+
 
 #:
 #: Dummy function to make the first "shellcheck" directive below non-global
@@ -506,6 +516,121 @@
 
 
 #:
+#: Use :command:`/usr/bin/procstat` to check if there are opened files or
+#: VM mappings with a given path prefix.
+#:
+#: Args:
+#:   $1 (str, optional): The path prefix to check open files for.
+#:       This must 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_from_all_proc() {
+    local _path_prefix
+
+    local _command _fd _fd_type _vnode_type _path _pid _kve_type _kve_path _rc
+
+    _path_prefix="${1-}"
+    case "${_path_prefix}" in
+        '')
+            # OK this matches at the root directory
+            _p1='/'
+            _p2='/'
+            ;;
+        /)
+            # OK this matches at the root directory
+            _p1='/'
+            _p2='/'
+            ;;
+        *//*)
+            fatal 1 "given path prefix must not contain consequtive slashes"
+            ;;
+        /*/)
+            # Remove trailing slash for equality check
+            _p1="${_path_prefix%/}"
+            # Hold the trailing slash as-is for prefix check
+            _p2="${_path_prefix}"
+            ;;
+        /*)
+            _p1="${_path_prefix}"
+            _p2="${_path_prefix}/"
+            ;;
+        *)
+            fatal 1 "given path prefix must be an absolute path"
+            ;;
+    esac
+    if [ -x "${JQ}" ]; then
+        # shellcheck disable=SC2016    # $cmd is really not to expand here
+        LC_ALL=C.UTF-8 /usr/bin/procstat --libxo=json -a file | LC_ALL=C.UTF-8 "${JQ}" -r '.procstat.files | map(.)| .[] | .command as $cmd | .files[] | [ $cmd, .fd, .fd_type, .vode_type, .path ] | @tsv' \
+        | {
+            _rc=0
+            while IFS=$'\t' read -r _command _fd _fd_type _vnode_type _path; do
+                case "${_path}" in
+                    "${_p1}"|"${_p2}"*)
+                        _rc=10
+                        ;;
+                    *)
+                        ;;
+                esac
+            done
+            [ "${_rc}" -ne 0 ] && return ${_rc}
+          }
+        LC_ALL=C.UTF-8 /usr/bin/procstat --libxo=json -a vm | LC_ALL=C.UTF-8 "${JQ}" -r $'.procstat.vm | map(.) | .[] | .process_id as $pid | .vm[] | [ $pid, .kve_type, .kve_path ] | @tsv' \
+        | {
+            _rc=0
+            while IFD=$'\t' read -r _pid _kve_type _kve_path; do
+                case "${_kve_path}" in
+                    "${_p1}"|"${_p2}"*)
+                        _rc=10
+                        ;;
+                    *)
+                        ;;
+                esac
+            done
+            return ${_rc}
+          }
+    else
+        /usr/bin/procstat --libxo=text,no-locale -a file \
+        | LC_ALL=C /usr/bin/awk -v OFS=$'\t' '{ print $2, $3, $4, $10; }' \
+        | {
+            _rc=0
+            while IFS=$'\t' read -r _command _fd _fd_type _path; do
+                case "${_path}" in
+                    "${_p1}"|"${_p2}"*)
+                        _rc=10
+                        ;;
+                    *)
+                        ;;
+                esac
+            done
+            [ "${_rc}" -ne 0 ] && return ${_rc}
+          }
+        /usr/bin/procstat --libxo=text,no-locale -a vm \
+        | LC_ALL=C /usr/bin/awk -v OFS=$'\t' '{ print $1, $10, $11; }' \
+        | {
+            _rc=0
+            while IFD=$'\t' read -r _pid _kve_type _kve_path; do
+                case "${_kve_path}" in
+                    "${_p1}"|"${_p2}"*)
+                        _rc=10
+                        ;;
+                    *)
+                        ;;
+                esac
+            done
+            return ${_rc}
+          }
+    fi
+}
+
+
+#:
 #: Check the validity of ZFS dataset names.
 #:
 #: See: ZFS Component Naming Requirements