changeset 128:3dcae0e91769

Move all admin scripts into the "sbin" folder
author Franz Glasner <fzglas.hg@dom66.de>
date Thu, 17 Oct 2019 09:09:13 +0200
parents 37737f225887
children 4aeff9d5275d
files Makefile bin/check-ports bin/fjail bin/fpkg pkg-plist sbin/check-ports sbin/fjail sbin/fpkg
diffstat 8 files changed, 1103 insertions(+), 1103 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile	Wed Oct 16 08:56:32 2019 +0200
+++ b/Makefile	Thu Oct 17 09:09:13 2019 +0200
@@ -31,7 +31,7 @@
 do-extract:
 	${MKDIR} ${WRKSRC}/bin
 	${MKDIR} ${WRKSRC}/sbin
-.for _rp in bin/check-ports bin/fjail bin/fpkg sbin/bsmtp2dma
+.for _rp in sbin/check-ports sbin/fjail sbin/fpkg sbin/bsmtp2dma
 	${CP} -v ${SRC}/${_rp} ${WRKSRC}/${_rp}
 	${SED} -i "" -E -e "s|\\\$$Date\\\$$|\$$Date: ${HGDATE} \$$|" ${WRKSRC}/${_rp}
 	${SED} -i "" -E -e "s|\\\$$Revision\\\$$|\$$Revision: ${HGREVISION} \$$|" ${WRKSRC}/${_rp}
@@ -54,7 +54,7 @@
 .endfor
 
 do-install:
-.for _rp in bin/check-ports bin/fjail bin/fpkg sbin/bsmtp2dma
+.for _rp in sbin/check-ports sbin/fjail sbin/fpkg sbin/bsmtp2dma
 	${INSTALL_SCRIPT} ${WRKSRC}/${_rp} ${STAGEDIR}${PREFIX}/${_rp}
 .endfor
 	${MKDIR} ${STAGEDIR}${ETCDIR}
