Mercurial > hgrepos > FreeBSD > ports > sysutils > local-bsdtools
view bin/fjail @ 120:5366fb3b222c
Style
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Wed, 16 Oct 2019 00:03:08 +0200 |
| parents | 52523a19797e |
| children |
line wrap: on
line source
#!/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
