Mercurial > hgrepos > FreeBSD > ports > sysutils > local-bsdtools
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