--- a/bin/check-ports	Wed Oct 16 08:56:32 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,501 +0,0 @@
-#!/bin/sh
-# -*- indent-tabs-mode: nil; -*-
-: 'Check the version status of installed ports and compare them to
-repository versions.
-
-:Author:    Franz Glasner
-:Copyright: (c) 2017-2019 Franz Glasner.
-            All rights reserved.
-:License:   BSD 3-Clause "New" or "Revised" License.
-            See LICENSE for details.
-            If you cannot find LICENSE see
-            <https://opensource.org/licenses/BSD-3-Clause>
-:ID:        @(#)@@PKGORIGIN@@ $HGid$
-
-'
-
-VERSION="@@VERSION@@"
-
-#
-# Configuration directory
-#
-: ${CONFIGDIR:=@@ETCDIR@@}
-
-test -r "${CONFIGDIR}/tools.conf" && . "${CONFIGDIR}/tools.conf"
-
-#
-# Mapping configuration: installed package name -> original package name
-# Note: This is independent of any repo
-#
-: ${PACKAGE_MAPPING:=${CONFIGDIR}/package-mapping.conf}
-
-#
-# Local repository with non-public packages and/or ports with changed
-# OPTIONS (i.e. not using the defaults) or forks of official packages with
-# other package names
-#
-: ${LOCAL_REPO:=LocalRepo}
-
-#
-# Local repository with ports with default OPTIONS (i.e. unchanged)
-# but newer than the packages in the "FreeBSD" repository.
-# Some sort of a fast-track repository.
-#
-: ${LOCALBSDPORTS_REPO:=LocalBSDPorts}
-
-#
-# The official FreeBSD binary repository
-#
-: ${FREEBSD_REPO:=FreeBSD}
-
-#
-# Directly installed from ports
-#
-: ${PORTS_DIRECT_INSTALLED_REPO:=unknown-repository}
-
-#
-# For the workaround of the bug in pkg rquery -I
-#
-: ${PORTSDIR:=/usr/ports}
-: ${INDEXDIR:=${PORTSDIR}}
-: ${INDEXFILE:=@@INDEXFILE@@}
-
-
-get_remote_repo_versions() {
-    : 'Determine the remote repository versions of all packages in
-    repository `_repo`.
-
-    Args:
-        _repo: the name of the repote repository
-
-    Returns:
-        status 0 on success, 1 on errors
-
-    Output (Globals):
-        remote_versions_${_repo}: the versions of all packages in `_repo` and
-                                  their extended version status with respect to
-                                  locally installed packages
-
-    '
-    local _repo _data _rv
-
-    _repo=$1
-
-    _data=$(pkg version -U -R -r ${_repo} -v)
-    _rv=$?
-    eval remote_versions_${_repo}=\"\${_data}\"
-    return ${_rv}
-}
-
-get_remote_repo_data() {
-    : 'Get the extended package version information from the remote repository
-    `_repo` for package `_name`.
-
-    Args:
-        _repo: the name of the remote repository
-        _name: the package name
-
-    Input (Globals):
-        remote_versions_${_repo}: the extended version info for *all* packages
-                                  in repo `_repo`.
-
-    Returns:
-        status 0 on success, 1 on errors or if the package is not found
-        in the remote repository
-
-    Output (Globals):
-        remote_label_${_repo}:
-        remote_descr_${_repo}:
-
-    '
-    local _repo _name _rversions _rfqp _rl _rdescr
-
-    _repo=$1
-    _name=$2
-
-    eval _rversions=\"\${remote_versions_${_repo}}\"
-    while read _rfqp _rl _rdescr ; do
-        if [ ${_rfqp%-*} = ${_name} ] ; then
-            eval remote_label_${_repo}=\"\${_rl}\"
-            eval remote_descr_${_repo}=\"\${_rdescr}\"
-            return 0
-        fi
-    done <<EOF884657
-${_rversions}
-EOF884657
-    eval remote_label_${_repo}=""
-    eval remote_descr_${_repo}=""
-    return 1
-}
-
-get_local_index_versions() {
-    : 'Determine the extendes versions of all packages in the local index
-    (ports).
-
-    Returns:
-        status 0 on success or 1 on errors
-
-    Output (Globals):
-        local_index_versions:
-
-    '
-    local_index_versions=$(pkg version -I -v)
-}
-
-get_repo_for_installed_package() {
-    : 'Determine for a package `_name` from which repository is has been
-    installed.
-
-    Args:
-        _name: the name of the package to search for
-
-    Input (Globals):
-        installed_data  the output of ``pkg query "%n %v %R"`` of all
-                        installed packages
-
-    Returns:
-        0 on success, 1 on errors or if the package is not installed
-
-    Output (Globals):
-        repository: the repository from which the installed packages `_name`
-                    has been installed
-
-    '
-    local _name _n _v _r
-
-    _name=$1
-
-    while read _n _v _r ; do
-        if [ ${_name} = ${_n} ] ; then
-            repository=${_r}
-            return 0
-        fi
-    done <<EOF223777
-${installed_data}
-EOF223777
-    return 1
-}
-
-get_immediate_index_version() {
-    : 'Determine for package `_package` the version of the package in the
-    local ports index.
-
-    Args:
-        _package: the package name to search for
-
-    Input (Globals):
-        INDEXDIR:  the directory where to search the index file
-        INDEXFILE: the name of the index file
-
-    Returns:
-        0 on success, 1 on errors or if the package is not in the index
-
-    Output (Globals):
-        immediate_index_version: the version number of `_package` in the
-                                 index
-
-    '
-    local _package _line _fqpn _n _lines
-
-    _package=$1
-
-#    _val=$(pkg rquery -I "${_package}" | cut -f 1 -d '|')
-#    _rv=$?
-#    immediate_index_version=${_val##*-}
-#    return ${_rv}
-
-    if [ -r "${INDEXDIR}/${INDEXFILE}" ] ; then
-        #
-        # Note: Direct piping does not set immediate_index_version at return correctly
-        #       "_line" is set correctly and parsing works, but the return 0 seems to kill
-        #       some of the previous effects.
-        #
-        # "grep" does a fast pre-selection, reading, parsing and comparing is done for
-        # exact matching.
-        #
-        _lines=$(egrep '^'"${_package}" "${INDEXDIR}/${INDEXFILE}")
-        while read _line ; do
-            _fqpn="${_line%%|*}"
-            _n=${_fqpn%-*}
-	    if [ "${_package}" = "${_n}" ] ; then
-                immediate_index_version="${_fqpn##*-}"
-                return 0
-            fi
-        done <<EOF1334TGH1
-${_lines}
-EOF1334TGH1
-    fi
-
-    immediate_index_version=""
-    return 1
-}
-
-get_immediate_remote_repo_version() {
-    : 'Ask a remote repository for the version of a package.
-
-    Args:
-        _repo: the repository name
-        _name: the name of the package
-
-    Returns:
-        0 on success and other status codes otherwise
-
-    Output (Globals):
-        immediate_remote_repo_version_${_repo}: the version of package `_name`
-                                in repo `_repo`
-
-    '
-    local _repo _name _version _rv
-
-    _repo=$1
-    _name=$2
-
-    _version=$(pkg rquery -U -r "${_repo}" '%v' "${_name}")
-    _rv=$?
-    eval immediate_remote_repo_version_${_repo}=\"\${_version}\"
-    return ${_rv}
-}
-
-assert_local_version() {
-    : 'Check whether an installed package `_name` has given
-    version `_version`.
-
-    Args:
-        _name:    the package name
-        _version: the version to check for
-
-    Input (Globals):
-        installed_data: the output of ``pkg query "%n %v %R"`` of all
-                        installed packages
-
-    Returns:
-        - 0 if the installed version of package `_name` is equal to `_version`
-        - 1 if the installed version of package `_name` differs from `_version`
-        - 2 on other errors
-
-    '
-    local _name _version _n _v _r
-
-    _name=$1
-    _version=$2
-
-    while read _n _v _r ; do
-        if [ ${_name} = ${_n} ] ; then
-            if [ ${_version} != ${_v} ] ; then
-                return 1
-            else
-                return 0
-            fi
-        fi
-    done <<EOF223
-${installed_data}
-EOF223
-    return 2
-}
-
-get_mapping() {
-    : 'Determine whether a package `_package` is essentially the same as
-    another package.
-
-    Args:
-        _package: the new name of the package
-
-    Returns:
-        0 when a package mapping has been found, 1 otherwise
-
-    Output (Globals):
-        mapped_package_name: the name of the package on which `_package` is
-                             based on
-
-    This command reads from the mapping database in in file
-    `/usr/local/etc/local-bsdtools/package-mapping.conf`.
-    Example::
-
-        #
-        # _package                         mapped_package_name
-        #
-        fmg-nextcloud-php71                nextcloud-php71
-        fmg-nextcloud-twofactor_totp-php71 nextcloud-twofactor_totp-php71
-
-    '
-    local _package _n _mapped
-
-    _package=$1
-
-    if [ -r "${PACKAGE_MAPPING}" ] ; then
-        while read _n _mapped ; do
-            if [ "${_n}" = "${_package}" ] ; then
-                mapped_package_name="${_mapped}"
-                return 0
-            fi
-        done < ${PACKAGE_MAPPING}
-    fi
-    mapped_package_name=""
-    return 1
-}
-
-print_title() {
-    : 'Print the output title line for a package
-
-    Args:
-        _package: the package name
-        _repo:    the repository name
-
-    Input (Globals).
-        title_printed: a global that determines if the title really needs
-                       to be printed.
-
-                       If it is an empty string the the title is
-                       really printed and the variable is set to
-                       "yes".
-
-    Output (Globals):
-        title_printed: set to "yes" if the title has been printed
-
-    '
-    local _package _repo
-
-    _package=$1
-    _repo=$2
-    if [ -z "${title_printed}" ] ; then
-        echo "${_package}    (${_repo})"
-        title_printed=yes
-    fi
-}
-
-
-alldata_flag=""
-alldata_flag_LocalBSDPorts=""
-alldata_flag_LocalRepo=""
-short_flag=""
-verbose_flag=""
-
-while getopts "VAasv" _opt ; do
-    case ${_opt} in
-	V)
-            echo "check-ports v${VERSION} (rv:@@HGREVISION@@)"
-            exit 0
-	    ;;
-        A)
-            # print for every package the status of all repositories
-            alldata_flag=1
-            alldata_flag_LocalBSDPorts=1
-            alldata_flag_LocalRepo=1
-            ;;
-        a)
-            # print the data of all repos that have the package
-            alldata_flag=1
-            ;;
-        s)
-            # "short" output: if installed from FreeBSD repo: don't
-            # report if only the index is newer
-            short_flag=1
-            ;;
-        v)
-            # print all titles and repo of every installed always
-            verbose_flag=1
-            ;;
-        \?)
-            exit 2
-            ;;
-        *)
-            echo "option handling failed" >&2
-            exit 2
-            ;;
-    esac
-done
-
-if [ -n "${short_flag}" -a -n "${alldata_flag}" ]; then
-    echo "the -s option cannot be combined with -A or -a" >&2
-    exit 2
-fi
-
-installed_packages=$(pkg query '%n')
-installed_data="$(pkg query '%n %v %R' $installed_packages)"
-
-get_remote_repo_versions ${LOCAL_REPO}
-get_remote_repo_versions ${LOCALBSDPORTS_REPO}
-get_remote_repo_versions ${FREEBSD_REPO}
-get_local_index_versions
-
-while read lfqp llabel ldescr ; do
-    _installed_name=${lfqp%-*}
-    _installed_version=${lfqp##*-}
-    title_printed=""
-    get_repo_for_installed_package ${_installed_name}
-    get_mapping ${_installed_name}
-    if [ -n "${verbose_flag}" ] ; then
-        print_title "${lfqp}" "${repository}"
-    fi
-    if ! assert_local_version ${_installed_name} ${_installed_version} ; then
-        echo "Assertion failed: $lfqp ${_installed_name} ${_installed_version} ${llabel}" >&2
-        exit 1
-    fi
-    get_remote_repo_data ${LOCAL_REPO} ${_installed_name}
-    get_remote_repo_data ${LOCALBSDPORTS_REPO} ${_installed_name}
-    get_remote_repo_data ${FREEBSD_REPO} ${_installed_name}
-    _print_detail=""
-    if [ -n "${mapped_package_name}" ] ; then
-        _print_detail=1
-    fi
-    if [ \( -n "${alldata_flag}" \) ]; then
-        _print_detail=1
-    else
-        if [ -n "${short_flag}" ]; then
-            #
-            # NOTE: -s and -A/-a are incompatible: so "alldata_XXX" needs not
-            #       to be checked!
-            #
-            case "${repository}" in
-                "${FREEBSD_REPO}")
-                    if [ \( "${llabel}" != '<' -a "${llabel}" != '=' \) -o "${remote_label_FreeBSD}" != '=' -o "${remote_label_LocalRepo}" != '?' -o "${remote_label_LocalBSDPorts}" != '?' ]; then
-                        _print_detail=1
-                    fi
-                    ;;
-                "${LOCAL_REPO}")
-                    _print_detail=1
-                    ;;
-                "${LOCALBSDPORTS_REPO}")
-                    if [ "${llabel}" != '=' -o "${remote_label_FreeBSD}" != '>' -o "${remote_label_LocalRepo}" != '?' -o "${remote_label_LocalBSDPorts}" = '?' -o "${remote_label_LocalBSDPorts}" = '<' ]; then
-                        _print_detail=1
-                    fi
-                    ;;
-                "${PORTS_DIRECT_INSTALLED_REPO}")
-                    _print_detail=1
-                    ;;
-                *)
-                    echo "ERROR: unhandled repository: ${repository}" >&2
-                    exit 1
-                    ;;
-            esac
-        else
-            if [ \( \( "${llabel}" != '?' -a "${llabel}" != '=' \) -o \( "${remote_label_FreeBSD}" != '?' -a "${remote_label_FreeBSD}" != '=' \) -o \( "${remote_label_LocalBSDPorts}" != '?' -a "${remote_label_LocalBSDPorts}" != '=' \) -o \( "${remote_label_LocalRepo}" != '?' -a "${remote_label_LocalRepo}" != '=' \) \) -o \( "${repository}" = "${PORTS_DIRECT_INSTALLED_REPO}" \) ]; then
-                _print_detail=1
-            fi
-        fi
-    fi
-    if [ -n "${_print_detail}" ]; then
-        print_title "${lfqp}" "${repository}"
-        echo "   INDEX        : ${llabel} ${ldescr}"
-        echo "   FreeBSD      : ${remote_label_FreeBSD} ${remote_descr_FreeBSD}"
-        if [ \( -n "${alldata_flag_LocalBSDPorts}" \) -o \( "${remote_label_LocalBSDPorts}" != '?' \) ] ; then
-            echo "   LocalBSDPorts: ${remote_label_LocalBSDPorts} ${remote_descr_LocalBSDPorts}"
-        fi
-        if [ \( -n "${alldata_flag_LocalRepo}" \) -o \( "${remote_label_LocalRepo}" != '?' \) ] ; then
-            echo "   LocalRepo    : ${remote_label_LocalRepo} ${remote_descr_LocalRepo}"
-        fi
-        if [ -n "${mapped_package_name}" ] ; then
-	    echo "   ---> ${mapped_package_name}"
-            get_immediate_index_version "${mapped_package_name}"
-	    get_immediate_remote_repo_version ${LOCAL_REPO} ${mapped_package_name}
-            get_immediate_remote_repo_version ${LOCALBSDPORTS_REPO} ${mapped_package_name}
-            get_immediate_remote_repo_version ${FREEBSD_REPO} ${mapped_package_name}
-            echo "      INDEX        : ${immediate_index_version}"
-            echo "      FreeBSD      : ${immediate_remote_repo_version_FreeBSD}"
-	    echo "      LocalBSDPorts: ${immediate_remote_repo_version_LocalBSDPorts}"
-	    echo "      LocalRepo    : ${immediate_remote_repo_version_LocalRepo}"
-        fi
-    fi
-done <<EOF856661111299999
-${local_index_versions}
-EOF856661111299999
--- a/bin/fjail	Wed Oct 16 08:56:32 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,304 +0,0 @@
-#!/bin/sh
-# -*- indent-tabs-mode: nil; -*-
-: 'A very minimal BSD Jail management tool.
-
-:Author:    Franz Glasner
-:Copyright: (c) 2019 Franz Glasner.
-            All rights reserved.
-:License:   BSD 3-Clause "New" or "Revised" License.
-            See LICENSE for details.
-            If you cannot find LICENSE see
-            <https://opensource.org/licenses/BSD-3-Clause>
-:ID:        @(#)@@PKGORIGIN@@ $HGid$
-
-'
-
-set -eu
-
-VERSION="@@VERSION@@"
-
-USAGE='
-USAGE: fjail [ OPTIONS ] COMMAND [ COMMAND OPTIONS ] [ ARG ... ]
-
-OPTIONS:
-
-  -V    Print the program name and version number to stdout and exit
-
-  -h    Print this help message to stdout and exit
-
-COMMANDS:
-
-  datasets [-u] PARENT CHILD
-
-    Create ZFS datasets to be used within a jail
-
-    PARENT must exist already and CHILD must not exist.
-
-    -u        Do not automatically mount newly created datasets
-
-  privs MOUNTPOINT
-
-    Adjust some Unix privileges to mounted jail datasets
-
-  populate MOUNTPOINT BASETXZ
-
-    Populate the jail directory in MOUNTPOINT with the base system in BASETXZ
-
-  copy SOURCE-DATASET DEST-DATASET
-
-    Copy a tree of ZFS datasets with "zfs send -R" and "zfs receive".
-    Note that the destination dataset must not exist already.
-
-    -u        Do not automatically mount received datasets
-
-ENVIRONMENT:
-
-  All environment variables that affect "zfs" are effective also.
-
-DESCRIPTION:
-
-  All commands with the exception of "populate" require ZFS as
-  filesystem.
-'
-
-
-# Reset to standard umask
-umask 0022
-
-
-#
-# "datasets" -- create the ZFS dataset tree
-#
-# command_datasets [ -u ] parent-dataset child-dataset
-#
-#    -u  do not automatically mount newly created datasets
-#
-command_datasets() {
-    # parent ZFS dataset -- child ZFS dataset name
-    local _pds _cds
-    # and its mount point
-    local _pmp _get _dummy
-    # full name of the dataset
-    local _ds
-    # dynamic ZFS options
-    local _zfsopts
-
-    _zfsopts=""
-    while getopts "u" _opt ; do
-        case ${_opt} in
-            u)
-                # do not mount newly created datasets
-                _zfsopts="${_zfsopts} -u"
-                ;;
-            \?|:)
-                return 2;
-                ;;
-        esac
-    done
-    shift $((OPTIND-1))
-    OPTIND=1
-
-    _pds="$1"
-    if [ -z "${_pds}" ]; then
-        echo "ERROR: no parent dataset given" >&2
-        return 2
-    fi
-    _get=$(zfs get -H mountpoint "${_pds}" 2>/dev/null) || { echo "ERROR: dataset \`${_pds}' does not exist" >&2; return 1; }
-    IFS=$'\t' read _dummy _dummy _pmp _dummy <<EOF
-${_get}
-EOF
-    case "${_pmp}" in
-        none)
-            echo "ERROR: dataset \`${_pds}' has no mountpoint" >&2
-            return 1
-            ;;
-        legacy)
-            echo "ERROR: dataset \`${_pds}' has a \`${_mp}' mountpoint" >&2
-            return 1
-            ;;
-        *)
-            # VOID
-            ;;
-    esac
-    _cds="$2"
-    if [ -z "${_cds}" ]; then
-        echo "ERROR: no child dataset given" >&2
-        return 2
-    fi
-    _ds="${_pds}/${_cds}"
-    echo "Resulting new root dataset is \`${_ds}' at mountpoint \`${_pmp}/${_cds}'"
-    if zfs get -H mountpoint "${_ds}" >/dev/null 2>/dev/null; then
-        echo "ERROR: dataset \`${_ds}' does already exist" >&2
-        return 1
-    fi
-    zfs create ${_zfsopts} -o atime=off                                                                      "${_ds}"
-    zfs create ${_zfsopts} -o sync=disabled -o setuid=off                                                    "${_ds}/tmp"
-    zfs create ${_zfsopts}                                                                                   "${_ds}/usr"
-    zfs create ${_zfsopts}                                                                                   "${_ds}/var"
-    zfs create ${_zfsopts} -o exec=off -o setuid=off                                                         "${_ds}/var/audit"
-    zfs create ${_zfsopts} -o exec=off -o setuid=off                                                         "${_ds}/var/cache"
-    zfs create ${_zfsopts} -o exec=off -o setuid=off -o compression=off                                      "${_ds}/var/cache/pkg"
-    zfs create ${_zfsopts} -o exec=off -o setuid=off -o compression=off                                      "${_ds}/var/crash"
-    zfs create ${_zfsopts} -o exec=off -o setuid=off                                                         "${_ds}/var/db"
-    zfs create ${_zfsopts} -o exec=on -o setuid=off                                                          "${_ds}/var/db/pkg"
-    zfs create ${_zfsopts} -o readonly=on -o exec=off -o setuid=off                                          "${_ds}/var/empty"
-    zfs create ${_zfsopts} -o exec=off -o setuid=off -o primarycache=metadata                                "${_ds}/var/log"
-    zfs create ${_zfsopts} -o exec=off -o setuid=off -o atime=on                                             "${_ds}/var/mail"
-    zfs create ${_zfsopts} -o sync=disabled -o exec=off -o setuid=off -o compression=off -o primarycache=all "${_ds}/var/run"
-    zfs create ${_zfsopts} -o sync=disabled -o setuid=off                                                    "${_ds}/var/tmp"
-}
-
-
-#
-# "populate" -- populate the datasets with content from a FreeBSD base.txz
-#
-# command_populate mountpoint basetxz
-#
-command_populate() {
-    # MOUNTPOINT -- base.txz
-    local _mp _basetxz
-
-    _mp="$1"
-    _basetxz="$2"
-
-    if [ -z "${_mp}" ]; then
-        echo "ERROR: no mountpoint given" >&2
-        return 2
-    fi
-    if [ -z "${_basetxz}" ]; then
-        echo "ERROR: no base.txz given" >&2
-        return 2
-    fi
-    if [ ! -d "${_mp}" ]; then
-        echo "ERROR: mountpoint \`${_mp}' does not exist" >&2
-        return 1
-    fi
-    if [ ! -r "${_basetxz}" ]; then
-        echo "ERROR: file \`${_basetxz}' is not readable" >&2
-        return 1
-    fi
-
-    tar -C "${_mp}" --exclude=./var/empty -xJp -f "${_basetxz}" || { echo "ERROR: tar encountered errors" >&2; return 1; }
-}
-
-
-#
-# "copy" -- ZFS copy of datasets
-#
-# command_copy source-dataset destination-dataset
-#
-command_copy() {
-    # source dataset -- destination dataset
-    local _source _dest
-    # dynamic ZFS options
-    local _zfsopts
-
-    _zfsopts=""
-    while getopts "u" _opt ; do
-        case ${_opt} in
-            u)
-                # do not mount newly created datasets
-                _zfsopts="${_zfsopts} -u"
-                ;;
-            \?|:)
-                return 2;
-                ;;
-        esac
-    done
-    shift $((OPTIND-1))
-    OPTIND=1
-
-    _source="$1"
-    if [ -z "${_source}" ]; then
-        echo "ERROR: no source dataset given" >&2
-        return 2
-    fi
-    _dest="$2"
-    if [ -z "${_dest}" ]; then
-        echo "ERROR: no source dataset given" >&2
-        return 2
-    fi
-    zfs send -R -n -v ${_source} || { echo "ERROR: ZFS operation failed in no-op mode" >&2; return 1; }
-    zfs send -R "${_source}" | zfs receive ${_zfsopts} "${_dest}"  || { echo "ERROR: ZFS operation failed" >&2; return 1; }
-}
-
-
-#
-# "privs" -- adjust privileges
-#
-# To be used when all ZFS datasets are mounted.
-#
-command_privs() {
-    # mountpoint
-    local _mp _d
-
-    _mp="$1"
-    if [ -z "${_mp}" ]; then
-        echo "ERROR: no mountpoint given" >&2
-        return 2
-    fi
-    if [ ! -d "${_mp}" ]; then
-        echo "ERROR: directory \`${_mp}' does not exist" >&2
-        return 1
-    fi
-    for _d in tmp var/tmp ; do
-       chmod 01777 "${_mp}/${_d}"
-    done
-    chown root:mail "${_mp}/var/mail"
-    chmod 0775 "${_mp}/var/mail"
-}
-
-
-#
-# Global option handling
-#
-while getopts "Vh" _opt ; do
-    case ${_opt} in
-        V)
-            echo "fjail v${VERSION} (rv:@@HGREVISION@@)"
-            exit 0
-            ;;
-        h)
-            echo "${USAGE}"
-            exit 0
-            ;;
-        \?)
-            exit 2;
-            ;;
-        *)
-            echo "ERROR: option handling failed" >&2
-            exit 2
-            ;;
-    esac
-done
-
-#
-# Reset the Shell's option handling system to prepare for handling
-# command-local options.
-#
-shift $((OPTIND-1))
-OPTIND=1
-
-test $# -gt 0 || { echo "ERROR: no command given" >&2; exit 2; }
-
-command="$1"
-shift
-
-case "${command}" in
-    datasets)
-        command_datasets "$@"
-        ;;
-    privs)
-        command_privs "$@"
-        ;;
-    populate)
-        command_populate "$@"
-        ;;
-    copy)
-        command_copy "$@"
-        ;;
-    *)
-        echo "ERROR: unknown command \`${command}'" >&2
-        exit 2
-        ;;
-esac
--- a/bin/fpkg	Wed Oct 16 08:56:32 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,293 +0,0 @@
-#!/bin/sh
-# -*- indent-tabs-mode: nil; -*-
-: 'A pkg frontend for common operations that also operates in all
-running jails.
-
-:Author:    Franz Glasner
-:Copyright: (c) 2019 Franz Glasner.
-            All rights reserved.
-:License:   BSD 3-Clause "New" or "Revised" License.
-            See LICENSE for details.
-            If you cannot find LICENSE see
-            <https://opensource.org/licenses/BSD-3-Clause>
-:ID:        @(#)@@PKGORIGIN@@ $HGid$
-
-'
-
-VERSION="@@VERSION@@"
-
-USAGE='
-USAGE: fpkg [ OPTIONS] COMMAND [ COMMAND-OPTIONS ]
-
-OPTIONS:
-
-  -V    Print the program name and version number to stdout and exit
-
-  -h    Print this help message to stdout and exit
-
-COMMANDS:
-
-  audit
-
-    `pkg audit` on the local host and all running visible jails
-
-  update
-
-    `pkg update` on the local host and all running visible jails
-
-  upgrade
-
-    `pkg upgrade` on the local host and all running visible jails
-
-  upgrade-check
-
-    `pkg upgrade -n` on the local host and all running visible jails
-
-  check-fast-track
-    Check packages installed from the LocalBSDPorts repository against
-    the repositories `FreeBSD` and `LocalBSDPorts` on the local host
-    and all visible jails
-     
-
-ENVIRONMENT:
-
-  FPKG_AUDIT_FLAGS
-                 Additional flags given to `pkg audit`
-                 (Default: -Fr)
-
-  FPKG_UPDATE_FLAGS
-                 Additional flags given to `pkg update`
-                 (Default: empty)
-
-  FPKG_UPGRADE_FLAGS
-                 Additional flags given to `pkg upgrade` and `pkg upgrade -n`
-                 (Default: empty)
-
-  FPKG_SIGN
-                 Marker for the begin of an output group (local host or jail)
-                 (Default: "===> ")
-
-  FPKG_SKIPSIGN
-                 Marker for the begin of a skipped output group
-                 (Default: "----> ")
-
-  All other environment variables that affect `pkg` are effective also.
-'
-
-#
-# Configuration directory
-#
-: ${CONFIGDIR:=@@ETCDIR@@}
-
-test -r "${CONFIGDIR}/tools.conf" && . "${CONFIGDIR}/tools.conf"
-
-: ${FPKG_AUDIT_FLAGS:=-Fr}
-: ${FPKG_UPDATE_FLAGS:=}
-: ${FPKG_UPGRADE_FLAGS:=}
-: ${FPKG_SIGN:='===> '}
-: ${FPKG_SKIPSIGN:='----> '}
-
-#
-# The official FreeBSD binary repository
-#
-: ${FREEBSD_REPO:=FreeBSD}
-
-#
-# Local repository with ports with default OPTIONS (i.e. unchanged)
-# but newer than the packages in the "FreeBSD" repository.
-# Some sort of a fast-track repository.
-#
-: ${LOCALBSDPORTS_REPO:=LocalBSDPorts}
-
-
-has_same_userland_version() {
-    : 'Check whether the jail `_jail` has the same FreeBSD userland version
-    as the host the the current process runs.
-
-    Args:
-        _jail: the running jail to check for
-
-    Returns:
-        0 if the userland versions match, 1 otherwise
-
-    '
-    local _jail _host_version _jail_version
-
-    _jail="$1"
-
-    _host_version=$(/bin/freebsd-version -u) || exit 1
-    _jail_version=$(jexec -l "${_jail}" /bin/freebsd-version -u) || exit 1
-    if [ "${_host_version%%-*}" = "${_jail_version%%-*}" ]; then
-        return 0
-    fi
-    return 1
-}
-
-
-command_audit() {
-    : 'Do a local `pkg audit -Fr` and also for all running jails
-
-    '
-    echo "${FPKG_SIGN}LOCALHOST"
-    pkg audit ${FPKG_AUDIT_FLAGS}
-    for _j in $(jls -N | awk '{if(NR>1)print $1}' | sort); do
-        echo ""
-        echo "${FPKG_SIGN}JAIL: ${_j}"
-        if has_same_userland_version "${_j}"; then
-            pkg -j "${_j}" audit ${FPKG_AUDIT_FLAGS}
-        else
-            echo "${FPKG_SKIPSIGN}SKIPPED because of different userland"
-        fi
-    done
-}
-
-
-command_update() {
-    : 'Do a local `pkg update` and also for all running jails
-
-    '
-    echo "${FPKG_SIGN}LOCALHOST"
-    pkg update ${FPKG_UPDATE_FLAGS}
-    for _j in $(jls -N | awk '{if(NR>1)print $1}' | sort); do
-        echo ""
-        echo "${FPKG_SIGN}JAIL: ${_j}"
-        if has_same_userland_version "${_j}"; then
-            pkg -j "${_j}" update ${FPKG_UPDATE_FLAGS}
-        else
-            echo "${FPKG_SKIPSIGN}SKIPPED because of different userland"
-        fi
-    done
-}
-
-
-command_upgrade() {
-    : 'Do a local `pkg upgrade` and also for all running jails
-
-    '
-    echo "${FPKG_SIGN}LOCALHOST"
-    pkg upgrade ${FPKG_UPGRADE_FLAGS}
-    for _j in $(jls -N | awk '{if(NR>1)print $1}' | sort); do
-        echo ""
-        echo "${FPKG_SIGN}JAIL: ${_j}"
-        if has_same_userland_version "${_j}"; then
-            pkg -j "${_j}" upgrade ${FPKG_UPGRADE_FLAGS}
-        else
-            echo "${FPKG_SKIPSIGN}SKIPPED because of different userland"
-        fi
-    done
-}
-
-
-command_upgrade_check() {
-    : 'Do a local `pkg upgrade -n` and also for all running jails
-
-    '
-    echo "${FPKG_SIGN}LOCALHOST"
-    pkg upgrade -n ${FPKG_UPGRADE_FLAGS}
-    for _j in $(jls -N | awk '{if(NR>1)print $1}' | sort); do
-        echo ""
-        echo "${FPKG_SIGN}JAIL: ${_j}"
-        if has_same_userland_version "${_j}"; then
-            pkg -j "${_j}" upgrade -n ${FPKG_UPGRADE_FLAGS}
-        else
-            echo "${FPKG_SKIPSIGN}SKIPPED because of different userland"
-        fi
-    done
-}
-
-
-command_check_fasttrack() {
-    : 'Check the fast-track repository versions against the canonical
-    FreeBSD repository versions.
-
-    Input (Globals):
-        FREEBSD_REPO:       the (canonical) FreeBSD repository name
-        LOCALBSDPORTS_REPO: the fast-track repository name
-
-    '
-    local _name local _repo _j
-
-    echo "${FPKG_SIGN}LOCALHOST"
-    pkg query '%n %R' |
-        while read _name _repo; do
-            if [ "${_repo}" = "${LOCALBSDPORTS_REPO}" ]; then
-                echo "   ${_name}"
-                printf "      %-15s : %s\n" "${LOCALBSDPORTS_REPO}" "$(pkg version -U -r ${LOCALBSDPORTS_REPO} -n ${_name} -v)"
-                printf "      %-15s : %s\n" "${FREEBSD_REPO}" "$(pkg version -U -r ${FREEBSD_REPO} -n ${_name} -v)"
-            fi
-        done
-    for _j in $(jls -N | awk '{if(NR>1)print $1}' | sort); do
-        echo ""
-        echo "${FPKG_SIGN}JAIL: ${_j}"
-        if has_same_userland_version "${_j}"; then
-            pkg -j "${_j}" query '%n %R' |
-                while read _name _repo; do
-                    if [ "${_repo}" = "${LOCALBSDPORTS_REPO}" ]; then
-                        echo "   ${_name}"
-                        printf "      %s-15s : %s\n" "${LOCALBSDPORTS_REPO}" "$(pkg -j ${_j} version -U -r ${LOCALBSDPORTS_REPO} -n ${_name} -v)"
-                        printf "      %-15s : %s\n" "${FREEBSD_REPO}" "$(pkg -j ${_j} version -U -r ${FREEBSD_REPO} -n ${_name} -v)"
-            fi
-                done
-        else
-            echo "${FPKG_SKIPSIGN}SKIPPED because of different userland"
-        fi
-    done
-}
-
-
-#
-# Global option handling
-#
-while getopts "Vh" _opt ; do
-    case ${_opt} in
-        V)
-            echo "fpkg v${VERSION} (rv:@@HGREVISION@@)"
-            exit 0
-            ;;
-        h)
-            echo "${USAGE}"
-            exit 0
-            ;;
-        \?)
-            exit 2;
-            ;;
-        *)
-            echo "ERROR: option handling failed" >&2
-            exit 2
-            ;;
-    esac
-done
-
-#
-# Reset the Shell's option handling system to prepare for handling
-# command-local options.
-#
-shift $((OPTIND-1))
-OPTIND=1
-
-command="$1"
-shift
-
-test -n "$command" || { echo "ERROR: no command given" >&2; exit 2; }
-
-case "${command}" in
-    audit)
-        command_audit "$@"
-        ;;
-    update)
-        command_update "$@"
-        ;;
-    upgrade)
-        command_upgrade "$@"
-        ;;
-    upgrade-check|upgrade_check)
-        command_upgrade_check "$@"
-        ;;
-    check-fast-track|check-fasttrack|check_fast_track|check_fasttrack)
-        command_check_fasttrack "$@"
-        ;;
-    *)
-        echo "ERROR: unknown command \`${command}'" >&2
-        exit 2;
-        ;;
-esac
--- a/pkg-plist	Wed Oct 16 08:56:32 2019 +0200
+++ b/pkg-plist	Thu Oct 17 09:09:13 2019 +0200
@@ -1,10 +1,10 @@
 @comment DIRECTORIES
 @dir %%ETCDIR%%
 @comment FILES
