Mercurial > hgrepos > FreeBSD > ports > sysutils > local-bsdtools
diff sbin/ftjail @ 658:260a81d769a6
Implemented "ftjail check-freebsd-update": thorough check for preconditions to a successful run of "ftjail freebsd-update".
All checks that "ftjail freebsd-update" does are replicated in
"ftjail check-freebsd-update".
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Sat, 28 Sep 2024 19:12:05 +0200 |
| parents | db22766df6a4 |
| children | 82a98db83a13 |
line wrap: on
line diff
--- a/sbin/ftjail Sat Sep 28 14:55:57 2024 +0200 +++ b/sbin/ftjail Sat Sep 28 19:12:05 2024 +0200 @@ -61,6 +61,7 @@ _p_datadir='@@DATADIR@@' [ "${_p_datadir#@@DATADIR}" = '@@' ] && _p_datadir="$(dirname "$0")"/../share/local-bsdtools . "${_p_datadir}/common.subr" +. "${_p_datadir}/farray.sh" # Reset to standard umask @@ -858,6 +859,189 @@ #: +#: Callback for _print_check_errors +#: +_print_check_error() { + printf '%s CHECK: %s\n' '-' "$3" 1>&2 + return 0 +} + + +#: +#: Print all the errors to stderr +#: +_print_check_errors() { + farray_istrue "$1" || return 0 + echo "There are ERRORs to be resolved before \`freebsd-update' can be run:" 1>&2 + farray_for_each "$1" _print_check_error +} + + +#: +#: Callback for _print_check_warnings +#: +_print_check_warning() { + printf '%s WARNING: %s\n' '-' "$3" 1>&2 + return 0 +} + + +#: +#: Print all the warnings to stderr +#: +_print_check_warnings() { + farray_istrue "$1" || return 0 + echo "There are WARNINGs to be considered before \`freebsd-update' should be run:" 1>&2 + farray_for_each "$1" _print_check_warning +} + + +#: +#: Implement the "check-freebsd-update" command for a thin jail +#: +command_check_freebsd_update() { + local _directory _new_origin _etcupdate_tarball + local _opt_keep _opt_old_origin + + local _errors _warnings _rc + local _directory _new_origin _etcupdate_tarball + local _dir_basename _dir_mounts _jailname _tmp _line _log_sock + local _root_dataset _root_mountpoint _root_type _root_options + local _mnt_device _mnt_mountpoint _mnt_type _mnt_options + + _rc=0 + + _warnings='' + farray_create _warnings XXX + _errors='' + farray_create _errors + + _opt_keep="no" + _opt_old_origin="" + while getopts "ko:" _opt ; do + case "${_opt}" in + k) + _opt_keep="yes" + ;; + o) + _opt_old_origin="$OPTARG" + ;; + \?|:) + return 2; + ;; + esac + done + shift $((OPTIND-1)) + OPTIND=1 + + _directory="${1-}" + _new_origin="${2-}" + _etcupdate_tarball="${3-}" + + if [ -z "${_directory}" ]; then + farray_append _errors "no directory given" + else + [ -d "${_directory}" ] || farray_append _errors "directory \`${_directory}' does not exist" + fi + if [ -z "${_new_origin}" ]; then + farray_append _errors "no new origin given" + else + zfs list -H -o name -t snapshot "${_new_origin}" >/dev/null 2>/dev/null || farray_append _errors "ZFS dataset snapshot for the new origin \`${_new_origin}' does not exist" + fi + if [ -n "${_etcupdate_tarball}" ]; then + [ -r "${_etcupdate_tarball}" ] || farray_append _errors "given etcupdate tarball does not exist and/or is not readable" + fi + + if [ -n "${_directory}" ]; then + + _dir_basename="$(basename "${_directory}")" + + set +e + _jailname="$(_get_jail_from_path "${_directory}")" + _tmp=$? + set -e + case ${_tmp} in + 0) + farray_append _errors "Jail \`${_jailname}' is running. Please stop it." + ;; + 1) + farray_append _errors "Cannot determine jail name" + ;; + 3) + true + ;; + 2) + farray_append _errors "Jail \`${_jailname}' is currently yet dying. Please wait." + ;; + *) + farray_append _errors "UNHANDLED RETURN VALUE from _get_jail_from_path()" + ;; + esac + + # + # Check whether additional log sockets are opened at their default + # locations. Because they hinder proper unmounting of filesystems. + # + for _log_sock in /var/run/log /var/run/logpriv ; do + if [ -S "${_directory}${_log_sock}" ]; then + farray_append _errors "log socket is open at \`${_directory}${_log_sock}'" + fi + done + + # Check whether there are any open files or VM mappings within the jail. + if ! _check_no_open_files_from_all_proc "${_directory}" ; then + farray_append _errors "There are open files or memory mappings within the jail" + fi + + _dir_mounts="$(_get_mounts_at_directory "${_directory}")" + + # + # Check preconditions thoroughly! + # + # Check that the first item/line is a read-only ZFS mount directly + # at the given directory. This must also be its configured + # mountpoint in ZFS. + # Also check that it is a clone proper. + # + IFS=$'\t' read -r _root_dataset _root_mountpoint _root_type _root_options _line <<EOF4tHGCSSf5d7d9cf +${_dir_mounts} +EOF4tHGCSSf5d7d9cf + [ "${_root_mountpoint}" != "${_directory}" ] && farray_append _errors "found root mountpoint does not match given directory" + [ "${_root_type}" != "zfs" ] && farray_append _errors "root mountpoint is not from a ZFS dataset" + _root_readonly="$(zfs get -H -o value readonly "${_root_dataset}")" + [ "${_root_readonly}" != "on" ] && farray_append _errors "the root dataset is not mounted read-only" + _root_origin="$(zfs get -H -o value origin "${_root_dataset}")" + if [ -n "${_opt_old_origin}" ]; then + [ "${_opt_old_origin}" != "${_root_origin}" ] && farray_append _errors "origin mismatch" + else + [ "${_root_origin}" = '-' ] && farray_append _errors "the root dataset is not a ZFS clone" + 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 + farray_append _errors "There are open files or memory mapping on file system \`${_mnt_mountpoint}'" + fi + done <<EOF4tHGCAASL775f9f320205 +${_dir_mounts} +EOF4tHGCAASL775f9f320205 + fi + + if farray_istrue _errors; then + _print_check_errors _errors + _rc=1 + fi + # Warnings do not influence the return code + _print_check_warnings _warnings + + farray_destroy _errors + farray_destroy _warnings + return ${_rc} +} + + +#: #: Implement the "freebsd-update" command for a thin jail #: #: .. note:: FreeBSD's :command:`etcupdate` also executes @@ -1160,11 +1344,13 @@ echo "ERROR: use \`fjail configure' instead" 1>&2; exit 2 ;; + check-freebsd-update) + command_check_freebsd_update "$@" + ;; freebsd-update) command_freebsd_update "$@" ;; *) - echo "ERROR: unknown command \`${command}'" 1>&2 - exit 2 + fatal 2 "unknown command \`${command}'" ;; esac