-bin/check-ports
-bin/fjail
-bin/fpkg
 sbin/bsmtp2dma
+sbin/check-ports
+sbin/fjail
+sbin/fpkg
 @sample %%ETCDIR%%/tools.conf.sample
 @sample %%ETCDIR%%/package-mapping.conf.sample
 @sample %%ETCDIR%%/bsmtp2dma.conf.sample
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sbin/check-ports	Thu Oct 17 09:09:13 2019 +0200
@@ -0,0 +1,501 @@
+#!/bin/sh
+# -*- indent-tabs-mode: nil; -*-
+: 'Check the version status of installed ports and compare them to
+repository versions.
+
+:Author:    Franz Glasner
+:Copyright: (c) 2017-2019 Franz Glasner.
+            All rights reserved.
+:License:   BSD 3-Clause "New" or "Revised" License.
+            See LICENSE for details.
+            If you cannot find LICENSE see
+            <https://opensource.org/licenses/BSD-3-Clause>
+:ID:        @(#)@@PKGORIGIN@@ $HGid$
+
+'
+
+VERSION="@@VERSION@@"
+
+#
+# Configuration directory
+#
+: ${CONFIGDIR:=@@ETCDIR@@}
+
+test -r "${CONFIGDIR}/tools.conf" && . "${CONFIGDIR}/tools.conf"
+
+#
+# Mapping configuration: installed package name -> original package name
+# Note: This is independent of any repo
+#
+: ${PACKAGE_MAPPING:=${CONFIGDIR}/package-mapping.conf}
+
+#
+# Local repository with non-public packages and/or ports with changed
+# OPTIONS (i.e. not using the defaults) or forks of official packages with
+# other package names
+#
+: ${LOCAL_REPO:=LocalRepo}
+
+#
+# Local repository with ports with default OPTIONS (i.e. unchanged)
+# but newer than the packages in the "FreeBSD" repository.
+# Some sort of a fast-track repository.
+#
+: ${LOCALBSDPORTS_REPO:=LocalBSDPorts}
+
+#
+# The official FreeBSD binary repository
+#
+: ${FREEBSD_REPO:=FreeBSD}
+
+#
+# Directly installed from ports
+#
+: ${PORTS_DIRECT_INSTALLED_REPO:=unknown-repository}
+
+#
+# For the workaround of the bug in pkg rquery -I
+#
+: ${PORTSDIR:=/usr/ports}
+: ${INDEXDIR:=${PORTSDIR}}
+: ${INDEXFILE:=@@INDEXFILE@@}
+
+
+get_remote_repo_versions() {
+    : 'Determine the remote repository versions of all packages in
+    repository `_repo`.
+
+    Args:
+        _repo: the name of the repote repository
+
+    Returns:
+        status 0 on success, 1 on errors
+
+    Output (Globals):
+        remote_versions_${_repo}: the versions of all packages in `_repo` and
+                                  their extended version status with respect to
+                                  locally installed packages
+
+    '
+    local _repo _data _rv
+
+    _repo=$1
+
+    _data=$(pkg version -U -R -r ${_repo} -v)
+    _rv=$?
+    eval remote_versions_${_repo}=\"\${_data}\"
+    return ${_rv}
+}
+
+get_remote_repo_data() {
+    : 'Get the extended package version information from the remote repository
+    `_repo` for package `_name`.
+
+    Args:
+        _repo: the name of the remote repository
+        _name: the package name
+
+    Input (Globals):
+        remote_versions_${_repo}: the extended version info for *all* packages
+                                  in repo `_repo`.
+
+    Returns:
+        status 0 on success, 1 on errors or if the package is not found
+        in the remote repository
+
+    Output (Globals):
+        remote_label_${_repo}:
+        remote_descr_${_repo}:
+
+    '
+    local _repo _name _rversions _rfqp _rl _rdescr
+
+    _repo=$1
+    _name=$2
+
+    eval _rversions=\"\${remote_versions_${_repo}}\"
+    while read _rfqp _rl _rdescr ; do
+        if [ ${_rfqp%-*} = ${_name} ] ; then
+            eval remote_label_${_repo}=\"\${_rl}\"
+            eval remote_descr_${_repo}=\"\${_rdescr}\"
+            return 0
+        fi
+    done <<EOF884657
+${_rversions}
+EOF884657
+    eval remote_label_${_repo}=""
+    eval remote_descr_${_repo}=""
+    return 1
+}
+
+get_local_index_versions() {
+    : 'Determine the extendes versions of all packages in the local index
+    (ports).
+
+    Returns:
+        status 0 on success or 1 on errors
+
+    Output (Globals):
+        local_index_versions:
+
+    '
+    local_index_versions=$(pkg version -I -v)
+}
+
+get_repo_for_installed_package() {
+    : 'Determine for a package `_name` from which repository is has been
+    installed.
+
+    Args:
+        _name: the name of the package to search for
+
+    Input (Globals):
+        installed_data  the output of ``pkg query "%n %v %R"`` of all
+                        installed packages
+
+    Returns:
+        0 on success, 1 on errors or if the package is not installed
+
+    Output (Globals):
+        repository: the repository from which the installed packages `_name`
+                    has been installed
+
+    '
+    local _name _n _v _r
+
+    _name=$1
+
+    while read _n _v _r ; do
+        if [ ${_name} = ${_n} ] ; then
+            repository=${_r}
+            return 0
+        fi
+    done <<EOF223777
+${installed_data}
+EOF223777
+    return 1
+}
+
+get_immediate_index_version() {
+    : 'Determine for package `_package` the version of the package in the
+    local ports index.
+
+    Args:
+        _package: the package name to search for
+
+    Input (Globals):
+        INDEXDIR:  the directory where to search the index file
+        INDEXFILE: the name of the index file
+
+    Returns:
+        0 on success, 1 on errors or if the package is not in the index
+
+    Output (Globals):
+        immediate_index_version: the version number of `_package` in the
+                                 index
+
+    '
+    local _package _line _fqpn _n _lines
+
+    _package=$1
+
+#    _val=$(pkg rquery -I "${_package}" | cut -f 1 -d '|')
+#    _rv=$?
+#    immediate_index_version=${_val##*-}
+#    return ${_rv}
+
+    if [ -r "${INDEXDIR}/${INDEXFILE}" ] ; then
+        #
+        # Note: Direct piping does not set immediate_index_version at return correctly
+        #       "_line" is set correctly and parsing works, but the return 0 seems to kill
+        #       some of the previous effects.
+        #
+        # "grep" does a fast pre-selection, reading, parsing and comparing is done for
+        # exact matching.
+        #
+        _lines=$(egrep '^'"${_package}" "${INDEXDIR}/${INDEXFILE}")
+        while read _line ; do
+            _fqpn="${_line%%|*}"
+            _n=${_fqpn%-*}
+	    if [ "${_package}" = "${_n}" ] ; then
+                immediate_index_version="${_fqpn##*-}"
+                return 0
+            fi
+        done <<EOF1334TGH1
+${_lines}
+EOF1334TGH1
+    fi
+
+    immediate_index_version=""
+    return 1
+}
+
+get_immediate_remote_repo_version() {
+    : 'Ask a remote repository for the version of a package.
+
+    Args:
+        _repo: the repository name
+        _name: the name of the package
+
+    Returns:
+        0 on success and other status codes otherwise
+
+    Output (Globals):
+        immediate_remote_repo_version_${_repo}: the version of package `_name`
+                                in repo `_repo`
+
+    '
+    local _repo _name _version _rv
+
+    _repo=$1
+    _name=$2
+
+    _version=$(pkg rquery -U -r "${_repo}" '%v' "${_name}")
+    _rv=$?
+    eval immediate_remote_repo_version_${_repo}=\"\${_version}\"
+    return ${_rv}
+}
+
+assert_local_version() {
+    : 'Check whether an installed package `_name` has given
+    version `_version`.
+
+    Args:
+        _name:    the package name
+        _version: the version to check for
+
+    Input (Globals):
+        installed_data: the output of ``pkg query "%n %v %R"`` of all
+                        installed packages
+
+    Returns:
+        - 0 if the installed version of package `_name` is equal to `_version`
+        - 1 if the installed version of package `_name` differs from `_version`
+        - 2 on other errors
+
+    '
+    local _name _version _n _v _r
+
+    _name=$1
+    _version=$2
+
+    while read _n _v _r ; do
+        if [ ${_name} = ${_n} ] ; then
+            if [ ${_version} != ${_v} ] ; then
+                return 1
+            else
+                return 0
+            fi
+        fi
+    done <<EOF223
+${installed_data}
+EOF223
+    return 2
+}
+
+get_mapping() {
+    : 'Determine whether a package `_package` is essentially the same as
+    another package.
+
+    Args:
+        _package: the new name of the package
+
+    Returns:
+        0 when a package mapping has been found, 1 otherwise
+
+    Output (Globals):
+        mapped_package_name: the name of the package on which `_package` is
+                             based on
+
+    This command reads from the mapping database in in file
+    `/usr/local/etc/local-bsdtools/package-mapping.conf`.
+    Example::
+
+        #
+        # _package                         mapped_package_name
+        #
+        fmg-nextcloud-php71                nextcloud-php71
+        fmg-nextcloud-twofactor_totp-php71 nextcloud-twofactor_totp-php71
+
+    '
+    local _package _n _mapped
+
+    _package=$1
+
+    if [ -r "${PACKAGE_MAPPING}" ] ; then
+        while read _n _mapped ; do
+            if [ "${_n}" = "${_package}" ] ; then
+                mapped_package_name="${_mapped}"
+                return 0
+            fi
+        done < ${PACKAGE_MAPPING}
+    fi
+    mapped_package_name=""
+    return 1
+}
+
+print_title() {
+    : 'Print the output title line for a package
+
+    Args:
+        _package: the package name
+        _repo:    the repository name
+
+    Input (Globals).
+        title_printed: a global that determines if the title really needs
+                       to be printed.
+
+                       If it is an empty string the the title is
+                       really printed and the variable is set to
+                       "yes".
+
+    Output (Globals):
+        title_printed: set to "yes" if the title has been printed
+
+    '
+    local _package _repo
+
+    _package=$1
+    _repo=$2
+    if [ -z "${title_printed}" ] ; then
+        echo "${_package}    (${_repo})"
+        title_printed=yes
+    fi
+}
+
+
+alldata_flag=""
+alldata_flag_LocalBSDPorts=""
+alldata_flag_LocalRepo=""
+short_flag=""
+verbose_flag=""
+
+while getopts "VAasv" _opt ; do
+    case ${_opt} in
+	V)
+            echo "check-ports v${VERSION} (rv:@@HGREVISION@@)"
+            exit 0
+	    ;;
+        A)
+            # print for every package the status of all repositories
+            alldata_flag=1
+            alldata_flag_LocalBSDPorts=1
+            alldata_flag_LocalRepo=1
+            ;;
+        a)
+            # print the data of all repos that have the package
+            alldata_flag=1
+            ;;
+        s)
+            # "short" output: if installed from FreeBSD repo: don't
+            # report if only the index is newer
+            short_flag=1
+            ;;
+        v)
+            # print all titles and repo of every installed always
+            verbose_flag=1
+            ;;
+        \?)
+            exit 2
+            ;;
+        *)
+            echo "option handling failed" >&2
+            exit 2
+            ;;
+    esac
+done
+
+if [ -n "${short_flag}" -a -n "${alldata_flag}" ]; then
+    echo "the -s option cannot be combined with -A or -a" >&2
+    exit 2
+fi
+
+installed_packages=$(pkg query '%n')
+installed_data="$(pkg query '%n %v %R' $installed_packages)"
+
+get_remote_repo_versions ${LOCAL_REPO}
+get_remote_repo_versions ${LOCALBSDPORTS_REPO}
+get_remote_repo_versions ${FREEBSD_REPO}
+get_local_index_versions
+
+while read lfqp llabel ldescr ; do
+    _installed_name=${lfqp%-*}
+    _installed_version=${lfqp##*-}
+    title_printed=""
+    get_repo_for_installed_package ${_installed_name}
+    get_mapping ${_installed_name}
+    if [ -n "${verbose_flag}" ] ; then
+        print_title "${lfqp}" "${repository}"
+    fi
+    if ! assert_local_version ${_installed_name} ${_installed_version} ; then
+        echo "Assertion failed: $lfqp ${_installed_name} ${_installed_version} ${llabel}" >&2
+        exit 1
+    fi
+    get_remote_repo_data ${LOCAL_REPO} ${_installed_name}
+    get_remote_repo_data ${LOCALBSDPORTS_REPO} ${_installed_name}
+    get_remote_repo_data ${FREEBSD_REPO} ${_installed_name}
+    _print_detail=""
+    if [ -n "${mapped_package_name}" ] ; then
+        _print_detail=1
+    fi
+    if [ \( -n "${alldata_flag}" \) ]; then
+        _print_detail=1
+    else
+        if [ -n "${short_flag}" ]; then
+            #
+            # NOTE: -s and -A/-a are incompatible: so "alldata_XXX" needs not
+            #       to be checked!
+            #
+            case "${repository}" in
+                "${FREEBSD_REPO}")
+                    if [ \( "${llabel}" != '<' -a "${llabel}" != '=' \) -o "${remote_label_FreeBSD}" != '=' -o "${remote_label_LocalRepo}" != '?' -o "${remote_label_LocalBSDPorts}" != '?' ]; then
+                        _print_detail=1
+                    fi
+                    ;;
+                "${LOCAL_REPO}")
+                    _print_detail=1
+                    ;;
+                "${LOCALBSDPORTS_REPO}")
+                    if [ "${llabel}" != '=' -o "${remote_label_FreeBSD}" != '>' -o "${remote_label_LocalRepo}" != '?' -o "${remote_label_LocalBSDPorts}" = '?' -o "${remote_label_LocalBSDPorts}" = '<' ]; then
+                        _print_detail=1
+                    fi
+                    ;;
+                "${PORTS_DIRECT_INSTALLED_REPO}")
+                    _print_detail=1
+                    ;;
+                *)
+                    echo "ERROR: unhandled repository: ${repository}" >&2
+                    exit 1
+                    ;;
+            esac
+        else
+            if [ \( \( "${llabel}" != '?' -a "${llabel}" != '=' \) -o \( "${remote_label_FreeBSD}" != '?' -a "${remote_label_FreeBSD}" != '=' \) -o \( "${remote_label_LocalBSDPorts}" != '?' -a "${remote_label_LocalBSDPorts}" != '=' \) -o \( "${remote_label_LocalRepo}" != '?' -a "${remote_label_LocalRepo}" != '=' \) \) -o \( "${repository}" = "${PORTS_DIRECT_INSTALLED_REPO}" \) ]; then
+                _print_detail=1
+            fi
+        fi
+    fi
+    if [ -n "${_print_detail}" ]; then
+        print_title "${lfqp}" "${repository}"
+        echo "   INDEX        : ${llabel} ${ldescr}"
+        echo "   FreeBSD      : ${remote_label_FreeBSD} ${remote_descr_FreeBSD}"
+        if [ \( -n "${alldata_flag_LocalBSDPorts}" \) -o \( "${remote_label_LocalBSDPorts}" != '?' \) ] ; then
+            echo "   LocalBSDPorts: ${remote_label_LocalBSDPorts} ${remote_descr_LocalBSDPorts}"
+        fi
+        if [ \( -n "${alldata_flag_LocalRepo}" \) -o \( "${remote_label_LocalRepo}" != '?' \) ] ; then
+            echo "   LocalRepo    : ${remote_label_LocalRepo} ${remote_descr_LocalRepo}"
+        fi
+        if [ -n "${mapped_package_name}" ] ; then
+	    echo "   ---> ${mapped_package_name}"
+            get_immediate_index_version "${mapped_package_name}"
+	    get_immediate_remote_repo_version ${LOCAL_REPO} ${mapped_package_name}
+            get_immediate_remote_repo_version ${LOCALBSDPORTS_REPO} ${mapped_package_name}
+            get_immediate_remote_repo_version ${FREEBSD_REPO} ${mapped_package_name}
+            echo "      INDEX        : ${immediate_index_version}"
+            echo "      FreeBSD      : ${immediate_remote_repo_version_FreeBSD}"
+	    echo "      LocalBSDPorts: ${immediate_remote_repo_version_LocalBSDPorts}"
+	    echo "      LocalRepo    : ${immediate_remote_repo_version_LocalRepo}"
+        fi
+    fi
+done <<EOF856661111299999
+${local_index_versions}
+EOF856661111299999
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sbin/fjail	Thu Oct 17 09:09:13 2019 +0200
@@ -0,0 +1,304 @@
+#!/bin/sh
+# -*- indent-tabs-mode: nil; -*-
+: 'A very minimal BSD Jail management tool.
+
+:Author:    Franz Glasner
+:Copyright: (c) 2019 Franz Glasner.
+            All rights reserved.
+:License:   BSD 3-Clause "New" or "Revised" License.
+            See LICENSE for details.
+            If you cannot find LICENSE see
+            <https://opensource.org/licenses/BSD-3-Clause>
+:ID:        @(#)@@PKGORIGIN@@ $HGid$
+
+'
+
+set -eu
+
+VERSION="@@VERSION@@"
+
+USAGE='
+USAGE: fjail [ OPTIONS ] COMMAND [ COMMAND OPTIONS ] [ ARG ... ]
+
+OPTIONS:
+
+  -V    Print the program name and version number to stdout and exit
+
+  -h    Print this help message to stdout and exit
+
+COMMANDS:
+
+  datasets [-u] PARENT CHILD
+
+    Create ZFS datasets to be used within a jail
+
+    PARENT must exist already and CHILD must not exist.
+
+    -u        Do not automatically mount newly created datasets
+
+  privs MOUNTPOINT
+
+    Adjust some Unix privileges to mounted jail datasets
+
+  populate MOUNTPOINT BASETXZ
+
+    Populate the jail directory in MOUNTPOINT with the base system in BASETXZ
+
+  copy SOURCE-DATASET DEST-DATASET
+
+    Copy a tree of ZFS datasets with "zfs send -R" and "zfs receive".
+    Note that the destination dataset must not exist already.
+
+    -u        Do not automatically mount received datasets
+
+ENVIRONMENT:
+
+  All environment variables that affect "zfs" are effective also.
+
+DESCRIPTION:
+
+  All commands with the exception of "populate" require ZFS as
+  filesystem.
+'
+
+
+# Reset to standard umask
+umask 0022
+
+
+#
+# "datasets" -- create the ZFS dataset tree
+#
+# command_datasets [ -u ] parent-dataset child-dataset
+#
+#    -u  do not automatically mount newly created datasets
+#
+command_datasets() {
+    # parent ZFS dataset -- child ZFS dataset name
+    local _pds _cds
+    # and its mount point
+    local _pmp _get _dummy
+    # full name of the dataset
+    local _ds
+    # dynamic ZFS options
+    local _zfsopts
+
+    _zfsopts=""
+    while getopts "u" _opt ; do
+        case ${_opt} in
+            u)
+                # do not mount newly created datasets
+                _zfsopts="${_zfsopts} -u"
+                ;;
+            \?|:)
+                return 2;
+                ;;
+        esac
+    done
+    shift $((OPTIND-1))
+    OPTIND=1
+
+    _pds="$1"
+    if [ -z "${_pds}" ]; then
+        echo "ERROR: no parent dataset given" >&2
+        return 2
+    fi
+    _get=$(zfs get -H mountpoint "${_pds}" 2>/dev/null) || { echo "ERROR: dataset \`${_pds}' does not exist" >&2; return 1; }
+    IFS=$'\t' read _dummy _dummy _pmp _dummy <<EOF
+${_get}
+EOF
+    case "${_pmp}" in
+        none)
+            echo "ERROR: dataset \`${_pds}' has no mountpoint" >&2
+            return 1
+            ;;
+        legacy)
+            echo "ERROR: dataset \`${_pds}' has a \`${_mp}' mountpoint" >&2
+            return 1
+            ;;
+        *)
+            # VOID
+            ;;
+    esac
+    _cds="$2"
+    if [ -z "${_cds}" ]; then
+        echo "ERROR: no child dataset given" >&2
+        return 2
+    fi
+    _ds="${_pds}/${_cds}"
+    echo "Resulting new root dataset is \`${_ds}' at mountpoint \`${_pmp}/${_cds}'"
+    if zfs get -H mountpoint "${_ds}" >/dev/null 2>/dev/null; then
+        echo "ERROR: dataset \`${_ds}' does already exist" >&2
+        return 1
+    fi
+    zfs create ${_zfsopts} -o atime=off                                                                      "${_ds}"
+    zfs create ${_zfsopts} -o sync=disabled -o setuid=off                                                    "${_ds}/tmp"
+    zfs create ${_zfsopts}                                                                                   "${_ds}/usr"
+    zfs create ${_zfsopts}                                                                                   "${_ds}/var"
+    zfs create ${_zfsopts} -o exec=off -o setuid=off                                                         "${_ds}/var/audit"
+    zfs create ${_zfsopts} -o exec=off -o setuid=off                                                         "${_ds}/var/cache"
+    zfs create ${_zfsopts} -o exec=off -o setuid=off -o compression=off                                      "${_ds}/var/cache/pkg"
+    zfs create ${_zfsopts} -o exec=off -o setuid=off -o compression=off                                      "${_ds}/var/crash"
+    zfs create ${_zfsopts} -o exec=off -o setuid=off                                                         "${_ds}/var/db"
+    zfs create ${_zfsopts} -o exec=on -o setuid=off                                                          "${_ds}/var/db/pkg"
+    zfs create ${_zfsopts} -o readonly=on -o exec=off -o setuid=off                                          "${_ds}/var/empty"
+    zfs create ${_zfsopts} -o exec=off -o setuid=off -o primarycache=metadata                                "${_ds}/var/log"
+    zfs create ${_zfsopts} -o exec=off -o setuid=off -o atime=on                                             "${_ds}/var/mail"
+    zfs create ${_zfsopts} -o sync=disabled -o exec=off -o setuid=off -o compression=off -o primarycache=all "${_ds}/var/run"
+    zfs create ${_zfsopts} -o sync=disabled -o setuid=off                                                    "${_ds}/var/tmp"
+}
+
+
+#
+# "populate" -- populate the datasets with content from a FreeBSD base.txz
+#
+# command_populate mountpoint basetxz
+#
+command_populate() {
+    # MOUNTPOINT -- base.txz
+    local _mp _basetxz
+
+    _mp="$1"
+    _basetxz="$2"
+
+    if [ -z "${_mp}" ]; then
+        echo "ERROR: no mountpoint given" >&2
+        return 2
+    fi
+    if [ -z "${_basetxz}" ]; then
+        echo "ERROR: no base.txz given" >&2
+        return 2
+    fi
+    if [ ! -d "${_mp}" ]; then
+        echo "ERROR: mountpoint \`${_mp}' does not exist" >&2
+        return 1
+    fi
+    if [ ! -r "${_basetxz}" ]; then
+        echo "ERROR: file \`${_basetxz}' is not readable" >&2
+        return 1
+    fi
+
+    tar -C "${_mp}" --exclude=./var/empty -xJp -f "${_basetxz}" || { echo "ERROR: tar encountered errors" >&2; return 1; }
+}
+
+
+#
+# "copy" -- ZFS copy of datasets
+#
+# command_copy source-dataset destination-dataset
+#
+command_copy() {
+    # source dataset -- destination dataset
+    local _source _dest
+    # dynamic ZFS options
+    local _zfsopts
+
+    _zfsopts=""
+    while getopts "u" _opt ; do
+        case ${_opt} in
+            u)
+                # do not mount newly created datasets
+                _zfsopts="${_zfsopts} -u"
+                ;;
+            \?|:)
+                return 2;
+                ;;
+        esac
+    done
+    shift $((OPTIND-1))
+    OPTIND=1
+
+    _source="$1"
+    if [ -z "${_source}" ]; then
+        echo "ERROR: no source dataset given" >&2
+        return 2
+    fi
+    _dest="$2"
+    if [ -z "${_dest}" ]; then
+        echo "ERROR: no source dataset given" >&2
+        return 2
+    fi
+    zfs send -R -n -v ${_source} || { echo "ERROR: ZFS operation failed in no-op mode" >&2; return 1; }
+    zfs send -R "${_source}" | zfs receive ${_zfsopts} "${_dest}"  || { echo "ERROR: ZFS operation failed" >&2; return 1; }
+}
+
+
+#
+# "privs" -- adjust privileges
+#
+# To be used when all ZFS datasets are mounted.
+#
+command_privs() {
+    # mountpoint
+    local _mp _d
+
+    _mp="$1"
+    if [ -z "${_mp}" ]; then
+        echo "ERROR: no mountpoint given" >&2
+        return 2
+    fi
+    if [ ! -d "${_mp}" ]; then
+        echo "ERROR: directory \`${_mp}' does not exist" >&2
+        return 1
+    fi
+    for _d in tmp var/tmp ; do
+       chmod 01777 "${_mp}/${_d}"
+    done
+    chown root:mail "${_mp}/var/mail"
+    chmod 0775 "${_mp}/var/mail"
+}
+
+
+#
+# Global option handling
+#
+while getopts "Vh" _opt ; do
+    case ${_opt} in
+        V)
+            echo "fjail v${VERSION} (rv:@@HGREVISION@@)"
+            exit 0
+            ;;
+        h)
+            echo "${USAGE}"
+            exit 0
+            ;;
+        \?)
+            exit 2;
+            ;;
+        *)
+            echo "ERROR: option handling failed" >&2
+            exit 2
+            ;;
+    esac
+done
+
+#
+# Reset the Shell's option handling system to prepare for handling
+# command-local options.
+#
+shift $((OPTIND-1))
+OPTIND=1
+
+test $# -gt 0 || { echo "ERROR: no command given" >&2; exit 2; }
+
+command="$1"
+shift
+
+case "${command}" in
+    datasets)
+        command_datasets "$@"
+        ;;
+    privs)
+        command_privs "$@"
+        ;;
+    populate)
+        command_populate "$@"
+        ;;
+    copy)
+        command_copy "$@"
+        ;;
+    *)
+        echo "ERROR: unknown command \`${command}'" >&2
+        exit 2
+        ;;
+esac
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sbin/fpkg	Thu Oct 17 09:09:13 2019 +0200
@@ -0,0 +1,293 @@
+#!/bin/sh
+# -*- indent-tabs-mode: nil; -*-
+: 'A pkg frontend for common operations that also operates in all
+running jails.
+
+:Author:    Franz Glasner
+:Copyright: (c) 2019 Franz Glasner.
+            All rights reserved.
+:License:   BSD 3-Clause "New" or "Revised" License.
+            See LICENSE for details.
+            If you cannot find LICENSE see
+            <https://opensource.org/licenses/BSD-3-Clause>
+:ID:        @(#)@@PKGORIGIN@@ $HGid$
+
+'
+
+VERSION="@@VERSION@@"
+
+USAGE='
+USAGE: fpkg [ OPTIONS] COMMAND [ COMMAND-OPTIONS ]
+
+OPTIONS:
+
+  -V    Print the program name and version number to stdout and exit
+
+  -h    Print this help message to stdout and exit
+
+COMMANDS:
+
+  audit
+
+    `pkg audit` on the local host and all running visible jails
+
+  update
+
+    `pkg update` on the local host and all running visible jails
+
+  upgrade
+
+    `pkg upgrade` on the local host and all running visible jails
+
+  upgrade-check
+
+    `pkg upgrade -n` on the local host and all running visible jails
+
+  check-fast-track
+    Check packages installed from the LocalBSDPorts repository against
+    the repositories `FreeBSD` and `LocalBSDPorts` on the local host
+    and all visible jails
+     
+
+ENVIRONMENT:
+
+  FPKG_AUDIT_FLAGS
+                 Additional flags given to `pkg audit`
+                 (Default: -Fr)
+
+  FPKG_UPDATE_FLAGS
+                 Additional flags given to `pkg update`
+                 (Default: empty)
+
+  FPKG_UPGRADE_FLAGS
+                 Additional flags given to `pkg upgrade` and `pkg upgrade -n`
+                 (Default: empty)
+
+  FPKG_SIGN
+                 Marker for the begin of an output group (local host or jail)
+                 (Default: "===> ")
+
+  FPKG_SKIPSIGN
+                 Marker for the begin of a skipped output group
+                 (Default: "----> ")
+
+  All other environment variables that affect `pkg` are effective also.
+'
+
+#
+# Configuration directory
+#
+: ${CONFIGDIR:=@@ETCDIR@@}
+
+test -r "${CONFIGDIR}/tools.conf" && . "${CONFIGDIR}/tools.conf"
+
+: ${FPKG_AUDIT_FLAGS:=-Fr}
+: ${FPKG_UPDATE_FLAGS:=}
+: ${FPKG_UPGRADE_FLAGS:=}
+: ${FPKG_SIGN:='===> '}
+: ${FPKG_SKIPSIGN:='----> '}
+
+#
+# The official FreeBSD binary repository
+#
+: ${FREEBSD_REPO:=FreeBSD}
+
+#
+# Local repository with ports with default OPTIONS (i.e. unchanged)
+# but newer than the packages in the "FreeBSD" repository.
+# Some sort of a fast-track repository.
+#
+: ${LOCALBSDPORTS_REPO:=LocalBSDPorts}
+
+
+has_same_userland_version() {
+    : 'Check whether the jail `_jail` has the same FreeBSD userland version
+    as the host the the current process runs.
+
+    Args:
+        _jail: the running jail to check for
+
+    Returns:
+        0 if the userland versions match, 1 otherwise
+
+    '
+    local _jail _host_version _jail_version
+
+    _jail="$1"
+
+    _host_version=$(/bin/freebsd-version -u) || exit 1
+    _jail_version=$(jexec -l "${_jail}" /bin/freebsd-version -u) || exit 1
+    if [ "${_host_version%%-*}" = "${_jail_version%%-*}" ]; then
+        return 0
+    fi
+    return 1
+}
+
+
+command_audit() {
+    : 'Do a local `pkg audit -Fr` and also for all running jails
+
+    '
+    echo "${FPKG_SIGN}LOCALHOST"
+    pkg audit ${FPKG_AUDIT_FLAGS}
+    for _j in $(jls -N | awk '{if(NR>1)print $1}' | sort); do
+        echo ""
+        echo "${FPKG_SIGN}JAIL: ${_j}"
+        if has_same_userland_version "${_j}"; then
+            pkg -j "${_j}" audit ${FPKG_AUDIT_FLAGS}
+        else
+            echo "${FPKG_SKIPSIGN}SKIPPED because of different userland"
+        fi
+    done
+}
+
+
+command_update() {
+    : 'Do a local `pkg update` and also for all running jails
+
+    '
+    echo "${FPKG_SIGN}LOCALHOST"
+    pkg update ${FPKG_UPDATE_FLAGS}
+    for _j in $(jls -N | awk '{if(NR>1)print $1}' | sort); do
+        echo ""
+        echo "${FPKG_SIGN}JAIL: ${_j}"
+        if has_same_userland_version "${_j}"; then
+            pkg -j "${_j}" update ${FPKG_UPDATE_FLAGS}
+        else
+            echo "${FPKG_SKIPSIGN}SKIPPED because of different userland"
+        fi
+    done
+}
+
+
+command_upgrade() {
+    : 'Do a local `pkg upgrade` and also for all running jails
+
+    '
+    echo "${FPKG_SIGN}LOCALHOST"
+    pkg upgrade ${FPKG_UPGRADE_FLAGS}
+    for _j in $(jls -N | awk '{if(NR>1)print $1}' | sort); do
+        echo ""
+        echo "${FPKG_SIGN}JAIL: ${_j}"
+        if has_same_userland_version "${_j}"; then
+            pkg -j "${_j}" upgrade ${FPKG_UPGRADE_FLAGS}
+        else
+            echo "${FPKG_SKIPSIGN}SKIPPED because of different userland"
+        fi
+    done
+}
+
+
+command_upgrade_check() {
+    : 'Do a local `pkg upgrade -n` and also for all running jails
+
+    '
+    echo "${FPKG_SIGN}LOCALHOST"
+    pkg upgrade -n ${FPKG_UPGRADE_FLAGS}
+    for _j in $(jls -N | awk '{if(NR>1)print $1}' | sort); do
+        echo ""
+        echo "${FPKG_SIGN}JAIL: ${_j}"
+        if has_same_userland_version "${_j}"; then
+            pkg -j "${_j}" upgrade -n ${FPKG_UPGRADE_FLAGS}
+        else
+            echo "${FPKG_SKIPSIGN}SKIPPED because of different userland"
+        fi
+    done
+}
+
+
+command_check_fasttrack() {
+    : 'Check the fast-track repository versions against the canonical
+    FreeBSD repository versions.
+
+    Input (Globals):
+        FREEBSD_REPO:       the (canonical) FreeBSD repository name
+        LOCALBSDPORTS_REPO: the fast-track repository name
+
+    '
+    local _name local _repo _j
+
+    echo "${FPKG_SIGN}LOCALHOST"
+    pkg query '%n %R' |
+        while read _name _repo; do
+            if [ "${_repo}" = "${LOCALBSDPORTS_REPO}" ]; then
+                echo "   ${_name}"
+                printf "      %-15s : %s\n" "${LOCALBSDPORTS_REPO}" "$(pkg version -U -r ${LOCALBSDPORTS_REPO} -n ${_name} -v)"
+                printf "      %-15s : %s\n" "${FREEBSD_REPO}" "$(pkg version -U -r ${FREEBSD_REPO} -n ${_name} -v)"
+            fi
+        done
+    for _j in $(jls -N | awk '{if(NR>1)print $1}' | sort); do
+        echo ""
+        echo "${FPKG_SIGN}JAIL: ${_j}"
+        if has_same_userland_version "${_j}"; then
+            pkg -j "${_j}" query '%n %R' |
+                while read _name _repo; do
+                    if [ "${_repo}" = "${LOCALBSDPORTS_REPO}" ]; then
+                        echo "   ${_name}"
+                        printf "      %s-15s : %s\n" "${LOCALBSDPORTS_REPO}" "$(pkg -j ${_j} version -U -r ${LOCALBSDPORTS_REPO} -n ${_name} -v)"
+                        printf "      %-15s : %s\n" "${FREEBSD_REPO}" "$(pkg -j ${_j} version -U -r ${FREEBSD_REPO} -n ${_name} -v)"
+            fi
+                done
+        else
+            echo "${FPKG_SKIPSIGN}SKIPPED because of different userland"
+        fi
+    done
+}
+
+
+#
+# Global option handling
+#
+while getopts "Vh" _opt ; do
+    case ${_opt} in
+        V)
+            echo "fpkg v${VERSION} (rv:@@HGREVISION@@)"
+            exit 0
+            ;;
+        h)
+            echo "${USAGE}"
+            exit 0
+            ;;
+        \?)
+            exit 2;
+            ;;
+        *)
+            echo "ERROR: option handling failed" >&2
+            exit 2
+            ;;
+    esac
+done
+
+#
+# Reset the Shell's option handling system to prepare for handling
+# command-local options.
+#
+shift $((OPTIND-1))
+OPTIND=1
+
+command="$1"
+shift
+
+test -n "$command" || { echo "ERROR: no command given" >&2; exit 2; }
+
+case "${command}" in
+    audit)
+        command_audit "$@"
+        ;;
+    update)
+        command_update "$@"
+        ;;
+    upgrade)
+        command_upgrade "$@"
+        ;;
+    upgrade-check|upgrade_check)
+        command_upgrade_check "$@"
+        ;;
+    check-fast-track|check-fasttrack|check_fast_track|check_fasttrack)
+        command_check_fasttrack "$@"
+        ;;
+    *)
+        echo "ERROR: unknown command \`${command}'" >&2
+        exit 2;
+        ;;
+esac